/* Inter, self-hosted. One variable file covers 400-700, replacing three Google
   Fonts families (Raleway, Roboto, Roboto Mono) that were also off-brand.
   font-display: swap so text is readable during the font load rather than
   invisible. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/assets/fonts/InterVariable.woff2") format("woff2");
}

/* =============================================================================
   Hawkin Connect — design tokens (2026 brand)
   -----------------------------------------------------------------------------
   THE ONLY :root BLOCK ON THIS SITE. Everything else consumes these.

   The site previously carried SEVEN :root blocks — one shared, six inlined per
   page — which had drifted: some named the body font --sans, others --body;
   several omitted --mono and the status colours; api.html referenced a
   var(--accent) that was never defined anywhere. Component CSS must reference
   the SEMANTIC names below, never the raw brand values.
   ============================================================================= */

:root {
  /* ---------------------------------------------------------------------------
     Brand primitives — do not reference these directly from component CSS.
     Values from the 2026 brand book. Note the brand specifies #F4F4F4 and
     #212121, NOT pure white/black.
     --------------------------------------------------------------------------- */
  --hd-blue: #3b53a4; /* Primary Blue */
  --hd-blue-dark: #1f3f8a; /* Dark Blue */
  --hd-blue-black: #2f3442; /* Blue Black */
  --hd-accent: #0fa2ee; /* Accent Blue */
  --hd-off-white: #f4f4f4; /* Off White */
  --hd-black: #212121; /* Black */
  --hd-olive: #544f0a;
  --hd-plum: #921476;

  /* Stoplight — RESERVED by the brand for data visualisation, reports and
     performance metrics. Not decoration. */
  --hd-green: #3f9e5a;
  --hd-yellow: #fb9f02;
  --hd-brick: #ab2022;
  --hd-red: #e3362c;

  /* Derived ramp. The brand supplies almost no neutrals, so these are a
     blue-tinted grey scale rather than pure greys — keeps "blue and white
     dominant at all times" true even in secondary text and borders. */
  --hd-ink-900: #14171e;
  --hd-ink-800: #1c2029;
  --hd-ink-700: #2f3442; /* = Blue Black */
  --hd-ink-600: #3d4354;
  --hd-ink-500: #5a6076;
  --hd-ink-400: #858ba0;
  --hd-ink-300: #b9bdc9;
  --hd-ink-200: #dde0e7;
  --hd-ink-100: #eceef2;
  --hd-ink-050: #f4f4f4; /* = Off White */

  /* Dark-mode text blue. Primary Blue on a dark canvas measures 2.43:1, which
     fails WCAG AA outright — it cannot carry text or links in dark mode. This
     lightened tint measures 6.75:1 on --surface-canvas. */
  --hd-blue-300: #8fa0dc;

  /* ---------------------------------------------------------------------------
     Semantic roles — LIGHT (default)
     --------------------------------------------------------------------------- */
  --surface-canvas: var(--hd-ink-050);
  --surface-raised: #ffffff;
  --surface-sunken: var(--hd-ink-100);
  /* Flips with the theme — light page, dark band; dark page, light band. */
  --surface-inverse: var(--hd-ink-700);
  /*
   * Always dark, in BOTH themes. The footer and the API band are dark by
   * design, not by inversion — using --surface-inverse there would turn them
   * light in dark mode, which reads as a bug rather than a theme. Dark mode
   * goes deeper instead, per the brand's "layered blues".
   */
  --surface-deep: var(--hd-ink-700);
  --text-on-deep: rgb(255 255 255 / 0.87);
  --surface-accent-subtle: rgb(59 83 164 / 0.06);
  --surface-overlay: rgb(255 255 255 / 0.96);

  --text-primary: var(--hd-black); /* 14.64:1 on canvas */
  --text-secondary: var(--hd-ink-500); /*  5.67:1 */
  /* NOT --hd-ink-400: that measures 3.08:1 here, which only clears AA for large
     text — and muted copy is small by definition. #666D80 is the lightest tint
     on this ramp that still passes at body size. */
  --text-muted: #666d80; /*  4.70:1 */
  --text-on-accent: #ffffff;
  --text-on-inverse: rgb(255 255 255 / 0.87);
  --text-link: var(--hd-blue); /*  6.45:1 */
  --text-link-hover: var(--hd-blue-dark); /*  8.94:1 */

  --border-subtle: var(--hd-ink-200);
  --border-default: var(--hd-ink-300);
  --border-strong: var(--hd-ink-700);
  --border-accent: var(--hd-blue);

  --accent: var(--hd-blue);
  --accent-hover: var(--hd-blue-dark);
  /* Accent Blue is 2.57:1 on Off White — DECORATIVE ONLY. Never text. */
  --accent-bright: var(--hd-accent);
  --focus-ring: 0 0 0 2px var(--surface-canvas), 0 0 0 4px var(--hd-accent);

  /* Code — a dark block on a light page, preserving today's look */
  --code-bg: var(--hd-ink-700);
  --code-fg: #e8eaf0;
  --code-border: var(--hd-ink-600);
  --code-inline-bg: rgb(59 83 164 / 0.08);
  --code-inline-fg: var(--hd-blue-dark);

  /* Syntax. Deliberately NOT the stoplight palette — highlighting is
     decorative, and the brand reserves stoplight for status and data-viz. */
  --code-comment: var(--hd-ink-400);
  --code-keyword: #c08fd4;
  --code-string: #7fc6a0;
  --code-variable: #7fb6e8;
  --code-number: #d9b96a;
  --code-method: #e8a64a;

  /* Engineering-drawing grid. Consumed by .bg-graph / .bg-blueprint. */
  --grid-line: rgb(59 83 164 / 0.1);
  --grid-line-strong: rgb(59 83 164 / 0.2);
  --grid-minor: 8px;
  --grid-major: 40px;

  /* ---------------------------------------------------------------------------
     Status — indicator vs text are SEPARATE roles, deliberately.
     Measured on --surface-canvas: Yellow is 1.90:1 and Green 3.06:1, so the
     brand hue can fill a dot, border or badge, but the accompanying text needs
     a darker derived shade. Using the raw hue for text would regress
     accessibility versus the site as it stands today.
     --------------------------------------------------------------------------- */
  --status-success: var(--hd-green);
  --status-success-bg: rgb(63 158 90 / 0.1);
  --status-success-text: #2c7040; /*  5.46:1 */

  --status-warning: var(--hd-yellow);
  --status-warning-bg: rgb(251 159 2 / 0.12);
  --status-warning-text: #7a4d00; /*  6.61:1 */

  --status-danger: var(--hd-red);
  --status-danger-bg: rgb(227 54 44 / 0.1);
  --status-danger-text: var(--hd-brick); /*  6.45:1 */

  /* Informational states are BLUE, not stoplight — per the brand rule that
     blue and white stay dominant. */
  --status-info: var(--hd-blue);
  --status-info-bg: rgb(59 83 164 / 0.08);
  --status-info-text: var(--hd-blue-dark);

  /* ---------------------------------------------------------------------------
     Geometry — the 2026 brand is square. Live hawkindynamics.com is 0px.
     --------------------------------------------------------------------------- */
  --radius-sm: 0;
  --radius-md: 0;
  --radius-lg: 0;
  --hairline: 1px;
  --header-h: 68px;
  --topbar-h: 48px;

  --shadow-sm: 0 1px 2px rgb(47 52 66 / 0.06);
  --shadow-md: 0 2px 8px rgb(47 52 66 / 0.08);
  --shadow-lg: 0 8px 24px rgb(47 52 66 / 0.12);

  /* ---------------------------------------------------------------------------
     Typography
     Abolition (titles) and JAF Facit are commercial and ship no webfont files,
     so --font-display resolves to Inter today. The WEIGHT, TRANSFORM and
     TRACKING are tokenised alongside the family on purpose: Abolition is a
     condensed display face and will not want Inter's Medium weight or 0.12em
     tracking, so swapping it later is a change to these four values rather than
     a hunt through every heading rule.
     --------------------------------------------------------------------------- */
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-display: "Inter", var(--font-body);
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --font-display-weight: 500; /* Inter Medium, per the brand's section-header role */
  --font-display-transform: uppercase;
  --font-display-tracking: 0.12em;
  --tracking-tight: -0.02em;

  --leading-tight: 1.15;
  --leading-normal: 1.6;
  --leading-loose: 1.7;

  color-scheme: light;
}

