/* GearMotive — hand-written replacement for ~30 Kadence/plugin stylesheets.
 *
 * Structure mirrors the original's rendered anatomy (tools/measure.mjs), not
 * Kadence's class names. Anything that differs from the measured original is
 * marked FIX with the defect it repairs — see PROJECT.md's defect table.
 */

@import url("/assets/fonts/montserrat.css");
@import url("tokens.css");

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

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

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

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--fs-body);
  font-weight: var(--fw-body);
  line-height: var(--lh-body);
  overflow-x: hidden;
}

img, svg, video, iframe { max-width: 100%; height: auto; display: block; }
img { border-radius: inherit; }

h1, h2, h3, h4 { margin: 0 0 var(--space-tight); font-weight: var(--fw-bold); }
h1 { font-size: var(--fs-h1); line-height: var(--lh-h1); }
h2 { font-size: var(--fs-h2); line-height: var(--lh-h2); }
h3 { font-size: var(--fs-h3); line-height: var(--lh-h3); }

p { margin: 0 0 var(--space-tight); }
p:last-child { margin-bottom: 0; }

a { color: var(--link); }
a:hover, a:focus-visible { text-decoration-thickness: 2px; }

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

hr {
  border: 0;
  border-top: 1px solid currentColor;
  opacity: 0.35;
  margin: var(--space-block) 0;
}

/* FIX: the original's skip link rendered at 2.91:1 and was positioned where it
 * could be seen. Standard visually-hidden-until-focus instead. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--footer);
  color: #fff;
  padding: 12px 20px;
  border-radius: 0 0 var(--r) 0;
}
.skip-link:focus { left: 0; }

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

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container--narrow { max-width: calc(var(--narrow) + var(--gutter) * 2); }

/* ONE band treatment for the whole site: the shared photograph under a grey
 * overlay, white text.
 *
 * The original had five — 31 bands on #555555@0.90, 14 on #ffffff@0.90, and 13
 * flat surface/mid/dark — which is why the blog and the archives read as a
 * different site. Collapsing them removed four modifier classes, the per-row
 * inline backgrounds, and the tone plumbing that produced them.
 *
 * The overlay is #555555 at 0.90 — the site's own Kadence palette6, which is
 * what 31 of the original's bands already used. White body text on it is
 * 5.74:1 worst case, taking "worst case" to mean the photo underneath is pure
 * white, which is the only honest way to judge text over an image. */
.section {
  position: relative;
  padding-block: var(--space-section);
  /* The race car — what 19 of the original's dark bands used. Deliberately a
   * different photograph from the hero's gearbox, so the page has variety
   * without needing per-row backgrounds. */
  background-image: url("/assets/wp-content/uploads/2021/02/car-racing-4394450_1920.jpg");
  background-size: cover;
  background-position: center;
  background-attachment: fixed;
  color: #fff;
}

.section::before {
  content: "";
  position: absolute;
  inset: 0;
  background: #555555;
  opacity: 0.9;
}
.section > * { position: relative; }

