/* ═══════════════════════════════════════════════════════════════════════════
   Raylux — marketing site

   DIRECTION: instrument datasheet. The reference is a Beckhoff / Phoenix
   Contact / Keysight product catalogue, not a SaaS landing page. Numbered
   sections, ruled spec tables, monospace for every measured value, numbered
   figures. Engineers buy from datasheets; the page is shaped like one.

   This deliberately does NOT imitate the Nexus console any more. The earlier
   version wore the product's own chrome — a 52px icon rail, a topbar with a
   dummy search box, dashboard panels at 13px — which is why it read as the
   config hub rather than a company site. Structure, not styling, was the
   problem: the palette and hairline discipline below are carried over intact.

   WHAT IS DELIBERATE, so a future edit does not "clean it up" into the median:
     - IBM Plex Sans/Mono. IBM's technical family, not Inter or Geist.
     - No border-radius anywhere. No shadows on anything in the page plane.
     - Rules and whitespace separate content. There are no cards.
     - Values are monospace and tabular; prose is not.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Palette is the Nexus console's, so the site and the product agree — see
   web/src/index.css in the Raylux-SCADA repo, which is the source of truth.

   Light is the default: plant-floor HMIs are read in bright rooms, and the
   engineers this is aimed at expect a light instrument face. Dark is the
   opt-in, and the choice persists. */
:root {
  color-scheme: light;
  --bg: #f6f7f9;
  --paper: #ffffff;
  --sunken: #eef1f5;
  --input: #ffffff;
  --border: #e3e6ea;
  --border-subtle: #edeff2;
  --border-strong: #d3d9df;
  --rule: #0d1521;
  --text: #1a2330;
  --text-bright: #0d1521;
  --secondary: #5b6572;
  --muted: #8a93a0;
  /* #4a9eff is tuned for a near-black surface and drops to ~2.7:1 on white.
     Each theme takes the blue that works on its own background. */
  --accent: #1e88e5;
  --accent-fill: #1565c0;
  --success: #2e9e44;
  --warning: #f57c00;
  --error: #e12d39;
  --hover: rgba(30, 136, 229, 0.05);
  --accent-wash: rgba(30, 136, 229, 0.08);
}

/* Alarm colours do NOT change between themes. They are routed to the HMI
   colour standard so a critical reads the same here as on an operator screen;
   --success does shift, because it is chrome rather than screen semantics. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #16171c;
  --paper: #1a1b20;
  --sunken: #131419;
  --input: #15161b;
  --border: #2e3038;
  --border-subtle: #26282f;
  --border-strong: #3a3d47;
  --rule: #e3e4e8;
  --text: #c9cbd1;
  --text-bright: #e3e4e8;
  --secondary: #a6aab3;
  --muted: #8a8f98;
  --accent: #4a9eff;
  --accent-fill: #1e6fd9;
  --success: #98c379;
  --hover: rgba(255, 255, 255, 0.05);
  --accent-wash: rgba(74, 158, 255, 0.1);
}

* {
  box-sizing: border-box;
}

html {
  background: var(--bg);
  -webkit-text-size-adjust: 100%;
}

/* 16px base, not the console's 13px. App density is why the old page felt like
   a tool rather than something to read. */
body {
  min-height: 100vh;
  margin: 0;
  color: var(--text);
  background: var(--bg);
  font-family: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: 16px;
  line-height: 1.6;
  overflow-wrap: break-word;
}

