/* ==========================================================================
   SecureWebX public site — "The Ledger Console, at reading scale"
   --------------------------------------------------------------------------
   The CRM at app.securewebx.com is a precision back-office instrument: hairline
   rules, tabular numerals, one deep green over cool slate, and a dark chrome
   frame around a light workspace. This stylesheet carries that same instrument
   into marketing type sizes. The page rhythm is the app's rhythm: dark
   instrument bands alternating with light ledger pages, everything divided by
   1px rules rather than boxes and shadows.

   Tokens are ported verbatim from /assets/css/app.css so the two properties
   resolve to the same greens, slates, radii and shadows. Marketing-scale type,
   the band system and the ledger components below are additions.
   No build step: this single file is the production stylesheet.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Cool slate ramp (slight blue temperature, not neutral gray) */
  --slate-25:  #fafbfc;
  --slate-50:  #f5f7fa;
  --slate-100: #eef1f5;
  --slate-200: #e2e7ee;
  --slate-300: #cbd3df;
  --slate-400: #9aa6b8;
  --slate-500: #6b7889;
  --slate-600: #4d5969;
  --slate-700: #38424f;
  --slate-800: #232c37;
  --slate-900: #151c24;

  /* Brand green */
  --green-50:  #e9f6ef;
  --green-100: #c9ead8;
  --green-200: #94d6b3;
  --green-400: #34a96c;
  --green-500: #1f8f57;
  --green-600: #197a49;
  --green-700: #13603a;

  --info-50:  #e8f1fc;  --info-500:  #2563c9;  --info-700:  #1b4894;
  --warn-50:  #fdf3e2;  --warn-500:  #b9740a;  --warn-700:  #8a560a;
  --violet-50:#f0ecfb;  --violet-500:#6d44c9;  --violet-700:#52329a;

  /* Semantic — light page */
  --bg:            #ffffff;
  --surface:       #ffffff;
  --surface-2:     var(--slate-25);
  --surface-3:     var(--slate-50);
  --border:        var(--slate-200);
  --border-strong: var(--slate-300);
  --hair:          #e6eaf0;
  --text:          var(--slate-900);
  --text-soft:     var(--slate-600);
  --text-muted:    #616d7c;
  --accent:        var(--green-500);
  --accent-hover:  var(--green-600);
  --accent-quiet:  var(--green-50);

  /* Semantic — dark instrument band. Deeper than the app chrome so the
     marketing hero reads as the instrument's case, and the app chrome
     (#0e1116) reads as the screen inside it. */
  --ink:           #090c10;
  --ink-2:         #0e1116;
  --ink-3:         #141922;
  --ink-hair:      rgba(255,255,255,.075);
  --ink-hair-2:    rgba(255,255,255,.13);
  --ink-surface:   rgba(255,255,255,.035);
  --ink-text:      #f4f6f8;
  --ink-soft:      rgba(244,246,248,.66);
  --ink-mute:      rgba(244,246,248,.56);
  --ink-green:     #7fe0aa;
  --ink-green-2:   #34a96c;
  --ink-glow:      rgba(31,143,87,.30);

  /* Type */
  --font-sans: 'Geist', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --font-mono: 'Geist Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

  --fs-micro: 0.6875rem;  /* 11 — mono micro-caps */
  --fs-xs:    0.75rem;    /* 12 */
  --fs-sm:    0.875rem;   /* 14 */
  --fs-base:  1rem;       /* 16 */
  --fs-md:    1.0625rem;  /* 17 — body reading size */
  --fs-lg:    1.1875rem;  /* 19 */
  --fs-xl:    1.375rem;   /* 22 */

  /* Spacing */
  --sp-1: .25rem; --sp-2: .5rem;  --sp-3: .75rem; --sp-4: 1rem;
  --sp-5: 1.5rem; --sp-6: 2rem;   --sp-7: 2.5rem; --sp-8: 3rem;
  --sp-10: 4rem;  --sp-12: 5.5rem; --sp-14: 7rem;

  --r-sm: 6px; --r-md: 9px; --r-lg: 12px; --r-xl: 16px; --r-full: 999px;

  --shadow-xs: 0 1px 2px rgba(21,28,36,.05);
  --shadow-sm: 0 1px 3px rgba(21,28,36,.07), 0 1px 2px rgba(21,28,36,.04);
  --shadow-md: 0 4px 12px rgba(21,28,36,.08), 0 2px 4px rgba(21,28,36,.04);
  --shadow-lg: 0 12px 32px rgba(21,28,36,.14);

  --nav-h: 68px;
  --gutter: 24px;
  --maxw: 1160px;
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 16px);
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body {
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  line-height: 1.6;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
img, svg, video { max-width: 100%; display: block; }
button { font: inherit; color: inherit; }
/* Inline link colour is one step down the green ramp from --accent for the
   same reason the primary button is: 4.1:1 against white is under AA. */
a { color: var(--green-600); text-decoration: none; }
a:hover { color: var(--green-700); text-decoration: underline; }
ul, ol { margin: 0; padding: 0; list-style: none; }
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}
.band-dark :where(a, button, input, select, textarea, summary):focus-visible { outline-color: var(--ink-green); }

/* Screen-reader-only text. Defined here because this stylesheet is standalone;
   nothing on the public site may assume the app's app.css is present. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 200;
  background: var(--green-600); color: #fff; padding: 10px 16px; border-radius: var(--r-md);
  font-size: var(--fs-sm); font-weight: 600; transition: top .15s ease;
}
.skip-link:focus { top: 12px; text-decoration: none; }

/* --------------------------------------------------------------------------
   3. Type scale
   -------------------------------------------------------------------------- */
h1, h2, h3, h4 { font-weight: 600; color: var(--text); letter-spacing: -0.022em; line-height: 1.14; }
/* The stylesheet only ever asks for 500 and 600, but <strong> and <b> default
   to 700, which would drag a fourth Geist file onto every first paint for
   inline emphasis alone. 600 next to a 400 body still reads clearly as
   emphasis and matches the heading weight, so the family ships as 400/500/600.
   If you ever set font-weight:700 anywhere, add it back to the font request in
   layout.php or the browser will synthesise a fake bold. */
strong, b { font-weight: 600; }
/* Same reasoning for the mono face: pinning it to 500 means Geist Mono ships as
   two weights instead of three. */
.mono { font-weight: 500; }

.display {
  font-size: clamp(2.35rem, 5.4vw, 3.9rem);
  line-height: 1.03;
  letter-spacing: -0.038em;
  font-weight: 600;
}
.display-sm {
  font-size: clamp(2rem, 4.4vw, 3rem);
  line-height: 1.06;
  letter-spacing: -0.034em;
  font-weight: 600;
}
.h2 {
  font-size: clamp(1.65rem, 3vw, 2.35rem);
  line-height: 1.1;
  letter-spacing: -0.03em;
  font-weight: 600;
}

.lead {
  font-size: clamp(1.0625rem, 1.5vw, 1.1875rem);
  line-height: 1.62;
  color: var(--text-soft);
}
.band-dark .lead { color: var(--ink-soft); }

.prose p { color: var(--text-soft); }
.prose p + p { margin-top: var(--sp-4); }

/* Mono micro-caps — the ledger's label voice. Used for eyebrows, column
   headings, section indices and any label that is data about the content
   rather than the content itself. */
.mcap {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: .14em;
  color: var(--text-muted);
}
.band-dark .mcap { color: var(--ink-mute); }
.mcap-accent { color: var(--green-600); }
.band-dark .mcap-accent { color: var(--ink-green); }

.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-weight: 500; }

/* --------------------------------------------------------------------------
   4. Layout: bands, container, rules
   -------------------------------------------------------------------------- */
.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 var(--gutter); }
.wrap-narrow { max-width: 800px; }

.band { position: relative; }
.band-pad    { padding: var(--sp-12) 0; }
.band-pad-sm { padding: var(--sp-10) 0; }

.band-light  { background: var(--bg); }
.band-paper > *:not(.band-media):not(.band-scrim) { position: relative; z-index: 2; }
.band-tint   { background: var(--surface-3); }
.band-rule   { border-top: 1px solid var(--hair); }

/* The dark instrument band: near-black case, a single green glow, and a faint
   graph-paper grid masked to fade at the edges. This is the same glow the app's
   sidebar and auth screens use, scaled up. */
