/* ==========================================================================
   Structured PM Ltd · base layer and primitives
   Reads tokens.css. Declares no raw values of its own.

   Load order on every page:
     <link rel="stylesheet" href="/assets/css/tokens.css">
     <link rel="stylesheet" href="/assets/css/base.css">

   Fonts are self hosted from /assets/fonts. Nothing in this file makes a
   third-party request, so the head is safe to load before the cookie banner
   is answered.
   ========================================================================== */

/* --- Fonts, self hosted, Latin subset ----------------------------------- */

/* One variable file covers 400 to 700, which is every display weight the
   system uses. It replaced three separate faces and still costs 35KB. */
@font-face {
  font-family: 'Archivo';
  src: url('../fonts/archivo-var.woff2') format('woff2-variations'),
       url('../fonts/archivo-var.woff2') format('woff2');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Montserrat';
  src: url('../fonts/montserrat-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Montserrat';
  src: url('../fonts/montserrat-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Montserrat';
  src: url('../fonts/montserrat-600.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../fonts/jetbrains-mono-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}


/* --- Reset -------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

body, h1, h2, h3, h4, p, figure, blockquote, dl, dd { margin: 0; }

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

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

img, picture, svg { max-width: 100%; display: block; }

input, button, textarea, select { font: inherit; color: inherit; }


/* --- Elements ----------------------------------------------------------- */

body {
  background: var(--spm-light);
  color: var(--spm-navy);
  font-family: var(--spm-font-body);
  font-size: var(--spm-size-body);
  font-weight: var(--spm-weight-regular);
  line-height: var(--spm-leading-body);
  -webkit-font-smoothing: antialiased;
}

/* Display type is always uppercase and sits in navy, or in light when it is
   on a navy ground. Weight 700, the top of Archivo's range. Bebas had one
   weight and this is the reason the size tokens came down: Archivo at 700
   reads as a headline at a smaller size than Bebas needed. */
h1, h2, h3, .spm-display {
  font-family: var(--spm-font-display);
  font-weight: var(--spm-weight-display);
  text-transform: uppercase;
  letter-spacing: var(--spm-tracking-display);
  line-height: var(--spm-leading-display);
  color: var(--spm-navy);
}

h1, .spm-display-1 { font-size: var(--spm-size-display-1); }
h2, .spm-display-2 { font-size: var(--spm-size-display-2); }
h3               { font-size: var(--spm-size-h2); line-height: var(--spm-leading-tight); }
h4, .spm-h3      {
  font-family: var(--spm-font-display);
  font-weight: var(--spm-weight-display);
  text-transform: uppercase;
  letter-spacing: var(--spm-tracking-display);
  font-size: var(--spm-size-h3);
  line-height: var(--spm-leading-tight);
  color: var(--spm-navy);
}

p { max-width: var(--spm-measure); }
p + p { margin-top: var(--spm-space-6); }

a { color: inherit; }

strong { font-weight: var(--spm-weight-semibold); }


/* --- Layout primitives -------------------------------------------------- */

.spm-container {
  width: 100%;
  max-width: var(--spm-container);
  margin-inline: auto;
  padding-inline: var(--spm-gutter);
}

/* Body copy never exceeds 66 characters. */
.spm-measure { max-width: var(--spm-measure); }

.spm-section { padding-block: var(--spm-section); }

/* Grids reflow on content width, not device names. */
.spm-grid {
  display: grid;
  gap: var(--spm-space-6);
  grid-template-columns: repeat(auto-fit, minmax(var(--spm-grid-min), 1fr));
}

/* Fixed four across, for spec'd sets of four. auto-fit cannot reach four at
   the 1180px container once the 260px minimum and the gutter are counted. */
.spm-grid--4 { grid-template-columns: 1fr; }

@media (min-width: 600px)  { .spm-grid--4 { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1000px) { .spm-grid--4 { grid-template-columns: repeat(4, 1fr); } }

/* Editorial split, 7 and 5. Single column until there is room for two. */
.spm-split {
  display: grid;
  gap: var(--spm-space-12);
  grid-template-columns: 1fr;
}

@media (min-width: 900px) {
  .spm-split { grid-template-columns: 7fr 5fr; }
  .spm-split--8-4 { grid-template-columns: 8fr 4fr; }
  .spm-split--half { grid-template-columns: 1fr 1fr; }
}


/* --- Navy panel ---------------------------------------------------------
   A presentation surface, not a dark mode. Everything inside inverts. */

.spm-panel-navy {
  background: var(--spm-navy);
  color: var(--spm-on-navy);
}

.spm-panel-navy h1,
.spm-panel-navy h2,
.spm-panel-navy h3,
.spm-panel-navy h4,
.spm-panel-navy .spm-display,
.spm-panel-navy .spm-wordmark { color: var(--spm-on-navy); }

.spm-panel-navy .spm-label   { color: var(--spm-on-navy-70); }
.spm-panel-navy .spm-lead,
.spm-panel-navy p            { color: var(--spm-on-navy-70); }
.spm-panel-navy .spm-rule    { background: var(--spm-rule-on-navy); }


/* --- Type primitives ---------------------------------------------------- */

.spm-lead {
  font-size: var(--spm-size-lead);
  font-weight: var(--spm-weight-medium);
  line-height: var(--spm-leading-lead);
  max-width: var(--spm-measure);
}

.spm-small { font-size: var(--spm-size-small); }

/* Mono labels sit above blocks and act as a table of contents. Metadata
   only: labels, references, versions, dates. Never body copy. */
.spm-label {
  font-family: var(--spm-font-mono);
  font-weight: var(--spm-weight-medium);
  font-size: var(--spm-size-label);
  letter-spacing: var(--spm-tracking-label);
  text-transform: uppercase;
  color: var(--spm-ink-50);
  display: block;
}

.spm-muted { color: var(--spm-ink-70); }


/* --- Dividers -----------------------------------------------------------
   Hairline rule for structure, short navy rule to open a section, orange
   rule only above a call to action. */

.spm-rule {
  border: 0;
  height: var(--spm-hairline);
  background: var(--spm-rule);
  margin: 0;
}

/* Modifiers are written at two-class specificity so they survive inside a
   navy panel, where the plain hairline is dimmed to the inverted rule. */
.spm-rule.spm-rule--open,
.spm-rule.spm-rule--action,
.spm-rule.spm-rule--lime {
  width: 64px;
  height: 2px;
}

.spm-rule.spm-rule--open   { background: var(--spm-navy); }
.spm-rule.spm-rule--action { background: var(--spm-orange); }

/* Lime opens the StepWise pages, per the landing page spec. */
.spm-rule.spm-rule--lime   { background: var(--spm-lime); }

/* The section-opening rule inverts on navy. The orange and lime ones do not,
   because their colour is the point. */
.spm-panel-navy .spm-rule.spm-rule--open { background: var(--spm-on-navy); }


/* --- Buttons ------------------------------------------------------------
   Labels are verbs. One orange button per view, and it is the single most
   important action on the page. Secondary is the navy outline, tertiary is
   the underlined mono link. Radius 2px, never pill shaped. */

.spm-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--spm-space-2);
  min-height: var(--spm-target);
  padding: var(--spm-space-3) var(--spm-space-8);
  border: 2px solid transparent;
  border-radius: var(--spm-radius);
  font-family: var(--spm-font-mono);
  font-size: var(--spm-size-fine);
  font-weight: var(--spm-weight-medium);
  letter-spacing: var(--spm-tracking-button);
  text-transform: uppercase;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--spm-duration-fast) var(--spm-ease),
              border-color var(--spm-duration-fast) var(--spm-ease),
              color var(--spm-duration-fast) var(--spm-ease);
}

/* Primary. Navy label on orange measures 4.72:1 and clears AA for normal
   text. White on orange is 3.43:1 and fails, so it is not offered. */
.spm-btn--primary {
  background: var(--spm-orange);
  color: var(--spm-on-orange);
  border-color: var(--spm-orange);
}

.spm-btn--primary:hover,
.spm-btn--primary:focus-visible {
  background: var(--spm-orange-hover);
  border-color: var(--spm-orange-hover);
}

.spm-btn--secondary {
  background: transparent;
  color: var(--spm-navy);
  border-color: var(--spm-navy);
}

.spm-btn--secondary:hover,
.spm-btn--secondary:focus-visible {
  background: var(--spm-navy);
  color: var(--spm-on-navy);
}

/* Filled navy on a light ground. The strongest action available inside a
   card without spending the page's one orange element, which the brand rule
   reserves for the primary action of the viewport.

   A contact page is the case this exists for: booking a call is the primary
   action and takes the orange, but the form still needs a submit that reads
   as the obvious thing to press. Light on navy measures 16.19:1. */
.spm-btn--solid {
  background: var(--spm-navy);
  color: var(--spm-on-navy);
  border-color: var(--spm-navy);
}

.spm-btn--solid:hover,
.spm-btn--solid:focus-visible {
  background: var(--spm-surface);
  border-color: var(--spm-surface);
}

/* On a navy ground the light button outranks the orange one, which is how
   the approved block ordered its two routes: Self-Serve in white, Guided in
   orange. Navy on white is 16.19:1. */
.spm-btn--light {
  background: var(--spm-paper);
  color: var(--spm-navy);
  border-color: var(--spm-paper);
}

.spm-btn--light:hover,
.spm-btn--light:focus-visible {
  background: var(--spm-light);
  border-color: var(--spm-light);
}

/* Outlined, for a tertiary action on a navy ground. */
.spm-btn--ghost {
  background: transparent;
  color: var(--spm-on-navy);
  border-color: var(--spm-on-navy-50);
}

.spm-btn--ghost:hover,
.spm-btn--ghost:focus-visible {
  background: var(--spm-on-navy);
  color: var(--spm-navy);
  border-color: var(--spm-on-navy);
}

.spm-panel-navy .spm-btn--secondary {
  color: var(--spm-on-navy);
  border-color: var(--spm-on-navy);
}

.spm-panel-navy .spm-btn--secondary:hover,
.spm-panel-navy .spm-btn--secondary:focus-visible {
  background: var(--spm-on-navy);
  color: var(--spm-navy);
}

/* Tertiary. Mono, underlined, no box. */
.spm-btn--tertiary {
  min-height: var(--spm-target);
  padding: 0;
  background: none;
  border: 0;
  font-family: var(--spm-font-mono);
  font-size: var(--spm-size-label);
  font-weight: var(--spm-weight-medium);
  letter-spacing: var(--spm-tracking-label);
  text-transform: uppercase;
  color: var(--spm-navy);
  text-decoration: underline;
  text-underline-offset: 6px;
}

.spm-panel-navy .spm-btn--tertiary { color: var(--spm-on-navy); }

.spm-btn[disabled],
.spm-btn[aria-disabled='true'] {
  background: transparent;
  color: var(--spm-ink-50);
  border-color: var(--spm-rule-strong);
  cursor: not-allowed;
}


/* --- Cards and callouts -------------------------------------------------
   Mono reference, display title, body copy, optional footer meta. */

.spm-card {
  background: var(--spm-paper);
  border: var(--spm-border);
  border-radius: var(--spm-radius);
  padding: var(--spm-space-8);
}

/* Lime holds the tint, navy holds the text. Legal notes and reminders only,
   never a sales claim. */
.spm-callout {
  background: var(--spm-lime-tint);
  border-left: 2px solid var(--spm-lime);
  border-radius: var(--spm-radius);
  padding: var(--spm-space-6);
  color: var(--spm-navy);
}


/* --- Forms --------------------------------------------------------------
   Four fields at most, plain consent wording, no pre-ticked boxes. */

.spm-field { display: block; margin-bottom: var(--spm-space-6); }

.spm-field > .spm-label { margin-bottom: var(--spm-space-2); }

.spm-input {
  width: 100%;
  min-height: var(--spm-target);
  padding: var(--spm-space-3) var(--spm-space-4);
  background: var(--spm-paper);
  color: var(--spm-navy);
  border: 1px solid var(--spm-rule-strong);
  border-radius: var(--spm-radius);
  font-size: var(--spm-size-body);
}

.spm-input:focus-visible { border-color: var(--spm-navy); }

/* Select and textarea share the input's box so a form reads as one control
   repeated, not three that were styled separately.

   The select carries its own arrow as a background image rather than the
   platform one, because the platform arrow ignores the border colour and
   breaks the line. It is an inline SVG data URI: an external file would be a
   second request for 200 bytes, and the CSP allows data: for images. */
.spm-select {
  appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%230F2233' stroke-width='1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--spm-space-4) center;
  padding-right: var(--spm-space-12);
}

.spm-textarea {
  min-height: 160px;
  resize: vertical;
  line-height: var(--spm-leading-body);
}

/* Required marker. Mono and orange-ink, because the brand orange measures
   3.07:1 on the light ground and this is small type. */
.spm-req {
  font-family: var(--spm-font-mono);
  color: var(--spm-orange-ink);
}

/* Invalid only after the field has been touched and submit attempted, never
   on first paint. contact.js sets data-validated on the form. */
[data-validated='true'] .spm-input:invalid { border-color: var(--spm-orange-ink); }

/* Help text sits under the field in mono, 10px, never italic. */
.spm-help {
  display: block;
  margin-top: var(--spm-space-2);
  font-family: var(--spm-font-mono);
  font-size: 10px;
  letter-spacing: var(--spm-tracking-label);
  text-transform: uppercase;
  color: var(--spm-ink-50);
  font-style: normal;
}


/* --- Focus --------------------------------------------------------------
   Visible focus on every control, no exceptions. */

:focus-visible {
  outline: 2px solid var(--spm-orange);
  outline-offset: 3px;
}


/* --- Motion -------------------------------------------------------------
   Rise and fade. Movement reveals structure. Nothing bounces. */

/* The hidden state is scoped to .spm-js, which site.js sets on the root
   element. Without JavaScript the class never lands, so the content simply
   renders. Never hide content behind a script that might not run. */
.spm-js .spm-reveal {
  opacity: 0;
  transform: translateY(var(--spm-rise));
  transition: opacity var(--spm-duration) var(--spm-ease),
              transform var(--spm-duration) var(--spm-ease);
}

.spm-js .spm-reveal.is-visible { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .spm-js .spm-reveal { opacity: 1; transform: none; }
}


/* --- Utilities ---------------------------------------------------------- */

.spm-visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.spm-stack > * + * { margin-top: var(--spm-space-6); }
.spm-stack-tight > * + * { margin-top: var(--spm-space-3); }

/* Spacing utilities, so pages never carry an inline style attribute. */
.spm-mt-3  { margin-top: var(--spm-space-3); }
.spm-mt-4  { margin-top: var(--spm-space-4); }
.spm-mt-6  { margin-top: var(--spm-space-6); }
.spm-mt-8  { margin-top: var(--spm-space-8); }
.spm-mt-12 { margin-top: var(--spm-space-12); }
.spm-mb-4  { margin-bottom: var(--spm-space-4); }
.spm-mb-12 { margin-bottom: var(--spm-space-12); }
.spm-full  { width: 100%; }
