/* ==========================================================================
   Site Support Group — service pages
   --------------------------------------------------------------------------
   Loaded after brand.css and styles.css. styles.css supplies the nav, footer,
   buttons, type scale and form styles; this file adds only what the service
   pages introduce. Nothing here overrides a homepage rule.

   Every page sets --svc on <body> to its service line's segment colour, and
   the accents below inherit from it, so one stylesheet dresses all six
   disciplines without a per-page variant.
   ========================================================================== */

body.svc-page {
  --svc: var(--accent);
  --svc-wash: color-mix(in srgb, var(--svc) 7%, transparent);
  --svc-line: color-mix(in srgb, var(--svc) 24%, transparent);
}
/* color-mix is well supported, but a hard fallback keeps older engines from
   rendering transparent washes as nothing at all. */
@supports not (color: color-mix(in srgb, red 50%, blue)) {
  body.svc-page { --svc-wash: rgba(8, 98, 244, 0.06); --svc-line: rgba(8, 98, 244, 0.24); }
}

/* The nav is fixed; service pages have no full-bleed hero to sit under it. */
.svc-page main { padding-top: var(--nav-h); }

.svc-page section { padding-block: var(--section-pad-tight); }
.svc-page section:first-child { padding-top: clamp(40px, 6vh, 72px); }

/* ---------- Breadcrumb ---------- */

.breadcrumb {
  padding: 20px 0 0;
  font-size: 0.85rem; color: var(--ink-soft);
}
.breadcrumb ol {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  list-style: none; margin: 0; padding: 0;
}
.breadcrumb li:not(:last-child)::after {
  content: "/"; margin-left: 6px; color: var(--line-strong);
}
.breadcrumb a { color: var(--ink-soft); text-decoration: none; }
.breadcrumb a:hover { color: var(--svc); text-decoration: underline; }
.breadcrumb [aria-current="page"] { color: var(--ink); font-weight: 600; }

/* ---------- Page hero ---------- */

.svc-hero__grid {
  display: grid; gap: clamp(28px, 5vw, 64px);
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  align-items: center;
}
.svc-hero__eyebrow {
  font-size: 0.82rem; font-weight: 700;
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  color: var(--svc); margin: 0 0 1.1em;
}
.svc-hero h1 {
  font-family: var(--font-display);
  font-size: var(--fs-h1); font-weight: 700;
  line-height: var(--lh-tight); letter-spacing: var(--tracking-tight);
  margin: 0 0 0.4em; text-wrap: balance;
}
.svc-hero__lede {
  font-size: var(--fs-lede); color: var(--ink-soft);
  line-height: var(--lh-lede); max-width: 54ch; margin: 0 0 var(--sp-6);
}
.svc-hero__actions { display: flex; flex-wrap: wrap; gap: 14px; }

.svc-hero__media {
  position: relative; border-radius: var(--r-panel); overflow: hidden;
  box-shadow: var(--shadow-panel); background: var(--bg-alt);
  aspect-ratio: 4 / 3;
}
.svc-hero__media img { width: 100%; height: 100%; object-fit: cover; }

/* Turnaround / warranty / collection promises, as a spec strip rather than
   chips. Same reasoning as .brandwall: these are facts, not controls, and the
   pill shape made three plain statements look like dismissible tags. Label
   above value, divided by hairlines, reads as the key figures on a datasheet.
   (column-reverse, because the markup leads with the <b> value so that the
   value still comes first for a screen reader and a crawler.)
   The markup stays deliberately plain either way, which is what keeps the
   values trivially extractable by a crawler or an answer engine. */
.promises {
  display: flex; flex-wrap: wrap; gap: 0;
  list-style: none; margin: 0 0 var(--sp-6); padding: 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.promises li {
  display: flex; flex-direction: column-reverse; gap: 3px;
  padding: 14px clamp(18px, 2.4vw, 30px) 14px 0;
  margin-right: clamp(18px, 2.4vw, 30px);
  border-right: 1px solid var(--line);
  font-size: var(--fs-micro); font-weight: 500; color: var(--ink-soft);
  line-height: 1.35;
}
.promises li:last-child { border-right: 0; margin-right: 0; padding-right: 0; }
.promises b {
  font-family: var(--font-display);
  font-size: 1.15rem; font-weight: 700; color: var(--ink);
  letter-spacing: var(--tracking-tight);
}

/* ---------- Top-of-page alert ----------
   Sits directly under the hero, before any other content, on pages carrying a
   caveat a visitor must not miss — currently the OEM restriction on safety
   device repair. Deliberately the loudest component on the site: it is the one
   place we are telling someone NOT to buy something without checking first, so
   it has to out-compete the hero for attention.
   Amber rather than red: this is "stop and check", not "danger". */

.pagealert {
  display: flex; gap: 18px; align-items: flex-start;
  padding: clamp(20px, 3vw, 28px) clamp(20px, 3vw, 32px);
  border-radius: var(--r-panel);
  background: rgba(180, 105, 14, 0.07);
  border: 1px solid rgba(180, 105, 14, 0.32);
  border-left: 5px solid var(--warn);
}
.pagealert__icon {
  flex: 0 0 auto; width: 26px; height: 26px; margin-top: 1px;
  border-radius: 50%; background: var(--warn); color: #fff;
  display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 700; font-size: 1rem; line-height: 1;
}
.pagealert h2 {
  font-family: var(--font-display); font-size: 1.08rem; font-weight: 700;
  margin: 0 0 0.5em; color: var(--ink); letter-spacing: -0.01em;
}
.pagealert p { color: var(--ink); margin: 0 0 0.7em; max-width: 74ch; font-size: 0.97rem; }
.pagealert p:last-child { margin-bottom: 0; }
.pagealert strong { font-weight: 700; }
.pagealert a { color: var(--accent-deep); }

/* On an article the alert sits in the centred measure, above the key points. */
.article .pagealert { margin: 0 0 var(--sp-6); }

/* ---------- Direct-answer block ----------
   A question as a heading with a short, self-contained answer underneath.
   This is the shape answer engines quote: no pronouns reaching back into
   earlier paragraphs, no "as mentioned above", one claim per sentence. */

.answer {
  border-left: 3px solid var(--svc);
  background: var(--svc-wash);
  border-radius: 0 var(--r-panel) var(--r-panel) 0;
  padding: clamp(20px, 3vw, 30px) clamp(20px, 3vw, 34px);
  margin: 0 0 var(--sp-6);
}
.answer h2, .answer h3 {
  font-family: var(--font-display); font-size: var(--fs-h4);
  font-weight: 700; margin: 0 0 0.6em; color: var(--ink);
}
.answer p { color: var(--ink-soft); margin: 0 0 0.8em; max-width: var(--measure); }
.answer p:last-child { margin-bottom: 0; }
.answer strong { color: var(--ink); }

/* The featured question at the head of the FAQ list. It sits on the alternate
   band rather than the page ground, where a 7% tint of the service colour is
   nearly invisible — so it takes a solid surface and lifts off the band
   instead. It reads as the first, biggest question, which is what it is. */
.answer--lead {
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--svc);
  box-shadow: var(--shadow-card);
}
.answer--lead h2 { font-size: var(--fs-h3); }