.band-dark {
  background: var(--ink);
  color: var(--ink-text);
  overflow: hidden;
}
.band-dark h1, .band-dark h2, .band-dark h3, .band-dark h4 { color: var(--ink-text); }
.band-dark .prose p { color: var(--ink-soft); }
.band-dark::before {
  content: "";
  position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background-image:
    linear-gradient(to right,  rgba(255,255,255,.030) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255,255,255,.030) 1px, transparent 1px);
  background-size: 76px 76px;
  -webkit-mask-image: radial-gradient(ellipse 100% 76% at 50% 26%, #000 0%, transparent 78%);
          mask-image: radial-gradient(ellipse 100% 76% at 50% 26%, #000 0%, transparent 78%);
}
.band-dark::after {
  content: "";
  position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background-image: radial-gradient(900px 620px at 18% -12%, var(--ink-glow), transparent 68%);
}
.band-dark > *:not(.band-media):not(.band-scrim) { position: relative; z-index: 3; }
.band-dark.no-grid::before { display: none; }

/* Section head — mono index, rule, title, optional lead. */
.sec-head { max-width: 720px; margin-bottom: var(--sp-8); }
.sec-head .sec-index {
  display: flex; align-items: center; gap: var(--sp-3);
  margin-bottom: var(--sp-4);
}
.sec-head .sec-index::after {
  content: ""; flex: 1; height: 1px; background: var(--hair); min-width: 24px;
}
.band-dark .sec-head .sec-index::after { background: var(--ink-hair); }
.sec-head .lead { margin-top: var(--sp-4); }
.sec-head-wide { max-width: 880px; }
.sec-head-center { margin-left: auto; margin-right: auto; text-align: center; }
.sec-head-center .sec-index { justify-content: center; }
.sec-head-center .sec-index::before,
.sec-head-center .sec-index::after { content: ""; flex: 1; height: 1px; background: var(--hair); min-width: 24px; }
.band-dark .sec-head-center .sec-index::before { background: var(--ink-hair); }

/* --------------------------------------------------------------------------
   5. Buttons — same geometry as the app, one size up for reading scale
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  height: 46px; padding: 0 var(--sp-5);
  border: 1px solid transparent; border-radius: var(--r-md);
  font-size: var(--fs-base); font-weight: 600; letter-spacing: -0.005em;
  cursor: pointer; white-space: nowrap; text-decoration: none;
  transition: background .14s ease, border-color .14s ease, color .14s ease, transform .05s ease, box-shadow .14s ease;
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn .ico { width: 17px; height: 17px; flex: none; }
.btn-primary { background: var(--green-600); color: #fff; box-shadow: var(--shadow-xs); }
/* Hover inverts to the palest green with the deepest green text: 6.6:1, and it
   reads as lighter, which is what a hover should do. Going one step DOWN the
   green ramp (the previous behaviour) made the button darker on hover and the
   label harder to read, and no brighter green can carry white text at AA. */
.btn-primary:hover { background: var(--green-50); color: var(--green-700); border-color: var(--green-100); }
.btn-secondary { background: var(--surface); color: var(--text); border-color: var(--border-strong); }
.btn-secondary:hover { background: var(--slate-50); border-color: var(--slate-400); }
.btn-sm { height: 38px; padding: 0 var(--sp-4); font-size: var(--fs-sm); }
.btn-lg { height: 52px; padding: 0 var(--sp-6); font-size: var(--fs-md); }
.btn-block { width: 100%; }

/* On the dark band the outline button is a hairline in the case metal. */
.band-dark .btn-secondary,
.btn-outline-dark {
  background: var(--ink-surface); color: var(--ink-text);
  border-color: var(--ink-hair-2);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
}
.band-dark .btn-secondary:hover,
.btn-outline-dark:hover { background: rgba(255,255,255,.075); border-color: rgba(255,255,255,.22); color: var(--ink-text); }

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

/* Arrow link — the quiet tertiary action. The arrow slides on hover. */
.arrow-link {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-base); font-weight: 600; color: var(--green-600);
}
.arrow-link svg { width: 16px; height: 16px; transition: transform .16s ease; }
.arrow-link:hover { text-decoration: none; color: var(--green-700); }
.arrow-link:hover svg { transform: translateX(3px); }
.band-dark .arrow-link { color: var(--ink-green); }
.band-dark .arrow-link:hover { color: #a7ecc6; }

/* --------------------------------------------------------------------------
   6. Navigation

   The bar is dark on every page and in every state, and the mark is always the
   white one. The app does the same thing: a dark topbar over a light
   workspace. The earlier version swapped to the black mark once the page
   scrolled, which put a black logo on the dark scrolled bar and made it vanish.
   There is now no state in which the dark mark is used.
   -------------------------------------------------------------------------- */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  height: var(--nav-h);
  display: flex; align-items: center;
  color: var(--ink-text);
  border-bottom: 1px solid transparent;
  transition: background .22s ease, border-color .22s ease, backdrop-filter .22s ease;
}
/* Over a dark hero the bar starts invisible so the photograph runs to the top
   of the window, and only takes on its own surface once the page moves. */
.nav-over-dark { background: transparent; }
/* Pages that open on a light band carry the surface from the first frame,
   otherwise a white mark would sit on a white hero. */
.nav-solid, .nav.is-stuck {
  background: rgba(9, 12, 16, .88);
  backdrop-filter: saturate(160%) blur(18px);
  -webkit-backdrop-filter: saturate(160%) blur(18px);
  border-bottom-color: var(--ink-hair);
}
.nav-inner { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 var(--gutter); display: flex; align-items: center; gap: var(--sp-5); }
.nav-brand { display: flex; align-items: center; flex: none; }
.nav-brand:hover { text-decoration: none; }
/* Only the height is set. A second fixed dimension would squash the mark;
   width:auto keeps the 1044x291 ratio at any size. */
.nav-logo { height: 40px; width: auto; }

.nav-links { display: flex; align-items: center; gap: var(--sp-1); margin-left: var(--sp-4); flex: 1; min-width: 0; }
.nav-link {
  display: inline-flex; align-items: center; height: 36px; padding: 0 var(--sp-3);
  border-radius: var(--r-md);
  font-size: var(--fs-sm); font-weight: 500; color: var(--ink-text); opacity: .74;
  transition: opacity .14s ease, background .14s ease;
  white-space: nowrap;
}
/* Hover has to read as a lift, not a smudge. At .08 over a green-tinted dark
   band the plate looked like a darker green patch, which is the opposite of
   what a hover should say. .16 plus full-strength text is unmistakable. */
