/* ============================================================
   Utility layer — small primitives used by the JS renderers.
   Loaded last so it can align older component blocks.
   ============================================================ */

.xs {
  font-size: 10px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}
.dim {
  color: var(--text-3);
}
.accent {
  color: var(--accent);
}

.lnk {
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--border-strong);
  text-underline-offset: 3px;
  transition: color 0.16s, text-decoration-color 0.16s;
}
.lnk:hover {
  color: var(--accent);
  text-decoration-color: var(--accent-dim);
}

/* Chip variants */
.chip--ok {
  border-color: color-mix(in oklab, var(--ok) 45%, transparent);
  color: var(--ok);
  background: color-mix(in oklab, var(--ok) 10%, transparent);
}
.chip--mono {
  font-family: var(--font-mono);
  letter-spacing: 0.08em;
}
button.chip:hover {
  border-color: var(--accent-dim);
  color: var(--accent);
}

.chiprow {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
@media (max-width: 799.98px) {
  .chiprow--hero {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 6px;
  }
  .chiprow--hero .chip {
    width: 100%;
    min-width: 0;
    white-space: normal;
    line-height: 1.25;
    height: auto;
    min-height: 46px;
    justify-content: center;
    align-items: center;
    text-align: center;
    font-size: 10px;
    letter-spacing: 0.03em;
    padding: 8px 6px;
    border-radius: var(--r-sm);
  }
  .chiprow--hero .chip svg {
    display: none;
  }
}

/* Tick list (sheet + package bodies) */
.ticks {
  display: grid;
  gap: var(--space-2);
}
.ticks li {
  display: grid;
  grid-template-columns: 15px 1fr;
  gap: var(--space-3);
  font-size: var(--text-sm);
  color: var(--text-2);
  line-height: 1.55;
}
.ticks li::before {
  content: '';
  width: 6px;
  height: 6px;
  margin-top: 8px;
  border-radius: 1px;
  background: var(--accent);
  opacity: 0.55;
}

/* Filter bar extras */
.filters__sep {
  width: 1px;
  align-self: stretch;
  min-height: 22px;
  background: var(--border);
  margin-inline: var(--space-2);
}
.filter--soft {
  text-transform: none;
  letter-spacing: 0.04em;
  font-size: 10.5px;
  opacity: 0.9;
}

/* Tool groups */
.tool-group {
  display: grid;
  gap: var(--space-3);
}
.tool-group > h4 {
  color: var(--accent);
  font-weight: 450;
}

/* Card flash when reached from the command palette */
.flash {
  animation: cardFlash 1.4s var(--ease);
}
@keyframes cardFlash {
  0%,
  100% {
    box-shadow: 0 0 0 0 transparent;
  }
  18%,
  62% {
    box-shadow: 0 0 0 2px var(--accent-dim), 0 0 34px -6px var(--accent-glow);
  }
}

/* Notice variants */
.notice--warn {
  border-left-color: var(--warn);
}
.notice--ok {
  border-left-color: var(--ok);
}
.notice--bad {
  border-left-color: var(--danger);
}
.notice--bad strong {
  color: var(--danger);
}

/* SEO cloud accepts buttons as well as links */
.seo-cloud button {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--text-3);
  padding: 3px 7px;
  border: 1px solid var(--divider);
  border-radius: var(--r-xs);
  transition: all 0.16s;
  text-align: left;
}
.seo-cloud button:hover {
  color: var(--accent);
  border-color: var(--accent-dim);
}
.foot-col button {
  font-size: var(--text-sm);
  color: var(--text-2);
  text-align: left;
}
.foot-col button:hover {
  color: var(--accent);
}
.foot-col li {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.foot-col li.foot-reply {
  display: block;
  margin-top: var(--space-3);
  font-family: var(--font);
  font-size: 12.5px;
  line-height: 1.45;
  letter-spacing: 0.01em;
  text-transform: none;
  color: var(--text-3);
  max-width: 34ch;
}
.foot-col li > svg {
  width: 14px;
  height: 14px;
  color: var(--text-3);
  flex: none;
}

/* Contact grid icons */
.contact-grid dt {
  display: flex;
  align-items: center;
  gap: 6px;
}
.contact-grid dt svg {
  width: 12px;
  height: 12px;
  color: var(--accent);
}

/* Section head reveal spacing helper */
.stack {
  display: grid;
  gap: var(--space-5);
}
.stack--tight {
  gap: var(--space-3);
}

/* Fault detail: code chips row inside sheet */
.sheet__body .chiprow button {
  cursor: pointer;
}

/* Body scroll lock */
body.locked {
  overflow: hidden;
}

/* Terminal helper reused outside the terminal */
.mono.xs {
  font-family: var(--font-mono);
}

/* Print: keep the report readable */
@media print {
  .site-bar,
  .site-header,
  .dock,
  .wa-float,
  .drawer,
  .overlay,
  .palette,
  .ticker,
  .hero__media {
    display: none !important;
  }
}

/* ---------- Section grid overlay stacking ----------
   .grid-bg is an absolutely positioned child overlay. Content inside the
   same section must sit above it so links and buttons stay clickable. */
.section > .shell {
  position: relative;
  z-index: 1;
}

/* Form controls must remain clickable above decorative layers */
.book__form,
.vit__manual,
.vit__console {
  pointer-events: auto;
}
.book__form select,
.vit__manual select {
  pointer-events: auto !important;
  cursor: pointer;
}

/* ---------- Grid min-width safety ----------
   Grid and flex items default to min-width:auto, so one long mono string
   (a VIN, a part number, a fault code list) can push a track wider than
   its container and create a horizontal scrollbar. Rather than redefining
   every layout, we let the items themselves shrink and wrap. */
.vit__body > *,
.cards > *,
.faults > *,
.feat-grid > *,
.pkgs > *,
.doors > *,
.steps > *,
.tool-list > *,
.tools-wrap > *,
.book > *,
.trade > *,
.split > *,
.foot-grid > *,
.contact-grid > *,
.vit__manual > *,
.field--2 > *,
.dtc__in > *,
.stats > * {
  min-width: 0;
}

.vit__stage,
.vit-log,
.fault,
.feat,
.job,
.dtc-hit,
.sheet__body,
.pkg,
.tool,
.spec,
.basket {
  min-width: 0;
  overflow-wrap: anywhere;
}
.card {
  min-width: 0;
  overflow-wrap: break-word;
}
.cards {
  width: 100%;
}

.hero__media {
  overflow: hidden;
}

/* Absolute last-resort guard: nothing may create a horizontal scrollbar. */
html,
body {
  overflow-x: clip;
}

/* Multi-word nav labels ("Voor garages") must not wrap to two lines. */
.nav a {
  white-space: nowrap;
}
#navMain > a[hidden] {
  display: none !important;
}

