/*
 * NEXO presentation site — dependency-free, light, brand-token driven.
 *
 * PALETTE: the CORPORATE tokens (branding/palette/tokens.json → `nexo`),
 * not the Hub application's. The app is dark because operators stare at it
 * all day; the company's brand is light (#FFFFFF / #0F172A) and that is what
 * nexocharge.xyz already uses. Getting this wrong made the first version of
 * this site look like a screenshot of the product instead of the company.
 *
 * PRODUCT COLOURS are load-bearing, not decoration: Hub is cyan (#06B6D4),
 * Edge is rust (#C2410C) — the same colours their "X" marks carry in
 * branding/logo/*/svg. Every product surface picks its accent from these, so
 * the two are never confusable at a glance.
 *
 * SECTION RHYTHM mirrors nexocharge: full-bleed bands alternating white,
 * neutral and a product tint, each a soft 135° gradient. It is what stops a
 * page of text from reading as a page of text.
 */

@font-face {
  font-family: 'Poppins';
  src: url('/branding/fonts/web/Poppins-Regular.woff2') format('woff2'),
    url('/branding/fonts/Poppins/Poppins-Regular.ttf') format('truetype');
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'Poppins';
  src: url('/branding/fonts/web/Poppins-Medium.woff2') format('woff2'),
    url('/branding/fonts/Poppins/Poppins-Medium.ttf') format('truetype');
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: 'Poppins';
  src: url('/branding/fonts/web/Poppins-SemiBold.woff2') format('woff2'),
    url('/branding/fonts/Poppins/Poppins-SemiBold.ttf') format('truetype');
  font-weight: 600;
  font-display: swap;
}

:root {
  /* Corporate */
  --bg: #ffffff;
  --fg: #0f172a;
  --muted: #64748b;
  --faint: #94a3b8;
  --line: #e2e8f0;

  /* Products */
  --hub: #06b6d4;
  --hub-ink: #0e7490;
  --edge: #c2410c;
  --edge-ink: #9a3412;

  --radius: 20px;
  --shadow: 0 8px 24px rgba(0, 0, 0, 0.06);
  --shadow-lg: 0 18px 44px rgba(15, 23, 42, 0.1);
  --max: 1140px;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}
html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: 'Poppins', system-ui, -apple-system, sans-serif;
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

a {
  color: inherit;
  text-decoration: none;
}

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

/* ── Header ───────────────────────────────────────────────── */

.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(255, 255, 255, 0.88);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}
.site-header .wrap {
  display: flex;
  align-items: center;
  gap: 28px;
  height: 72px;
}
/* img OR svg: the wordmarks are inlined at build time (see
   website/tools/inline-logos.mjs) so the page's own Poppins applies to the
   live <text> inside them. Both forms are styled so a build without that
   step degrades to the old rendering instead of collapsing the header. */
.site-header .logo img,
.site-header .logo svg {
  height: 28px;
  width: auto;
  display: block;
}
.site-nav {
  display: flex;
  gap: 26px;
  margin-left: auto;
  align-items: center;
  font-size: 15px;
  font-weight: 500;
}
.site-nav a {
  color: var(--muted);
}
.site-nav a:hover,
.site-nav a[aria-current='page'] {
  color: var(--fg);
}

/* ── Buttons ──────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 13px 26px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  font-weight: 500;
  font-size: 16px;
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
.btn:hover {
  transform: translateY(-1px);
}

.btn-hub {
  background: var(--hub);
  color: #ffffff;
  box-shadow: 0 6px 18px rgba(6, 182, 212, 0.28);
}
.btn-edge {
  background: var(--edge);
  color: #ffffff;
  box-shadow: 0 6px 18px rgba(194, 65, 12, 0.26);
}
.btn-dark {
  background: var(--fg);
  color: #ffffff;
}
.btn-ghost {
  border-color: var(--line);
  color: var(--fg);
  background: #ffffff;
}
.btn-ghost:hover {
  border-color: #cbd5e1;
}

/* ── Section bands ────────────────────────────────────────── */