.section h1, .section h2, .section h3, .section h4 { color: #fff; }
.section a { color: var(--link-on-dark); }

/* The alternate band: a DIFFERENT photograph under a near-white overlay, dark
 * text. Alternating is what stops a long page reading as one slab — and it is
 * the pairing the original used on the front page and /references/.
 *
 * Worst case (photo underneath pure black → surface #e6e6e6): --ink 8.02:1,
 * --link 7.88:1. --muted was 4.38:1 and is now #676767, 4.53:1. */
.section--light {
  background-image: url("/assets/wp-content/uploads/2020/11/koppalogolla-1536x864.jpg");
  color: var(--ink);
}
.section--light::before { background: #ffffff; }
.section--light h1,
.section--light h2,
.section--light h3,
.section--light h4 { color: var(--ink); }
.section--light a { color: var(--link); }

/* ⚠ A component that paints its own light surface must restate BOTH its ink and
 * its link colour, in every band. Inheriting the band's is how 49 gallery
 * captions once shipped as white-on-white, and how they came back as pale
 * --link-on-dark on a white plate the moment the dark band grew links.
 *
 * One list, deliberately: every light-surface component belongs here, so adding
 * a new one is a single edit rather than a new rule. Must stay AFTER both band
 * rules — same specificity (0,1,1), so source order decides. */
.card, .gallery figcaption, .accordion details, .post-card, .form-field {
  color: var(--ink);
}
/* Headings need saying separately: .section h2 sets #fff explicitly, so a
 * heading inside a card never inherits the card's colour. 19 "Features" h2s
 * shipped white-on-white on the product pages before this line existed. */
.card :is(h1, h2, h3, h4), .accordion details :is(h1, h2, h3, h4),
.post-card :is(h1, h2, h3, h4) {
  color: var(--ink);
}
.card a, .gallery figcaption a, .accordion details a, .post-card a,
.form-field a {
  color: var(--link);
}

/* .testimonial paints a DARK surface, so it is NOT in that list. Its only link
 * is the name chip, which states #fff on the red chip further down. */
.testimonial { color: var(--on-dark); }

/* ⚠ iOS Safari cannot render a fixed background. */
@media (max-width: 1024px), (hover: none) {
  .section { background-attachment: scroll; }
}

/* A section whose background is a photograph. The scrim is the FIX for the
 * 128 undecidable-contrast occurrences: white text on an arbitrary image. */
.section--photo {
  position: relative;
  background-repeat: no-repeat;
  color: #fff;
  /* The design: content scrolls over a photograph held still behind it. Which
   * bands do this is measured per row, not assumed — see build.mjs. */
  background-attachment: var(--bg-attachment, scroll);
}

.hero { background-attachment: var(--bg-attachment, scroll); }

/* ⚠ iOS Safari cannot render a fixed background — it either janks badly or
 * scales the image to the document height. The original disables it with
 * exactly this query (and so must we, or phones get a broken hero). */
@media (max-width: 1024px), (hover: none) {
  .section--photo,
  .hero { background-attachment: scroll !important; }
}
/* The overlay is measured per row (colour + opacity) and passed in as custom
 * properties, because every band uses different values. --scrim-solid is only
 * the fallback for a band that had no overlay at all. */
.section--photo::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--overlay, var(--scrim-solid));
  opacity: var(--overlay-opacity, 1);
}
.section--photo > * { position: relative; }

/* ⚠ A component that paints its OWN light surface must state its own colour.
 *
 * `.section--photo` sets `color: #fff` for the text that sits directly on the
 * photograph — but an accordion panel or a card inside that band paints itself
 * white and the white text kept inheriting. That is 413 invisible words on the
 * product pages, and it looks fine in a screenshot of the band because the
 * band itself reads correctly. Anything with a light background belongs here.
 */
.card,
.accordion .accordion-body,
.accordion details,
.gallery figure,
.gallery figcaption,
.logos figcaption,
.post-card,
.post-card-body,
.form,
.form-status {
  color: var(--ink);
}
.section--photo .card a,
.section--photo .accordion-body a,
.section--photo .post-card a { color: var(--link); }

/* A band whose overlay is LIGHT keeps the normal dark ink — white text on a
 * white overlay is the exact defect this replaces. */
.section--photo-light { color: var(--ink); }
.section--photo-light h1,
.section--photo-light h2,
.section--photo-light h3 { color: var(--ink); }
.section--photo-light a { color: var(--link); }

.hero--light, .hero--light h1 { color: var(--ink); }

.grid { display: grid; gap: var(--space-block); }
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.stack > * + * { margin-top: var(--space-block); }

/* ---- Two-column text-and-picture rows ---------------------------------- */

/* Order is normalised to text-left / picture-right in build.mjs; this only
 * lays them out. `align-items: center` because the picture and the paragraph
 * are rarely the same height and the original centres them. */
.cols {
  display: grid;
  gap: var(--space-block);
  align-items: center;
}
/* Two of these stacked run together otherwise — the second block's heading
 * sits hard against the last paragraph of the first and reads as part of it. */
.cols + .cols,
.cols + .gallery,
.gallery + .cols,
.cols + .accordion { margin-top: var(--space-section); }

.cols--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cols--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.cols--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.col > * + * { margin-top: var(--space-tight); }
.col .figure { margin: 0; }
.col img { width: 100%; }

/* Stacking early, and always text-then-picture: at this width a picture above
 * its own heading reads as belonging to the section before it. */
@media (max-width: 860px) {
  .cols--2, .cols--3, .cols--4 { grid-template-columns: 1fr; }
}

/* ---- Header ------------------------------------------------------------ */

/* The original header is position:absolute, 90px, fully transparent, floating
 * over the hero. Reproduced — including the transparency — with the scrim
 * added underneath so the white links have a computable contrast. */