/* ---------- Generic prose ---------- */

.prose { max-width: var(--measure); }
.prose h2 {
  font-family: var(--font-display); font-size: var(--fs-h3); font-weight: 700;
  line-height: var(--lh-heading); letter-spacing: var(--tracking-tight);
  margin: 2em 0 0.5em;
}
.prose h2:first-child { margin-top: 0; }
.prose h3 {
  font-family: var(--font-display); font-size: var(--fs-h4);
  font-weight: 700; margin: 1.8em 0 0.4em;
}
.prose p, .prose li { color: var(--ink-soft); }
.prose ul, .prose ol { padding-left: 1.15em; margin: 0 0 1.2em; }
.prose li { margin-bottom: 0.5em; }
.prose li::marker { color: var(--svc); }
.prose strong { color: var(--ink); }
.prose a { color: var(--svc); }

.section-head { max-width: 62ch; margin: 0 0 var(--sp-7); }
.section-head h2 {
  font-family: var(--font-display); font-size: var(--fs-h2); font-weight: 700;
  line-height: var(--lh-tight); letter-spacing: var(--tracking-tight);
  margin: 0 0 0.4em; text-wrap: balance;
}
.section-head p { font-size: var(--fs-lede); color: var(--ink-soft); line-height: var(--lh-lede); margin: 0; }

.band-alt { background: var(--bg-alt); }

/* ---------- Four-step process ---------- */

.process {
  display: grid; gap: 20px; list-style: none; margin: 0; padding: 0;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  counter-reset: step;
}
.process li {
  position: relative; counter-increment: step;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-panel); padding: 26px 24px 24px;
  box-shadow: var(--shadow-card);
}
.process li::before {
  content: counter(step, decimal-leading-zero);
  display: block; margin-bottom: 12px;
  font-family: var(--font-display); font-size: 1.5rem; font-weight: 700;
  color: var(--svc); letter-spacing: -0.03em;
}
.process h3 { font-family: var(--font-display); font-size: 1.02rem; font-weight: 700; margin: 0 0 0.5em; }
.process p { color: var(--ink-soft); font-size: 0.94rem; margin: 0; }

/* ---------- Repair category grid ---------- */

.catgrid {
  display: grid; gap: 16px; list-style: none; margin: 0; padding: 0;
  grid-template-columns: repeat(auto-fill, minmax(228px, 1fr));
}
.catgrid a {
  display: flex; flex-direction: column; height: 100%;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-panel); padding: 20px;
  text-decoration: none; color: inherit;
  transition: border-color var(--t-base), box-shadow var(--t-base), transform var(--t-base) var(--ease-settle);
}
.catgrid a:hover {
  border-color: var(--svc-line); box-shadow: var(--shadow-card); transform: translateY(-2px);
}
.catgrid__thumb {
  display: grid; place-items: center;
  height: 92px; margin-bottom: 16px;
  background: var(--bg-alt); border-radius: 10px;
}
.catgrid__thumb img { max-height: 74px; width: auto; object-fit: contain; mix-blend-mode: multiply; }
/* Photographic thumbnails fill the tile instead. multiply is right for the
   OEM product cut-outs on white, and wrong for a real photograph. */
.catgrid__thumb--photo { overflow: hidden; }
.catgrid__thumb--photo img {
  max-height: none; width: 100%; height: 100%;
  object-fit: cover; mix-blend-mode: normal;
}
.catgrid h3 { font-family: var(--font-display); font-size: 1rem; font-weight: 700; margin: 0 0 0.35em; }
.catgrid p { color: var(--ink-soft); font-size: 0.88rem; margin: 0 0 14px; }
.catgrid span { margin-top: auto; color: var(--svc); font-weight: 700; font-size: 0.85rem; }

/* ---------- Faults / why-it-fails pairing -------------------------------
   The symptom list is what a maintenance engineer arrives looking for — they
   already know their panel is dead, they want to see it named. So it leads,
   at size, and the background on why these units fail demotes to a note
   alongside it. It used to be the other way round: two paragraphs of
   explanation before the reader could confirm they were in the right place. */

.faults {
  display: grid; gap: clamp(24px, 3.2vw, 48px);
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  align-items: start;
  margin: 0 0 var(--sp-8);
}

.faults__lead h2 {
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 2.9vw, 2.2rem);
  font-weight: 700; line-height: var(--lh-heading);
  letter-spacing: var(--tracking-tight);
  margin: 0 0 0.7em; text-wrap: balance;
}

.faultlist { list-style: none; margin: 0; padding: 0; }
.faultlist li {
  position: relative;
  padding: 13px 0 13px 26px;
  border-bottom: 1px solid var(--line);
  color: var(--ink); font-size: 1.02rem; line-height: 1.45;
}
.faultlist li:first-child { border-top: 1px solid var(--line); }
/* The mark's pin, same shape as the homepage card benefits. */
.faultlist li::before {
  content: ""; position: absolute; left: 0; top: 1.15em;
  width: 10px; height: 11px;
  clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
  background: var(--svc);
}

/* The demoted explanation. A note, not a column of body copy: tighter type,
   its own label, and a rule in the service colour so it still reads as part
   of this page rather than a generic aside. */
.tipbox {
  background: var(--bg-alt);
  border: 1px solid var(--line);
  border-top: 3px solid var(--svc);
  border-radius: var(--r-panel);
  padding: clamp(20px, 2.6vw, 28px);
  /* Deliberately NOT sticky. It was, and it read as the box chasing the
     reader down the page and flinching away from the nav — a side note should
     stay where it was put. */
}
.tipbox h3 {
  font-family: var(--font-display);
  font-size: 1.05rem; font-weight: 700; color: var(--ink);
  margin: 0 0 0.7em; letter-spacing: -0.01em;
}
.tipbox p {
  font-size: 0.94rem; line-height: 1.6; color: var(--ink-soft);
  margin: 0 0 0.9em;
}
.tipbox p:last-child { margin-bottom: 0; }

