/* AuthPulse design system — tokens + base.
   Grounds: INK (live system surfaces: site, monitoring) / PAPER (kept artefacts:
   reports, protocol, invoices). Never mix inside one block. */

/* Webfonts, self-hosted latin subsets. Plex Sans + Newsreader are variable
   (weight axis); Plex Mono ships static 400/500/600. */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400 700;
  font-stretch: 100%;
  font-display: swap;
  src: url("fonts/plex-sans-var-latin.woff2") format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/plex-mono-400-latin.woff2") format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/plex-mono-500-latin.woff2") format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/plex-mono-600-latin.woff2") format('woff2');
}
@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("fonts/newsreader-var-latin.woff2") format('woff2');
}
@font-face {
  font-family: 'Newsreader';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/newsreader-italic-latin.woff2") format('woff2');
}

:root {
  --font-sans: "IBM Plex Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --font-serif: "Newsreader", Georgia, "Times New Roman", serif;
}

/* ── AuthPulse colour system ───────────────────────────────────────────────
   Two grounds, and a law about which one you are allowed to use:

     INK   = the system talking. Live state, event streams, telemetry, the site.
     PAPER = the artefact you keep. Reports, the Protocol, invoices, receipts.

   Never mix the two inside one block. One brand signal (pulse green) doubles as
   the PASS verdict, so a healthy domain and the brand read the same. */
:root {
  /* Ink — the dark ground, in elevation order */
  --ink-1000: #070a0e;
  --ink-950: #0b0f14;
  --ink-900: #10151b;
  --ink-850: #151c24;
  --ink-800: #1a222b;
  --ink-750: #202a34;
  --ink-700: #232e39;
  --ink-600: #2f3b47;
  --ink-500: #46545f;
  --ink-400: #64707b;
  --ink-300: #8a96a1;
  --ink-200: #aeb8c1;
  --ink-100: #d3dae0;

  /* Paper — warm bone. Never pure white at scale. */
  --paper-000: #fffdf9;
  --paper-100: #f7f4ed;
  --paper-200: #efebe1;
  --paper-300: #e3ddd0;
  --paper-400: #d3cbba;

  /* Pulse — brand green / verdict PASS */
  --pulse-900: #143a2e;
  --pulse-800: #1e5342;
  --pulse-700: #266753;
  --pulse-600: #2f7d66;
  --pulse-500: #3e9478;
  --pulse-300: #8cc3b0;
  --pulse-200: #b9dccf;
  --pulse-100: #e2f0ea;
  --pulse-glow: #7fb8a4; /* dark grounds only — verdigris signal, no phosphor */

  /* Amber — verdict WARN / severity MEDIUM */
  --amber-700: #8c5c05;
  --amber-600: #b57a0a;
  --amber-500: #d59b21;
  --amber-300: #e7bd5c;
  --amber-100: #f8eccd;

  /* Ember — severity HIGH. The one warm hue, borrowed from nothing. */
  --ember-700: #96400f;
  --ember-600: #c4581f;
  --ember-500: #e0743a;
  --ember-100: #f9e3d5;

  /* Crimson — verdict FAIL / severity CRITICAL */
  --crimson-700: #8a2113;
  --crimson-600: #b02e1c;
  --crimson-500: #d24630;
  --crimson-300: #e08a79;
  --crimson-100: #f7ddd7;

  /* ── Semantic aliases: use these in product code ── */
  --bg-page: var(--paper-100);
  --bg-raised: var(--paper-000);
  --bg-sunken: var(--paper-200);
  --bg-inverse: var(--ink-900);
  --bg-inverse-raised: var(--ink-800);
  --bg-accent-soft: var(--pulse-100);

  --text-primary: var(--ink-900);
  --text-secondary: var(--ink-500);
  --text-muted: var(--ink-400);
  --text-inverse: var(--paper-100);
  --text-inverse-muted: var(--ink-200);
  --text-accent: var(--pulse-700);
  --text-link: var(--pulse-700);
  --text-link-hover: var(--ink-900);

  --border-hairline: var(--paper-300);
  --border-strong: var(--ink-900);
  --border-soft: var(--paper-200);
  --border-inverse: #2b3540;
  --border-focus: var(--pulse-600);

  --action-primary-bg: var(--ink-900);
  --action-primary-bg-hover: var(--ink-700);
  --action-primary-text: var(--paper-000);
  --action-accent-bg: var(--pulse-600);
  --action-accent-bg-hover: var(--pulse-700);
  --action-accent-text: #ffffff;

  --verdict-pass: var(--pulse-600);
  --verdict-pass-soft: var(--pulse-100);
  --verdict-warn: var(--amber-600);
  --verdict-warn-soft: var(--amber-100);
  --verdict-fail: var(--crimson-600);
  --verdict-fail-soft: var(--crimson-100);
  --verdict-unknown: var(--ink-300);
  --verdict-unknown-soft: var(--paper-200);
  /* Foreground pairs: text/icon colour to use ON the matching -soft ground. */
  --verdict-pass-fg: var(--pulse-700);
  --verdict-warn-fg: var(--amber-700);
  --verdict-fail-fg: var(--crimson-700);
  --verdict-unknown-fg: var(--ink-500);

  /* Severity ramp — for anomalies in report data, not for form validation */
  --sev-critical: var(--crimson-600);
  --sev-high: var(--ember-600);
  --sev-medium: var(--amber-600);
  --sev-low: var(--ink-400);
  --sev-resolved: var(--pulse-600);
}