.nav-link:hover { opacity: 1; text-decoration: none; background: rgba(255,255,255,.16); color: #fff; }
.nav-link.is-active { opacity: 1; font-weight: 600; }
.nav-actions { display: flex; align-items: center; gap: var(--sp-2); flex: none; }
.nav-signin {
  display: inline-flex; align-items: center; gap: 6px; height: 38px; padding: 0 var(--sp-3);
  border-radius: var(--r-md); font-size: var(--fs-sm); font-weight: 600; color: var(--ink-text); opacity: .78;
}
.nav-signin:hover { opacity: 1; text-decoration: none; background: rgba(255,255,255,.16); color: #fff; }
.nav-signin svg { width: 15px; height: 15px; }
.nav .btn-primary { background: var(--green-600); }
.nav .btn-primary:hover { background: var(--green-50); color: var(--green-700); }

.nav-toggle {
  display: none; align-items: center; justify-content: center;
  width: 40px; height: 40px; border: 1px solid rgba(255,255,255,.24); border-radius: var(--r-md);
  background: transparent; color: var(--ink-text); cursor: pointer; opacity: .8;
}
.nav-toggle:hover { opacity: 1; background: rgba(255,255,255,.07); }
.nav-toggle svg { width: 20px; height: 20px; }

/* Mobile drawer */
.nav-drawer {
  position: fixed; inset: var(--nav-h) 0 0 0; z-index: 99;
  background: var(--ink);
  padding: var(--sp-5) var(--gutter) var(--sp-8);
  display: flex; flex-direction: column; gap: var(--sp-1);
  overflow-y: auto;
  transform: translateY(-8px); opacity: 0; pointer-events: none; visibility: hidden;
  transition: opacity .18s ease, transform .18s ease, visibility 0s linear .18s;
}
/* visibility, not just opacity. With opacity:0 alone every link in the closed
   drawer stays keyboard-focusable, so a Tab from the logo walks a sighted
   keyboard user through six invisible links before reaching the page. Delaying
   the visibility change until the fade finishes keeps the close animation. */
.nav-drawer[data-open="1"] { transform: none; opacity: 1; pointer-events: auto; visibility: visible; transition-delay: 0s; }
/* Direct children only. Unscoped, `.nav-drawer a` also caught the store badge
   links, and `.nav-drawer a svg { width:16px }` outranked `.store-badge
   { width:auto }` on specificity, which rendered a 42px-tall badge 16px wide.
   A squashed badge is worse than no badge, and it is vendor artwork besides. */
.nav-drawer > a {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--sp-4) 0; border-bottom: 1px solid var(--ink-hair);
  color: var(--ink-text); font-size: var(--fs-lg); font-weight: 500; letter-spacing: -0.015em;
}
.nav-drawer > a:hover { text-decoration: none; color: var(--ink-green); }
.nav-drawer > a svg { width: 16px; height: 16px; opacity: .4; }
.nav-drawer .drawer-actions { margin-top: var(--sp-6); display: flex; flex-direction: column; gap: var(--sp-3); }
.nav-drawer .drawer-actions a { justify-content: center; }

body.nav-open { overflow: hidden; }

.page-body { padding-top: var(--nav-h); }
.page-body.hero-flush { padding-top: 0; }

/* --------------------------------------------------------------------------
   7. Photographic bands

   Photography sits on its own element rather than on a background shorthand,
   so the stack is explicit and each layer can be tuned on its own:

     .band-media  the graded photograph
     .band-scrim  the gradient that buys the type its contrast
     ::before     the graph-paper grid (dark bands)
     ::after      the green glow (dark bands)
     content      z-index 1, above all of it

   The photographs are graded on the server (desaturated, pulled down, and
   colorised toward the ink green) rather than with a CSS filter, because a
   filter on a full-bleed layer is repainted on every scroll frame.
   -------------------------------------------------------------------------- */
/* No overflow:hidden here: both layers are absolutely positioned to the band's
   own box and cannot spill, and clipping would break the position:sticky page
   index that lives inside two of these sections. */
.band-photo { position: relative; }
.band-media {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-size: cover; background-position: center;
  background-repeat: no-repeat;
}
.band-scrim { position: absolute; inset: 0; z-index: 1; pointer-events: none; }

/* Dark band scrim: opaque where the copy sits, thinning across so the picture
   is actually visible on the far side instead of being a rumour. */
.band-dark .band-scrim {
  background-image:
    linear-gradient(97deg, var(--ink) 0%, rgba(9,12,16,.95) 30%, rgba(9,12,16,.66) 58%, rgba(9,12,16,.86) 100%),
    linear-gradient(to bottom, rgba(9,12,16,.75) 0%, transparent 26%, transparent 62%, rgba(9,12,16,.9) 100%);
}
/* Centred variant for the closing bands, where the copy is centred and the
   photograph should read as a wash behind it rather than a side panel. */
.hero .band-scrim {
  background-image:
    linear-gradient(to bottom, rgba(9,12,16,.97) 0%, rgba(9,12,16,.58) 28%, rgba(9,12,16,.54) 66%, rgba(9,12,16,.90) 100%),
    linear-gradient(104deg, rgba(9,12,16,.50) 0%, rgba(9,12,16,.22) 34%, rgba(9,12,16,.58) 54%, rgba(9,12,16,.90) 72%, rgba(9,12,16,.93) 100%);
}
.band-dark.scrim-center .band-scrim {
  background-image:
    radial-gradient(115% 130% at 50% 50%, rgba(9,12,16,.82) 0%, rgba(9,12,16,.93) 46%, var(--ink) 82%),
    linear-gradient(to bottom, rgba(9,12,16,.8), transparent 22%, transparent 74%, rgba(9,12,16,.95));
}
/* Quiet variant: the picture is a texture under a dense block of content. */
.band-dark.scrim-deep .band-scrim {
  background-image:
    linear-gradient(to right, var(--ink) 0%, rgba(9,12,16,.96) 44%, rgba(9,12,16,.84) 100%),
    linear-gradient(to bottom, rgba(9,12,16,.7), transparent 30%, transparent 70%, rgba(9,12,16,.92));
}

/* Light bands take the paper treatment: a near-white frame at a few percent,
   feathered so it never competes with text. */
.band-paper .band-media { opacity: .105; }
.band-paper.band-tint .band-media { opacity: .13; }
.band-paper .band-scrim {
  background-image:
    linear-gradient(to bottom, var(--bg) 0%, rgba(255,255,255,.55) 18%, rgba(255,255,255,.55) 78%, var(--bg) 100%);
}
.band-paper.band-tint .band-scrim {
  background-image:
    linear-gradient(to bottom, var(--surface-3) 0%, rgba(245,247,250,.5) 20%, rgba(245,247,250,.5) 76%, var(--surface-3) 100%);
}
/* Paper on the right only, for split sections where the copy runs down the left. */
.band-paper.paper-right .band-scrim {
  background-image:
    linear-gradient(to right, var(--bg) 0%, rgba(255,255,255,.86) 40%, rgba(255,255,255,.45) 100%),
    linear-gradient(to bottom, var(--bg), transparent 16%, transparent 84%, var(--bg));
}

/* Named frames. Declared as classes rather than inline custom properties so the
   Content Security Policy can keep style-src without 'unsafe-inline'. The -sm
   files are the same frame at 900px for phones. */
.ph-showroom   .band-media { background-image: url('/www/site/img/hero-showroom.jpg?v=20260822b'); background-position: 26% 74%; }
.ph-fibre      .band-media { background-image: url('/www/site/img/band-fibre.jpg?v=20260822b'); }
.ph-handover   .band-media { background-image: url('/www/site/img/band-handover.jpg?v=20260822b'); }
.ph-datacenter .band-media { background-image: url('/www/site/img/band-datacenter.jpg?v=20260822b'); }
.ph-signing    .band-media { background-image: url('/www/site/img/head-signing.jpg?v=20260822b'); }
.ph-lot        .band-media { background-image: url('/www/site/img/head-lot.jpg?v=20260822b'); }
.ph-district   .band-media { background-image: url('/www/site/img/head-district.jpg?v=20260822b'); background-position: 50% 22%; }
.ph-sacramento .band-media { background-image: url('/www/site/img/head-sacramento.jpg?v=20260822b'); }
.ph-floor      .band-media { background-image: url('/www/site/img/head-floor.jpg?v=20260905'); background-position: 62% 50%; }
.pp-showroom   .band-media { background-image: url('/www/site/img/paper-showroom.jpg?v=20260822b'); }
.pp-desk       .band-media { background-image: url('/www/site/img/paper-desk.jpg?v=20260822b'); }
.pp-lineup     .band-media { background-image: url('/www/site/img/paper-lineup.jpg?v=20260822b'); }
.pp-tower      .band-media { background-image: url('/www/site/img/paper-tower.jpg?v=20260822b'); }

@media (max-width: 900px) {
  /* A landscape night shot cropped to a portrait viewport shows a narrow
     vertical slice, and at the desktop framing that slice was the dark sky.
     Re-aimed at the lit facade, and the phone file is graded a stop brighter
     because there is far less of it on screen. */
  .ph-showroom   .band-media { background-image: url('/www/site/img/hero-showroom-sm.jpg?v=20260822b'); background-position: 44% 54%; }
  .ph-fibre      .band-media { background-image: url('/www/site/img/band-fibre-sm.jpg?v=20260822b'); }
  .ph-handover   .band-media { background-image: url('/www/site/img/band-handover-sm.jpg?v=20260822b'); }
  .ph-datacenter .band-media { background-image: url('/www/site/img/band-datacenter-sm.jpg?v=20260822b'); }
  .ph-signing    .band-media { background-image: url('/www/site/img/head-signing-sm.jpg?v=20260822b'); }
  .ph-lot        .band-media { background-image: url('/www/site/img/head-lot-sm.jpg?v=20260822b'); }
  .ph-district   .band-media { background-image: url('/www/site/img/head-district-sm.jpg?v=20260822b'); }
  .ph-sacramento .band-media { background-image: url('/www/site/img/head-sacramento-sm.jpg?v=20260822b'); }
  .ph-floor      .band-media { background-image: url('/www/site/img/head-floor-sm.jpg?v=20260905'); background-position: 58% 50%; }
  .pp-showroom   .band-media { background-image: url('/www/site/img/paper-showroom-sm.jpg?v=20260822b'); }
  .pp-desk       .band-media { background-image: url('/www/site/img/paper-desk-sm.jpg?v=20260822b'); }
  .pp-lineup     .band-media { background-image: url('/www/site/img/paper-lineup-sm.jpg?v=20260822b'); }
  .pp-tower      .band-media { background-image: url('/www/site/img/paper-tower-sm.jpg?v=20260822b'); }
  /* On a phone the copy runs the full width, so the side-weighted scrim would
     leave the picture under the last two lines. Straight vertical instead. */
  /* Still a vertical veil, but a lighter one. The first version buried the
     photograph entirely on a phone, which is where most of this traffic reads. */
  .band-dark .band-scrim {
    background-image: linear-gradient(to bottom, rgba(9,12,16,.94) 0%, rgba(9,12,16,.76) 30%, rgba(9,12,16,.80) 66%, rgba(9,12,16,.93) 100%);
  }
  .band-paper .band-scrim, .band-paper.paper-right .band-scrim {
    background-image: linear-gradient(to bottom, var(--bg), rgba(255,255,255,.6) 20%, rgba(255,255,255,.6) 80%, var(--bg));
  }
  .band-paper.band-tint .band-scrim {
    background-image: linear-gradient(to bottom, var(--surface-3), rgba(245,247,250,.55) 20%, rgba(245,247,250,.55) 80%, var(--surface-3));
  }
}

/* --------------------------------------------------------------------------
   8. Hero — the instrument face

   Not a copy column beside a screenshot. The band is read like the front of a
   measuring instrument: a labelled rule across the top, an oversized headline
   set against a deck that hangs off its right shoulder, and a full-width
   readout strip along the bottom carrying a real chain of custody. The strip
   is the thing that makes the page ours: it is the same audit chain the
   application detail page draws, laid out as a status track.
   -------------------------------------------------------------------------- */
/* The band no longer stretches to a full viewport. At 100vh the copy block was
   floated in the middle of a tall empty box and the readout strip was pushed
   off the fold on a laptop. */
.hero { display: flex; flex-direction: column; justify-content: flex-end; min-height: 86vh; min-height: 86svh; }
/* justify-content: flex-start, so the block sits high under the rule instead of
   being centred in whatever height is left over. */
.hero > .wrap { padding-top: calc(var(--nav-h) + var(--sp-7)); padding-bottom: var(--sp-10); flex: 1; display: flex; flex-direction: column; justify-content: flex-start; position: relative; z-index: 3; }

/* Top rule: two mono labels with a hairline stretched between them. */
.hero-rule { display: flex; align-items: center; gap: var(--sp-4); margin-bottom: var(--sp-8); }
.hero-rule .line { flex: 1; height: 1px; background: var(--ink-hair-2); min-width: 20px; }
.hero-rule .mcap { white-space: nowrap; }
.hero-rule .live { display: inline-flex; align-items: center; gap: 8px; }
.hero-rule .live .dot {
  width: 6px; height: 6px; border-radius: var(--r-full); background: var(--ink-green);
  box-shadow: 0 0 0 3px rgba(52,169,108,.18); flex: none;
}

/* Headline left, deck hanging off its right shoulder and pinned to the
   baseline. The asymmetry is the point: it reads as a spread, not a slide. */
.hero-main { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr); gap: var(--sp-8) var(--sp-10); align-items: start; }
.hero-main h1 { max-width: 15ch; }
/* Optical alignment: the deck's rule starts level with the headline's cap
   height rather than its em box, which is a few pixels lower. */