@media (max-width: 900px) {
  .faults { grid-template-columns: 1fr; }
}

/* ---------- Proof panel -------------------------------------------------
   A checklist that has been ticked off by hand, on the dark block. The ticks
   are drawn as an open pen stroke that overshoots its box, because a printed
   geometric checkmark reads as a UI state and this is meant to read as
   somebody having signed the work off.

   The tick colour is a lifted mint rather than --ok (#0B7A6B): the brand's
   status green is tuned for white backgrounds and goes muddy on navy. Same
   hue family, raised in lightness until it carries on the dark panel. */

.proof {
  background:
    radial-gradient(900px 400px at 12% -20%, rgba(8, 98, 244, 0.28), transparent 62%),
    var(--hub-bg);
  color: var(--hub-text);
  border-radius: var(--r-panel);
  padding: clamp(28px, 4vw, 52px);
}
.proof h2 {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  font-weight: 700; line-height: var(--lh-heading);
  letter-spacing: var(--tracking-tight);
  margin: 0 0 0.6em; color: #fff; text-wrap: balance;
}
.proof p { color: var(--hub-dim); max-width: 68ch; margin: 0 0 1.4em; }
.proof p:last-child { margin: 1.6em 0 0; font-size: 0.94rem; }

.ticklist {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
}
.ticklist li {
  position: relative;
  padding: 4px 0 4px 46px;
  color: var(--hub-text); line-height: 1.45;
}
/* The box. */
.ticklist li::before {
  content: ""; position: absolute; left: 0; top: 2px;
  width: 23px; height: 23px;
  border: 2px solid rgba(255, 255, 255, 0.34);
  border-radius: 5px;
}
/* The pen stroke over it — deliberately larger than the box and offset up and
   left so it breaks the outline the way a real tick does. */
.ticklist li::after {
  content: ""; position: absolute; left: 1px; top: -6px;
  width: 34px; height: 34px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' fill='none' stroke='%2340E0A8' stroke-width='3.1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5.4 17.1c2.1 1.3 4.1 3.1 5.9 5.4.5.6 1.2.5 1.5-.2C15.4 16 19.6 10.6 26.2 6.1'/%3E%3C/svg%3E") no-repeat center / contain;
}

/* ---------- Manufacturer wall ---------- */

/* A ruled index, not a bank of pills.
   Fifty manufacturer names in rounded chips read as a filter UI you cannot
   click: the shape promises interactivity, the tinted "key" variants look
   like active selections, and the ragged widths make a noisy mass out of what
   is simply a list. Set as a bordered index it reads as what it is — a
   capability list, closer to a parts catalogue than to a control. Emphasis on
   the most-seen names comes from weight and ink, which costs nothing and
   cannot be mistaken for a button. */
.brandwall {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: 0 clamp(16px, 2.4vw, 32px);
  list-style: none; margin: 0; padding: 0;
  border-top: 1px solid var(--line);
}
.brandwall li {
  padding: 11px 2px;
  border-bottom: 1px solid var(--line);
  font-size: 0.92rem; color: var(--ink-soft);
  line-height: 1.3;
}
.brandwall li.is-key { color: var(--ink); font-weight: 600; }

/* ---------- Stats ---------- */

.statrow {
  display: grid; gap: 20px; list-style: none; margin: 0; padding: 0;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}
.statrow div { border-top: 2px solid var(--svc); padding-top: 16px; }
.statrow dt {
  font-family: var(--font-display); font-size: clamp(1.8rem, 3.4vw, 2.6rem);
  font-weight: 700; line-height: 1; letter-spacing: -0.03em; color: var(--ink);
}
.statrow dd { margin: 8px 0 0; color: var(--ink-soft); font-size: 0.92rem; }

/* ---------- Dark contrast band ---------- */

.darkband {
  background: var(--hub-bg); color: var(--hub-text);
  background-image: radial-gradient(120% 90% at 80% 0%, rgba(8, 98, 244, 0.22), transparent 60%);
}
.darkband h2, .darkband h3, .darkband dt { color: var(--hub-text); }
.darkband p, .darkband li, .darkband dd { color: var(--hub-dim); }
.darkband .process li { background: rgba(255, 255, 255, 0.04); border-color: rgba(255, 255, 255, 0.1); box-shadow: none; }
.darkband .process li::before,
.darkband .statrow div { color: #6AA8FF; border-color: #6AA8FF; }
.darkband .brandwall li { background: rgba(255, 255, 255, 0.05); border-color: rgba(255, 255, 255, 0.12); color: var(--hub-dim); }
.darkband .brandwall li.is-key { color: var(--hub-text); border-color: rgba(106, 168, 255, 0.5); }

/* ---------- Case studies ---------- */

.casegrid {
  display: grid; gap: 20px;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
}
.case-card {
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-panel); overflow: hidden;
  text-decoration: none; color: inherit;
  transition: border-color var(--t-base), box-shadow var(--t-base), transform var(--t-base) var(--ease-settle);
}
.case-card:hover { border-color: var(--svc-line); box-shadow: var(--shadow-panel); transform: translateY(-3px); }
.case-card__media { aspect-ratio: 16 / 9; background: var(--bg-alt); overflow: hidden; }
.case-card__media img { width: 100%; height: 100%; object-fit: cover; }
.case-card__body { padding: 22px; display: flex; flex-direction: column; flex: 1; }
.case-card__tag {
  font-size: 0.74rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--svc); margin: 0 0 0.7em;
}
.case-card h3 { font-family: var(--font-display); font-size: 1.12rem; font-weight: 700; line-height: 1.25; margin: 0 0 0.5em; }
.case-card p { color: var(--ink-soft); font-size: 0.92rem; margin: 0 0 16px; }
.case-card__more { margin-top: auto; color: var(--svc); font-weight: 700; font-size: 0.86rem; }

/* Challenge / solution / result on a case study page */
.csr { display: grid; gap: clamp(28px, 4vw, 48px); }
.csr__block { display: grid; gap: 8px 32px; grid-template-columns: 190px minmax(0, 1fr); align-items: start; }
.csr__label {
  font-size: 0.78rem; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--svc); padding-top: 6px;
}
.csr__block h2 { font-family: var(--font-display); font-size: var(--fs-h3); font-weight: 700; line-height: 1.15; letter-spacing: var(--tracking-tight); margin: 0 0 0.5em; }
.csr__block p, .csr__block li { color: var(--ink-soft); }
.csr__block ul { padding-left: 1.15em; margin: 0 0 1em; }
.csr__block li { margin-bottom: 0.5em; }
.csr__block li::marker { color: var(--svc); }