/* ── Paper ground scope ──────────────────────────────────────────────────
   Artefacts you keep: reports, the Protocol, invoices, receipts.
   NOTE: base --text-muted (ink-400) is 2.75:1 on paper, below WCAG AA.
   On paper grounds muted text therefore uses ink-500 (7.10:1). */
.ap-paper {
  --text-muted: var(--ink-500);
  color: var(--text-primary);
  background: var(--bg-page);
}

/* ── Dark ground scope ───────────────────────────────────────────────────
   Put .ap-dark on any element that sits on ink. This is the DEFAULT ground
   for live-system surfaces: the marketing site, the monitoring views, alerts. */
.ap-dark {
  --bg-page: var(--ink-900);
  --bg-panel: var(--ink-850);
  --bg-raised: var(--ink-800);
  --bg-sunken: var(--ink-950);
  --text-primary: var(--paper-100);
  --text-secondary: var(--ink-200);
  --text-muted: var(--ink-300);
  --text-faint: var(--ink-400);
  --text-accent: var(--pulse-glow);
  --text-link: var(--pulse-glow);
  --text-link-hover: var(--paper-000);
  --border-hairline: rgba(255, 255, 255, 0.07);
  --border-soft: rgba(255, 255, 255, 0.045);
  --border-emphasis: rgba(255, 255, 255, 0.14);
  --border-strong: var(--paper-200);
  --action-primary-bg: var(--paper-100);
  --action-primary-bg-hover: var(--paper-000);
  --action-primary-text: var(--ink-900);
  --verdict-pass: var(--pulse-glow);
  --verdict-pass-soft: #0a2b21;
  --verdict-warn: var(--amber-500);
  --verdict-warn-soft: #2d2109;
  --verdict-fail: var(--crimson-500);
  --verdict-fail-soft: #34140e;
  --verdict-unknown: var(--ink-400);
  --verdict-unknown-soft: #141c23;
  --verdict-pass-fg: var(--pulse-glow);
  --verdict-warn-fg: var(--amber-300);
  --verdict-fail-fg: var(--crimson-300);
  --verdict-unknown-fg: var(--ink-200);
  --sev-critical: var(--crimson-500);
  --sev-high: var(--ember-500);
  --sev-medium: var(--amber-500);
  --sev-low: var(--ink-300);
  --sev-resolved: var(--pulse-glow);
  color: var(--text-primary);
  background: var(--bg-page);
}

/* ── Type system ───────────────────────────────────────────────────────────
   Plex Sans carries headlines and body. Plex Mono carries anything the machine
   said: DNS records, verdict labels, eyebrows, prices, dates. Newsreader appears
   once per page at most, for a sentence that wants to be read slowly. */