button,
input {
  font: inherit;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

a {
  color: var(--accent-fill);
}

img {
  max-width: 100%;
  height: auto;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 10;
  padding: 10px 16px;
  color: #ffffff;
  background: var(--accent-fill);
  font-weight: 700;
}

.skip-link:focus {
  left: 0;
}

h1:focus {
  outline: none;
}

/* A spec table's value column has no visible header — the label column already
   says what the table is. Screen readers still need one. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Every measured quantity is monospace and tabular — a port, a version, a
   poll rate, a level. Prose is not. That split is the datasheet's whole
   typographic argument, so keep it. */
.mono,
code,
.spec td:last-child,
.figure figcaption b,
.stat-value {
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-variant-numeric: tabular-nums;
}

/* ---------- page frame ---------- */

.wrap {
  width: min(1180px, 100% - 48px);
  margin-inline: auto;
}

/* ---------- masthead ----------
   A document header, not an app topbar: wordmark, contents, status. */

.masthead {
  border-bottom: 1px solid var(--border);
  background: var(--paper);
}

.masthead-in {
  display: flex;
  align-items: center;
  gap: 32px;
  min-height: 68px;
  flex-wrap: wrap;
}

.wordmark {
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  margin: 0;
  color: var(--text-bright);
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-decoration: none;
}

.wordmark span {
  color: var(--muted);
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.masthead nav {
  display: flex;
  gap: 4px;
  margin-right: auto;
  flex-wrap: wrap;
}

.masthead nav a {
  padding: 6px 10px;
  color: var(--secondary);
  font-size: 14px;
  text-decoration: none;
  border-bottom: 2px solid transparent;
}

.masthead nav a:hover {
  color: var(--text-bright);
}

.masthead nav a[aria-current="page"] {
  color: var(--text-bright);
  border-bottom-color: var(--accent);
}

/* Pre-launch stated as a document status line. Honest, and it belongs to the
   datasheet language rather than being a marketing banner bolted on. */
.status-line {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  color: var(--muted);
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
}

.status-line::before {
  content: "";
  width: 7px;
  height: 7px;
  background: var(--warning);
}

.theme-toggle {
  padding: 7px 10px;
  color: var(--secondary);
  background: transparent;
  border: 1px solid var(--border-strong);
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
}

.theme-toggle:hover {
  color: var(--text-bright);
  border-color: var(--accent);
}

.theme-toggle[aria-pressed="true"] {
  color: var(--accent);
  border-color: var(--accent);
}

/* ---------- hero ---------- */

.hero {
  padding: 88px 0 64px;
  border-bottom: 2px solid var(--rule);
}

.hero h1 {
  max-width: 18ch;
  margin: 0 0 24px;
  color: var(--text-bright);
  font-size: clamp(40px, 6.2vw, 76px);
  font-weight: 600;
  line-height: 1.02;
  letter-spacing: -0.02em;
}

.hero-lede {
  max-width: 62ch;
  margin: 0 0 32px;
  color: var(--secondary);
  font-size: clamp(17px, 1.7vw, 20px);
  line-height: 1.55;
}

.hero-actions {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
}

/* ---------- section numbering ----------
   Sections are numbered like clauses in a datasheet. The number is content,
   not decoration, so it lives in the markup. */

.section {
  padding: 72px 0;
  border-bottom: 1px solid var(--border);
}

.section-head {
  display: flex;
  align-items: baseline;
  gap: 16px;
  margin-bottom: 36px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--rule);
  flex-wrap: wrap;
}

.section-no {
  color: var(--accent);
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
}

.section-head h2 {
  margin: 0;
  color: var(--text-bright);
  font-size: clamp(22px, 2.6vw, 30px);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.section-head p {
  margin: 0;
  margin-left: auto;
  max-width: 46ch;
  color: var(--muted);
  font-size: 14px;
}

/* ---------- spec tables ----------
   The workhorse. Label left, value right, hairline between rows. No zebra
   striping, no rounded container, no card. */

.spec {
  width: 100%;
  border-collapse: collapse;
}

.spec th {
  padding: 0 0 10px;
  color: var(--muted);
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-align: left;
  border-bottom: 1px solid var(--rule);
}

.spec td {
  padding: 13px 0;
  vertical-align: top;
  border-bottom: 1px solid var(--border);
}

.spec td:first-child {
  width: 34%;
  padding-right: 24px;
  color: var(--text-bright);
  font-weight: 600;
}

.spec td:last-child {
  color: var(--secondary);
  font-size: 15px;
}

.spec tr:last-child td {
  border-bottom: 0;
}

/* Two spec tables side by side on wide screens. */
.spec-pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 0 56px;
}

/* ---------- module index ----------
   The four products as a ruled list with a leading designation, the way a
   catalogue indexes part numbers. Not feature cards. */

.modules {
  border-top: 1px solid var(--rule);
}

.module {
  display: grid;
  grid-template-columns: 92px minmax(0, 1.15fr) minmax(0, 1.6fr) auto;
  align-items: baseline;
  gap: 28px;
  padding: 26px 0;
  border-bottom: 1px solid var(--border);
  text-decoration: none;
  color: inherit;
}

.module:hover {
  background: var(--hover);
}

.module-no {
  color: var(--muted);
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 12px;
  letter-spacing: 0.1em;
}

.module h3 {
  margin: 0;
  color: var(--text-bright);
  font-size: 21px;
  font-weight: 600;
}

.module h3 small {
  display: block;
  margin-top: 4px;
  color: var(--muted);
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.module p {
  margin: 0;
  color: var(--secondary);
  font-size: 15px;
}

.module-go {
  color: var(--accent);
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 12px;
  white-space: nowrap;
}

/* ---------- figures ----------
   Numbered, captioned, full width, hairline border. A screenshot is evidence,
   so it is presented as a figure with a reference — not a floating card. */

.figure {
  margin: 0 0 44px;
}

.figure:last-child {
  margin-bottom: 0;
}

.figure img {
  display: block;
  width: 100%;
  border: 1px solid var(--border-strong);
  background: var(--sunken);
}

.figure figcaption {
  display: flex;
  gap: 14px;
  margin-top: 12px;
  padding-top: 10px;
  color: var(--secondary);
  font-size: 14px;
  line-height: 1.5;
  border-top: 1px solid var(--border);
}

.figure figcaption b {
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* A figure slot with nothing in it yet. Visible on purpose: a page that
   silently omits a screenshot looks finished when it is not. */
.figure-pending {
  display: grid;
  place-items: center;
  min-height: 220px;
  padding: 28px;
  color: var(--muted);
  background: var(--sunken);
  border: 1px dashed var(--border-strong);
  text-align: center;
  font-size: 14px;
}

/* ---------- prose ---------- */

.prose-pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 40px 56px;
}

.prose h3 {
  margin: 0 0 10px;
  color: var(--text-bright);
  font-size: 17px;
  font-weight: 600;
}

.prose p {
  margin: 0 0 12px;
  color: var(--secondary);
  font-size: 15px;
}

.prose p:last-child {
  margin-bottom: 0;
}

.prose ul {
  margin: 0 0 12px;
  padding-left: 18px;
  color: var(--secondary);
  font-size: 15px;
}

.prose strong {
  color: var(--text-bright);
  font-weight: 600;
}

/* ---------- buttons ---------- */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 0 22px;
  color: #ffffff;
  background: var(--accent-fill);
  border: 1px solid var(--accent-fill);
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}

.button:hover {
  background: var(--accent);
  border-color: var(--accent);
}

.button-quiet {
  color: var(--text-bright);
  background: transparent;
  border-color: var(--border-strong);
}

.button-quiet:hover {
  color: var(--accent);
  background: transparent;
  border-color: var(--accent);
}

/* ---------- signup ---------- */

.notify-form {
  max-width: 560px;
}

.notify-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
}

