/* BAC Transport — bactrans.co.za
   Single stylesheet, no build step. Tokens come from the inherited design
   system documented in docs/inherited/, trimmed to what is used here.
   Comments in this file are served to the browser: keep them about the CSS. */

:root {
  --accent: #e2202a;
  --text: #000000;
  --text-muted: #6d6f70;
  --surface: #ffffff;
  --surface-muted: #dddddd;
  --accent-soft: #fff3e8;
  --border: #d8dde8;
  --shadow: 0 20px 40px rgb(15 23 42 / 10%);
  --radius: 18px;
  --container-width: 1200px;
  --container-inset: 60px;
  --section-pad: clamp(56px, 8vw, 104px);
  --cut-height: clamp(40px, 6vw, 80px);
}

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

body {
  margin: 0;
  font-family: Roboto, "Helvetica Neue", Arial, sans-serif;
  line-height: 1.65;
  color: var(--text);
  background: var(--surface);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { line-height: 1.15; margin: 0 0 0.5em; }
h1 { font-size: clamp(2rem, 3vw, 3rem); }
h2 { font-size: clamp(1.6rem, 2.4vw, 2.3rem); }

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

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

/* Visible keyboard focus everywhere — spec §8. */
:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

@media (width <= 700px) { :root { --container-inset: 32px; } }

/* --- Roboto, self-hosted (DEVIATION 2: the sibling site never loads it) ---
   One variable file covers 100-900, so one @font-face rather than three.
   The full weight axis is put to work below: the tagline and lede lean on
   in-between weights (850, 380) a static font stack could never hit. */
@font-face {
  font-family: Roboto;
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/inc/fonts/roboto-latin-var.woff2") format("woff2");
  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+2074, U+20AC,
                 U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@property --draw {
  syntax: "<number>"; inherits: true; initial-value: 0;
}

/* --- buttons: pill, 48px, inherited pattern --- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 48px; padding: 0 30px;
  border-radius: 999px; border: 2px solid transparent;
  font-weight: 600; letter-spacing: .01em; text-decoration: none; cursor: pointer;
  transition: transform .18s ease, box-shadow .18s ease, background-color .18s ease,
              border-color .18s ease;
}
.btn:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
.btn:active { transform: translateY(0); }
.btn--solid { background: var(--accent); color: #fff; }
.btn--solid:hover { background: color-mix(in srgb, var(--accent) 88%, black); }
.btn--ghost { border-color: var(--text); color: var(--text); }
.btn--ghost:hover { border-color: var(--accent); background: var(--accent-soft); }

/* --- hero ---
   Warm dawn-to-white wash behind a single wayfinding line: the SADC freight
   corridor, abstracted rather than mapped. The line is the one bold move in
   this section; everything else stays quiet so it reads clearly. */
.hero {
  position: relative; overflow: hidden;
  padding-block: clamp(64px, 10vw, 136px);
  background: linear-gradient(180deg, var(--accent-soft) 0%, var(--surface) 72%);
  /* --draw is registered (inherits: true) and declared on THIS element via
     #hero.is-drawn below, so the transition must live here too — a typed
     custom property only animates smoothly on the element whose own
     specified value changes; descendants that merely inherit it (the
     .route-line / .route-node calc()s) just track the ticking value. */
  transition: --draw 2.2s cubic-bezier(.65, 0, .35, 1);
}
.hero__route {
  position: absolute; inset: 0; pointer-events: none;
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.hero__route svg { width: 100%; height: 100%; }

.route-line {
  stroke: url(#route-gradient); stroke-width: 3; stroke-linecap: round;
  filter: drop-shadow(0 0 6px rgb(226 32 42 / 25%));
  opacity: .55;
  stroke-dasharray: 1;
  stroke-dashoffset: calc(1 - var(--draw));
}
.route-node {
  /* Opacity is a plain discrete toggle on .is-drawn (not calc(var(--draw))):
     chaining a transition off a value that is itself mid-transition every
     frame keeps re-triggering the .9s delay and the node never settles. */
  fill: var(--accent); opacity: 0;
  transition: opacity .6s ease .9s;
}
#hero.is-drawn .route-node { opacity: .8; }
.route-node__ring {
  fill: none; stroke: var(--accent); stroke-width: 2;
  opacity: 0; transform-origin: 1060px 100px;
}
#hero.is-drawn { --draw: 1; }
#hero.is-drawn .route-node__ring {
  animation: route-pulse 1.6s ease-out 1.9s 1 both;
}
@keyframes route-pulse {
  0%   { opacity: .65; transform: scale(1); }
  100% { opacity: 0; transform: scale(2.4); }
}

.hero__inner { position: relative; }
/* Real mark is 327x210 (~1.56:1), sourced from a 1504px-wide JPEG banner —
   it cannot be scaled up without going soft, so it's displayed near its
   native size (~2x density at this width) rather than the wider, thinner
   footprint the typographic stand-in used. */
.hero__wordmark { display: block; height: auto; max-width: 160px; margin-bottom: 24px; }
.hero__tagline {
  font-size: clamp(2.4rem, 7vw, 5.25rem);
  font-weight: 850; letter-spacing: -0.02em; line-height: 1.05; margin-bottom: 22px;
}
.hero__tagline-accent { color: var(--accent); }
.hero__lede {
  max-width: 56ch; font-size: clamp(1rem, 1.3vw, 1.15rem); font-weight: 380;
  color: var(--text-muted);
}
.hero__actions { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 36px; }

@media (width <= 900px) {
  .hero { padding-block: clamp(48px, 12vw, 96px); }
}

@media (width <= 470px) {
  .hero__actions .btn { width: 100%; }
}

/* --- sections --- */
.section { position: relative; padding-block: var(--section-pad); }
.section__eyebrow {
  margin: 0 0 8px; font-size: .82rem; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; color: var(--accent);
}

/* Diagonal red cut (spec §3). A single tapering slash across the section's
   leading edge, thick on the left and thinning as it rises to the right —
   the same direction of travel the hero's route line takes, so the two read
   as one gesture rather than two unrelated red things. The section pays for
   the space it occupies with extra top padding, so the cut never crowds the
   eyebrow. */
.section--cut { padding-top: calc(var(--section-pad) + var(--cut-height) * .5); }
.section--cut::before {
  content: "";
  position: absolute; inset-inline: 0; top: 0;
  height: var(--cut-height);
  background: var(--accent);
  clip-path: polygon(0 40%, 100% 0, 100% 12%, 0 100%);
}

/* --- cards: the inherited pattern (border + radius + lift on hover) --- */
.card-grid { display: grid; gap: 24px; margin-top: 40px; }
.card-grid--3 { grid-template-columns: repeat(3, 1fr); }

.card {
  padding: 28px;
  border: 1px solid var(--border); border-radius: 22px;
  background: rgb(255 255 255 / 94%); box-shadow: var(--shadow);
  transition: transform .2s ease, box-shadow .2s ease;
}
.card:hover { transform: translateY(-4px); box-shadow: 0 26px 50px rgb(15 23 42 / 14%); }
.card__title { font-size: 1.3rem; margin-bottom: 10px; }
.card p { margin: 0; color: var(--text-muted); }

@media (width <= 900px) { .card-grid--3 { grid-template-columns: repeat(2, 1fr); } }

@media (width <= 700px) {
  .card-grid--3 { grid-template-columns: 1fr; }
  /* A full-width diagonal is nearly horizontal on a phone: it stops reading as
     a cut and just eats vertical space. Flatten it to a rule at that width. */
  .section--cut { padding-top: var(--section-pad); }
  .section--cut::before { height: 6px; clip-path: none; }
}

/* --- about ---
   Tinted with the same warm cream the hero fades out of, so the page returns
   to its opening note at the point it explains who the company is. */
.section--tinted { background: var(--accent-soft); }

.group { display: grid; grid-template-columns: 1.6fr 1fr; gap: 48px; align-items: start; }
.group__body p { max-width: 62ch; color: var(--text-muted); }
.group__body a { font-weight: 500; }

.group__facts {
  padding: 28px; border: 1px solid var(--border); border-radius: 22px;
  background: rgb(255 255 255 / 94%); box-shadow: var(--shadow);
}
.group__facts dl { margin: 0; display: grid; gap: 16px; }
.group__facts dt {
  font-size: .78rem; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-muted);
}
.group__facts dd { margin: 2px 0 0; font-size: 1.15rem; font-weight: 500; }

@media (width <= 900px) { .group { grid-template-columns: 1fr; gap: 32px; } }

/* --- identity: the block the verification actually depends on ---
   Selectable text throughout, never an image (acceptance criterion 2). Set as
   a ledger rather than a card grid: a reviewer is reading down a column and
   comparing each row against a document, so the labels stay in one rail. */
.identity__intro { max-width: 62ch; color: var(--text-muted); }
.identity {
  margin-top: 32px; padding: 32px;
  border: 1px solid var(--border); border-radius: 24px;
  background: rgb(255 255 255 / 96%); box-shadow: var(--shadow);
}
.identity__list { margin: 0; display: grid; gap: 0; }
.identity__row {
  display: grid; grid-template-columns: 260px 1fr; gap: 16px;
  padding: 16px 0; border-bottom: 1px solid var(--border);
}
.identity__row:last-of-type { border-bottom: 0; }
.identity__row dt { font-weight: 700; color: var(--text-muted); }
.identity__row dd { margin: 0; font-size: 1.08rem; }
.identity__cta { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 28px; }

@media (width <= 700px) {
  .identity { padding: 24px; }
  .identity__row { grid-template-columns: 1fr; gap: 4px; }
}
@media (width <= 470px) { .identity__cta .btn { width: 100%; } }

/* --- counters and footer --- */
.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;
}

/* Both counter rules are scoped through .counter deliberately. A counter is a
   .card, and .card p (0,1,1) outranks a bare .counter__value (0,1,0) — so the
   plan's flat selectors lost both the accent colour and the label's top margin
   to the card body style, and the numbers rendered muted grey. Qualifying with
   .counter takes them to (0,2,0), which wins without touching .card p. */
.counter { text-align: center; }
.counter .counter__value {
  margin: 0; font-size: clamp(2.4rem, 4.5vw, 3.4rem);
  font-weight: 700; line-height: 1; color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.counter .counter__label { margin: 8px 0 0; color: var(--text-muted); }

.site-footer { padding-block: 48px; background: var(--text); color: #fff; }
.site-footer a { color: #fff; }
.site-footer__inner {
  display: grid; grid-template-columns: 1fr auto; gap: 32px; align-items: end;
}
/* Uses the pre-made light variant, NOT a CSS filter. The mark is three brand
   colours (black, red, grey); invert() would turn the red cyan. */
.site-footer__wordmark { display: block; width: 150px; height: auto; }
.site-footer__address { margin: 16px 0 0; color: var(--surface-muted); }
.site-footer__legal { margin: 0; color: var(--surface-muted); font-size: .92rem; }

@media (width <= 900px) { .site-footer__inner { grid-template-columns: 1fr; align-items: start; } }

/* --- reduced motion: show the finished state, never a blank one --- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important; scroll-behavior: auto !important;
  }
  .route-line { --draw: 1; stroke-dashoffset: 0; }
  .route-node { opacity: .8; }
  /* animation-delay isn't covered by the animation-duration override above,
     and fill-mode: both means #hero.is-drawn .route-node__ring's 1.9s delay
     holds the ring at the keyframe's opacity: .65 for that whole real span
     before it would even start easing out — the opposite of an immediate
     final state. A plain opacity here can't fix it either: the running
     animation's per-frame value outranks a normal author declaration in the
     cascade regardless of specificity. Kill the animation outright instead,
     so the rule below is what actually governs opacity. */
  .route-node__ring { animation: none !important; opacity: 0; }
}