:root {
  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;

  --size-display-1: clamp(2.75rem, 6.2vw, 4.5rem);   /*  44 → 72 */
  --size-display-2: clamp(2.25rem, 4.6vw, 3.375rem); /*  36 → 54 */
  --size-h1: 2.5rem;      /* 40 */
  --size-h2: 1.875rem;    /* 30 */
  --size-h3: 1.375rem;    /* 22 */
  --size-h4: 1.125rem;    /* 18 */
  --size-lead: 1.25rem;   /* 20 */
  --size-body: 1.0625rem; /* 17 */
  --size-small: 0.9375rem;/* 15 */
  --size-micro: 0.8125rem;/* 13 */
  --size-label: 0.75rem;  /* 12 */
  --size-nano: 0.6875rem; /* 11 — dense product chrome and email meta only */

  --leading-tight: 1.04;
  --leading-snug: 1.16;
  --leading-normal: 1.35;
  --leading-body: 1.58;
  --leading-loose: 1.72;

  --tracking-tight: -0.022em;
  --tracking-snug: -0.012em;
  --tracking-normal: 0;
  --tracking-wide: 0.04em;
  --tracking-label: 0.11em;

  /* Composed roles */
  --type-display: var(--weight-semibold) var(--size-display-1) / var(--leading-tight) var(--font-sans);
  --type-h1: var(--weight-semibold) var(--size-h1) / var(--leading-snug) var(--font-sans);
  --type-h2: var(--weight-semibold) var(--size-h2) / var(--leading-snug) var(--font-sans);
  --type-h3: var(--weight-semibold) var(--size-h3) / var(--leading-normal) var(--font-sans);
  --type-lead: var(--weight-regular) var(--size-lead) / var(--leading-body) var(--font-sans);
  --type-body: var(--weight-regular) var(--size-body) / var(--leading-body) var(--font-sans);
  --type-small: var(--weight-regular) var(--size-small) / var(--leading-body) var(--font-sans);
  --type-mono: var(--weight-regular) var(--size-small) / var(--leading-normal) var(--font-mono);
  --type-record: var(--weight-regular) var(--size-micro) / 1.7 var(--font-mono);
  --type-label: var(--weight-medium) var(--size-label) / 1.2 var(--font-mono);
  --type-nano: var(--weight-medium) var(--size-nano) / 1.2 var(--font-mono);
  /* Telemetry: a value in a data position. Always tabular, always mono. */
  --type-data: var(--weight-regular) var(--size-micro) / 1.35 var(--font-mono);
  --type-data-lg: var(--weight-medium) var(--size-small) / 1.3 var(--font-mono);
  --type-quote: var(--weight-regular) 1.625rem / 1.42 var(--font-serif);
}

/* ── Space + layout ───────────────────────────────────────────────────────
   4px grid, but the useful jumps are named. Section rhythm is deliberately
   large: this brand breathes like a printed report, not a dashboard. */
:root {
  --space-0: 0;
  --space-05: 2px;
  --space-1: 4px;
  --space-15: 6px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-7: 32px;
  --space-8: 40px;
  --space-9: 56px;
  --space-10: 72px;
  --space-11: 96px;
  --space-12: 128px;

  --gutter: var(--space-6);
  --container-max: 1120px;
  --container-narrow: 720px;
  --container-wide: 1320px;
  --measure-prose: 62ch;
  --measure-lead: 46ch;

  --section-y: clamp(56px, 8vw, 112px); /* @kind spacing */
  --stack-tight: var(--space-3);
  --stack: var(--space-5);
  --stack-loose: var(--space-8);

  --control-height-sm: 34px;
  --control-height: 44px;
  --control-height-lg: 54px;
  --control-pad-x: var(--space-5);
  --field-pad-x: var(--space-4);
  --hit-min: 44px;
}

/* ── Surfaces: radii, borders, elevation, atmosphere ──────────────────────
   Radii stay small — a document brand, not a bubble brand. On paper, panels are
   hairline-bordered and flat. On ink, depth comes from a 1px top highlight and a
   one-step lighter ground, never from a glow and never from glass. */