/* =============================================================================
   DARK — "layered blues with white typography", per the brand's app rules.
   Not neutral black: the canvas keeps a blue cast.
   ============================================================================= */
:root[data-theme="dark"] {
  --surface-canvas: #171b24;
  --surface-raised: #1f2430;
  --surface-sunken: #12151c;
  --surface-inverse: var(--hd-ink-050);
  --surface-deep: var(--hd-ink-900);
  --text-on-deep: rgb(255 255 255 / 0.87);
  --surface-accent-subtle: rgb(143 160 220 / 0.1);
  --surface-overlay: rgb(23 27 36 / 0.96);

  --text-primary: var(--hd-off-white); /* 15.67:1 */
  --text-secondary: var(--hd-ink-300);
  --text-muted: var(--hd-ink-400);
  --text-on-inverse: var(--hd-black);
  --text-link: var(--hd-blue-300); /*  6.75:1 — NOT --hd-blue (2.43:1) */
  --text-link-hover: var(--hd-accent); /*  6.09:1 */

  --border-subtle: rgb(255 255 255 / 0.08);
  --border-default: rgb(255 255 255 / 0.16);
  --border-strong: rgb(255 255 255 / 0.32);
  --border-accent: var(--hd-blue-300);

  --accent: var(--hd-blue-300);
  --accent-hover: var(--hd-accent);
  --focus-ring: 0 0 0 2px var(--surface-canvas), 0 0 0 4px var(--hd-accent);

  --code-bg: var(--hd-ink-900);
  --code-border: rgb(255 255 255 / 0.1);
  --code-inline-bg: rgb(143 160 220 / 0.12);
  --code-inline-fg: var(--hd-blue-300);

  --grid-line: rgb(143 160 220 / 0.1);
  --grid-line-strong: rgb(143 160 220 / 0.18);

  /* On a dark canvas the raw stoplight hues have enough contrast to carry
     text themselves, so indicator and text converge. */
  --status-success-text: #6cc98a;
  --status-warning-text: #f5b942;
  --status-danger-text: #f0736a;
  --status-info-text: var(--hd-blue-300);

  --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);
  --shadow-md: 0 2px 8px rgb(0 0 0 / 0.45);
  --shadow-lg: 0 8px 24px rgb(0 0 0 / 0.5);

  color-scheme: dark;
}