.hero-deck { padding-top: 10px; }
.hero-deck .kicker { width: 46px; height: 2px; background: var(--ink-green); margin-bottom: var(--sp-5); }
.hero-deck .lead { margin-bottom: var(--sp-6); }
.hero-deck .btn-row { margin-bottom: var(--sp-5); }
.hero-note { font-size: var(--fs-sm); color: var(--ink-mute); }
.hero-note strong { color: var(--ink-soft); font-weight: 600; }

/* ---- The readout strip ---------------------------------------------------
   Full-bleed top rule, cells divided by hairlines, and a node dot sitting on
   the rule above each cell. Tabular mono times, so the row scans like an
   instrument rather than like a feature list. */
.custody {
  position: relative; z-index: 3; flex: none;
  border-top: 1px solid var(--ink-hair-2);
  background: rgba(0, 0, 0, .34);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}
.custody-inner { display: grid; grid-template-columns: minmax(0, .66fr) repeat(5, minmax(0, 1fr)); }
.custody-cap { padding: var(--sp-5) var(--sp-5) var(--sp-5) 0; border-right: 1px solid var(--ink-hair); min-width: 0; }
.custody-cap .sid {
  display: block; margin-top: 6px;
  font-family: var(--font-mono); font-size: var(--fs-base); font-weight: 600;
  color: var(--ink-text); letter-spacing: .07em;
}
.custody-cap .badge {
  display: inline-flex; align-items: center; gap: 6px; margin-top: var(--sp-3);
  padding: 4px 10px; border-radius: var(--r-full);
  background: rgba(52,169,108,.16); border: 1px solid rgba(127,224,170,.26);
  color: var(--ink-green); font-size: var(--fs-xs); font-weight: 600;
}
.custody-cap .badge .dot { width: 6px; height: 6px; border-radius: var(--r-full); background: currentColor; }
.custody-step { position: relative; padding: var(--sp-5) var(--sp-4); border-right: 1px solid var(--ink-hair); min-width: 0; }
.custody-step:last-child { border-right: 0; }
/* Node sitting on the strip's own top rule. */
.custody-step::before {
  content: ""; position: absolute; top: -4px; left: var(--sp-4);
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--ink-green); box-shadow: 0 0 0 3px rgba(9,12,16,.9);
}
.custody-step.is-open::before { background: var(--ink); border: 1px solid var(--ink-hair-2); }
.custody-step .ts { display: block; font-family: var(--font-mono); font-size: var(--fs-micro); font-variant-numeric: tabular-nums; color: var(--ink-green); letter-spacing: .08em; }
.custody-step.is-open .ts { color: var(--ink-mute); }
.custody-step .t { display: block; margin-top: 7px; font-size: var(--fs-sm); font-weight: 600; color: var(--ink-text); line-height: 1.3; }
.custody-step .m { display: block; margin-top: 4px; font-size: var(--fs-xs); color: var(--ink-mute); line-height: 1.4; }

@media (max-width: 1100px) {
  .hero-main { grid-template-columns: 1fr; align-items: start; gap: var(--sp-7); }
  .hero-main h1 { max-width: 20ch; }
  .custody-inner { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .custody-cap { grid-column: 1 / -1; border-right: 0; border-bottom: 1px solid var(--ink-hair); padding-right: 0; }
  .custody-step:nth-child(4) { border-right: 0; }
  .custody-step:nth-child(n+5) { border-top: 1px solid var(--ink-hair); }
}
@media (max-width: 680px) {
  .hero { min-height: 0; }
  .hero > .wrap { padding-top: calc(var(--nav-h) + var(--sp-6)); padding-bottom: var(--sp-7); }
  .hero-rule { margin-bottom: var(--sp-6); flex-wrap: wrap; gap: var(--sp-2); }
  .hero-rule .line { display: none; }
  .hero-rule .mcap { white-space: normal; }
  /* One label on a phone. The operator line wrapped this rule onto four
     cramped uppercase lines; the same fact sits in the footer and on
     /company, so the eyebrow keeps only the product label here. */
  .hero-rule > .mcap:not(.live) { display: none; }
  .hero-main h1 { max-width: none; }
  .custody-inner { grid-template-columns: 1fr; }
  /* One line per step on a phone: the rail runs down the left instead of
     across the top, so five entries stay a glance rather than a scroll. */
  .custody-step { border-right: 0; border-top: 1px solid var(--ink-hair); padding: var(--sp-4) 0 var(--sp-4) var(--sp-5); }
  .custody-step::before { top: var(--sp-5); left: 0; }
  .custody-step .ts { position: absolute; right: 0; top: var(--sp-5); }
  .custody-step .t { margin-top: 0; padding-right: 76px; }
  /* Caption, then id and status side by side, so the cap is two lines
     rather than a three-line stack. */
  .custody-cap { padding: var(--sp-4) 0; display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); }
  .custody-cap > .mcap { flex-basis: 100%; }
  .custody-cap .sid { margin-top: 0; }
  .custody-cap .badge { margin-top: 0; }
}

/* --------------------------------------------------------------------------
   9. Spec rail — the mono stat strip. Hairline-divided cells, no boxes.
   -------------------------------------------------------------------------- */