.notify-row input {
  min-width: 0;
  height: 46px;
  padding: 0 14px;
  color: var(--text-bright);
  background: var(--input);
  border: 1px solid var(--border-strong);
  border-right: 0;
  outline: none;
}

.notify-row input:focus-visible {
  border-color: var(--accent);
  outline-offset: -1px;
}

.notify-status {
  margin: 12px 0 0;
  color: var(--secondary);
  font-size: 14px;
}

.notify-status.is-ok {
  color: var(--success);
}

.notify-status.is-error {
  color: var(--error);
}

/* Honeypot: off-screen for people, still fillable by bots. */
.trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ---------- footer ---------- */

.site-footer {
  padding: 40px 0;
  color: var(--muted);
  border-top: 2px solid var(--rule);
  font-size: 14px;
}

.site-footer-in {
  display: flex;
  gap: 24px;
  justify-content: space-between;
  flex-wrap: wrap;
}

.site-footer nav {
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
}

.site-footer a {
  color: var(--secondary);
  text-decoration: none;
}

.site-footer a:hover {
  color: var(--accent);
}

/* ---------- 404 ---------- */

.notfound {
  padding: 120px 0;
}

.notfound-code {
  margin: 0 0 12px;
  color: var(--accent);
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 13px;
  letter-spacing: 0.16em;
}