:root {
  --radius-xs: 2px;
  --radius-sm: 4px;
  --radius-md: 6px;
  --radius-lg: 10px;
  --radius-pill: 999px;

  --border-width: 1px;
  --border-width-thick: 2px;
  --rule: var(--border-width) solid var(--border-hairline);
  --rule-strong: var(--border-width-thick) solid var(--border-strong);

  --shadow-none: none;
  --shadow-1: 0 1px 2px rgba(12, 17, 22, 0.06);
  --shadow-2: 0 4px 14px -4px rgba(12, 17, 22, 0.14);
  --shadow-3: 0 24px 48px -16px rgba(12, 17, 22, 0.28);
  --shadow-inset-top: inset 0 1px 0 rgba(255, 255, 255, 0.06);
  --focus-ring: 0 0 0 3px rgba(10, 134, 89, 0.3);
  --focus-ring-inverse: 0 0 0 3px rgba(53, 227, 154, 0.34);

  /* Dark elevation. Panel = ink-850 + hairline + top highlight. That is all. */
  --panel-bg: var(--ink-850);
  --panel-border: 1px solid rgba(255, 255, 255, 0.07); /* @kind other */
  --panel-highlight: inset 0 1px 0 rgba(255, 255, 255, 0.05); /* @kind shadow */
  --panel-shadow: 0 1px 0 rgba(0, 0, 0, 0.4), 0 18px 40px -28px rgba(0, 0, 0, 0.9);
  --panel-shadow-lifted: 0 1px 0 rgba(0, 0, 0, 0.4), 0 28px 60px -24px rgba(0, 0, 0, 0.95);

  /* Atmosphere. One soft green wash behind a hero; no blobs, no spheres. */
  --atmos-pulse: radial-gradient(120% 90% at 18% -10%, rgba(127, 184, 164, 0.1) 0%, rgba(127, 184, 164, 0.025) 38%, transparent 70%); /* @kind color */
  --atmos-deep: radial-gradient(90% 70% at 82% 0%, rgba(35, 46, 57, 0.9) 0%, transparent 68%); /* @kind color */
  --texture-trace: url("assets/trace.svg"); /* @kind other */
  --texture-grain: url("assets/grain.svg"); /* @kind other */
  --scrim-ink: linear-gradient(180deg, rgba(16, 21, 27, 0) 0%, rgba(16, 21, 27, 0.72) 62%, rgba(16, 21, 27, 0.94) 100%); /* @kind color */
  --scrim-fade-right: linear-gradient(90deg, rgba(16, 21, 27, 0) 0%, rgba(16, 21, 27, 0.96) 82%); /* @kind color */
}

/* ── Telemetry & data display ─────────────────────────────────────────────
   AuthPulse reads DMARC aggregate reports, so the product's native material is
   authentication events: a source IP, a provider, a volume, an alignment result.
   These tokens exist so an event looks identical in the hero, the dashboard,
   a printed report and a 600px email. */
:root {
  /* Event ticks: authenticated mail rises from the baseline, forged mail falls. */
  --trace-baseline: var(--ink-600);
  --trace-pass: var(--pulse-600);
  --trace-fail: var(--crimson-600);
  --trace-partial: var(--amber-600);
  --trace-idle: var(--ink-200);

  --viz-grid: rgba(12, 17, 22, 0.08);
  --viz-axis: var(--ink-300);
  --viz-series-1: var(--pulse-600);
  --viz-series-2: var(--ink-500);
  --viz-series-3: var(--crimson-600);
  --viz-series-4: var(--amber-600);

  /* Geometry of the event language. These are the brand's tells: 6px squares,
     2px ticks, 1px hairlines, never dots and never rounded. */
  --swatch-size: 6px; /* @kind spacing */
  --swatch-size-lg: 8px; /* @kind spacing */
  --tick-width: 2px; /* @kind spacing */
  --tick-gap: 3px; /* @kind spacing */
  --trace-height: 64px; /* @kind spacing */
  --row-height-dense: 34px; /* @kind spacing */
  --row-height: 44px; /* @kind spacing */
}

.ap-dark {
  --trace-baseline: rgba(255, 255, 255, 0.12);
  --trace-pass: var(--pulse-glow);
  --trace-fail: var(--crimson-500);
  --trace-partial: var(--amber-500);
  --trace-idle: var(--ink-600);
  --viz-grid: rgba(255, 255, 255, 0.06);
  --viz-axis: var(--ink-400);
  --viz-series-1: var(--pulse-glow);
  --viz-series-2: var(--ink-300);
  --viz-series-3: var(--crimson-500);
  --viz-series-4: var(--amber-500);
}

/* Numbers in data positions are always tabular. */
.ap-tnum { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }

/* ── Motion ───────────────────────────────────────────────────────────────
   Motion exists to show system behaviour: an event arriving, a verdict landing,
   a spike appearing. Short, flat, no bounce. Nothing moves for decoration
   except the trace sweep, and there is one of those per page. */
:root {
  --dur-instant: 90ms; /* @kind other */
  --dur-fast: 140ms; /* @kind other */
  --dur-base: 200ms; /* @kind other */
  --dur-slow: 320ms; /* @kind other */
  --dur-trace: 2600ms; /* @kind other */
  --dur-event: 480ms; /* @kind other */
  --dur-stream: 3200ms; /* @kind other */

  --ease-out: cubic-bezier(0.2, 0.7, 0.3, 1); /* @kind other */
  --ease-in-out: cubic-bezier(0.5, 0, 0.3, 1); /* @kind other */
  --ease-entrance: cubic-bezier(0.16, 0.84, 0.28, 1); /* @kind other */

  --transition-control: background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out), transform var(--dur-instant) var(--ease-out); /* @kind other */
}