.rail {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  border-top: 1px solid var(--hair);
  border-bottom: 1px solid var(--hair);
}
.band-dark .rail { border-color: var(--ink-hair); }
.rail-cell { padding: var(--sp-6) var(--sp-5); border-left: 1px solid var(--hair); min-width: 0; }
.band-dark .rail-cell { border-color: var(--ink-hair); }
.rail-cell:first-child { border-left: 0; padding-left: 0; }
.rail-cell .figure {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: clamp(1.5rem, 2.6vw, 2rem); font-weight: 500; letter-spacing: -0.03em;
  color: var(--text); line-height: 1.05; margin-bottom: var(--sp-3);
  overflow-wrap: anywhere;
}
.band-dark .rail-cell .figure { color: var(--ink-text); }
.rail-cell .caption { font-size: var(--fs-sm); color: var(--text-muted); line-height: 1.45; }
.band-dark .rail-cell .caption { color: var(--ink-mute); }

/* --------------------------------------------------------------------------
   10. Ledger rows — the editorial list. A full-width ruled row with a mono
   index on the left, title and body in the middle, and a quiet link at the
   right. Replaces the usual card grid; reads like a statement, not a brochure.
   -------------------------------------------------------------------------- */
.ledger-rows { border-top: 1px solid var(--hair); }
.band-dark .ledger-rows { border-color: var(--ink-hair); }
.lrow {
  display: grid;
  grid-template-columns: 64px minmax(0, .78fr) minmax(0, 1.5fr) auto;
  gap: var(--sp-5);
  align-items: start;
  padding: var(--sp-7) 0;
  border-bottom: 1px solid var(--hair);
  position: relative;
}
.band-dark .lrow { border-color: var(--ink-hair); }
.lrow-index { font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--text-muted); padding-top: 3px; font-variant-numeric: tabular-nums; }
.band-dark .lrow-index { color: var(--ink-mute); }
.lrow-title { min-width: 0; }
.lrow-title h3 { font-size: var(--fs-xl); letter-spacing: -0.024em; }
.lrow-title .sub { margin-top: var(--sp-2); font-size: var(--fs-sm); color: var(--text-muted); }
.band-dark .lrow-title .sub { color: var(--ink-mute); }
.lrow-body { min-width: 0; color: var(--text-soft); }
.band-dark .lrow-body { color: var(--ink-soft); }
.lrow-body p + .taglist { margin-top: var(--sp-4); }
.lrow-action { padding-top: 4px; }

/* Inline hairline tag list — capabilities under a row, set in mono micro-caps. */
.taglist { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.tag {
  display: inline-flex; align-items: center;
  padding: 4px 10px; border: 1px solid var(--border); border-radius: var(--r-full);
  font-family: var(--font-mono); font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: .08em;
  color: var(--text-soft); background: var(--surface-2); white-space: nowrap;
}
.band-dark .tag { border-color: var(--ink-hair-2); background: var(--ink-surface); color: var(--ink-soft); }

/* --------------------------------------------------------------------------
   11. Step ledger — the process. A rail across the top with numbered nodes.
   -------------------------------------------------------------------------- */
.steps {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0;
  border-top: 1px solid var(--hair);
}
.band-dark .steps { border-color: var(--ink-hair); }
.step {
  position: relative;
  padding: var(--sp-7) var(--sp-5) var(--sp-7) 0;
  border-right: 1px solid var(--hair);
  min-width: 0;
}
.band-dark .step { border-color: var(--ink-hair); }
.step:nth-child(3n) { border-right: 0; padding-right: 0; }
.step:nth-child(n+4) { border-top: 1px solid var(--hair); }
.band-dark .step:nth-child(n+4) { border-top-color: var(--ink-hair); }
.step-n {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: var(--r-full);
  border: 1px solid var(--border-strong); background: var(--surface);
  font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: 600; color: var(--text-soft);
  margin-bottom: var(--sp-4);
}
.band-dark .step-n { border-color: var(--ink-hair-2); background: var(--ink-2); color: var(--ink-green); }
.step h3 { font-size: var(--fs-lg); margin-bottom: var(--sp-2); letter-spacing: -0.02em; }
.step p { font-size: var(--fs-base); color: var(--text-soft); line-height: 1.58; }
.band-dark .step p { color: var(--ink-soft); }
.step:not(:nth-child(3n))::after {
  /* Connector nub sitting on the node's centre line, pointing to the next step. */
  content: ""; position: absolute; top: calc(var(--sp-7) + 15px); right: -3px;
  width: 5px; height: 5px; border-radius: 50%; background: var(--border-strong);
}
.band-dark .step:not(:nth-child(3n))::after { background: var(--ink-hair-2); }

/* --------------------------------------------------------------------------
   12. Feature grid — hairline panels, no drop shadows. A green top-rule wipes
   in on hover so the grid feels mechanical rather than bouncy.
   -------------------------------------------------------------------------- */
.fgrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px; background: var(--hair); border: 1px solid var(--hair); border-radius: var(--r-lg); overflow: hidden; }
.band-dark .fgrid { background: var(--ink-hair); border-color: var(--ink-hair); }
.fgrid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.fcell { position: relative; background: var(--surface); padding: var(--sp-6); min-width: 0; }
.band-dark .fcell { background: var(--ink-2); }
.fcell::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: var(--accent); transform: scaleX(0); transform-origin: left;
  transition: transform .22s cubic-bezier(.4,0,.2,1);
}
.band-dark .fcell::before { background: var(--ink-green); }
.fcell:hover::before { transform: scaleX(1); }
@media (prefers-reduced-motion: reduce) { .fcell::before { transition: none; } }
.fcell .ficon {
  display: inline-grid; place-items: center; width: 38px; height: 38px; border-radius: var(--r-md);
  background: var(--accent-quiet); color: var(--green-600); margin-bottom: var(--sp-4);
}
.band-dark .fcell .ficon { background: rgba(52,169,108,.14); color: var(--ink-green); }
.fcell .ficon svg { width: 19px; height: 19px; }
.fcell h3 { font-size: var(--fs-lg); margin-bottom: var(--sp-2); letter-spacing: -0.02em; }
.fcell p { font-size: var(--fs-base); color: var(--text-soft); line-height: 1.56; }
.band-dark .fcell p { color: var(--ink-soft); }

/* --------------------------------------------------------------------------
   13. Spec table — the app's ledger table at reading scale. Control on the
   left in the label voice, implementation on the right.
   -------------------------------------------------------------------------- */
.spec { width: 100%; border-collapse: collapse; }
.spec caption { text-align: left; padding-bottom: var(--sp-4); }
.spec th, .spec td { text-align: left; vertical-align: top; padding: var(--sp-4) var(--sp-4) var(--sp-4) 0; border-bottom: 1px solid var(--hair); }
.band-dark .spec th, .band-dark .spec td { border-color: var(--ink-hair); }
.spec thead th {
  font-family: var(--font-mono); font-size: var(--fs-micro); font-weight: 500;
  text-transform: uppercase; letter-spacing: .13em; color: var(--text-muted);
  padding-top: 0; border-bottom-color: var(--border-strong);
}
.band-dark .spec thead th { color: var(--ink-mute); border-bottom-color: var(--ink-hair-2); }
.spec tbody th { font-weight: 600; font-size: var(--fs-base); color: var(--text); width: 34%; }
.band-dark .spec tbody th { color: var(--ink-text); }
.spec tbody td { font-size: var(--fs-base); color: var(--text-soft); }
.band-dark .spec tbody td { color: var(--ink-soft); }
.spec tbody tr:last-child th, .spec tbody tr:last-child td { border-bottom: 0; }
.spec .mono { font-size: var(--fs-sm); }
.spec-wrap { width: 100%; overflow-x: auto; }

/* --------------------------------------------------------------------------
   14. Split section — copy on one side, an object on the other
   -------------------------------------------------------------------------- */
.split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--sp-10); align-items: start; }
.split-copy { max-width: 560px; }
.split.split-wide-right { grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr); }
.split.split-center { align-items: center; }

/* Checklist — hairline rows with a small green tick. */
.checks { margin-top: var(--sp-5); }
.checks li {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  padding: var(--sp-3) 0; border-top: 1px solid var(--hair);
  font-size: var(--fs-base); color: var(--text-soft);
}
.band-dark .checks li { border-color: var(--ink-hair); color: var(--ink-soft); }
.checks li:last-child { border-bottom: 1px solid var(--hair); }
.band-dark .checks li:last-child { border-bottom-color: var(--ink-hair); }
.checks svg { width: 17px; height: 17px; flex: none; color: var(--accent); margin-top: 3px; }
.band-dark .checks svg { color: var(--ink-green); }
.checks strong { color: var(--text); font-weight: 600; }
.band-dark .checks strong { color: var(--ink-text); }