.site-header {
  position: absolute;
  inset: 0 0 auto;
  height: var(--header-h);
  z-index: 20;
  color: #fff;
}
/* Solid header: used wherever nothing dark sits behind it — posts, archives,
 * the privacy pages. The original does exactly this; a transparent header over
 * a white section is white-on-white. */
/* Every page renders the same dark title band, so the header is transparent
 * everywhere — there is no solid variant any more. It existed for the three
 * articles, which used to have no band; giving them one made the whole
 * modifier dead code, and dead code in a header is exactly where per-page
 * drift creeps back in. */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  height: calc(var(--header-h) * 1.6);
  background: var(--scrim);
  pointer-events: none;
}
.site-header .container {
  position: relative;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-block);
}

.site-brand { display: flex; align-items: center; flex: 0 0 auto; }
.site-brand img { width: 200px; max-height: 72px; object-fit: contain; }

.nav { display: flex; }
.nav-lang-list { list-style: none; margin: 0; padding: 0; display: flex; }

.nav ul {
  display: flex;
  align-items: center;
  gap: 0;
  list-style: none;
  margin: 0;
  padding: 0;
}
.nav li { position: relative; }
.nav a {
  display: flex;
  align-items: center;
  height: 48px;
  padding-inline: 12px;
  color: #fff;
  text-decoration: none;
  white-space: nowrap;
}
.nav a:hover, .nav a:focus-visible { text-decoration: underline; }
.nav [aria-current="page"] { text-decoration: underline; text-underline-offset: 6px; }

/* Products submenu */
.nav .has-sub > button {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 48px;
  padding-inline: 12px;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.nav .has-sub > button::after {
  content: "";
  width: 7px; height: 7px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translateY(-2px);
}
.nav .sub {
  display: none;
  position: absolute;
  z-index: 30;              /* above the band below the header */
  top: 100%;
  left: 0;
  min-width: 260px;
  background: var(--footer);
  border-radius: 0 0 var(--r) var(--r);
  box-shadow: var(--shadow-card);
  padding: 6px 0;
}
.nav .has-sub[aria-expanded="true"] .sub,
.nav .has-sub:hover .sub,
.nav .has-sub:focus-within .sub { display: block; }
.nav .sub a { height: auto; padding: 10px 18px; }

.nav-lang a { gap: 8px; }
.nav-lang img { width: 18px; height: auto; display: inline-block; }

/* Mobile menu. The original's was a Kadence off-canvas drawer; this is the
 * same behaviour with markup the responsive gate recognises. */
.nav-toggle {
  display: none;
  align-items: center;
  gap: 8px;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  padding: 10px;
  cursor: pointer;
}
.nav-toggle span {
  display: block;
  width: 24px; height: 2px;
  background: currentColor;
  box-shadow: 0 7px currentColor, 0 -7px currentColor;
}

@media (max-width: 1100px) {
  .nav-toggle { display: flex; }
  .nav {
    display: none;
    position: absolute;
    top: var(--header-h);
    left: 0;
    right: 0;
    background: var(--footer);
    padding: var(--space-tight) var(--gutter) var(--space-block);
    box-shadow: var(--shadow-card);
  }
  .nav[data-open="true"] { display: block; }
  .nav ul { flex-direction: column; align-items: stretch; }
  .nav a, .nav .has-sub > button { height: auto; padding: 14px 0; width: 100%; }
  .nav .sub { position: static; display: block; background: none; box-shadow: none; padding: 0 0 0 18px; }
}

/* ---- Hero -------------------------------------------------------------- */

/* ONE hero background for the whole site.
 *
 * Defined here rather than inline per page so the band, the header over it and
 * the Products dropdown behave identically everywhere — which is the point:
 * the dropdown always has the same dark photograph behind it, so its links are
 * always legible. Pages used to inherit whatever photo their first row happened
 * to carry, or none at all, and the header changed character page to page.
 */
.hero {
  background-image: url("/assets/wp-content/uploads/2022/11/Gearmotive_tuotekuvat-132_2-jpg.webp");
  background-size: cover;
  background-position: center;
  --overlay: #000000;
  --overlay-opacity: 0.6;
  position: relative;
  min-height: 639px;
  display: grid;
  place-items: center;
  padding: calc(var(--header-h) + var(--space-block)) var(--gutter) var(--space-block);
  /* ⚠ background-COLOR, not the `background` shorthand. The shorthand resets
   * background-image to none, and sitting below the longhands above it silently
   * wiped the shared hero photograph — the band rendered flat #111 and looked
   * like the image had simply not been set. */
  background-color: #111;
  background-repeat: no-repeat;
  color: #fff;
  text-align: center;
  border-bottom: 6px solid var(--accent);
}
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--overlay, var(--scrim-solid));
  opacity: var(--overlay-opacity, 1);
}
.hero > * { position: relative; max-width: var(--content); }
.hero img { margin-inline: auto; }