/* ---------- Inline icon sizing safety ----------
   icon() emits a viewBox-only SVG with no width/height, so an unstyled
   icon inside a flex container stretches to fill it. These low-specificity
   defaults give every inline icon a sane size without overriding the
   purpose-built sizes elsewhere in the stylesheets. */
:where(.trade__i span, .mono, .chip, .tag, .hintline, .vit__meta, .busmap__foot, .job__why, .dtc-hit__sys) > svg {
  width: 13px;
  height: 13px;
  flex: 0 0 auto;
}

.trade__i span svg {
  width: 13px;
  height: 13px;
  flex: 0 0 auto;
}

/* Any icon inside a flex link must never stretch to fill the row. */
.drawer nav a > svg,
.foot-col a > svg,
.lnk > svg {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
}

/* ============================================================
   HEADER FIT — the desktop row (logo + 9 nav links + search hint
   + WhatsApp) is wider than the viewport between roughly 1060px
   and 1500px. `overflow-x: clip` on <html> hid the symptom, so the
   button was silently cut off. Fixed by moving the breakpoint to
   where the row genuinely fits and tightening it in between.
   ============================================================ */

.site-header__in {
  gap: var(--space-4);
  min-width: 0;
}
@media (max-width: 639.98px) {
  .header-tools {
    margin-left: auto;
  }
}
@media (max-width: 1239.98px) {
  .site-header__in {
    gap: 8px;
  }
}

/* Burger stays visible at every width so the 3-line menu is never clipped
   off the end of the header row. Below 1240px the full nav is in the drawer. */
.burger,
.burger.is-needed {
  display: grid !important;
}
@media (max-width: 1239.98px) {
  .nav {
    display: none !important;
  }
}

@media (min-width: 768px) and (max-width: 1239.98px) {
  .header__cta {
    margin-left: 0;
  }
}

@media (min-width: 1240px) {
  .header-oems {
    display: inline-flex;
    margin-left: 0;
    gap: 6px;
  }
}

/* The shell caps the header row at --shell no matter how wide the
   viewport gets, so the nav has a fixed budget of roughly 750px for
   nine links. Compact link padding applies at every desktop width;
   only the button labels come back once there is room. */