.notfound h1 {
  margin: 0 0 16px;
  color: var(--text-bright);
  font-size: clamp(32px, 5vw, 52px);
  font-weight: 600;
  line-height: 1.05;
}

.notfound p {
  max-width: 56ch;
  color: var(--secondary);
}

/* ---------- responsive ---------- */

@media (max-width: 860px) {
  .wrap {
    width: min(1180px, 100% - 32px);
  }

  .hero {
    padding: 56px 0 44px;
  }

  .section {
    padding: 48px 0;
  }

  /* The four-column part-number row collapses rather than crushing. The
     designation and the arrow are chrome, so they go first. */
  .module {
    grid-template-columns: minmax(0, 1fr);
    gap: 8px;
  }

  .module-no,
  .module-go {
    display: none;
  }

  .section-head p {
    margin-left: 0;
  }

  .spec td:first-child {
    width: 42%;
  }
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   COMPLIANCE PAGES — /source and /notices

   These two are named by URL in the EULA that ships in every installer, so
   they are load-bearing documents, not marketing pages. They are styled as
   the back matter of the same datasheet: same rules, same mono/prose split,
   no new visual vocabulary. A licence page that looked like a different site
   would read as less authoritative, not more.

   Nothing here introduces a radius, a shadow or a card. If you are adding one,
   you are on the wrong page.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ---------- the written offer ----------
   Set apart the way a datasheet sets apart a safety or certification clause:
   heavy rule top and bottom, not a tinted rounded box. This is the text the
   LGPL actually requires, so it must look like the operative part of the page
   rather than a callout. */

.clause {
  margin: 0 0 36px;
  padding: 26px 0;
  border-top: 2px solid var(--rule);
  border-bottom: 2px solid var(--rule);
}

.clause p {
  max-width: 74ch;
  margin: 0 0 14px;
  color: var(--text);
  font-size: 16px;
}

.clause p:last-child {
  margin-bottom: 0;
}

.clause strong {
  color: var(--text-bright);
  font-weight: 600;
}

.clause-ref {
  display: block;
  margin-bottom: 14px;
  color: var(--muted);
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* ---------- archive table ----------
   Five columns, hairline rows, every measured value monospace. Scrolls inside
   itself on narrow screens rather than forcing the page to scroll sideways. */

.table-scroll {
  overflow-x: auto;
}

.dl {
  width: 100%;
  min-width: 640px;
  border-collapse: collapse;
}

.dl th {
  padding: 0 16px 10px 0;
  color: var(--muted);
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-align: left;
  white-space: nowrap;
  border-bottom: 1px solid var(--rule);
}

.dl td {
  padding: 14px 16px 14px 0;
  vertical-align: baseline;
  border-bottom: 1px solid var(--border);
}

.dl tr:last-child td {
  border-bottom: 0;
}

.dl .c-name {
  color: var(--text-bright);
  font-weight: 600;
}

/* Version, licence and size are all measured values. */
.dl .c-ver,
.dl .c-lic,
.dl .c-size {
  color: var(--secondary);
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.dl .c-size {
  text-align: right;
}

.dl .c-get {
  text-align: right;
  white-space: nowrap;
}

.dl .c-get a {
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 12px;
  text-decoration: none;
}

.dl .c-get a:hover {
  text-decoration: underline;
}

/* Copyleft rows carry the obligation, so they are marked in the table itself
   rather than only in prose. A rule, not a highlight fill. */
.dl .is-copyleft .c-lic {
  color: var(--text-bright);
  font-weight: 600;
}

/* ---------- checksums / command blocks ---------- */

.pre {
  margin: 0 0 8px;
  padding: 16px 18px;
  overflow-x: auto;
  color: var(--secondary);
  background: var(--sunken);
  border: 1px solid var(--border);
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 12.5px;
  line-height: 1.7;
  tab-size: 2;
}

.pre b {
  color: var(--text-bright);
  font-weight: 600;
}

.pre-note {
  margin: 0 0 28px;
  color: var(--muted);
  font-size: 13px;
}

/* ---------- notice inventory ----------
   ~80 components. A row each would be five screens of scrolling, so packages
   are grouped by licence and set as a dense monospace column list — which is
   also how the closure is actually read. The licence is the heading because
   the licence is the thing with legal effect. */

.licence-block {
  padding: 22px 0;
  border-bottom: 1px solid var(--border);
}

.licence-block:last-child {
  border-bottom: 0;
}

.licence-head {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}

.licence-head h3 {
  margin: 0;
  color: var(--text-bright);
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.licence-count {
  color: var(--muted);
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.licence-head p {
  margin: 0 0 0 auto;
  max-width: 48ch;
  color: var(--muted);
  font-size: 13px;
}

.pkg-list {
  margin: 0;
  padding: 0;
  list-style: none;
  columns: 4 170px;
  column-gap: 32px;
}

.pkg-list li {
  color: var(--secondary);
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 12.5px;
  line-height: 1.85;
  break-inside: avoid;
}

/* ---------- footer, extended ----------
   The compliance pages have to be reachable from every page, and a company
   selling to plant operators is expected to state who it is. Both live in a
   second footer row under a hairline. */

.footer-legal {
  display: flex;
  gap: 20px 32px;
  margin-top: 26px;
  padding-top: 22px;
  border-top: 1px solid var(--border);
  justify-content: space-between;
  flex-wrap: wrap;
}

.footer-legal address {
  max-width: 46ch;
  color: var(--muted);
  font-size: 13px;
  font-style: normal;
  line-height: 1.6;
}

.footer-legal address b {
  color: var(--secondary);
  font-weight: 600;
}

.footer-legal nav {
  display: flex;
  gap: 20px;
  align-items: flex-start;
  flex-wrap: wrap;
}

.footer-legal nav a {
  font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace;
  font-size: 12px;
  letter-spacing: 0.06em;
}

@media (max-width: 860px) {
  .pkg-list {
    columns: 2 150px;
  }

  .licence-head p {
    margin-left: 0;
  }
}

/* ---------- utilities ----------
   These exist because the site's CSP is `style-src 'self'` with no
   'unsafe-inline'. A style="" attribute is BLOCKED by that policy — silently,
   because nothing renders wrong enough to notice locally, and the console
   error only appears once the header is actually applied. Several pages had
   inline styles that had therefore never taken effect in production.

   So: no style attributes anywhere on this site. If you need a one-off, add a
   named class here. Do not "simplify" one of these back into an inline style.
   Verified with `wrangler pages dev`, which serves _headers, so the console
   shows the violations. */

/* A designation line sitting above a page's h1. */
.eyebrow {
  margin-bottom: 18px;
}

.form-label {
  margin-bottom: 10px;
}

.stack-lg {
  margin-top: 28px;
}

.section-sub {
  margin: 40px 0 12px;
  color: var(--text-bright);
  font-size: 17px;
  font-weight: 600;
}

.block-gap {
  margin-top: 36px;
}

.block-gap-sm {
  margin-top: 26px;
}

/* Prose that has to stay readable when it is not in a .prose-pair column. */
.prose-wide {
  max-width: 74ch;
}

.prose-wide-gap {
  margin-top: 32px;
  max-width: 74ch;
}

/* Right-aligned column heads, paired with .c-size / .c-get on the cells. */
.dl th.num,
.dl th.act {
  text-align: right;
}

/* A two-column variant of .dl — component and licence only, no measured
   values, so it needs far less room before it has to scroll. */
.dl-narrow {
  min-width: 420px;
}