/* A page that is not the front page has a short hero. */
.hero--page { min-height: 340px; }

@media (max-width: 800px) {
  .hero { min-height: 420px; }
  .hero--page { min-height: 240px; }
}

/* ---- Cards, media ------------------------------------------------------ */

.card {
  background: var(--surface);
  border-radius: var(--r);
  box-shadow: var(--shadow-soft);
  padding: var(--space-block);
}
.figure { border-radius: var(--r); overflow: hidden; box-shadow: var(--shadow-card); }
.figure img { width: 100%; }

/* ---- Gallery ----------------------------------------------------------- */

.gallery { display: grid; gap: var(--space-tight); grid-template-columns: repeat(4, minmax(0, 1fr)); }
.gallery figure { margin: 0; border-radius: var(--r); overflow: hidden; background: var(--surface); box-shadow: var(--shadow-soft); }
.gallery img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }

/* FIX: gallery captions were #fff on #fff — 1.00:1, 49 occurrences, completely
 * invisible on /references/ and /fi/referenssit/. */
.gallery figcaption {
  padding: 10px 12px;
  font-size: var(--fs-xs);
  color: var(--ink);
  background: var(--surface);
}

@media (max-width: 1000px) { .gallery { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 700px)  { .gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ---- Logo grid (resellers) --------------------------------------------- */

.logos { display: grid; gap: var(--space-block); grid-template-columns: repeat(4, minmax(0, 1fr)); }
.logos figure { margin: 0; text-align: center; }
.logos img {
  width: 100%;
  max-width: 200px;
  height: 120px;
  object-fit: contain;
  margin-inline: auto;
  background: var(--surface);
  border-radius: var(--r);
  padding: 12px;
}
.logos figcaption { margin-top: 10px; font-size: var(--fs-small); }

@media (max-width: 1000px) { .logos { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 640px)  { .logos { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ---- Accordion --------------------------------------------------------- */

.accordion { display: grid; gap: 10px; }
.accordion details {
  background: var(--surface);
  border-radius: var(--r);
  box-shadow: var(--shadow-soft);
  overflow: hidden;
}
/* FIX: accordion titles were #fff on #f9f9f9 — 1.05:1, unreadable
 * ("SEQUENTIAL Shifter" on both ZF pages). Dark band, white text instead:
 * --band-dark against #fff is 12.6:1. */
.accordion summary {
  cursor: pointer;
  list-style: none;
  padding: 18px var(--space-block);
  background: var(--band-dark);
  color: #fff;
  font-size: 18px;
  font-weight: var(--fw-bold);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-tight);
}
.accordion summary::-webkit-details-marker { display: none; }
.accordion summary::after {
  content: "";
  flex: 0 0 auto;
  width: 9px; height: 9px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translateY(-3px);
  transition: transform 0.15s;
}
.accordion details[open] summary::after { transform: rotate(-135deg) translateY(-3px); }
.accordion .accordion-body { padding: var(--space-block); }

/* ---- Testimonials ------------------------------------------------------ */

/* Dark cards on a photo band, as measured. ⚠ The original is a CAROUSEL
 * showing 3 of 8; this is a grid showing all 8. Deliberate deviation — it
 * needs no JS, hides nothing from crawlers, and is keyboard-reachable.
 * Noted in PROJECT.md; say so rather than letting it read as fidelity. */
.testimonials { display: grid; gap: var(--space-block); grid-template-columns: repeat(3, minmax(0, 1fr)); }

.testimonial {
  background: var(--band-dark);
  color: var(--on-dark);
  border-radius: var(--r);
  box-shadow: var(--shadow-card);
  padding: var(--space-block);
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: var(--space-tight);
}
.testimonial h3 { color: #fff; margin: 0; font-size: var(--fs-h3); line-height: var(--lh-h3); }

/* Gold on --band-dark is 8.3:1 — the original used icon images at the same
 * hue, so this keeps the look and gains a text alternative. */
.testimonial-stars { color: #ffc400; letter-spacing: 2px; margin: 0; }

.testimonial-body { flex: 1; }

.testimonial-meta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-tight);
  text-align: left;
}
.testimonial-thumb {
  width: 96px; height: 72px;
  object-fit: cover;
  border-radius: var(--r-xs);
  background: var(--surface);
  flex: 0 0 auto;
}
/* FIX: name band was #fff on #ff0000 = 4.00:1. --accent-deep = 4.53:1. */
.testimonial-name {
  display: inline-block;
  background: var(--accent-deep);
  color: #fff;
  padding: 8px 14px;
  border-radius: var(--r-xs);
  font-weight: var(--fw-bold);
  font-size: var(--fs-small);
  margin: 0;
}
.testimonial-name a { color: #fff; }
/* FIX: occupation was #696969 on #2f2f2f = 2.44:1; --muted-on-dark is 4.53:1. */
.testimonial-role { color: var(--muted-on-dark); font-size: var(--fs-small); margin: 6px 0 0; }

@media (max-width: 1000px) { .testimonials { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px)  { .testimonials { grid-template-columns: 1fr; } }

/* ---- Video ------------------------------------------------------------- */

.video-grid { display: grid; gap: var(--space-block); grid-template-columns: repeat(3, minmax(0, 1fr)); }
.video {
  background: var(--footer);
  border-radius: var(--r);
  overflow: hidden;
}
.video-frame { position: relative; aspect-ratio: 16 / 9; }
.video-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* Click-to-play facade — see build.mjs. Nothing loads from Google until this
 * button is pressed. */
.video-facade {
  display: block;
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  padding: 0;
  border: 0;
  background: #000;
  cursor: pointer;
}
.video-facade img { width: 100%; height: 100%; object-fit: cover; }
.video-play {
  position: absolute;
  inset: 50% auto auto 50%;
  transform: translate(-50%, -50%);
  width: 68px; height: 48px;
  border-radius: 12px;
  background: var(--accent-deep);
}
.video-play::after {
  content: "";
  position: absolute;
  inset: 50% auto auto 50%;
  transform: translate(-40%, -50%);
  border-style: solid;
  border-width: 11px 0 11px 19px;
  border-color: transparent transparent transparent #fff;
}
.video-facade:hover .video-play { background: #c40000; }
.video-title {
  padding: 12px var(--space-tight);
  color: #fff;
  font-size: 13.6px;
}

@media (max-width: 1000px) { .video-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px)  { .video-grid { grid-template-columns: 1fr; } }

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

.article { max-width: 800px; margin-inline: auto; }
.article img { border-radius: var(--r); }
.article ul, .article ol { padding-left: 1.4em; }
.article li + li { margin-top: 8px; }

.entry-meta { font-size: var(--fs-small); color: var(--muted); margin-bottom: var(--space-block); }

.post-list { display: grid; gap: var(--space-block); grid-template-columns: repeat(3, minmax(0, 1fr)); }
.post-card { background: var(--surface); border-radius: var(--r); box-shadow: var(--shadow-soft); overflow: hidden; }
.post-card img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.post-card-body { padding: var(--space-block); }
.post-card h2 { font-size: var(--fs-h2-card); line-height: var(--lh-h2-card); }

@media (max-width: 1000px) { .post-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px)  { .post-list { grid-template-columns: 1fr; } }

/* The hashtag-style tag links under each article. These are deliberate SEO
 * structure — see CLAUDE.md. Do not remove because they look decorative. */
.tag-list { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--space-block); }
.tag-list a {
  font-size: var(--fs-tag);
  font-weight: var(--fw-bold);
  padding: 6px 14px;
  border-radius: var(--r-pill);
  background: var(--page);
  border: 1px solid var(--rule);
  text-decoration: none;
}

/* ---- Footer ------------------------------------------------------------ */

.site-footer {
  background: var(--footer);
  color: var(--on-dark);
  padding-block: var(--space-block);
}
.site-footer a { color: var(--link-on-dark); }
/* Column 1 carries the logo, the address AND the contact details, so it gets
 * the extra width. Columns 2 and 3 are the two funding logos. */
.footer-grid { display: grid; gap: var(--space-block); grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) minmax(0, 1fr); align-items: start; }

/* One class for BOTH funding logos — they link to the same page and must not
 * drift apart. inline-block so the link's hit area is the image, not the
 * full-width line box a bare inline <a> would give it. */
.footer-logo { display: inline-block; margin-top: var(--space-tight); }
.footer-logo img { display: block; }
.footer-cols { display: grid; gap: var(--space-block); grid-template-columns: repeat(3, minmax(0, 1fr)); }
.footer-title { font-size: var(--fs-eyebrow); line-height: var(--lh-eyebrow); text-transform: uppercase; color: var(--on-dark); }
.site-footer img { max-width: 200px; }

.footer-bottom {
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  margin-top: var(--space-block);
  padding-top: var(--space-block);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-tight);
  justify-content: space-between;
  align-items: center;
  font-size: var(--fs-xs);
}
/* FIX: "Created with ♥ by" was #696969 on #191919 = 3.20:1. */
.footer-credit { color: var(--muted-on-dark); }

@media (max-width: 1000px) {
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .footer-cols { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 640px) {
  .footer-grid, .footer-cols { grid-template-columns: 1fr; }
}

/* ---- Forms ------------------------------------------------------------- */

.form { display: grid; gap: var(--space-tight); }
.form fieldset { border: 1px solid var(--rule); border-radius: var(--r); padding: var(--space-block); margin: 0; }
.form legend { font-weight: var(--fw-bold); padding-inline: 8px; }
.form-row { display: grid; gap: var(--space-tight); grid-template-columns: repeat(2, minmax(0, 1fr)); }
.form-field { display: grid; gap: 6px; }
.form-field label { font-size: var(--fs-small); font-weight: var(--fw-bold); }
.form-field .req { color: var(--accent-deep); }

.form input[type="text"], .form input[type="email"], .form input[type="tel"],
.form select, .form textarea {
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid #c9c9c9;
  border-radius: var(--r-sm);
  padding: 12px 14px;
  width: 100%;
}
.form textarea { min-height: 140px; resize: vertical; }
.form input:focus-visible, .form select:focus-visible, .form textarea:focus-visible {
  border-color: var(--accent-deep);
}

.form-options { display: grid; gap: 10px; }
.form-check { display: flex; gap: 10px; align-items: flex-start; }
.form-check input { margin-top: 4px; flex: 0 0 auto; }

/* The honeypot. Must be reachable by nothing a human uses, and invisible
 * without display:none (some bots skip display:none fields). */
.form-hp {
  position: absolute;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}

/* The original has no buttons anywhere (see BRAND.md) — this is the sole
 * exception, because a form must have a submit control. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 28px;
  border: 0;
  border-radius: var(--r-sm);
  background: var(--accent-deep);
  color: #fff;
  font: inherit;
  font-weight: var(--fw-bold);
  cursor: pointer;
  text-decoration: none;
}
.btn:hover { background: #c40000; }
.btn[disabled] { opacity: 0.6; cursor: progress; }

.form-status { padding: var(--space-tight); border-radius: var(--r-sm); font-weight: var(--fw-bold); }
.form-status[data-type="success"] { background: #e6f4ea; color: #1b5e20; }
.form-status[data-type="error"]   { background: #fdecea; color: #8a1c12; }

@media (max-width: 640px) {
  .form-row { grid-template-columns: 1fr; }
}

/* ---- Long Finnish compounds -------------------------------------------- */

/* "Sekventiaalivaihteisto", "jälleenmyyjät", "tietosuojaseloste" overflow a
 * 320px viewport. Scoped to the breakpoint that actually fails, so wider
 * layouts are provably untouched. */
/* At 320px Finnish compounds ("sekventiaalivaihteisto", "kytkinkoppamuutokset",
 * "suorakytkentäratassarja") push past their container — the responsive gate
 * measured 5–66px of clipped text inside accordion panels and reseller
 * captions. Scoped to the breakpoint that actually fails, so wider layouts are
 * provably untouched. Body copy needs this as much as headings do. */
@media (max-width: 480px) {
  h1, h2, h3, h4,
  p, li, figcaption, dd, dt, td, th,
  .testimonial-name, .footer-title, .logos figcaption, .form-field label {
    hyphens: auto;
    overflow-wrap: anywhere;
    word-break: normal;
  }
  .accordion summary { overflow-wrap: anywhere; hyphens: auto; }
  .accordion .accordion-body { padding: var(--space-tight); }
  .logos figcaption { overflow-wrap: anywhere; }
}

/* ---- Motion ------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* ---- Post navigation --------------------------------------------------- */

.post-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-block);
  justify-content: space-between;
  max-width: 800px;
  margin: var(--space-section) auto 0;
  padding-top: var(--space-block);
  border-top: 1px solid var(--rule);
}
.post-nav-item { display: grid; gap: 4px; max-width: 340px; }
.post-nav-item span { font-size: var(--fs-xs); color: var(--muted); text-transform: uppercase; }
.post-nav-item:last-child:not(:only-child) { text-align: right; }

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

/* ---- Post header ------------------------------------------------------- */

.entry-eyebrow {
  font-size: var(--fs-tag);
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 8px;
}
.article > h1 { margin-bottom: 12px; }

/* A section heading the source content marked as <h1>. Demoted to <h2> for a
 * correct document outline; kept at h1 size so the page looks unchanged. */
.h1-size { font-size: var(--fs-h1); line-height: var(--lh-h1); }

/* ---- Testimonial carousel ---------------------------------------------- */

/* Front pages only. A scroll-snap track rather than a JS-positioned slider:
 * without JS it degrades to a scrollable row with every testimonial reachable,
 * and it needs no width maths that could disagree with the CSS. */
.testimonials--carousel {
  display: flex;
  gap: var(--space-block);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: thin;
  padding-bottom: var(--space-tight);
}
.testimonials--carousel > .testimonial {
  flex: 0 0 calc((100% - var(--space-block) * 2) / 3);
  scroll-snap-align: start;
}

.carousel-controls {
  display: flex;
  gap: var(--space-tight);
  justify-content: center;
  margin-top: var(--space-tight);
}
.carousel-btn {
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 50%;
  background: var(--accent-deep);
  color: #fff;
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
}
.carousel-btn:hover { background: #c40000; }
.carousel-btn[disabled] { opacity: 0.4; cursor: default; }

@media (max-width: 1000px) {
  .testimonials--carousel > .testimonial { flex-basis: calc((100% - var(--space-block)) / 2); }
}
@media (max-width: 640px) {
  .testimonials--carousel > .testimonial { flex-basis: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .testimonials--carousel { scroll-behavior: auto; }
}

/* ---- Article share buttons --------------------------------------------- */

/* Above and below the article, as the original had them. Real links, not
 * script-driven popups, so they work with JS off and can be opened in a new
 * tab deliberately. */
.share { display: flex; gap: 10px; margin: var(--space-block) 0; }
.share-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  color: #fff;
  text-decoration: none;
}
.share-btn svg { width: 17px; height: 17px; fill: currentColor; }
.share-btn--fb { background: #1877f2; }   /* 3.6:1 vs white — icon, not text */
.share-btn--x  { background: #000000; }
.share-btn:hover { opacity: 0.85; }

/* A one-sentence lead under a page title, inside the band. */
.hero-lead {
  max-width: 62ch;
  margin: var(--space-tight) auto 0;
  font-size: var(--fs-body);
}

/* ⚠ The hero band is dark, so a link inside it needs the light variant.
 * Moving /references/'s lead paragraph into the band put a #7e2121 link on
 * #111 at 1.91:1 — caught by the contrast gate, not by looking at it. */
.hero a { color: var(--link-on-dark); }
.hero--light a { color: var(--link); }

/* ---- The front page's opening shot ------------------------------------- */

/* The logo appears large in the hero, then flies to the header's brand slot
 * while the band collapses to just the menu height and the red rule — so the
 * content below gets the maximum vertical space.
 *
 * The landing coordinates are the header brand's real box, derived rather than
 * eyeballed: the container is 1290px wide with a 24px gutter, so its content
 * edge is `max(24px, (100vw - 1290px)/2 + 24px)`. Verified against the measured
 * brand position at 1100/1366/1920.
 *
 * ⚠ The opening height is a CLS budget, not a taste choice — moving the page
 * for real is what was asked for, and it is exactly what Google counts as
 * layout shift. Re-measure after any change (one-liner in CLAUDE.md).
 *
 * ⚠ CSS, not JS: the end state is the default, so without JS the page is simply
 * correct rather than stuck open, and nothing can flash.
 */

:root { --brand-left: max(24px, calc((100vw - 1290px) / 2 + 24px)); }

/* ⚠ The band NEVER changes height in layout. It is `--header-h` from the first
 * frame, and the tall opening shot is painted by ::after, which is absolutely
 * positioned and therefore shifts nothing. Animating the real height collapsed
 * 620px -> 90px and measured CLS 0.25 ("poor") on the site's most-linked page.
 *
 * ::after shrinks and .intro-rise translates up by exactly the same amount with
 * the same easing, so the band's bottom edge and the content's top edge stay
 * locked together — no gap, no overlap, and nothing in layout moves. */
/* The band bakes its own overlay in, so the hero's generic one must not double
 * up on top of it. */
.hero--intro::before { display: none; }

.hero--intro {
  /* +6 for the red rule, which ::after draws as its border-bottom. Without it
   * the rule overlaps the first 6px of the content below. */
  height: calc(var(--header-h) + 6px);
  min-height: calc(var(--header-h) + 6px);
  padding: 0;
  overflow: visible;
  border-bottom: 0;             /* the red rule belongs to ::after */
  background: none;
}

.hero-band {
  /* ⚠ `.hero > *` caps children at --content (1200px) and the grid centres
   * them, so the band stopped 166px short of the right edge — exactly where the
   * language switcher sits, which is why "Suomi" and "English" were the last
   * two links still resolving against the page background. */
  max-width: none;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--header-h);
  /* ⚠ NOT z-index: -1. That paints the band behind `body`'s own background, so
   * hit-testing reports the page colour before it ever reaches the band — the
   * contrast gate then resolved the nav's backdrop to #f7fafc and failed all 34
   * links at 1.05:1. The page LOOKED right, which is the dangerous part: the
   * band had become invisible to verification. */
  z-index: 0;
  /* Overlay baked in, so the band matches every other page's exactly. */
  background:
    linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.6)),
    url("/assets/wp-content/uploads/2022/11/Gearmotive_tuotekuvat-132_2-jpg.webp")
      center / cover no-repeat;
  border-bottom: 6px solid var(--accent);
  animation: hero-band 2.8s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

@keyframes hero-band {
  /* Holds briefly so the opening shot registers before it moves. */
  0%, 20% { height: min(69vh, 620px); }
  100%    { height: var(--header-h); }
}

.intro-rise {
  animation: intro-rise 2.8s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

@keyframes intro-rise {
  0%, 20% { transform: translateY(calc(min(69vh, 620px) - var(--header-h))); }
  100%    { transform: translateY(0); }
}

/* ⚠ `both` leaves a transform on .intro-rise, and ANY transform makes an
 * element a containing block — which breaks `background-attachment: fixed` on
 * every band inside it. Clear it once the animation is done. */
.intro-rise { animation-fill-mode: backwards; }

/* The flying logo. Absolute inside the hero, whose top-left IS the page's
 * top-left (the header is absolutely positioned over it), so the landing
 * coordinates are the header's own. */
.hero-fly {
  position: absolute;
  z-index: 1;                 /* above the band it flies over */
  left: var(--brand-left);
  top: 9px;
  width: 200px;
  height: 72px;
  object-fit: contain;
  animation: logo-fly 2.8s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

@keyframes logo-fly {
  0%, 20% {
    left: 50vw;
    top: min(22vh, 190px);
    width: min(62vw, 720px);
    height: min(30vh, 316px);
    transform: translateX(-50%);
  }
  100% {
    left: var(--brand-left);
    top: 9px;
    width: 200px;
    height: 72px;
    transform: translateX(0);
  }
}

/* The header's own logo waits for the flying one to arrive, then takes over.
 * They are the same size in the same place, so the swap is invisible. */
.has-intro .site-brand img {
  animation: brand-arrive 2.8s steps(1, end) both;
}

@keyframes brand-arrive {
  0%, 97% { opacity: 0; }
  100%    { opacity: 1; }
}

.has-intro .hero-fly {
  animation-name: logo-fly, fly-handoff;
}

@keyframes fly-handoff {
  0%, 97% { opacity: 1; }
  100%    { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .hero--intro,
  .hero-band,
  .hero-fly,
  .intro-rise,
  .has-intro .site-brand img { animation: none; }
  .hero-fly { opacity: 0; }
  .has-intro .site-brand img { opacity: 1; }
}

/* On a short viewport the opening shot barely differs from the end state, so
 * the movement reads as a glitch rather than an intro. */
@media (max-height: 620px) {
  .hero--intro,
  .hero-band,
  .hero-fly,
  .intro-rise,
  .has-intro .site-brand img { animation: none; }
  .hero-fly { opacity: 0; }
  .has-intro .site-brand img { opacity: 1; }
}