figure.shot { margin: 0; }
figure.shot img { width: 100%; border-radius: var(--r-panel); box-shadow: var(--shadow-card); }
figure.shot figcaption { margin-top: 10px; font-size: 0.85rem; color: var(--ink-soft); }

/* ---------- FAQ ----------
   <details> so it works with no JS, and so the answer text is present in the
   DOM whether or not it is expanded. */

.faq { max-width: 82ch; }
.faq details {
  border-bottom: 1px solid var(--line);
  padding: 4px 0;
}
.faq summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: flex-start; justify-content: space-between; gap: 20px;
  padding: 20px 0;
  font-family: var(--font-display); font-size: 1.05rem; font-weight: 700; color: var(--ink);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; flex: 0 0 auto; margin-top: 7px;
  width: 9px; height: 9px;
  border-right: 2px solid var(--svc); border-bottom: 2px solid var(--svc);
  transform: rotate(45deg);
  transition: transform var(--t-base) var(--ease-settle);
}
.faq details[open] summary::after { transform: rotate(225deg); margin-top: 11px; }
.faq details > div { padding: 0 0 22px; max-width: var(--measure); }
.faq details p { color: var(--ink-soft); margin: 0 0 0.8em; }
.faq details p:last-child { margin-bottom: 0; }
.faq details a { color: var(--svc); }

/* ---------- Closing CTA ---------- */

.cta-band__inner {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: clamp(20px, 4vw, 48px);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-panel); box-shadow: var(--shadow-panel);
  padding: clamp(28px, 4vw, 46px);
}
.cta-band h2 { font-family: var(--font-display); font-size: var(--fs-h3); font-weight: 700; line-height: 1.15; letter-spacing: var(--tracking-tight); margin: 0 0 0.4em; }
.cta-band p { color: var(--ink-soft); margin: 0; max-width: 52ch; }
.cta-band__actions { display: flex; flex-wrap: wrap; gap: 12px; }

/* ---------- Related services ---------- */

.related { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.related a {
  display: block; padding: 20px 22px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-panel);
  text-decoration: none; color: inherit;
  border-top: 3px solid var(--rel, var(--accent));
  transition: box-shadow var(--t-base), transform var(--t-base) var(--ease-settle);
}
.related a:hover { box-shadow: var(--shadow-card); transform: translateY(-2px); }
.related strong { display: block; font-family: var(--font-display); font-size: 1rem; margin-bottom: 5px; }
.related span { color: var(--ink-soft); font-size: 0.88rem; }

/* ==========================================================================
   Insights — index and articles
   ========================================================================== */

/* ---------- Index ---------- */

.insight-grid {
  display: grid; gap: 20px;
  grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
}
.insight-card {
  display: flex; flex-direction: column;
  padding: 26px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-panel);
  text-decoration: none; color: inherit;
  border-top: 3px solid var(--cat, var(--accent));
  transition: box-shadow var(--t-base), transform var(--t-base) var(--ease-settle);
}
.insight-card:hover { box-shadow: var(--shadow-panel); transform: translateY(-3px); }
.insight-card h3 {
  font-family: var(--font-display); font-size: 1.2rem; font-weight: 700;
  line-height: 1.2; letter-spacing: -0.015em; margin: 0 0 0.5em;
}
.insight-card p { color: var(--ink-soft); font-size: 0.93rem; margin: 0 0 18px; }
.insight-card__more { margin-top: auto; color: var(--cat, var(--accent)); font-weight: 700; font-size: 0.86rem; }

/* Shared by the card and the article header. */
.meta-line {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin: 0 0 14px;
  font-size: 0.76rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-soft);
}
.meta-line .cat { color: var(--cat, var(--accent)); }
.meta-line span + span::before { content: "·"; margin-right: 10px; color: var(--line-strong); }

/* Lead article on the index gets the full width and a larger type size. */
.insight-lead {
  display: grid; gap: clamp(24px, 4vw, 48px);
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  align-items: center;
  padding: clamp(28px, 4vw, 44px);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-panel); box-shadow: var(--shadow-card);
  margin-bottom: 22px;
  text-decoration: none; color: inherit;
  border-top: 3px solid var(--cat, var(--accent));
}
.insight-lead:hover { box-shadow: var(--shadow-panel); }
.insight-lead h2 {
  font-family: var(--font-display); font-size: clamp(1.6rem, 3vw, 2.2rem);
  font-weight: 700; line-height: 1.1; letter-spacing: var(--tracking-tight);
  margin: 0 0 0.45em; text-wrap: balance;
}
.insight-lead p { color: var(--ink-soft); margin: 0 0 18px; }
.insight-lead__media {
  border-radius: 10px; overflow: hidden; aspect-ratio: 4 / 3; background: var(--bg-alt);
}
.insight-lead__media img { width: 100%; height: 100%; object-fit: cover; }

/* ---------- Article ---------- */

.article { max-width: 74ch; margin-inline: auto; }
.article h1 {
  font-family: var(--font-display);
  font-size: clamp(2rem, 4.4vw, 3.1rem); font-weight: 700;
  line-height: 1.06; letter-spacing: var(--tracking-tight);
  margin: 0 0 0.4em; text-wrap: balance;
}
.article__dek {
  font-size: var(--fs-lede); color: var(--ink-soft);
  line-height: var(--lh-lede); margin: 0 0 var(--sp-6);
}
.article__hero {
  border-radius: var(--r-panel); overflow: hidden;
  box-shadow: var(--shadow-panel); margin: 0 0 var(--sp-7);
}
.article__hero img { width: 100%; display: block; }

.article__body > h2 {
  font-family: var(--font-display); font-size: clamp(1.4rem, 2.6vw, 1.9rem);
  font-weight: 700; line-height: 1.14; letter-spacing: var(--tracking-tight);
  margin: 2.2em 0 0.6em; scroll-margin-top: calc(var(--nav-h) + 16px);
}
.article__body > h3 {
  font-family: var(--font-display); font-size: 1.12rem; font-weight: 700;
  margin: 1.9em 0 0.5em;
}
.article__body p, .article__body li { color: var(--ink-soft); }
.article__body strong { color: var(--ink); }
.article__body a { color: var(--cat, var(--accent)); }
.article__body ul, .article__body ol { padding-left: 1.2em; margin: 0 0 1.3em; }
.article__body li { margin-bottom: 0.55em; }
.article__body li::marker { color: var(--cat, var(--accent)); }

