/* Triumph Cabling Systems — one stylesheet, no framework.
   Brand: navy #0A2E45, Archivo display (uppercase, tracked), Inter body. */

@font-face {
  font-family: 'Archivo';
  src: url('/assets/fonts/archivo-latin-ext.woff2') format('woff2');
  font-weight: 400 900; font-style: normal; font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Archivo';
  src: url('/assets/fonts/archivo-latin.woff2') format('woff2');
  font-weight: 400 900; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  src: url('/assets/fonts/inter-latin-ext.woff2') format('woff2');
  font-weight: 400 800; font-style: normal; font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter';
  src: url('/assets/fonts/inter-latin.woff2') format('woff2');
  font-weight: 400 800; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --navy: #0A2E45;
  --navy-deep: #061e2e;
  --navy-soft: #14405c;
  --accent: #126194;
  --accent-hover: #0d4a72;
  --accent-bright: #1890D7;
  --steel: #4A6B80;
  --ink: #17252E;
  --muted: #55707F;
  --line: #DCE4E9;
  /* --line is a hairline between blocks; interactive chrome needs 3:1 against
     its own ground to satisfy WCAG 1.4.11, which #DCE4E9 (1.29:1) does not. */
  --line-strong: #8FA3B0;
  --paper: #FFFFFF;
  --paper-alt: #F4F7F9;
  --wrap: 1180px;
  --gutter: clamp(1.25rem, 4vw, 2.5rem);
  --radius: 3px;
  --font-head: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.0625rem);
  line-height: 1.65;
  color: var(--ink);
  background: var(--paper);
}

img { max-width: 100%; height: auto; display: block; }
figure { margin: 0; }
ul, ol { padding-left: 1.25rem; }

h1, h2, h3 {
  font-family: var(--font-head);
  font-weight: 800;
  text-transform: uppercase;
  color: var(--navy);
  margin: 0 0 .5em;
  text-wrap: balance;
}
/* Uppercase reads larger than sentence case at the same size, so these run
   smaller than the sentence-case scale they replaced. Tracking eases off as
   the size drops, which is the opposite of what caps want at display size. */
h1 { font-size: clamp(1.55rem, 1.1rem + 1.9vw, 2.5rem); line-height: 1.06; letter-spacing: .055em; }
h2 { font-size: clamp(1.2rem, 1rem + .95vw, 1.7rem); line-height: 1.1; letter-spacing: .05em; }
/* The old clamp topped out at the same 17px as body copy and sat BELOW it on
   every phone (15.36px against 16px at 320), so caps and tracking were
   carrying the hierarchy alone. */
h3 { font-size: clamp(1.0625rem, 1rem + .35vw, 1.25rem); line-height: 1.25; letter-spacing: .045em; font-weight: 700; }
h3.label, h4 {
  font-family: var(--font-body); font-size: .8125rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--steel);
  margin: 0 0 .75em;
}