/* --------------------------------------------------------------------------
   15. Pull quote / statement block
   -------------------------------------------------------------------------- */
.statement {
  max-width: 860px;
  border-left: 2px solid var(--accent);
  padding: var(--sp-2) 0 var(--sp-2) var(--sp-6);
  font-size: clamp(1.25rem, 2.2vw, 1.6rem);
  line-height: 1.38; letter-spacing: -0.024em; font-weight: 500; color: var(--text);
}
.band-dark .statement { border-left-color: var(--ink-green); color: var(--ink-text); }

/* --------------------------------------------------------------------------
   16. Sticky page index (platform / security long pages)
   -------------------------------------------------------------------------- */
.doc-layout { display: grid; grid-template-columns: 208px minmax(0, 1fr); gap: var(--sp-10); align-items: start; }
.doc-index { position: sticky; top: calc(var(--nav-h) + var(--sp-6)); }
.doc-index .mcap { display: block; padding-bottom: var(--sp-3); border-bottom: 1px solid var(--hair); margin-bottom: var(--sp-2); }
.doc-index a {
  display: block; padding: 9px 0 9px var(--sp-3);
  border-left: 2px solid var(--hair);
  font-size: var(--fs-sm); color: var(--text-muted); font-weight: 500;
  transition: color .14s ease, border-color .14s ease;
}
.doc-index a:hover { color: var(--text); border-left-color: var(--border-strong); text-decoration: none; }
.doc-index a.is-active { color: var(--green-600); border-left-color: var(--accent); }
.doc-section + .doc-section { margin-top: var(--sp-12); padding-top: var(--sp-10); border-top: 1px solid var(--hair); }
.doc-section > .sec-head { margin-bottom: var(--sp-6); }

/* --------------------------------------------------------------------------
   17. Audience cards (three doors)
   -------------------------------------------------------------------------- */
.doors { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-5); }
.door {
  display: flex; flex-direction: column;
  padding: var(--sp-6); border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--surface); min-width: 0;
  transition: border-color .16s ease, box-shadow .16s ease, transform .16s ease;
}
.door:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); text-decoration: none; transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce) { .door:hover { transform: none; } }
.door .door-icon { display: inline-grid; place-items: center; width: 40px; height: 40px; border-radius: var(--r-md); background: var(--accent-quiet); color: var(--green-600); margin-bottom: var(--sp-4); }
.door .door-icon svg { width: 20px; height: 20px; }
.door h3 { font-size: var(--fs-lg); margin-bottom: var(--sp-2); letter-spacing: -0.02em; }
.door p { font-size: var(--fs-base); color: var(--text-soft); line-height: 1.55; flex: 1; }
.door .arrow-link { margin-top: var(--sp-5); }

/* --------------------------------------------------------------------------
   18. CTA band
   -------------------------------------------------------------------------- */
.cta { text-align: center; }
.cta .display-sm { max-width: 760px; margin: 0 auto var(--sp-5); }
.cta .lead { max-width: 620px; margin: 0 auto; }
.cta .btn-row { justify-content: center; margin-top: var(--sp-7); }
.cta-fine { margin-top: var(--sp-5); font-size: var(--fs-sm); color: var(--ink-mute); }

/* --------------------------------------------------------------------------
   19. Forms (contact / request access)
   -------------------------------------------------------------------------- */
.form-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
  padding: var(--sp-7); box-shadow: var(--shadow-sm);
}
.field { margin-bottom: var(--sp-4); min-width: 0; }
.field > label { display: block; font-size: var(--fs-sm); font-weight: 600; color: var(--text); margin-bottom: 6px; }
.field .req { color: var(--green-600); font-weight: 600; }
.field .hint { display: block; margin-top: 5px; font-size: var(--fs-xs); color: var(--text-muted); }
.input, .textarea, .select {
  width: 100%; max-width: 100%;
  font: inherit; font-size: var(--fs-base);
  color: var(--text); background: var(--surface);
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
  padding: 11px 13px;
  transition: border-color .14s ease, box-shadow .14s ease;
}
.textarea { min-height: 132px; resize: vertical; line-height: 1.55; }
.select { appearance: none; -webkit-appearance: none; padding-right: 38px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7889' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center;
}
.input::placeholder, .textarea::placeholder { color: var(--slate-400); }
.input:hover, .textarea:hover, .select:hover { border-color: var(--slate-400); }
.input:focus, .textarea:focus, .select:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(31,143,87,.16);
}
.field-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4); }
.form-foot { margin-top: var(--sp-5); padding-top: var(--sp-5); border-top: 1px solid var(--hair); display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }
.form-foot .fine { font-size: var(--fs-xs); color: var(--text-muted); max-width: 380px; }

/* Honeypot. Positioned off-screen rather than display:none, because some bots
   skip fields that are display:none and fill everything else. It is out of the
   tab order and out of the accessibility tree in the markup. */
.hp { position: absolute; left: -9999px; top: auto; width: 1px; height: 1px; overflow: hidden; }