/* Contents list. Plain anchors — no JS, no scroll-spy. */
.toc {
  background: var(--bg-alt); border-radius: var(--r-panel);
  padding: 22px 26px; margin: 0 0 var(--sp-7);
}
.toc p {
  margin: 0 0 10px; font-size: 0.76rem; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-soft);
}
.toc ol { margin: 0; padding-left: 1.1em; }
.toc li { margin-bottom: 6px; color: var(--ink-soft); }
.toc a { color: var(--ink); text-decoration: none; font-weight: 600; font-size: 0.94rem; }
.toc a:hover { color: var(--cat, var(--accent)); text-decoration: underline; }

/* Key points — the block an answer engine is most likely to lift whole. */
.keypoints {
  border: 1px solid var(--line); border-left: 3px solid var(--cat, var(--accent));
  border-radius: 0 var(--r-panel) var(--r-panel) 0;
  background: var(--surface);
  padding: 24px 28px; margin: 0 0 var(--sp-7);
}
.keypoints h2 {
  font-family: var(--font-display); font-size: 1rem; font-weight: 700;
  margin: 0 0 0.7em; letter-spacing: 0;
}
.keypoints ul { margin: 0; padding-left: 1.15em; }
.keypoints li { color: var(--ink-soft); margin-bottom: 0.5em; }
.keypoints li:last-child { margin-bottom: 0; }

/* Callouts. .callout--note is context; .callout--warn is a genuine caution and
   is used sparingly, mostly around safety-related claims. */
.callout {
  border-radius: var(--r-panel); padding: 20px 24px; margin: 0 0 1.5em;
  border: 1px solid var(--line); background: var(--bg-alt);
}
.callout p { margin: 0 0 0.7em; }
.callout p:last-child { margin-bottom: 0; }
.callout__label {
  display: block; margin-bottom: 8px;
  font-size: 0.74rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-soft);
}
.callout--warn { background: rgba(198, 39, 59, 0.05); border-color: rgba(198, 39, 59, 0.25); }
.callout--warn .callout__label { color: var(--danger); }

/* ---------- Before / after gallery ----------
   Pairs a "before" and an "after" shot of the same component. The state chip
   is part of the figure rather than the caption so the pairing survives a
   one-column collapse on mobile, where the two images are no longer visually
   side by side. */

.ba-grid {
  display: grid; gap: 18px;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  margin: 0 0 1.8em;
}
.ba-grid--single { grid-template-columns: minmax(0, 1fr); }

.ba {
  margin: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-panel);
  overflow: hidden;
}
.ba img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  display: block; background: var(--bg-alt);
}
.ba--tall img { aspect-ratio: 3 / 4; }
.ba figcaption { padding: 14px 16px 16px; }

/* Squared to --r-chip. This one is a genuine state marker rather than prose in
   a pill, so it keeps its tint — but the radius system has a chip step, and a
   badge should use it rather than the button shape. */