.vh {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
p { margin: 0 0 1.1em; }
p:last-child { margin-bottom: 0; }

a { color: #0d5b8a; text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--accent-hover); }

/* Amber alone is 8.07:1 on navy but 1.75:1 on white, and outline-offset puts
   the ring on the page ground rather than the control - so the light-ground
   case needs the navy plate behind it to be seen at all. */
:focus-visible { outline: 3px solid #FFB703; outline-offset: 2px; box-shadow: 0 0 0 5px var(--navy); }

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

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: #fff; color: var(--navy); padding: .75rem 1rem; font-weight: 600;
}
.skip:focus { left: 0; }

/* ---------- buttons ---------- */
.btn {
  display: inline-block; font-weight: 600; font-size: .9375rem;
  letter-spacing: .04em; text-transform: uppercase; text-decoration: none;
  padding: .8rem 1.4rem; border-radius: var(--radius); border: 2px solid transparent;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.btn-accent { background: var(--accent); color: #fff; border-color: #2E7FB5; }
.btn-accent:hover { background: var(--accent-hover); border-color: var(--accent-hover); color: #fff; }
.btn-ghost { color: #fff; border-color: rgba(255,255,255,.55); }
.btn-ghost:hover { background: #fff; color: var(--navy); border-color: #fff; }
.btn-navy { background: var(--navy); color: #fff; border-color: var(--navy); }
.btn-navy:hover { background: var(--navy-soft); border-color: var(--navy-soft); color: #fff; }

/* ---------- header ---------- */
.site-head { background: var(--navy); color: #fff; position: relative; z-index: 20; }
.head-inner { display: flex; align-items: center; gap: 1.5rem; padding-block: .9rem; }
.brand { flex: 0 0 auto; line-height: 0; color: inherit; }
.brand img { width: clamp(178px, 16vw, 218px); height: auto; }

.site-nav { margin-left: auto; display: flex; align-items: center; gap: 1.35rem; }
.site-nav ul { display: flex; gap: 1.15rem; list-style: none; margin: 0; padding: 0; }
.site-nav a:not(.btn) {
  color: #E8EFF3; text-decoration: none; font-size: .8125rem; font-weight: 600;
  letter-spacing: .09em; text-transform: uppercase; padding-block: .4rem;
  border-bottom: 2px solid transparent; display: block;
}
.site-nav a:not(.btn):hover { color: #fff; border-bottom-color: var(--accent-bright); }
.head-actions { display: flex; align-items: center; gap: .9rem; }
.head-phone {
  color: #fff; font-weight: 600; text-decoration: none; font-size: .95rem; white-space: nowrap;
}
.head-phone:hover { color: #fff; text-decoration: underline; }
.head-actions .btn { padding: .6rem 1rem; font-size: .75rem; letter-spacing: .06em; white-space: nowrap; }

/* active page */
body[data-nav="underground"] a[data-nav="underground"],
body[data-nav="services"] a[data-nav="services"],
body[data-nav="projects"] a[data-nav="projects"],
body[data-nav="dir"] a[data-nav="dir"],
body[data-nav="company"] a[data-nav="company"],
body[data-nav="safety"] a[data-nav="safety"],
body[data-nav="contact"] a[data-nav="contact"] { color: #fff; border-bottom-color: var(--accent-bright); }

.nav-toggle {
  display: none; margin-left: auto; align-items: center; gap: .55rem;
  background: none; border: 2px solid rgba(255,255,255,.4); border-radius: var(--radius);
  color: #fff; padding: .5rem .8rem; font: inherit; font-size: .8125rem; font-weight: 600;
  letter-spacing: .09em; text-transform: uppercase; cursor: pointer;
}
.nav-toggle-bars, .nav-toggle-bars::before, .nav-toggle-bars::after {
  display: block; width: 18px; height: 2px; background: #fff; content: ''; position: relative;
}
.nav-toggle-bars::before { top: -6px; }
.nav-toggle-bars::after { top: 4px; }

@media (max-width: 1040px) {
  /* Raised from 980px: the desktop row needs 1041px to fit its brand, six nav
     items, the phone number and the Contact button.
     The pages run five to nine screens on a phone, so the way back to the menu
     and the phone number cannot be a scroll to the top. The bar is trimmed to
     ~64px to earn the space it now permanently occupies. */
  /* the hairline is the only thing separating the bar from a navy band once it
     is scrolling over one */
  .site-head { position: sticky; top: 0; box-shadow: 0 1px 0 rgba(255,255,255,.14); }
  html { scroll-padding-top: 5rem; }
  .head-inner { padding-block: .65rem; }
  .brand img { width: 158px; }

  .nav-toggle { display: flex; padding: .65rem .9rem; }
  .head-inner { flex-wrap: wrap; gap: 1rem; }
  .site-nav {
    display: none; flex-basis: 100%; flex-direction: column; align-items: stretch;
    gap: 0; margin-left: 0; padding-bottom: .5rem;
    /* the open menu is taller than a short phone in landscape */
    max-height: calc(100vh - 5rem); overflow-y: auto;
  }
  .site-nav.is-open { display: flex; }
  /* overflow-y: auto computes overflow-x to auto too, so the drawer clips on
     both axes and an outset focus ring lands outside the box. Draw it inside. */
  .site-nav a:focus-visible { outline-offset: -3px; box-shadow: none; }
  .site-nav ul { flex-direction: column; gap: 0; }
  .site-nav li { border-top: 1px solid rgba(255,255,255,.14); }
  .site-nav a { padding: .95rem .2rem; font-size: .9375rem; border-bottom: none; }
  .site-nav a:hover { border-bottom: none; }
  body[data-nav] .site-nav a[data-nav]{ border-bottom: none; }
  .head-actions {
    flex-direction: column; align-items: stretch; gap: .75rem;
    padding-top: 1rem; border-top: 1px solid rgba(255,255,255,.14);
  }
  .head-actions .btn { text-align: center; padding: .85rem 1rem; font-size: .875rem; }
  .head-phone { text-align: center; font-size: 1.05rem; }
}

/* ---------- home hero (split: copy panel + photo) ---------- */
.hero { background: var(--navy); color: #fff; position: relative; }
/* An even scrim, not a directional one: a gradient kept the clip visible on
   the right and buried it behind the words on the left, which read as the
   video only covering part of the band. .68 over the brightest frame in the
   clip still leaves white text above 4.5:1. */
.hero-media { position: absolute; inset: 0; overflow: hidden; background: var(--navy); }
/* The clip is graded dark and the scrim takes another two thirds of it, so it
   read as murky. Lifting the clip itself rather than thinning the scrim is the
   free move: measured over all 57 frames, the worst-case pixel behind the copy
   is already clipped to white, so brightness(1.25) leaves white text at 5.95:1
   where thinning the scrim to .60 for the same lift drops it to 4.55:1. */
.hero-media video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block; filter: brightness(1.25);
}
.hero-media::after {
  content: ''; position: absolute; inset: 0;
  background: rgba(6,30,46,.68);
}
.hero-inner {
  position: relative; z-index: 1; padding-block: clamp(3rem, 7vw, 5.5rem);
  text-shadow: 0 1px 12px rgba(3,16,25,.55);
}
.hero-inner > * { max-width: 46rem; }
.hero h1 { color: #fff; margin-bottom: .55em; font-size: clamp(1.55rem, 1.15rem + 1.55vw, 2.2rem); }
.hero .eyebrow { color: #E8EFF3; }
.hero p { color: #fff; font-size: clamp(1.0625rem, 1rem + .35vw, 1.2rem); max-width: 34em; }
/* .actions is the generic form: /dir/ was spacing a button pair with a
   margin utility on the wrapping <p> and an ml-05 between the two buttons,
   which also made it the one place on the site where two ragged-width
   buttons stacked on a phone instead of going full width. */
.hero-actions, .cta-actions, .actions { display: flex; flex-wrap: wrap; gap: .85rem; }
.hero-actions, .actions { margin-top: 1.75rem; }
.eyebrow {
  font-family: var(--font-body); font-size: .8125rem; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--steel);
  margin: 0 0 1rem;
}
@media (max-width: 860px) {
  .hero-inner > * { max-width: none; }
}

/* ---------- interior page head ---------- */
.page-head { background: var(--navy); color: #fff; padding-block: clamp(2.25rem, 5vw, 3.5rem); }
.page-head h1 { color: #fff; margin-bottom: .35em; }
.page-head p { color: #D6E3EB; max-width: 40em; font-size: clamp(1.0625rem, 1rem + .3vw, 1.175rem); }
.page-head .eyebrow { color: #9FC4DA; }
/* Every dark band needs its own link colour, or links inherit the light-ground
   blue. :not(.btn) is load-bearing: without it these two rules out-specify
   .btn-accent and .btn-ghost and repaint their labels. The hover pair was
   painting the ghost button's label white over its own white hover fill -
   1.00:1, the label disappeared under the cursor on all nine pages. */
.page-head a:not(.btn), .hero a:not(.btn), .cta-band a:not(.btn),
.section-navy a:not(.btn), .stat a { color: #BBDCF0; }
.page-head a:not(.btn):hover, .hero a:not(.btn):hover,
.cta-band a:not(.btn):hover, .section-navy a:not(.btn):hover { color: #fff; }
.crumb { font-size: .8125rem; color: #9FC4DA; margin: 0 0 1rem; }
.crumb a { color: #C9DDE8; }

/* ---------- generic sections ---------- */
.section { padding-block: clamp(2.75rem, 6vw, 4.5rem); }
.section-alt { background: var(--paper-alt); }
.section-navy { background: var(--navy); color: #E8EFF3; }
.section-navy h2, .section-navy h3 { color: #fff; }
.section-navy .eyebrow { color: #9FC4DA; }
.lead { font-size: clamp(1.0625rem, 1rem + .35vw, 1.2rem); color: var(--muted); max-width: 42em; }
.prose { max-width: 44em; }
.prose h2 { margin-top: 2em; }
.prose h2:first-child, .prose .eyebrow + h2 { margin-top: 0; }
/* .wrap.prose keeps the page's left edge; only the lines are narrowed */
.wrap.prose { max-width: var(--wrap); }
.wrap.prose > * { max-width: 44em; }

/* a wide photo used as a band rather than a column */
.band img { width: 100%; }
.band figcaption { color: var(--muted); font-size: .8125rem; padding-top: .6rem; }

.grid { display: grid; gap: clamp(1.25rem, 3vw, 2rem); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); }
/* Below 46rem three cards cannot make a row without stranding one, so stack
   them deliberately instead of resolving to 2 + 1. */
@media (max-width: 46rem) { .grid-3 { grid-template-columns: 1fr; } }
.split { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 24rem), 1fr)); gap: clamp(1.75rem, 4vw, 3.25rem); align-items: center; }
@media (min-width: 62rem) { .split-wide { grid-template-columns: 1.4fr 1fr; } }
.split-top { align-items: start; }

/* a bare photo strip: no card chrome, and it reads on the navy band */
.photo-strip { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); gap: clamp(1rem, 2vw, 1.5rem); }
/* 4 photos over a 3-wide track left one alone across the whole tablet band. */
@media (min-width: 40.0625rem) and (max-width: 73.6875rem) {
  .photo-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.photo-strip img { border-radius: var(--radius); aspect-ratio: 3 / 2; object-fit: cover; width: 100%; }

.card {
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius);
  padding: clamp(1.35rem, 2.5vw, 1.85rem);
}
.card h3 { margin-bottom: .4em; }
.card p:last-child { margin-bottom: 0; }
.card-link { display: block; text-decoration: none; color: inherit; transition: border-color .15s ease; }
.card-link:hover { border-color: var(--navy); color: inherit; }
.card-link .more { color: var(--accent); font-weight: 600; font-size: .875rem; letter-spacing: .05em; text-transform: uppercase; }

/* The gap above a tick list was hand-set at five different values across six
   pages (0, .5, 1, 1.25 and 1.5rem), so peer sections did not line up. The
   component owns it now and the utilities are off every call site. */
.ticks { list-style: none; margin: 1rem 0 0; padding: 0; display: grid; gap: .5rem; }
.ticks li { padding-left: 1.6rem; position: relative; }
.ticks li::before {
  content: ''; position: absolute; left: 0; top: .62em;
  width: .5rem; height: .5rem; background: var(--accent); border-radius: 50%;
}
.ticks-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); column-gap: 1.75rem; }
.section-navy .ticks li::before { background: #7FB6D6; }

.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr)); gap: 1.5rem; }
/* Four stats in a half-width column: auto-fit would give three across and leave
   one orphan on its own row, so this block is squared off deliberately. */
.stats-2x2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* Three of them auto-fit to two columns and orphan the third, so square this
   one off too - one column on a phone, where a third of 350px is unreadable. */
.stats-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 40rem) { .stats-3 { grid-template-columns: 1fr; } }
.stat .n {
  font-family: var(--font-head); font-weight: 800; letter-spacing: .04em;
  font-size: clamp(1.7rem, 1.3rem + 1.5vw, 2.25rem); color: #fff; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.stat p { color: #BFD4E0; font-size: .9375rem; margin: .5rem 0 0; }

/* ---------- projects ---------- */
.proj-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr)); gap: clamp(1.25rem, 2.5vw, 1.75rem); }
/* Two columns and an odd number of cards leaves a hole beside the last one.
   Letting it span the row reads as deliberate rather than broken. */
@media (min-width: 40.0625rem) and (max-width: 63.9375rem) {
  .proj-grid > :last-child:nth-child(odd) { grid-column: 1 / -1; }
}
.proj { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: #fff; }
.proj img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.proj .body { padding: 1.15rem 1.25rem 1.35rem; }
.proj h3 { font-size: 1.1rem; margin-bottom: .3em; }
.proj p { font-size: .9375rem; color: var(--muted); margin: 0; }
.proj .tag {
  display: inline-block; font-size: .75rem; font-weight: 600; letter-spacing: .1em;
  text-transform: uppercase; color: var(--steel); margin-bottom: .55rem;
}
.proj .tag a { color: inherit; text-decoration: none; }
.proj .tag a:hover, .proj .tag a:focus-visible { text-decoration: underline; }
.filters { display: flex; flex-wrap: wrap; gap: .6rem; margin-bottom: 2rem; }
.filters button {
  font: inherit; font-size: .8125rem; font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; cursor: pointer; padding: .55rem 1.1rem;
  background: #fff; color: var(--navy); border: 2px solid var(--line-strong); border-radius: 999px;
  transition: border-color .15s ease, background-color .15s ease;
}
.filters button:hover { border-color: var(--navy); }
.filters button[aria-pressed="true"] { background: var(--navy); border-color: var(--navy); color: #fff; }

/* ---------- logos ---------- */
.logo-row {
  /* min(100%, …) is the guard every other auto-fit grid here uses; without it
     this was the one grid that could demand a track wider than the screen.
     Column counts are pinned below 1180 because auto-fit landed on 5 tracks
     for 11 marks (5+5+1) and on 1 track on a phone. */
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 8.5rem), 1fr));
  gap: clamp(1.25rem, 3vw, 2.5rem);
  /* fixed row height reserves the space, so nothing shifts when the marks load */
  grid-auto-rows: 46px; align-items: center; justify-items: center;
}
@media (max-width: 40rem) { .logo-row { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 40.0625rem) and (max-width: 73.6875rem) {
  .logo-row { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.logo-row img {
  max-height: 46px; max-width: 100%; width: auto; height: auto;
  /* the source marks carry white boxes; multiply drops them into the page.
     They run in their own colours - a client list is worth more when the
     reader recognises the marks at a glance. */
  mix-blend-mode: multiply;
}
/* Was an auto-fit grid, which is the wrong container: an equal ~130-160px
   track width-limits the 5.6:1 DIR mark to 23-29px against two 72px badges,
   and justify-items: center pushed the first badge 12-57px inside the page's
   left edge. Flex lets each mark take its natural width, so the row starts on
   the page edge and every mark is limited by the row height instead. */
.cert-row { display: flex; flex-wrap: wrap; align-items: center; gap: 1.75rem; }
.cert-row img { max-height: 72px; max-width: min(250px, 100%); width: auto; height: auto; }


/* ---------- steps ---------- */
.steps { counter-reset: step; list-style: none; margin: 0; padding: 0; display: grid; gap: 1.35rem; }
.steps li { counter-increment: step; padding-left: 3.25rem; position: relative; }
.steps li::before {
  content: counter(step); position: absolute; left: 0; top: 0;
  width: 2.25rem; height: 2.25rem; border-radius: 50%;
  background: var(--navy); color: #fff; font-family: var(--font-head); font-weight: 800;
  display: grid; place-items: center;
}
.steps h3 { margin-bottom: .2em; }

/* ---------- tables ---------- */
.table-scroll { overflow-x: auto; }
table { border-collapse: collapse; width: 100%; font-size: .9375rem; font-variant-numeric: tabular-nums; }
th, td { text-align: left; padding: .7rem .9rem; border-bottom: 1px solid var(--line); }
th { font-size: .75rem; letter-spacing: .1em; text-transform: uppercase; color: var(--steel); }

/* ---------- forms ---------- */
.form { display: grid; gap: 1.1rem; }
.field { display: grid; gap: .4rem; }
.field label { font-size: .8125rem; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--steel); }
.field input, .field textarea {
  font: inherit; font-size: 1rem; padding: .75rem .85rem; color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: var(--radius); background: #fff; width: 100%;
}
.field textarea { min-height: 9rem; resize: vertical; }
.field input:focus, .field textarea:focus { border-color: var(--navy); }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.form-note { font-size: .875rem; color: var(--muted); }
/* A live region has to be in the accessibility tree BEFORE its content
   changes, or the announcement is dropped. display:none until the same tick
   the text arrives meant a blind visitor got silence on submit, either way.
   So it stays rendered and collapses to nothing instead. */
.form-status { border-radius: var(--radius); font-size: .9375rem; }
.form-status:not(.is-ok):not(.is-err) { height: 0; overflow: hidden; }
.form-status.is-ok { padding: .9rem 1.1rem; background: #E7F3EA; border: 1px solid #9CC9A9; color: #1D5B2C; }
.form-status.is-err { padding: .9rem 1.1rem; background: #FBEAEC; border: 1px solid #E0A2A8; color: #8A1721; }

/* ---------- CTA band + footer ---------- */
.cta-band { background: var(--navy-soft); color: #fff; }
.cta-inner {
  display: flex; flex-wrap: wrap; gap: 1.75rem; align-items: center; justify-content: space-between;
  padding-block: clamp(2rem, 4vw, 2.75rem);
}
.cta-band h2 { color: #fff; margin-bottom: .3em; }
.cta-band p { color: #D6E3EB; max-width: 40em; margin: 0; }

.site-foot { background: var(--navy-deep); color: #C6D6E0; padding-block: clamp(1.75rem, 3vw, 2.5rem) 1.25rem; font-size: .9375rem; }
.foot-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); gap: 1.75rem 2rem; }
/* Once all four columns fit side by side, hand the brand column the extra width
   so its line of copy sits on two lines instead of four - that one paragraph was
   the tallest thing in the footer. */
/* Between the phone block and 62rem, auto-fit lands on three tracks for four
   columns and strands the "Site" list on a row of its own. */
@media (min-width: 40.0625rem) and (max-width: 61.9375rem) {
  .foot-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 62rem) { .foot-grid { grid-template-columns: 1.5fr 1fr 1fr 1.1fr; } }
.site-foot h2 { font-size: .8125rem; font-family: var(--font-body); letter-spacing: .12em; text-transform: uppercase; color: #8FB0C4; margin-bottom: .7em; }
.site-foot a { color: #DCE9F1; }
.site-foot a:hover { color: #fff; }
.foot-brand img { width: 185px; }
.foot-brand p { margin-top: .75rem; max-width: 30em; }
.foot-badges img { width: 175px; margin-top: .6rem; }
/* Seven links in one column ran taller than everything beside it. Two columns
   makes it four rows and costs no width - the labels are short. */
.foot-links { list-style: none; margin: 0; padding: 0; display: grid; gap: .4rem 1.25rem; grid-template-columns: repeat(2, auto); justify-content: start; }
.addr { font-style: normal; }
.foot-legal {
  display: flex; flex-wrap: wrap; gap: .5rem 2rem; justify-content: space-between;
  margin-top: 1.75rem; padding-top: 1.1rem; border-top: 1px solid rgba(255,255,255,.12);
  font-size: .8125rem; color: #8FB0C4;
}
.foot-legal p { margin: 0; }

/* ---------- phones ----------
   Everything above already reflows on its own - the fluid type and the auto-fit
   grids handle the width. What a thumb needs is different from what a narrow
   column needs, so this block is only about touch size and type floors. */
@media (max-width: 640px) {
  /* A row of standalone links is read as a list of buttons, so each one gets a
     44px row. Links inside a sentence are deliberately left alone: padding them
     out would break the paragraph they sit in. */
  .foot-links { gap: 0 1.25rem; }
  /* Stacked one-per-row, the four footer blocks ran longer than the screen.
     The two addresses sit happily side by side; the brand and the link list
     keep the full width. Held back below 22.5rem, where the email address
     would be wider than half the screen. */
  @media (min-width: 22.5rem) {
    .foot-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .foot-brand, .foot-grid > :last-child { grid-column: 1 / -1; }
    /* "Houston headquarters" takes two lines in a half-width column and
       "Austin office" takes one, which left the two addresses off by a line. */
    /* .site-foot is 15px/1.65 = 24.75px a line, so 2.4em (36px) sat between
       one line and two and left the two addresses 13.5px apart - the fault
       this rule exists to fix. 3.3em is exactly two lines. Scoped off the
       full-width "Site" column, which has nothing to equalise against. */
    .foot-grid > div:not(:last-child) > h2 { min-height: 3.3em; }
  }
  .foot-grid a[href^="mailto:"] { overflow-wrap: anywhere; }
  .foot-links a { display: inline-block; padding-block: .8rem; }
  /* p:has(br) is the test for a contact detail - those are one per line, prose
     is not. The blanket tel:/mailto: rule this replaces fired inside /dir/'s
     "request a quote" sentence and tore the paragraph apart: 46/36/27px line
     pitch against a 26.6px line-height. */
  .crumb a,
  .card p > a:only-child,
  p:has(br) > a { display: inline-block; padding-block: .75rem; }
  /* Padding the link would leave the tick bullet floating above the text, so
     the row grows and the bullet moves with it. */
  .ticks li > a:only-child { display: inline-block; padding-block: .6rem; }
  .ticks li:has(> a:only-child)::before { top: calc(.62em + .6rem); }
  .filters button { padding-block: .7rem; }

  /* Two ragged-width buttons stacked read as a mistake; full width reads as a
     pair and doubles the target at the same time. */
  .hero-actions, .cta-actions, .actions { flex-direction: column; align-items: stretch; }
  /* .cta-actions is a flex ITEM of .cta-inner, so it shrinks to its content and
     stretching the buttons inside only fills that narrow box. */
  .cta-actions { flex: 1 1 100%; }
  .hero-actions .btn, .cta-actions .btn, .actions .btn, .form button[type="submit"] {
    text-align: center; padding-block: .95rem;
  }
  .form button[type="submit"] { display: block; width: 100%; }

  /* 12-13px is comfortable at arm's length on a desktop and small in a hand. */
  .eyebrow, h3.label, h4 { font-size: .875rem; }
  .band figcaption, .proj .tag, th { font-size: .8125rem; }
}

/* ---------- utilities ----------
   These exist so no page needs an inline style="" attribute: the CSP in
   _headers sets style-src 'self', which blocks inline styles outright. */
.mt-1 { margin-top: 1rem; }
.mt-15 { margin-top: 1.5rem; }
.mt-2 { margin-top: 2rem; }
.mt-25 { margin-top: 2.5rem; }
.mb-15 { margin-bottom: 1.5rem; }
.measure-52 { max-width: 52rem; }
/* DIR-CPO-4781 was splitting after the second hyphen on four pages - it is
   the number an agency puts on a purchase order. */
.nowrap { white-space: nowrap; }
/* the address broke after the dot at 641px: "sales@triumph-cs." / "com".
   Footer only keeps overflow-wrap, where the column really is narrow. */
main a[href^="mailto:"] { white-space: nowrap; }
.cap-left { text-align: left; padding: .5rem 0; }
.defn-note { color: #9FC4DA; margin-top: -.6rem; }