.notice {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  padding: var(--sp-4) var(--sp-5); border-radius: var(--r-md);
  border: 1px solid var(--border); background: var(--surface-2);
  font-size: var(--fs-base); margin-bottom: var(--sp-5);
}
.notice svg { width: 19px; height: 19px; flex: none; margin-top: 2px; }
.notice-ok { border-color: var(--green-200); background: var(--green-50); color: var(--green-700); }
.notice-ok svg { color: var(--green-600); }
.notice-err { border-color: #f3c4c4; background: #fdecec; color: #9a2727; }
.notice-err svg { color: #c63434; }

/* Contact rail beside the form */
.contact-aside .cblock { padding: var(--sp-5) 0; border-top: 1px solid var(--hair); }
.contact-aside .cblock:first-of-type { border-top: 0; padding-top: 0; }
.contact-aside .cblock h3 { font-size: var(--fs-base); margin-bottom: 6px; }
.contact-aside .cblock p { font-size: var(--fs-sm); color: var(--text-soft); }
.contact-aside .cblock a { font-weight: 500; }

/* --------------------------------------------------------------------------
   20. FAQ / disclosure list
   -------------------------------------------------------------------------- */
.faq { border-top: 1px solid var(--hair); }
.faq details { border-bottom: 1px solid var(--hair); }
.faq summary {
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-4);
  padding: var(--sp-5) 0; cursor: pointer; list-style: none;
  font-size: var(--fs-lg); font-weight: 600; letter-spacing: -0.018em; color: var(--text);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary .chev { width: 20px; height: 20px; flex: none; color: var(--text-muted); margin-top: 3px; transition: transform .18s ease; }
.faq details[open] summary .chev { transform: rotate(180deg); }
.faq .faq-body { padding: 0 0 var(--sp-5); max-width: 760px; color: var(--text-soft); }
.faq .faq-body p + p { margin-top: var(--sp-3); }

/* --------------------------------------------------------------------------
   21. Footer
   -------------------------------------------------------------------------- */
.foot { background: var(--ink); color: var(--ink-soft); padding: var(--sp-10) 0 var(--sp-6); border-top: 1px solid var(--ink-hair); }
.foot a { color: var(--ink-soft); }
.foot a:hover { color: var(--ink-text); text-decoration: none; }
.foot-grid { display: grid; grid-template-columns: minmax(0, 1.6fr) repeat(3, minmax(0, 1fr)); gap: var(--sp-8); padding-bottom: var(--sp-8); border-bottom: 1px solid var(--ink-hair); }
/* Five columns once the mobile app has its own. The brand column narrows
   rather than the link columns squeezing. */
.foot-grid-5 { grid-template-columns: minmax(0, 1.35fr) repeat(3, minmax(0, .82fr)) minmax(0, 1fr); gap: var(--sp-7); }
.foot-brand .foot-logo { height: 34px; width: auto; margin-bottom: var(--sp-4); }
.foot-brand p { font-size: var(--fs-sm); color: var(--ink-mute); max-width: 320px; line-height: 1.6; }
.foot-col h4 { font-family: var(--font-mono); font-size: var(--fs-micro); font-weight: 500; text-transform: uppercase; letter-spacing: .14em; color: var(--ink-mute); margin-bottom: var(--sp-4); }
.foot-col li { margin-bottom: 10px; }
.foot-col a { font-size: var(--fs-sm); }
.foot-bottom { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; padding-top: var(--sp-5); font-size: var(--fs-xs); color: var(--ink-mute); }
.foot-bottom .legal-links { display: flex; gap: var(--sp-5); flex-wrap: wrap; }
.foot-bottom a { font-size: var(--fs-xs); }

/* The sitemap row: every page on the site in one ruled line under the link
   columns, so the whole map is one glance from any footer. Entries are
   separated by a hairline dot rather than a pipe, in the strip's own voice. */
.foot-map { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--sp-3) var(--sp-5); padding: var(--sp-5) 0; border-bottom: 1px solid var(--ink-hair); }
.foot-map > .mcap { flex: none; color: var(--ink-mute); }
/* The dot sits in the middle of the gap, drawn to the left of every entry.
   The list clips at its own left edge, so the entry that starts a wrapped
   line loses its dot instead of opening the line with one. The small
   negative margins keep focus outlines from being clipped with it. */
.foot-map ul { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 24px; list-style: none; min-width: 0; overflow: hidden; padding: 3px 0 3px 4px; margin: -3px 0 -3px -4px; }
.foot-map li { position: relative; display: flex; align-items: center; }
.foot-map li::before { content: ""; position: absolute; left: -13.5px; top: 50%; margin-top: -1.5px; width: 3px; height: 3px; border-radius: 50%; background: var(--ink-hair-2); }
.foot-map a { font-size: var(--fs-sm); }
.foot-map a[aria-current="page"] { color: var(--ink-text); }

/* --------------------------------------------------------------------------
   22. Page header (interior pages)
   -------------------------------------------------------------------------- */
.phead { padding: calc(var(--nav-h) + var(--sp-10)) 0 var(--sp-10); }
.phead .display-sm { max-width: 820px; margin-bottom: var(--sp-5); }
.phead .lead { max-width: 660px; }
.phead .btn-row { margin-top: var(--sp-7); }
.phead-eyebrow { margin-bottom: var(--sp-5); }

/* --------------------------------------------------------------------------
   23. Responsive
   -------------------------------------------------------------------------- */
@media (max-width: 1040px) {
  .split, .split.split-wide-right { grid-template-columns: 1fr; gap: var(--sp-8); }
  .split-copy { max-width: none; }
  .doc-layout { grid-template-columns: 1fr; gap: var(--sp-6); }
  .doc-index { position: static; }
  /* Once the rail lies flat it reads as chips, not as a ruled index. Ragged
     underlined links with uneven gaps looked scattered; pills in the app's
     segmented-tab voice keep the row tidy at any wrap. */
  .doc-index nav { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
  .doc-index a {
    border: 1px solid var(--border); border-radius: var(--r-full);
    padding: 7px 14px; margin-right: 0; background: var(--surface);
  }
  .doc-index a:hover { border-color: var(--border-strong); color: var(--text); }
  .doc-index a.is-active { border-color: var(--green-200); background: var(--green-50); color: var(--green-700); }
  .foot-grid, .foot-grid-5 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-7); }
}
@media (max-width: 900px) {
  :root { --nav-h: 62px; }
  .nav-links, .nav-actions .nav-signin, .nav-actions .btn { display: none; }
  .nav-actions .nav-toggle { display: inline-flex; }
  .nav-links { display: none; }
  .lrow { grid-template-columns: 44px minmax(0, 1fr); gap: var(--sp-3) var(--sp-4); padding: var(--sp-6) 0; }
  .lrow-body { grid-column: 2; }
  .lrow-action { grid-column: 2; padding-top: 0; }
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .step:nth-child(3n) { border-right: 1px solid var(--hair); padding-right: var(--sp-5); }
  .band-dark .step:nth-child(3n) { border-right-color: var(--ink-hair); }
  .step:nth-child(2n) { border-right: 0; padding-right: 0; }
  .step:nth-child(n+3) { border-top: 1px solid var(--hair); }
  .band-dark .step:nth-child(n+3) { border-top-color: var(--ink-hair); }
  .step::after { display: none; }
  .fgrid, .fgrid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .doors { grid-template-columns: 1fr; }
  .rail { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rail-cell { padding: var(--sp-5) var(--sp-4); }
  .rail-cell:first-child { padding-left: var(--sp-4); border-left: 0; }
  .rail-cell:nth-child(2n+1) { border-left: 0; padding-left: 0; }
  .rail-cell:nth-child(n+3) { border-top: 1px solid var(--hair); }
  .band-dark .rail-cell:nth-child(n+3) { border-top-color: var(--ink-hair); }
}
@media (max-width: 680px) {
  :root { --gutter: 20px; }
  body { font-size: var(--fs-base); }
  .band-pad { padding: var(--sp-10) 0; }
  .band-pad-sm { padding: var(--sp-8) 0; }
  /* The hero's top spacing lives on .hero > .wrap (section 8). A second
     padding here once stacked on top of it and counted the nav twice, which
     opened a dead half-screen above the eyebrow. Nothing extra belongs here. */
  .phead { padding: calc(var(--nav-h) + var(--sp-8)) 0 var(--sp-8); }
  .sec-head { margin-bottom: var(--sp-6); }
  .doc-section + .doc-section { margin-top: var(--sp-8); padding-top: var(--sp-8); }
  .doc-section > .sec-head { margin-bottom: var(--sp-5); }
  .steps { grid-template-columns: 1fr; }
  .step, .step:nth-child(3n), .step:nth-child(2n) { border-right: 0; padding: var(--sp-5) 0; }
  .step:nth-child(n+2) { border-top: 1px solid var(--hair); }
  .band-dark .step:nth-child(n+2) { border-top-color: var(--ink-hair); }
  .fgrid, .fgrid-2 { grid-template-columns: 1fr; }
  /* Reading-scale cards: the icon sits beside the title instead of on its own
     row, and the padding drops a step. Full desktop cells stacked one wide
     made every card section a tall repetitive column. */
  .fcell { padding: var(--sp-5); display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: var(--sp-3); align-items: center; }
  .fcell .ficon { width: 34px; height: 34px; margin-bottom: 0; }
  .fcell .ficon svg { width: 18px; height: 18px; }
  .fcell h3 { margin-bottom: 0; font-size: var(--fs-base); }
  .fcell p { grid-column: 1 / -1; margin-top: var(--sp-3); font-size: var(--fs-sm); line-height: 1.6; }
  .door { padding: var(--sp-5); display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: var(--sp-3); align-items: center; }
  .door .door-icon { width: 36px; height: 36px; margin-bottom: 0; }
  .door .door-icon svg { width: 18px; height: 18px; }
  .door h3 { margin-bottom: 0; }
  .door p { grid-column: 1 / -1; margin-top: var(--sp-3); }
  .door .arrow-link { grid-column: 1 / -1; margin-top: var(--sp-4); }
  /* Ledger rows go single column: the 44px index gutter squeezed the body
     while section heads sat at the page gutter, so nothing lined up. The
     index becomes a label above the title. */
  .lrow { grid-template-columns: 1fr; gap: var(--sp-1); padding: var(--sp-6) 0; }
  .lrow-index { padding-top: 0; }
  .lrow-title { margin-top: var(--sp-1); }
  .lrow-body { grid-column: 1; margin-top: var(--sp-2); }
  .lrow-action { grid-column: 1; margin-top: var(--sp-2); }
  .field-row { grid-template-columns: 1fr; gap: 0; }
  .form-card { padding: var(--sp-5); }
  .spec tbody th { width: auto; display: block; border-bottom: 0; padding-bottom: 4px; }
  .spec tbody td { display: block; padding-top: 0; }
  .spec thead { display: none; }
  /* Link columns pair up instead of stacking five deep; only the brand keeps
     the full width. The store-badge column pairs with Company. */
  .foot-grid, .foot-grid-5 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-7) var(--sp-5); }
  .foot-brand { grid-column: 1 / -1; }
  .statement { padding-left: var(--sp-4); }
  .foot-map { gap: var(--sp-3); }
  .foot-map ul { column-gap: 18px; }
  .foot-map li::before { left: -10.5px; }
  .btn-row .btn { width: 100%; }
}
@media (max-width: 420px) {
  .rail { grid-template-columns: 1fr; }
  .rail-cell, .rail-cell:first-child, .rail-cell:nth-child(2n+1) { border-left: 0; padding-left: 0; padding-right: 0; }
  .rail-cell:nth-child(n+2) { border-top: 1px solid var(--hair); }
  .band-dark .rail-cell:nth-child(n+2) { border-top-color: var(--ink-hair); }
}