@media (min-width: 1240px) {
  .site-header__in {
    gap: 8px;
  }
  .nav {
    display: flex;
    gap: 0;
    flex: 0 0 auto;
    min-width: auto;
    margin-right: 0;
  }
  .nav a {
    padding: 8px 8px;
    font-size: var(--text-xs);
  }
  .header-oems {
    margin-left: 2px;
  }
  .header__cta {
    flex: none;
    margin-left: auto;
  }
}

@media (min-width: 1180px) and (max-width: 1499.98px) {
  .header__cta .kbd-hint [data-t],
  .header__cta .btn--wa span {
    display: none;
  }
  .header__cta .kbd-hint {
    padding-inline: 10px;
  }
  .header__cta .btn--wa {
    padding-inline: 12px;
  }
}

/* ============================================================
   DIGITAL TWIN BARS — .grow__fill is a <span>, so the inline width
   set by animateTwin() was ignored and every bar stayed empty.
   Blockifying it makes the simulation actually render.
   ============================================================ */
.grow__fill {
  display: block;
}

/* "ORIGINEEL" broke onto a second line inside the 58px label column. */
.grow {
  grid-template-columns: 70px 1fr 92px;
}
.grow__n {
  white-space: nowrap;
}
@media (max-width: 420px) {
  .grow {
    grid-template-columns: 62px 1fr 84px;
    gap: var(--space-2);
  }
  .grow__n {
    font-size: 8.5px;
    letter-spacing: 0.06em;
  }
}

/* Palette footer: the key glyph lives in a <kbd> so applyI18n() can
   replace only the label without wiping the arrow characters. */
.palette__foot span {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.palette__foot em {
  font-style: normal;
}
.palette__foot kbd {
  font-family: var(--font-mono);
  font-size: 9.5px;
  line-height: 1;
  padding: 3px 5px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface-3);
  color: var(--text-2);
}

/* ============================================================
   HERO IS ALWAYS DARK
   The hero sits on a dark workshop photograph, so in light theme the
   inherited near-black text became unreadable. The hero (and the
   utility bar / unstuck header that float over it) redeclare the
   neutral tokens locally, so every child stays light-on-dark while
   the rest of the page follows the active theme.
   ============================================================ */
[data-theme='light'] .hero,
[data-theme='light'] .site-header:not(.stuck) {
  --text: #f2f5f8;
  --text-2: #b7bec9;
  --text-3: #838b98;
  --border: rgba(255, 255, 255, 0.16);
  --divider: rgba(255, 255, 255, 0.1);
  --surface: rgba(255, 255, 255, 0.05);
  --surface-2: rgba(255, 255, 255, 0.09);
  --surface-3: rgba(255, 255, 255, 0.14);
  --accent: #00d4f0;
  --accent-dim: rgba(0, 212, 240, 0.3);
  /* --bg feeds .btn--primary's text colour and the hero tint, and the veil
     keeps the workshop photo dark enough to carry white type. */
  --bg: #0a0c10;
  --img-veil: 0.44;
  --scrim: rgba(3, 4, 7, 0.72);
  --ok: #2fd68a;
  --warn: #f0a13a;
  --danger: #f4536b;
  color: var(--text);
}

/* The veiled hero photo is drawn at partial opacity, so in light theme it
   composited onto white and washed out. Giving the hero its own dark
   backdrop (and a tint that resolves to that same colour) keeps it a
   deliberate dark band above the white page. */
[data-theme='light'] .hero {
  background-color: #0a0c10;
  --hero-tint: linear-gradient(
    180deg,
    rgba(6, 7, 10, 0.5) 0%,
    rgba(6, 7, 10, 0.72) 46%,
    #0a0c10 100%
  );
}

/* The one-line symptom summary was ellipsised mid-sentence on phones and
   tablets, so the useful part of the sentence never reached the reader.
   Below the desktop grid it clamps to two lines instead of one. */
@media (max-width: 899.98px) {
  .fault__sym {
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    line-height: 1.45;
  }
}

/* The equipment photo is far shorter than the 21-item tool list, which left a
   tall empty column beside it. Pinning it below the sticky header keeps the
   photo in view for the whole list instead of leaving a visual hole. */
@media (min-width: 1000px) {
  .tools-wrap .tools-img {
    position: sticky;
    top: calc(var(--header-h, 64px) + var(--space-6));
  }
}