.ba__state {
  display: inline-block; margin-bottom: 7px;
  padding: 3px 9px; border-radius: var(--r-chip);
  font-size: 0.7rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
}
.ba__state--before { background: rgba(198, 39, 59, 0.1); color: #A31F30; }
.ba__state--during { background: rgba(180, 105, 14, 0.12); color: #8A5009; }
.ba__state--after { background: rgba(11, 122, 107, 0.12); color: var(--ok); }

.ba figcaption p { margin: 0; font-size: 0.88rem; color: var(--ink-soft); line-height: 1.5; }

/* Tables inside articles scroll horizontally rather than forcing the page to. */
.table-wrap { overflow-x: auto; margin: 0 0 1.6em; -webkit-overflow-scrolling: touch; }
.article__body table { border-collapse: collapse; width: 100%; min-width: 460px; font-size: 0.93rem; }
.article__body th, .article__body td {
  text-align: left; padding: 11px 14px; border-bottom: 1px solid var(--line); vertical-align: top;
}
.article__body th {
  font-family: var(--font-display); font-weight: 700; color: var(--ink);
  border-bottom-color: var(--line-strong); white-space: nowrap;
}
.article__body td { color: var(--ink-soft); }
.article__body tbody tr:last-child td { border-bottom: 0; }

/* Byline / provenance footer on each article. */
.article__foot {
  margin-top: var(--sp-7); padding-top: var(--sp-5);
  border-top: 1px solid var(--line);
  font-size: 0.9rem; color: var(--ink-soft);
}

/* ==========================================================================
   Repair enquiry modal
   --------------------------------------------------------------------------
   Native <dialog>, so the focus trap, backdrop, page inertness and
   Escape-to-close are the browser's job rather than ours. The form inside
   reuses .field / .field--half / .form-status from styles.css unchanged — the
   only thing added here is the dialog chrome and the two-column grid those
   field classes expect.
   ========================================================================== */

.enquiry {
  width: min(660px, calc(100vw - 32px));
  /* dvh, with vh as the fallback for engines that lack it. vh does not shrink
     when a mobile keyboard opens, so the panel kept its full height and pushed
     the fields the user was typing into off the bottom of the screen. */
  max-height: min(88vh, 900px);
  max-height: min(88dvh, 900px);
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-panel);
  background: var(--surface);
  color: var(--ink);
  box-shadow: 0 40px 90px -30px rgba(10, 37, 64, 0.5);
  /* THE WHOLE PANEL SCROLLS, heading included.
     The heading used to sit outside the scrolling region, so it was pinned
     while only the fields moved. With a keyboard open on a phone that left a
     sliver of form visible under a fixed header and no way to recover the
     space. Scrolling the lot lets the user push the heading away and put the
     field they are typing into wherever they can see it. */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
.enquiry::backdrop {
  background: rgba(7, 17, 32, 0.55);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}

/* Entrance. Skipped entirely under reduced motion (see the block at the end). */
@keyframes enquiry-in {
  from { opacity: 0; transform: translateY(12px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}
.enquiry[open] { animation: enquiry-in 0.22s var(--ease-settle); }

/* No max-height and no inner scroller: the dialog itself is the scroll
   container now, so this just stacks. */
.enquiry__inner {
  display: flex; flex-direction: column;
}

.enquiry__head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 20px;
  padding: 26px clamp(22px, 4vw, 32px) 18px;
  border-bottom: 1px solid var(--line);
}
.enquiry__head h2 {
  font-family: var(--font-display); font-size: 1.3rem; font-weight: 700;
  letter-spacing: -0.015em; margin: 0 0 0.3em;
}
.enquiry__head p { color: var(--ink-soft); font-size: 0.93rem; margin: 0; }

.enquiry__close {
  flex: 0 0 auto; width: 36px; height: 36px; margin: -6px -6px 0 0;
  display: grid; place-items: center;
  background: none; border: 1px solid transparent; border-radius: 50%;
  color: var(--ink-soft); font-size: 1.5rem; line-height: 1; cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}
.enquiry__close:hover { background: var(--bg-alt); color: var(--ink); }

/* Scrolling moved up to .enquiry so the heading travels with the form. */
.enquiry__body {
  padding: 24px clamp(22px, 4vw, 32px) 28px;
}

/* .field sets display:grid, which beats the user-agent [hidden]{display:none}
   on specificity — so hidden fields would still render without this. Needed
   because the modal toggles the repair-only fields per mode. */
.enquiry [hidden] { display: none !important; }

.enquiry__form {
  display: grid; grid-template-columns: 1fr 1fr; gap: 18px;
}
.enquiry__form .btn { grid-column: span 2; justify-self: start; }
.enquiry__form .form-status { grid-column: span 2; }

/* Section divider inside the form, separating "who you are" from
   "what has failed". */
.enquiry__legend {
  grid-column: span 2;
  margin: 4px 0 -4px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  font-size: 0.76rem; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-soft);
}

.enquiry__legal {
  grid-column: span 2; margin: 0;
  font-size: 0.8rem; color: var(--ink-soft);
}
.enquiry__legal a { color: var(--accent); }

/* Success state, swapped in place of the form. */
.enquiry__done { padding: 8px 0 4px; }
.enquiry__done h2 {
  font-family: var(--font-display); font-size: 1.3rem; font-weight: 700;
  margin: 0 0 0.4em; outline: none;
}
.enquiry__done p { color: var(--ink-soft); margin: 0 0 1em; }
.enquiry__done .btn { margin-top: 6px; }

@media (max-width: 560px) {
  .enquiry__form { grid-template-columns: 1fr; }
  .enquiry__form .field, .enquiry__form .field--half,
  .enquiry__form .btn, .enquiry__form .form-status,
  .enquiry__legend, .enquiry__legal { grid-column: span 1; }
}

/* ---------- Responsive ---------- */

@media (max-width: 900px) {
  .insight-lead { grid-template-columns: 1fr; }
  .insight-lead__media { order: -1; aspect-ratio: 16 / 9; }
  .svc-hero__grid { grid-template-columns: 1fr; }
  .svc-hero__media { aspect-ratio: 16 / 10; }
  .csr__block { grid-template-columns: 1fr; gap: 4px; }
  .csr__label { padding-top: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .catgrid a, .case-card, .related a, .faq summary::after,
  .nav__dropdown-panel, .nav__dropdown-trigger::after,
  .insight-card, .enquiry__close {
    transition: none !important;
  }
  .catgrid a:hover, .case-card:hover, .related a:hover, .insight-card:hover { transform: none; }
  .enquiry[open] { animation: none; }
}


/* ==========================================================================
   Site Support Group — REPAIR CATEGORY GRID  (Direction A: Technical Editorial)
   --------------------------------------------------------------------------
   Merged in from the approved prototype.
   Applies to the repair hub today; the same treatment rolls out to the
   remaining service pages next.

   Replaces the 14 identical bordered cards of .catgrid with a two-tier index:

     Tier 1  four flagship tiles, large, photographed part filling the tile,
             text overlaid on a scrim. On hover (fine pointer only) a 2.5s
             silent orbit clip cross-fades in over the still.
     Tier 2  the remaining ten, same treatment at a smaller size, name only.

   The editorial register comes from three things, not from decoration:
   monospaced index numerals, one hairline rule per tile, and type that is
   allowed to be large. Everything else is photograph.

   Tokens only — no literal colours except the scrim, which has to be a black
   ramp to stay legible over an unknown photograph.
   ========================================================================== */

/* ==========================================================================
   FULL-BLEED HERO
   --------------------------------------------------------------------------
   The photograph runs edge to edge and the copy sits on it, matching the tile
   treatment below so the page reads as one idea rather than two.

   Motion is a CSS transform on the still (`.hero-full--css`). A generated
   video of this shot was tried and rejected: the probes read as unconvincing,
   and its motion turned out to be nothing more than a slow camera push-in —
   the probes never moved relative to the board — so the transform reproduces
   it for 0KB instead of 222KB, stays sharp at any width, and puts no
   compression artefacts into dense PCB detail.

   The <video> rules below are kept because they cost nothing and a better
   clip may yet exist. To use one, drop the --css class and add a <video> to
   __media. The rejected clip is parked outside the deploy tree at
   prototype-assets/hero/lean-crf31.mp4 — do not ship it without re-reviewing.
   ========================================================================== */

/* Items stay stretched so the photograph and the scrim fill the band; only the
   copy block opts out, via its own align-self. */
.hero-full {
  position: relative; isolation: isolate;
  display: grid; grid-template-columns: minmax(0, 1fr);
  min-height: clamp(430px, 62vh, 620px);
  overflow: hidden;
  background: var(--c-navy);
}
/* Sections carry vertical rhythm padding site-wide (`.svc-page section`, two
   classes). A full-bleed band must not, or the photograph stops short of the
   edges and the grid row sizes to the copy rather than the band. Matched at
   the same specificity and won on source order — this file loads after
   services.css. The hero's breathing room comes from __inner instead. */
.svc-page .hero-full { padding: 0; }

.hero-full__media { grid-area: 1 / 1; position: relative; overflow: hidden; }
.hero-full__media img,
.hero-full__media video {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  display: block;
}
/* The still sits underneath as the poster and as the reduced-motion fallback;
   the clip is generated from it, so there is nothing to see at the handover. */
.hero-full__media video { z-index: 1; }

/* CSS-motion variant. Origin held on the probe tips so the push converges on
   the point of interest rather than the middle of the board. */
.hero-full--css .hero-full__media video { display: none; }
.hero-full--css .hero-full__media img {
  transform-origin: 56% 34%;
  animation: hero-push 26s var(--ease-settle) infinite alternate;
  will-change: transform;
}
@keyframes hero-push {
  from { transform: scale(1); }
  to   { transform: scale(1.13); }
}

/* Plain variant, for pages with no photograph worth showing (the insights
   index). Same band, same type, brand gradient instead of an image — so the
   structure stays identical across the site rather than one page reverting to
   a different hero shape. The scrim is skipped: there is nothing to hold the
   text off, and layering it over the gradient only muddies it. */
.hero-full--plain { background: linear-gradient(135deg, #071120 0%, #0A2540 46%, #0E2D4C 100%); }
.hero-full--plain::after { display: none; }
.hero-full__media--plain { background: none; }

/* Two-axis scrim. The horizontal ramp carries the copy block on wide screens,
   where the text sits left over a busy green board; the vertical ramp takes
   over on narrow ones once the copy spans the full width. */
.hero-full::after {
  content: ""; grid-area: 1 / 1; z-index: 1; pointer-events: none;
  background:
    linear-gradient(to right, rgba(4, 12, 24, 0.88) 0%, rgba(4, 12, 24, 0.72) 38%, rgba(4, 12, 24, 0.28) 72%, rgba(4, 12, 24, 0.18) 100%),
    linear-gradient(to top, rgba(4, 12, 24, 0.55) 0%, rgba(4, 12, 24, 0) 55%);
}

.hero-full__inner {
  grid-area: 1 / 1; z-index: 2; align-self: center;
  /* .wrap sets margin-inline:auto, and auto margins switch off grid stretch —
     the block would size to max-content and centre itself, putting the h1 out
     of line with every section heading below it. Explicit width restores the
     shared gutter. */
  width: 100%;
  padding-block: clamp(48px, 7vh, 88px);
}
.hero-full__eyebrow {
  font-size: 0.82rem; font-weight: 700;
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  color: rgba(255, 255, 255, 0.72); margin: 0 0 1.1em;
}
/* 21ch, not 16ch. The headline is two sentences of ~19 characters; capping at
   16 forced a three-line stack squeezed into the left third of a wide band,
   which is what made the copy look lost against all that board. 21ch lets it
   break once, at the full stop, where it wants to. */
.hero-full h1 {
  font-family: var(--font-display);
  font-size: var(--fs-h1); font-weight: 700;
  line-height: var(--lh-tight); letter-spacing: var(--tracking-tight);
  margin: 0 0 0.44em; color: #fff;
  max-width: 21ch; text-wrap: balance;
}
.hero-full__lede {
  font-size: var(--fs-lede); line-height: var(--lh-lede);
  color: rgba(255, 255, 255, 0.84);
  max-width: 58ch; margin: 0 0 var(--sp-6);
}
/* The three commercial facts. Pure white against the 84% body gives them the
   lift without a second colour, which would fight the photograph. */
.hero-full__lede strong { color: #fff; font-weight: 700; }

.hero-full__actions { display: flex; flex-wrap: wrap; gap: 14px; }
/* The ghost button's default ink-on-light border disappears over a photo. */
.hero-full .btn--ghost {
  border-color: rgba(255, 255, 255, 0.55); color: #fff; background: transparent;
}
.hero-full .btn--ghost:hover {
  border-color: #fff; background: rgba(255, 255, 255, 0.14);
}

@media (max-width: 760px) {
  .hero-full { min-height: clamp(400px, 56vh, 520px); }
  .hero-full h1 { max-width: none; }
}

/* ---------- Collapsed detail sections ------------------------------------
   Both panels start closed. The copy stays in the DOM and in the markup, so
   it is still crawled and still eligible for the FAQ schema — collapsing is a
   presentation choice, not a content one.

   Presented as a card rather than as bare rules. Two closed summaries centred
   at 82ch on an near-white ground read as leftovers between the hero and the
   grid: no edges, no weight, acres of margin either side. Giving them the
   site's existing panel idiom — white surface, hairline, panel radius, card
   shadow — and letting them span the full measure makes the section look
   deliberate at the cost of nothing new. */

.foldout-section { padding-block: clamp(44px, 5.5vh, 72px) !important; }

/* Capped so the card relates to the text inside it. Full-bleed looked right
   closed and wrong open — the body sits at a reading measure, so a 1144px
   panel came back only half filled. Left-aligned to the page gutter rather
   than centred: the empty space then falls to the outside edge, where it
   reads as margin, instead of splitting either side of a floating block. */
.foldout {
  max-width: 900px; margin: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-card);
  padding: 0 clamp(18px, 2.6vw, 32px);
}
.foldout details { border-bottom: 1px solid var(--line); padding: 0; }
.foldout details:last-child { border-bottom: 0; }

.foldout summary {
  font-size: var(--fs-h4);
  padding: clamp(20px, 2.4vw, 26px) 0;
  transition: color var(--t-base);
}
.foldout summary:hover { color: var(--svc); }
/* The chevron is centred against the taller summary type. */
.foldout summary::after { margin-top: 10px; }
.foldout details[open] summary::after { margin-top: 14px; }
.foldout details[open] summary { color: var(--svc); }
.foldout details > div { padding: 0 0 26px; max-width: 74ch; }

/* ---------- "Not listed?" prompt -----------------------------------------
   Replaces the explanatory paragraph that used to sit under the section
   heading. One line, one button, on one row. */

.notlisted {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sp-4) var(--sp-5);
  margin: 0 0 var(--sp-6);
}
.notlisted p {
  font-size: var(--fs-lede); color: var(--ink-soft);
  line-height: var(--lh-lede); margin: 0;
}
.notlisted .btn { flex: none; }

/* Heading sits tighter to the prompt than the default section rhythm. */
.section-head--tight { margin-bottom: var(--sp-4); }

/* ---------- Page footnotes -----------------------------------------------
   The collection offer is qualified. The qualifier lives at the foot of the
   page rather than in the hero, where it would undercut the claim mid-
   sentence — but the marker in the hero is a real link to it, so anyone who
   wants the terms is one click away rather than left hunting. */

.pagenotes {
  padding-block: var(--sp-6) var(--sp-7);
  border-top: 1px solid var(--line);
  scroll-margin-top: calc(var(--nav-h) + 16px);
}
.pagenotes p {
  font-size: var(--fs-micro); color: var(--ink-soft);
  line-height: 1.55; margin: 0; max-width: 70ch;
}
.pagenotes p + p { margin-top: 0.7em; }
.pagenotes strong { color: var(--ink); }

/* Sits inside the case study's own section rather than at the very foot of
   the page, so the attribution stays attached to the story it qualifies. */
.casenote { margin-top: var(--sp-7); }
/* Briefly marks the note when arrived at from the hero marker. */
.pagenotes:target p { color: var(--ink); font-weight: 600; }

.fn-ref {
  color: inherit; text-decoration: none;
  font-size: 0.75em; vertical-align: super; line-height: 0;
  padding: 0 0.1em;
}
.fn-ref:hover, .fn-ref:focus-visible { text-decoration: underline; }

.tiles { display: grid; gap: var(--sp-4); list-style: none; margin: 0; padding: 0; }

/* Tier 1 — flagships. Two up; the four categories that carry the search
   intent (AutoStore, drives, HMI/PLC, PCB). */
.tiles--lead { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* Tier 2 — the remaining ten. auto-fill so the row count follows the
   viewport rather than being pinned to a magic number. */
.tiles--rest { grid-template-columns: repeat(auto-fill, minmax(196px, 1fr)); gap: var(--sp-3); margin-top: var(--sp-3); }

/* The <li> is a grid so its single <a> stretches to the row height. Without
   this a tile grown by a long name leaves its neighbours short and the row
   bottoms go ragged. */
.tile { margin: 0; display: grid; }

/* Media and body are stacked in ONE grid cell rather than the body being
   absolutely positioned. The row is then sized by whichever is taller, so a
   three-line name on a narrow tile pushes the tile down instead of spilling
   out of a fixed aspect-ratio box and being clipped. The media stretches to
   whatever height results — object-fit keeps the crop honest. */
.tile a {
  position: relative; display: grid; grid-template-columns: minmax(0, 1fr);
  overflow: hidden; isolation: isolate;
  border-radius: var(--r-panel);
  background: var(--c-navy);
  text-decoration: none; color: #fff;
  transition: transform var(--t-base) var(--ease-settle), box-shadow var(--t-base);
}
.tile__media, .tile__body { grid-area: 1 / 1; min-width: 0; }

/* The aspect ratio lives on a zero-content spacer, not on the media. As a
   grid item the spacer sets the row's MINIMUM height; the media, having no
   intrinsic ratio of its own, then stretches to whatever the row actually
   becomes. Put the ratio on the media instead and it resolves to a fixed
   height, so a tile grown by a three-line name shows a band of bare
   background under the photograph. */
.tile a::before { content: ""; grid-area: 1 / 1; }
.tiles--lead .tile a::before { aspect-ratio: 16 / 10; }
.tiles--rest .tile a::before { aspect-ratio: 4 / 3; }
.tile a:hover { transform: translateY(-2px); box-shadow: var(--shadow-card); }
.tile a:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }

/* ---------- Media layer -------------------------------------------------- */

.tile__media { position: relative; display: block; }

.tile__media img,
.tile__media video {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  display: block;
}
/* The clip is generated from the still it sits on, so the two are frame-
   identical at t=0 and the cross-fade has nothing to betray it. It is only
   revealed once the decoder reports playback — preload="none" means the
   first hover has to fetch, and fading in early would flash a black frame. */
.tile__media video { opacity: 0; transition: opacity var(--t-slow) ease; }
/* Driven by the class alone, not by :hover. The script only adds is-playing
   while the clip is actually running — on hover for a mouse, for as long as a
   finger is down on touch — and :hover would have gated the touch case out.
   :active is no good either: the browser drops it the moment it takes the
   gesture over for scrolling, which is exactly when the clip should keep
   playing. */
.tile__media video.is-playing { opacity: 1; }

/* Scrim. Two stops rather than a linear ramp: the copy sits in the bottom
   third, so the gradient is held near-transparent across the top half and
   does the work late. Deepens slightly on hover so text stays readable when
   the clip brightens under it. */
.tile__media::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(
    to bottom,
    rgba(4, 12, 24, 0.08) 0%,
    rgba(4, 12, 24, 0.16) 42%,
    rgba(4, 12, 24, 0.68) 76%,
    rgba(4, 12, 24, 0.88) 100%
  );
  transition: opacity var(--t-base);
}
.tile a:hover .tile__media::after { opacity: 0.94; }

/* ---------- Text layer --------------------------------------------------- */

.tile__body {
  z-index: 2; align-self: end;
  padding: var(--sp-5);
  display: flex; flex-direction: column; gap: 6px;
}
.tiles--rest .tile__body { padding: var(--sp-4); gap: 4px; }

.tile__index {
  font-family: var(--font-mono);
  font-size: var(--fs-micro); font-weight: 500;
  letter-spacing: 0.08em;
  color: rgba(255, 255, 255, 0.62);
}
/* The rule is the editorial tell: one hairline under the index, drawn from
   nothing on hover. It is the only thing on the tile that animates besides
   the clip. */
.tile__index::after {
  content: ""; display: block; height: 1px; margin-top: 8px;
  background: rgba(255, 255, 255, 0.5);
  width: 22px;
  transition: width var(--t-slow) var(--ease-settle);
}
.tile a:hover .tile__index::after { width: 64px; }

.tile__name {
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 1.9vw, 1.5rem);
  font-weight: 700; line-height: var(--lh-heading);
  letter-spacing: var(--tracking-tight);
  margin: 0; color: #fff;
  text-wrap: balance;
}
.tiles--rest .tile__name { font-size: 1rem; letter-spacing: -0.012em; }

.tile__short {
  font-size: var(--fs-small); line-height: 1.45;
  margin: 0; max-width: 42ch;
  color: rgba(255, 255, 255, 0.82);
}

/* ---------- Responsive --------------------------------------------------- */

@media (max-width: 760px) {
  .tiles--lead { grid-template-columns: 1fr; }
  .tiles--rest { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
  .tiles--rest .tile a::before { aspect-ratio: 3 / 2; }
}

/* ---------- Motion and input ---------------------------------------------
   The clip is a nicety for someone pointing at a tile with a mouse. On touch
   there is no hover, and hijacking long-press collides with the OS text and
   image menus — so coarse pointers never load a clip at all. The <video> is
   still in the DOM but preload="none" means it costs nothing. */

/* Touch keeps the clip. This used to hide it outright on coarse pointers,
   back when the only trigger was hover and a touch device could never fire
   one. tile-hover.js now plays it for as long as a finger is on the tile —
   including while that finger is dragging the page — so the element has to
   stay in the layer. preload="none" means it still costs nothing until
   someone actually touches it. */

@media (prefers-reduced-motion: reduce) {
  /* Both treatments fall back to the same still frame. */
  .hero-full__media video { display: none; }
  .hero-full__media img { animation: none; transform: none; }
  .tile a, .tile a:hover { transform: none; transition: none; }
  .tile__media video { display: none; }
  .tile__index::after, .tile a:hover .tile__index::after { width: 22px; transition: none; }
  .tile__media::after { transition: none; }
}