/* --------------------------------------------------------------------------
   24. Motion — one quiet entrance, disabled for reduced-motion. Elements are
   visible by default and only hidden once JS confirms it will reveal them, so
   a script failure can never leave the page blank.
   -------------------------------------------------------------------------- */
/* Desktop only. On a phone a fast flick can carry a block through the
   observer's window between callbacks, and a block that misses its cue sits
   at opacity 0 forever: whole sections rendered as blank bands. The script
   only arms the observer above 900px; this guard keeps the CSS honest even
   if that changes. Content on phones is simply visible. */
@media (min-width: 901px) {
  .js-reveal [data-reveal] { opacity: 0; transform: translateY(10px); }
  .js-reveal [data-reveal].is-in { opacity: 1; transform: none; transition: opacity .5s ease, transform .5s cubic-bezier(.22,1,.36,1); }
}
@media (prefers-reduced-motion: reduce) {
  .js-reveal [data-reveal] { opacity: 1; transform: none; }
  /* Everything that moves on hover stops moving. Colour and border feedback is
     kept, so the affordance survives. */
  .store-link:hover, .door:hover, .btn:active, .arrow-link:hover svg { transform: none; }
  .store-link, .door, .fcell::before, .arrow-link svg { transition: none; }
}

@media print {
  /* Photographic layers and the store badges are screen furniture. On paper
     they waste toner and, at print contrast, the scrim over a dark frame turns
     body copy into grey on grey. */
  .nav, .nav-drawer, .foot, .skip-link, .band-media, .band-scrim, .store-row { display: none !important; }
  .band-dark { background: #fff !important; color: #111 !important; }
  .band-dark::before, .band-dark::after { display: none !important; }
  .page-body { padding-top: 0; }
  a { color: #111 !important; text-decoration: none !important; }
}

/* --------------------------------------------------------------------------
   25. A handful of spacing utilities. Kept to this short, closed list on
   purpose: the site carries no inline styles at all so that the Content
   Security Policy can keep style-src locked to 'self' without an
   'unsafe-inline' escape hatch.
   -------------------------------------------------------------------------- */
.mt-4 { margin-top: var(--sp-4); }
.mt-5 { margin-top: var(--sp-5); }
.mt-6 { margin-top: var(--sp-6); }
.mt-7 { margin-top: var(--sp-7); }
.mb-5 { margin-bottom: var(--sp-5); }

/* A quieter glow for bands that sit directly under the hero, so two lit
   sections never stack and wash each other out. */
.band-dark.glow-faint::after { background-image: radial-gradient(700px 340px at 50% 50%, rgba(31,143,87,.10), transparent 70%); }

/* A feature cell can be a link (the 404 index). Keep it reading as a panel
   rather than as a run of blue link text. */
a.fcell { display: block; color: inherit; }
a.fcell:hover { text-decoration: none; }


/* --------------------------------------------------------------------------
   26. App Store and Google Play badges

   Drawn inline (see store_badge() in lib.php) so they stay sharp at any
   density. Sized by height only, with width:auto, so the artwork can never be
   squashed. The hover is a lift of the hairline border rather than a colour
   change, because neither badge's colours are ours to alter.
   -------------------------------------------------------------------------- */
.store-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }
/* flex:none on the link and max-width:none on the artwork. The base reset sets
   svg { max-width: 100% }, which caps the badge's width while its height stays
   fixed, and a badge squashed out of ratio is worse than no badge. These two
   declarations make the row wrap instead of distorting. */
.store-link { display: inline-flex; flex: 0 0 auto; border-radius: 7px; line-height: 0; transition: transform .14s ease, filter .14s ease; }
.store-link:hover { text-decoration: none; transform: translateY(-1px); filter: brightness(1.18); }
.store-link:active { transform: translateY(0); }
.store-link:focus-visible { outline: 2px solid var(--ink-green); outline-offset: 3px; }
.store-badge { height: 44px; width: auto; max-width: none; display: block; }
.store-row-sm .store-badge { height: 38px; }
.store-row-lg .store-badge { height: 50px; }
/* Height is the only dimension anything is allowed to set on a badge. This
   wins on specificity over any ambient `... svg { width: … }` rule. */
.store-row .store-link .store-badge { width: auto; max-width: none; }
/* On a light band the badge keeps its black plate, so the hairline needs to be
   dark instead of white or it disappears. */
.band-light .store-badge rect, .band-tint .store-badge rect,
.form-card .store-badge rect { stroke: rgba(0,0,0,.28); }
.band-light .store-link:focus-visible, .band-tint .store-link:focus-visible { outline-color: var(--accent); }

/* The "also on mobile" line under a call to action. */
.store-note { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3) var(--sp-4); min-width: 0; }
.store-note .mcap { flex: none; }

/* Home band: the app, given its own room. */
.appband-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--sp-10); align-items: center; }
.applist { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-5) var(--sp-6); }
.applist .appitem { min-width: 0; }
.applist .appitem h3 { font-size: var(--fs-base); margin-bottom: 5px; display: flex; align-items: center; gap: 8px; }
.applist .appitem h3 svg { width: 17px; height: 17px; flex: none; color: var(--ink-green); }
.applist .appitem p { font-size: var(--fs-sm); color: var(--ink-soft); line-height: 1.5; }
@media (max-width: 1040px) { .appband-grid { grid-template-columns: 1fr; gap: var(--sp-7); } }
@media (max-width: 560px) { .applist { grid-template-columns: 1fr; gap: var(--sp-4); } .store-badge { height: 40px; } }

/* Footer column of badges. */
.foot-col .store-row { margin-top: var(--sp-4); flex-direction: column; align-items: flex-start; gap: var(--sp-2); }
.foot-col .store-badge { height: 40px; }

/* Drawer badges. */
.nav-drawer .store-row { margin-top: var(--sp-5); }
.nav-drawer .store-row .store-badge { height: 42px; }


/* --------------------------------------------------------------------------
   27. Increased-contrast preference

   Someone who has asked their operating system for more contrast is telling us
   the photographs behind the type are working against them. Deepen every scrim
   and drop the paper textures out entirely. Everything still reads as the same
   design, with the decoration turned down.
   -------------------------------------------------------------------------- */
@media (prefers-contrast: more) {
  .band-dark .band-scrim,
  .hero .band-scrim,
  .band-dark.scrim-center .band-scrim,
  .band-dark.scrim-deep .band-scrim {
    background-image: linear-gradient(to bottom, rgba(9,12,16,.95), rgba(9,12,16,.95));
  }
  .band-paper .band-media { opacity: 0; }
  .band-dark::before { display: none; }
  :root { --ink-mute: rgba(244,246,248,.72); --text-muted: #4d5969; }
}


/* --------------------------------------------------------------------------
   28. LeadLocate integration page (/leadlocate)

   An interior header that carries the readout strip along its bottom edge,
   the way the home hero does. The band becomes a column so the strip sits
   flush under the copy rather than inside the band's bottom padding, and each
   step names which of the two products it happened in.
   -------------------------------------------------------------------------- */
.phead.phead-strip { padding-bottom: 0; display: flex; flex-direction: column; }
.phead-strip > .wrap { padding-bottom: var(--sp-10); }
.phead-strip .custody { margin-top: auto; }
.custody-step .sys {
  display: inline-block; margin-top: 8px;
  font-family: var(--font-mono); font-size: var(--fs-micro); font-weight: 500;
  text-transform: uppercase; letter-spacing: .1em; color: var(--ink-mute);
}
/* Direction line under a spec-table label: which way a record travels. */
.spec .spec-dir {
  display: block; margin-top: 4px;
  font-family: var(--font-mono); font-size: var(--fs-micro); font-weight: 500;
  text-transform: uppercase; letter-spacing: .1em; color: var(--text-muted);
}
.band-dark .spec .spec-dir { color: var(--ink-green); }
/* Two rows whose end links differ in length ("leadlocate.com" against
   "Platform") would otherwise size the auto column per row and put the two
   body columns a few pixels apart. A fixed end column on wide screens only;
   the phone layout below 900px reflows the row and is left alone. */
@media (min-width: 901px) {
  .ledger-fixed .lrow { grid-template-columns: 64px minmax(0, .78fr) minmax(0, 1.5fr) 150px; }
}
/* The closing band's app line, centred like everything else in a .cta. */
.cta .store-note { justify-content: center; margin-top: var(--sp-7); }
@media (max-width: 680px) {
  .phead-strip > .wrap { padding-bottom: var(--sp-8); }
  .custody-step .sys { margin-top: 6px; }
}