/* Follow the OS unless the user has explicitly chosen light. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --surface-canvas: #171b24;
    --surface-raised: #1f2430;
    --surface-sunken: #12151c;
    --surface-inverse: var(--hd-ink-050);
    --surface-deep: var(--hd-ink-900);
    --text-on-deep: rgb(255 255 255 / 0.87);
    --surface-accent-subtle: rgb(143 160 220 / 0.1);
    --surface-overlay: rgb(23 27 36 / 0.96);

    --text-primary: var(--hd-off-white);
    --text-secondary: var(--hd-ink-300);
    --text-muted: var(--hd-ink-400);
    --text-on-inverse: var(--hd-black);
    --text-link: var(--hd-blue-300);
    --text-link-hover: var(--hd-accent);

    --border-subtle: rgb(255 255 255 / 0.08);
    --border-default: rgb(255 255 255 / 0.16);
    --border-strong: rgb(255 255 255 / 0.32);
    --border-accent: var(--hd-blue-300);

    --accent: var(--hd-blue-300);
    --accent-hover: var(--hd-accent);

    --code-bg: var(--hd-ink-900);
    --code-border: rgb(255 255 255 / 0.1);
    --code-inline-bg: rgb(143 160 220 / 0.12);
    --code-inline-fg: var(--hd-blue-300);

    --grid-line: rgb(143 160 220 / 0.1);
    --grid-line-strong: rgb(143 160 220 / 0.18);

    --status-success-text: #6cc98a;
    --status-warning-text: #f5b942;
    --status-danger-text: #f0736a;
    --status-info-text: var(--hd-blue-300);

    --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);
    --shadow-md: 0 2px 8px rgb(0 0 0 / 0.45);
    --shadow-lg: 0 8px 24px rgb(0 0 0 / 0.5);

    color-scheme: dark;
  }
}

/* =============================================================================
   Graphic language — "engineering systems, technical documentation".
   Grids are generated rather than shipped as PNGs: patterns/graphpaper-sm.png
   is 1920x1080, 58KB, carries a baked-in diagonal fade AND a column of notebook
   punch-holes down its left edge, so it does not tile. These are ~200 bytes,
   crisp at any DPI, and theme-aware because the line colour is a token.
   ============================================================================= */