.band {
  padding: 80px 0;
}
.band-white {
  background: #ffffff;
}
.band-neutral {
  background: linear-gradient(135deg, #fafafa, #f4f4f5);
}
.band-slate {
  background: linear-gradient(135deg, #f1f5f9, #e2e8f0);
}
/* Product tints — same construction, each product's own hue. */
.band-hub {
  background: linear-gradient(135deg, #ecfeff, #cffafe);
}
.band-edge {
  background: linear-gradient(135deg, #fff7ed, #ffedd5);
}
.band-ink {
  background: linear-gradient(135deg, #0f172a, #1e293b);
  color: #f8fafc;
}
.band-ink .lead,
.band-ink p {
  color: #cbd5e1;
}

.band h2 {
  font-size: clamp(23px, 2.7vw, 29px);
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0 0 14px;
}
.band > .wrap > p.lead {
  font-size: 17.5px;
  color: var(--muted);
  max-width: 60ch;
  margin: 0;
}

.eyebrow {
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 600;
  margin: 0 0 14px;
  color: var(--muted);
}
.eyebrow-hub {
  color: var(--hub-ink);
}
.eyebrow-edge {
  color: var(--edge-ink);
}

/* ── Hero ─────────────────────────────────────────────────── */

.hero {
  padding: 92px 0 84px;
  text-align: center;
  background: radial-gradient(1000px 420px at 50% -10%, #ecfeff 0%, #ffffff 62%);
}
.hero h1 {
  font-size: clamp(30px, 4.2vw, 42px);
  line-height: 1.15;
  font-weight: 600;
  letter-spacing: -0.03em;
  margin: 0 auto 20px;
  max-width: 24ch;
}
.hero p.lead {
  font-size: clamp(17px, 1.9vw, 19px);
  color: var(--muted);
  max-width: 56ch;
  margin: 0 auto 34px;
}
.cta-row {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  justify-content: center;
}
.hero-left,
.hero-left .cta-row {
  text-align: left;
  justify-content: flex-start;
}
.hero-left h1,
.hero-left p.lead {
  margin-left: 0;
  margin-right: 0;
}

/*
 * Product lockup: the NEXO wordmark plus the product name.
 *
 * The wordmark alone does not say which product you are looking at — its only
 * distinguishing feature is the colour of the X, which nobody decodes on a
 * first visit. The name is spelled out next to it, in that product's colour.
 * The LIGHT logo variant is the one for light backgrounds; using the dark
 * variant here rendered near-white letters on cream.
 *
 * BASELINE, NOT CENTRE. The product word sits on the same baseline as the
 * N, E and O — vertically centring it instead leaves the word floating a
 * couple of pixels high, which is exactly what reads as "two things pasted
 * together" rather than one lockup.
 *
 * The artwork carries dead space below the letters: the wordmark's text
 * baseline is at y=50.4498 (tspan y=145, shifted -40 by the text transform
 * and -54.55022 by the group) inside a 54.600349-unit viewBox, so 7.6% of
 * the image height hangs below the baseline. `align-items: baseline` uses an
 * <img>'s bottom margin edge as its baseline, so pulling that edge up by
 * exactly that 7.6% makes the image's baseline BE the letters' baseline and
 * the flex alignment does the rest. The figure is font-independent — the
 * baseline comes from the `y` attribute, not from Poppins' metrics — so it
 * survives the font falling back inside the <img>'s isolated document.
 */
.lockup {
  --logo-h: 40px;
  --logo-descent: 0.076;
  display: inline-flex;
  align-items: baseline;
  gap: 14px;
  margin-bottom: 26px;
}
.lockup img,
.lockup svg {
  height: var(--logo-h);
  width: auto;
  display: block;
  margin-bottom: calc(var(--logo-h) * var(--logo-descent) * -1);
}
.lockup .product {
  font-size: calc(var(--logo-h) * 0.82);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1;
}
.product-edge {
  color: var(--edge);
}
.product-hub {
  color: var(--hub-ink);
}
@media (max-width: 640px) {
  .lockup {
    --logo-h: 30px;
  }
}

/* ── Cards & grids ────────────────────────────────────────── */

.grid {
  display: grid;
  gap: 24px;
  margin-top: 44px;
}
.grid-2 {
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}
.grid-3 {
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.grid-4 {
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

.card {
  background: #ffffff;
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 32px;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.card h3 {
  font-size: 21px;
  font-weight: 600;
  margin: 0 0 10px;
}
.card p {
  color: var(--muted);
  margin: 0 0 20px;
  font-size: 16px;
}
.card p:last-child {
  margin-bottom: 0;
}

/* Product card: big coloured X, accent hairline, lift on hover. */
.card-product {
  border-top: 4px solid var(--line);
  padding-top: 30px;
}
.card-product:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
}
.card-product.is-hub {
  border-top-color: var(--hub);
}
.card-product.is-edge {
  border-top-color: var(--edge);
}
.card-product .mark {
  height: 56px;
  display: block;
  margin-bottom: 22px;
}

.feature h3 {
  font-size: 17px;
  margin-bottom: 8px;
}
.feature p {
  font-size: 15.5px;
  margin-bottom: 0;
}
.feature .glyph {
  width: 46px;
  height: 46px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  margin-bottom: 18px;
  font-size: 20px;
}

/*
 * Symbol glyphs, drawn from the product's own SCADA library.
 *
 * CSS mask rather than <img>, for two reasons. The symbols are authored with
 * fill="currentColor", which an <img> cannot inherit — they would all render
 * black. And more than half the library has unbalanced <g> tags, which the
 * app tolerates because it inlines the markup through innerHTML (lenient HTML
 * parsing) but an <img> does not, because that path parses strict XML: four
 * of the six in the first version of this strip silently rendered as broken
 * images. A mask uses the file as a shape and takes its colour from
 * background-color, so it sidesteps both problems.
 */
.sym {
  -webkit-mask: var(--sym) center / 62% no-repeat;
  mask: var(--sym) center / 62% no-repeat;
}
.glyph-hub.sym {
  background-color: var(--hub-ink);
}
.glyph-edge.sym {
  background-color: var(--edge-ink);
}
.glyph-slate.sym {
  background-color: #334155;
}
/* The tinted tile behind a masked glyph has to come from a wrapper, since the
   element's own background is the glyph colour. */
.glyph-tile {
  width: 46px;
  height: 46px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  margin-bottom: 18px;
}
.tile-hub {
  background: #cffafe;
}
.tile-edge {
  background: #ffedd5;
}
.tile-slate {
  background: #e2e8f0;
}
.glyph-tile .sym {
  width: 30px;
  height: 30px;
  -webkit-mask-size: contain;
  mask-size: contain;
}
.glyph-hub {
  background: #cffafe;
  color: var(--hub-ink);
}
.glyph-edge {
  background: #ffedd5;
  color: var(--edge-ink);
}
.glyph-slate {
  background: #e2e8f0;
  color: #334155;
}

/* ── Numbered steps ───────────────────────────────────────── */

.steps {
  counter-reset: step;
  display: grid;
  gap: 24px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  margin-top: 44px;
}
.step {
  background: #ffffff;
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 30px;
  position: relative;
}
.step::before {
  counter-increment: step;
  content: counter(step);
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--fg);
  color: #ffffff;
  font-weight: 600;
  font-size: 16px;
  margin-bottom: 18px;
}
.step h3 {
  font-size: 18px;
  font-weight: 600;
  margin: 0 0 8px;
}
.step p {
  color: var(--muted);
  font-size: 15.5px;
  margin: 0;
}

/* ── Stats ────────────────────────────────────────────────── */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 24px;
  margin-top: 40px;
}
.stat {
  text-align: center;
}
.stat .n {
  font-size: clamp(28px, 3.4vw, 36px);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.1;
}
.stat .l {
  color: var(--muted);
  font-size: 15px;
  margin-top: 6px;
}
.n-hub {
  color: var(--hub-ink);
}
.n-edge {
  color: var(--edge-ink);
}

/* ── Product screenshots ──────────────────────────────────── */

/*
 * The frame's background is the APP's page colour, not white: a screenshot
 * whose aspect ratio does not exactly match its box would otherwise show a
 * white sliver along one edge and read as a rendering bug. `line-height: 0`
 * kills the inline-image descender gap for the same reason.
 *
 * Every <img> carries explicit width/height so the browser reserves the box
 * before the bytes arrive — no layout shift, which is a ranked Core Web Vital.
 */
.shot {
  border-radius: 18px;
  overflow: hidden;
  border: 1px solid rgba(15, 23, 42, 0.08);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.22);
  background: #0b0f17;
  line-height: 0;
}
.shot img {
  display: block;
  width: 100%;
  height: auto;
}
figure.shot-fig {
  margin: 44px 0 0;
}
figure.shot-fig figcaption {
  margin-top: 12px;
  font-size: 13.5px;
  color: var(--faint);
  text-align: center;
  line-height: 1.5;
}
.shots {
  display: grid;
  gap: 28px;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  margin-top: 44px;
}
.shots figure.shot-fig {
  margin: 0;
}

/* ── Symbol strip (real SCADA glyphs from the product) ────── */

.symbols {
  display: flex;
  gap: 18px;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 40px;
}
.symbols .tile {
  width: 88px;
  height: 88px;
  background: #ffffff;
  border-radius: 18px;
  box-shadow: var(--shadow);
  display: grid;
  place-items: center;
}
.symbols .tile .sym {
  width: 52px;
  height: 52px;
  -webkit-mask-size: contain;
  mask-size: contain;
  background-color: var(--edge-ink);
}

/* ── FAQ (no JS: native details/summary) ──────────────────── */

.faq {
  margin-top: 40px;
  display: grid;
  gap: 12px;
}
.faq details {
  background: #ffffff;
  border-radius: 14px;
  box-shadow: var(--shadow);
  padding: 4px 24px;
}
.faq summary {
  cursor: pointer;
  padding: 18px 0;
  font-weight: 500;
  font-size: 17px;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 12px;
}
.faq summary::-webkit-details-marker {
  display: none;
}
.faq summary::before {
  content: '+';
  color: var(--muted);
  font-size: 20px;
  width: 16px;
}
.faq details[open] summary::before {
  content: '−';
}
.faq p {
  color: var(--muted);
  margin: 0 0 20px 28px;
  font-size: 16px;
}

/* ── Download block ───────────────────────────────────────── */

.dl {
  background: #ffffff;
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: 36px;
  margin-top: 40px;
  text-align: left;
}
.dl-head {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
}
.dl-meta {
  display: flex;
  gap: 36px;
  flex-wrap: wrap;
  margin-top: 28px;
  padding-top: 26px;
  border-top: 1px solid var(--line);
}
.dl-meta dt {
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 6px;
  font-weight: 600;
}
.dl-meta dd {
  margin: 0;
  font-size: 16px;
}
.mono {
  font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  font-size: 13px;
  word-break: break-all;
}
.note {
  border-left: 3px solid #f59e0b;
  background: #fffbeb;
  border-radius: 0 12px 12px 0;
  padding: 16px 20px;
  margin: 28px 0 0;
  color: #78350f;
  font-size: 15.5px;
  text-align: left;
}
.note strong {
  font-weight: 600;
}
pre.cmd {
  background: #0f172a;
  color: #e2e8f0;
  border-radius: 12px;
  padding: 15px 18px;
  overflow-x: auto;
  font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  font-size: 13px;
  margin: 14px 0 0;
}

ul.plain {
  list-style: none;
  padding: 0;
  margin: 26px 0 0;
  color: var(--muted);
}
ul.plain li {
  padding: 9px 0 9px 28px;
  position: relative;
  font-size: 16.5px;
}
ul.plain li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 19px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.35;
}

/* ── Scroll-in animation (respects reduced motion) ────────── */

/*
 * INVERTED ON PURPOSE: `.reveal` is VISIBLE by default and only hidden once
 * reveal.js has armed itself by putting `.reveal-armed` on <html>.
 *
 * The obvious way round — hide in CSS, show from JS — means every way the
 * script can fail to run (not loaded, blocked, parse error, scripting off)
 * produces a blank page instead of a missing animation. Arming from the same
 * file that un-arms guarantees the two cannot come apart.
 */
.reveal-armed .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.8s ease, transform 0.8s ease;
}
.reveal-armed .reveal.in {
  opacity: 1;
  transform: none;
}
@media (prefers-reduced-motion: reduce) {
  .reveal-armed .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
  html {
    scroll-behavior: auto;
  }
}

/* ── Footer ───────────────────────────────────────────────── */

.site-footer {
  background: #0f172a;
  color: #94a3b8;
  padding: 48px 0;
  font-size: 15px;
}
.site-footer .wrap {
  display: flex;
  gap: 30px;
  flex-wrap: wrap;
  align-items: center;
}
.site-footer a {
  color: #cbd5e1;
}
.site-footer a:hover {
  color: #ffffff;
}
.site-footer .spacer {
  margin-left: auto;
}
.site-footer img,
.site-footer svg {
  height: 24px;
  width: auto;
}

@media (max-width: 640px) {
  body {
    font-size: 16px;
  }
  .site-header .wrap {
    height: 62px;
    gap: 14px;
  }
  .site-nav {
    gap: 15px;
    font-size: 14px;
  }
  .hero {
    padding: 60px 0 52px;
  }
  .band {
    padding: 56px 0;
  }
  .card,
  .step,
  .dl {
    padding: 24px;
  }
}