@keyframes ap-trace { from { stroke-dashoffset: 240; } to { stroke-dashoffset: 0; } }
@keyframes ap-fade-up { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
/* An event arrives: the tick grows out of the baseline it belongs to. */
@keyframes ap-tick-in { from { transform: scaleY(0.04); opacity: 0.2; } to { transform: scaleY(1); opacity: 1; } }
/* A row is inserted at the top of a live stream. */
@keyframes ap-row-in { from { opacity: 0; transform: translateY(-6px); background-color: rgba(127, 184, 164, 0.07); } to { opacity: 1; transform: none; background-color: transparent; } }
/* A verdict lands. Used once, on the thing the reader must notice. */
@keyframes ap-blip { 0% { box-shadow: 0 0 0 0 rgba(127, 184, 164, 0.5); } 70% { box-shadow: 0 0 0 7px rgba(127, 184, 164, 0); } 100% { box-shadow: 0 0 0 0 rgba(127, 184, 164, 0); } }
@keyframes ap-blip-fail { 0% { box-shadow: 0 0 0 0 rgba(210, 70, 48, 0.5); } 70% { box-shadow: 0 0 0 7px rgba(210, 70, 48, 0); } 100% { box-shadow: 0 0 0 0 rgba(210, 70, 48, 0); } }
@keyframes ap-scan-sweep { from { transform: translateX(-100%); } to { transform: translateX(100%); } }

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-instant: 1ms; /* @kind other */
    --dur-fast: 1ms; /* @kind other */
    --dur-base: 1ms; /* @kind other */
    --dur-slow: 1ms; /* @kind other */
    --dur-event: 1ms; /* @kind other */
  }
  *, *::before, *::after { animation-duration: 1ms !important; animation-iteration-count: 1 !important; }
}

/* ── Base element styling ─────────────────────────────────────────────────
   Deliberately thin. Sets the grounds, the type defaults, links, selection,
   focus and the two prose helpers. Everything else is a component. */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg-page);
  color: var(--text-primary);
  font: var(--type-body);
  letter-spacing: var(--tracking-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 { margin: 0; letter-spacing: var(--tracking-tight); text-wrap: balance; }
h1 { font: var(--type-h1); }
h2 { font: var(--type-h2); }
h3 { font: var(--type-h3); letter-spacing: var(--tracking-snug); }
h4 { font: var(--weight-semibold) var(--size-h4) / var(--leading-normal) var(--font-sans); letter-spacing: var(--tracking-snug); }
p { margin: 0 0 var(--space-4); text-wrap: pretty; }
p:last-child { margin-bottom: 0; }
strong, b { font-weight: var(--weight-semibold); }
small { font-size: var(--size-small); }
code, kbd, samp, pre { font-family: var(--font-mono); font-size: 0.94em; }

a {
  color: var(--text-link);
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  text-decoration-color: color-mix(in srgb, var(--text-link) 42%, transparent);
  transition: color var(--dur-fast) var(--ease-out), text-decoration-color var(--dur-fast) var(--ease-out);
}
a:hover { color: var(--text-link-hover); text-decoration-color: currentColor; }
a:active { color: var(--text-link-hover); }

:focus-visible { outline: 2px solid var(--border-focus); outline-offset: 2px; }
::selection { background: var(--pulse-200); color: var(--ink-900); }
.ap-dark ::selection { background: var(--pulse-800); color: var(--paper-000); }

hr { border: 0; border-top: var(--rule); margin: var(--space-8) 0; }

/* Two prose helpers, since this brand ships a lot of written explanation. */
.ap-prose { max-width: var(--measure-prose); }
.ap-prose > * + h2 { margin-top: var(--space-8); }
.ap-prose > * + h3 { margin-top: var(--space-6); }
.ap-prose p { color: var(--text-secondary); }
.ap-prose li { color: var(--text-secondary); margin-bottom: var(--space-2); }

/* Every number in a data position is tabular. */
.ap-data { font: var(--type-data); font-variant-numeric: tabular-nums; }

/* Eyebrow / machine label. Used above nearly every section heading. */
.ap-label {
  font: var(--type-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
}