.bg-graph {
  background-image:
    repeating-linear-gradient(
      to right,
      var(--grid-line-strong) 0 1px,
      transparent 1px var(--grid-major)
    ),
    repeating-linear-gradient(
      to bottom,
      var(--grid-line-strong) 0 1px,
      transparent 1px var(--grid-major)
    ),
    repeating-linear-gradient(to right, var(--grid-line) 0 1px, transparent 1px var(--grid-minor)),
    repeating-linear-gradient(to bottom, var(--grid-line) 0 1px, transparent 1px var(--grid-minor));
}

/* Fade the grid out before it reaches body copy — "visual restraint" and
   "information-forward" made mechanical rather than left to judgement. */
.bg-graph--fade {
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, transparent 85%);
  mask-image: linear-gradient(to bottom, #000 0%, transparent 85%);
}

.bg-blueprint {
  background-color: var(--surface-inverse);
  background-image:
    repeating-linear-gradient(
      to right,
      rgb(255 255 255 / 0.14) 0 1px,
      transparent 1px var(--grid-major)
    ),
    repeating-linear-gradient(
      to bottom,
      rgb(255 255 255 / 0.14) 0 1px,
      transparent 1px var(--grid-major)
    ),
    repeating-linear-gradient(
      to right,
      rgb(255 255 255 / 0.06) 0 1px,
      transparent 1px var(--grid-minor)
    ),
    repeating-linear-gradient(
      to bottom,
      rgb(255 255 255 / 0.06) 0 1px,
      transparent 1px var(--grid-minor)
    );
}

/* Thin outlined shapes with registration marks — "pinpoint areas of importance
   and guide attention with precision". Outline, never fill; no shadow. */
.blueprint-frame {
  position: relative;
  outline: var(--hairline) solid var(--border-accent);
  outline-offset: 10px;
}
.blueprint-frame::before,
.blueprint-frame::after {
  content: "";
  position: absolute;
  width: 14px;
  height: 14px;
  border: 0 solid var(--accent);
}
.blueprint-frame::before {
  top: -16px;
  left: -16px;
  border-top-width: var(--hairline);
  border-left-width: var(--hairline);
}
.blueprint-frame::after {
  right: -16px;
  bottom: -16px;
  border-right-width: var(--hairline);
  border-bottom-width: var(--hairline);
}

/* Section header role: Inter Medium, all caps, tracked, with a leading rule. */
.eyebrow {
  font-family: var(--font-display);
  font-weight: var(--font-display-weight);
  text-transform: var(--font-display-transform);
  letter-spacing: var(--font-display-tracking);
  font-size: 0.75rem;
  color: var(--accent);
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.eyebrow::before {
  content: "";
  width: 20px;
  height: var(--hairline);
  background: currentColor;
  flex: none;
}

/* Icons inherit text colour from the currentColor sprite. */
.icon {
  width: 1em;
  height: 1em;
  fill: currentColor;
  flex: none;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
