/**
 * Theme Name:       Kaisum Eye
 * Theme URI:        https://eye-massager.com/
 * Author:           Kaisum
 * Description:      Editorial product theme for eye-massager.com. Light, typographic, scroll-driven. Motion is native CSS (scroll/view timelines) — no framework, no jQuery.
 * Version:     4.4.0
 * Requires at least: 6.5
 * Tested up to:     7.1
 * Requires PHP:     8.0
 * License:          GPL-2.0-or-later
 * License URI:      https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:      kaisum-eye
 */

/* ═══════════════════════════════════════════════════════════════ BASE */

:root {
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-io: cubic-bezier(0.65, 0, 0.35, 1);
  --r: 22px;
  --r-lg: 36px;
  --canvas: var(--wp--preset--color--canvas, #eaf4fb);
  --paper: var(--wp--preset--color--paper, #fff);
  --ink: var(--wp--preset--color--ink, #111827);
  --muted: var(--wp--preset--color--muted, #5b6470);
  --line: var(--wp--preset--color--line, #d9e4f0);
  --primary: var(--wp--preset--color--primary, #41a5de);
  --primary-ink: var(--wp--preset--color--primary-ink, #1d73a5);
  --primary-dark: var(--wp--preset--color--primary-dark, #14496b);
  --gut: clamp(1.25rem, 4vw, 3rem);

  /* Surface ladder. --ground is the page field, --surface is what lifts off
     it. Every card, table and panel paints --surface so the tint behind it
     does the separating; sections only need a class where they leave the
     ground. */
  --ground: var(--canvas);
  --surface: var(--paper);

  /* Shadows carry the brand navy rather than a neutral black: over a blue
     ground a grey shadow reads as dirt. Three steps replace six unrelated
     one-off opacities that were scattered through the file. */
  --shadow-sm:
    0 1px 2px rgba(20, 73, 107, 0.06),
    0 2px 8px -2px rgba(20, 73, 107, 0.08);
  --shadow-md:
    0 2px 4px rgba(20, 73, 107, 0.06),
    0 12px 28px -8px rgba(20, 73, 107, 0.12);
  --shadow-lg:
    0 4px 8px rgba(20, 73, 107, 0.08),
    0 30px 60px -20px rgba(20, 73, 107, 0.18);

  /* The lit stage every product photo sits on. It used to fade white -> canvas,
     which worked while the page was white and dissolves now that canvas is the
     ground. Fading to a tint *lighter* than the ground keeps the stage reading
     as a lit surface in front of the page instead of a hole in it. Seven
     components share this, so it is a token rather than seven literals. */
  --stage-edge: color-mix(in srgb, var(--canvas) 55%, var(--paper));
  --stage-42: radial-gradient(
    circle at 50% 42%,
    var(--paper),
    var(--stage-edge)
  );
  --stage-45: radial-gradient(
    circle at 50% 45%,
    var(--paper),
    var(--stage-edge)
  );
}

* {
  box-sizing: border-box;
}

/* clip, not hidden: hidden would make html a scroll container and break the
   sticky header. clip contains stray overflow without that side effect. */
html {
  scroll-behavior: smooth;
  overflow-x: clip;
}

/* The revamp took the tint off body on the understanding that section bands
   would carry the rhythm instead; the bands were never built, so the site has
   been running on flat white ever since -- 72% of the home page. The ground
   comes back, and the bands below make it a ladder rather than a wash. */
body {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: clip;
  background: var(--ground);
}

::selection {
  background: var(--primary-dark);
  color: var(--paper);
}

img {
  max-width: 100%;
  height: auto;
}

/* ══════════════════════════════════════════════════════════ PRIMITIVES */

.k-label {
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  /* The eyebrow opens every section on the site, so it is the cheapest place
     to put the brand. primary-ink is 4.65:1 on the tinted ground -- it clears
     AA where --primary (2.46:1) never could. */
  color: var(--primary-ink);
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin: 0 0 1.5rem;
}

.k-label::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--primary);
  flex: 0 0 auto;
}

/* Serif italic for the one word per headline that should feel authored. */
.k-em {
  font-family: var(--wp--preset--font-family--editorial);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.02em;
}

.k-lead {
  font-size: var(--wp--preset--font-size--large);
  line-height: 1.5;
  color: var(--muted);
  max-width: 40ch;
  letter-spacing: -0.014em;
}

.k-hair {
  height: 1px;
  background: var(--line);
  border: 0;
  margin: 0;
}

/* ══════════════════════════════════════════════════════════════ HEADER */

.k-header {
  position: sticky;
  top: 0;
  z-index: 90;
  background: transparent;
  padding-block: 1rem;
}

/* Glass on a pseudo-element: backdrop-filter on the header itself would make
   it a containing block for the position:fixed menu overlay. */
.k-header::before {
  content: "";
  position: absolute;
  inset: 0;
  /* Was a canvas glass, which became canvas over canvas the moment the ground
     turned tint -- the bar dissolved into the page and its --line underline is
     only 1.15:1 against it. A paper glass reads as a plane above the tint and
     joins seamlessly onto the white relief bands. */
  background: color-mix(in srgb, var(--paper) 78%, transparent);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  border-bottom: 1px solid transparent;
  pointer-events: none;
  transition:
    background-color 0.25s var(--ease),
    border-color 0.25s var(--ease),
    box-shadow 0.25s var(--ease);
}

/* ui.js has toggled this class on the header since it was written and nothing
   ever styled it. At rest the bar stays quiet; once the page moves under it,
   it commits to being a surface. */
.k-header.is-scrolled::before {
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  border-bottom-color: var(--line);
  box-shadow: var(--shadow-sm);
}

.k-header > * {
  position: relative;
}
.k-header .wp-block-site-title a {
  text-decoration: none;
  color: var(--ink);
  font-size: 1.125rem;
}

.k-nav-wrap {
  gap: 2rem;
  align-items: center;
}

.k-header .wp-block-navigation {
  font-size: 0.9rem;
  font-weight: 480;
  gap: 1.75rem;
  letter-spacing: -0.01em;
}
.k-header .wp-block-navigation a {
  text-decoration: none;
  color: var(--muted);
  white-space: nowrap;
  transition: color 0.2s var(--ease);
}
.k-header .wp-block-navigation a:hover {
  color: var(--ink);
}
.k-header .wp-block-navigation a[aria-current] {
  color: var(--primary-ink);
}

.k-header .wp-block-navigation .wp-block-navigation__submenu-container {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--shadow-lg);
  padding: 0.5rem;
  min-width: 16rem;
  margin-top: 0.5rem;
}

/* The visual gap between the trigger and the dropdown belongs to neither, so
   the pointer leaves the menu item crossing it and the dropdown closes before
   it can be clicked. This invisible bridge spans the gap and is a descendant
   of the same list item, so :hover holds the whole way down. */
.k-header .wp-block-navigation .wp-block-navigation__submenu-container::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: -0.75rem;
  height: 0.75rem;
}

/* A taller hit area on the top-level items, so the pointer does not fall out
   of a text-height target on the way to the menu. */
.k-header .wp-block-navigation > ul > .wp-block-navigation-item > a {
  padding-block: 0.75rem;
}

/* Nested submenus open to the side; their bridge has to be on the flank. */
.k-header
  .wp-block-navigation__submenu-container
  .wp-block-navigation__submenu-container::before {
  top: 0;
  bottom: 0;
  left: -0.5rem;
  right: auto;
  width: 0.5rem;
  height: auto;
}

.k-header .wp-block-navigation .wp-block-navigation__submenu-container li a {
  padding: 0.65rem 0.85rem;
  border-radius: 9px;
  display: block;
  width: 100%;
}

.k-header
  .wp-block-navigation
  .wp-block-navigation__submenu-container
  li
  a:hover {
  background: var(--canvas);
  color: var(--ink);
}

@media (min-width: 981px) {
  .k-header .wp-block-navigation__responsive-container-open:not(.always-shown) {
    display: none !important;
  }
}

@media (max-width: 980px) {
  .k-header .wp-block-navigation__responsive-container-open:not(.always-shown) {
    display: grid;
  }
  .k-header
    .wp-block-navigation__responsive-container:not(.is-menu-open):not(
      .always-shown
    ) {
    display: none;
  }
  .k-nav-wrap {
    gap: 0.75rem;
  }
  .k-nav-wrap .wp-block-navigation {
    order: 2;
  }
}

.k-header .wp-block-navigation__responsive-container-open {
  flex: 0 0 auto;
  align-self: center;
  box-sizing: border-box;
  width: 2.6rem;
  height: 2.6rem;
  min-height: 0;
  padding: 0;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 100px;
  background: var(--paper);
  color: var(--ink);
}

/* The overlay inherited the desktop bar's 1.75rem gap and a display-size type
   scale, so the rows were 46px of link separated by 28px of nothing and the
   list ran off the bottom of a 390x844 phone before Contact Us. A phone menu is
   a utility list, not a statement: rows that touch, divided by a hairline, at
   reading size. */
.wp-block-navigation__responsive-container.is-menu-open {
  /* One inset for the whole menu, tracking the page gutter so the labels line
     up with the content behind them, but never tighter than 1.25rem. */
  --menu-inset: max(1.25rem, var(--wp--style--root--padding-left));
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100dvh;
  background: var(--canvas) !important;
  /* Dividers run edge to edge, so the inset belongs to the rows, not here. */
  padding: 0 !important;
  overflow-y: auto;
}

/* The gap is the whole problem: it is set on the shared nav selector for the
   desktop bar, where it separates items along a row, and it lands on all three
   levels of the overlay. `align-items` matters just as much -- core packs the
   column to flex-start, so the list sized to its widest label (200px) instead
   of the viewport, and every divider stopped short. */
.wp-block-navigation__responsive-container.is-menu-open,
.wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation__responsive-container-content,
.wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation__container {
  gap: 0 !important;
  align-items: stretch !important;
}

.wp-block-navigation__responsive-container.is-menu-open a {
  color: var(--ink) !important;
  font-size: 1.0625rem;
  font-weight: 500;
  letter-spacing: -0.015em;
  /* Core sets the item's padding with more weight than this selector carries. */
  padding: 0.8rem var(--menu-inset) !important;
  width: 100%;
}

.wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation-item {
  width: 100%;
  border-bottom: 1px solid var(--line);
}

/* A parent lays out as: label | chevron on the first row, submenu wrapped onto
   its own full-width row beneath. */
.wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation-submenu {
  display: flex;
  /* Core's setCascadingProperties leaves this as column on the item. */
  flex-direction: row !important;
  flex-wrap: wrap;
  align-items: center;
}
.wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation-submenu
  > .wp-block-navigation-item__content {
  flex: 1;
  width: auto;
}

/* Core hides this toggle in the overlay because it does nothing there --
   submenus are forced open and aria-expanded stays true whatever you tap.
   Showing it, as the reference design does, would put a control on screen that
   a pointer and a screen reader both read as expandable and that never
   collapses, so leave it hidden; the indent and the muted colour already say
   the group belongs to the row above. */
.wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation__submenu-icon {
  display: none !important;
}

/* Our own disclosure, because core's is inert in the overlay and rewrites its
   own aria-expanded. Hidden everywhere else: the same markup is a hover
   dropdown on a desktop, where nothing should be collapsible. */
.k-subtoggle {
  display: none;
}

.wp-block-navigation__responsive-container.is-menu-open .k-subtoggle {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 3rem;
  height: 2.75rem;
  align-self: center;
  margin-right: calc(var(--menu-inset) - 1rem);
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.wp-block-navigation__responsive-container.is-menu-open .k-subtoggle svg {
  transition: transform 0.25s var(--ease);
}
.wp-block-navigation__responsive-container.is-menu-open
  .k-subtoggle[aria-expanded="true"]
  svg {
  transform: rotate(180deg);
}

/* Closed is the default. The parent keeps its own bottom border, so the row
   stays divided either way: from the submenu's top border when open, from the
   item's own when shut. */
.wp-block-navigation__responsive-container.is-menu-open
  .k-sub.is-closed
  > .wp-block-navigation__submenu-container {
  display: none !important;
}

/* Sits on the logo's line rather than jammed into the corner, and matches the
   button it replaced -- same 2.6rem circle as the header's menu control. */
.wp-block-navigation__responsive-container-close {
  position: absolute;
  top: 1.15rem;
  right: var(--menu-inset);
  width: 2.6rem;
  height: 2.6rem;
  padding: 0;
  display: grid;
  place-items: center;
  border-radius: 100px;
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--ink);
}
.wp-block-navigation__responsive-container-close svg {
  width: 16px;
  height: 16px;
}

.wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation__submenu-container {
  flex: 0 0 100%;
  background: transparent !important;
  border: 0 !important;
  /* Draws the divider under the parent row, which the label and the chevron
     each only half span. */
  border-top: 1px solid var(--line) !important;
  box-shadow: none !important;
  padding: 0 !important;
  gap: 0 !important;
  min-width: 0;
}
.wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation__submenu-container
  a {
  font-size: 0.9375rem;
  font-weight: 450;
  color: var(--muted) !important;
  padding: 0.6rem var(--menu-inset) 0.6rem calc(var(--menu-inset) + 1rem) !important;
}
.wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation__submenu-container
  .wp-block-navigation-item:last-child {
  border-bottom: 0;
}

/* The overlay covers the header (z-index 100000 against 90) and WordPress
   leaves no open-state hook on <body>, so the real mark cannot be kept
   visible. Restate it here; style.css sits at the theme root, so the relative
   path resolves. */
.wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation__responsive-container-content::before {
  content: "";
  display: block;
  flex: 0 0 auto;
  height: 2.6rem;
  margin: 0 var(--menu-inset) 0.75rem;
  background: url("assets/img/logo.png") left center / auto 1.5rem no-repeat;
}

.wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation__responsive-container-content {
  padding-top: 1.15rem !important;
}

/* The stage hero is gone (see patterns/hero-slider.php), but its CTA-row
   class lives on: the cta-quote pattern's closing band still uses it. */
.k-stage__cta {
  display: flex;
  gap: 0.75rem;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 2.25rem;
}

/* ══════════════════════════════════════════════════════════ SCROLL CUE */

.k-scrollcue {
  position: absolute;
  bottom: 3rem;
  left: 50%;
  translate: -50%;
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.625rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
  display: grid;
  justify-items: center;
  gap: 0.6rem;
  z-index: 3;
}

.k-scrollcue::after {
  content: "";
  width: 1px;
  height: 40px;
  background: linear-gradient(var(--muted), transparent);
  animation: k-drop 2.4s var(--ease-io) infinite;
  transform-origin: top;
}

@keyframes k-drop {
  0% {
    scale: 1 0;
    opacity: 0;
  }
  40% {
    scale: 1 1;
    opacity: 1;
  }
  100% {
    scale: 1 1;
    opacity: 0;
  }
}

/* ══════════════════════════════════════════════════════════════ TICKER */

.k-ticker {
  border-block: 1px solid var(--line);
  padding-block: 1.15rem;
  overflow: hidden;
  mask-image: linear-gradient(
    90deg,
    transparent,
    #000 8%,
    #000 92%,
    transparent
  );
  /* Was --paper, which on the tinted ground read as a floating white strip
     rather than a rule across the page. The two hairlines carry it. */
  background: transparent;
}

.k-ticker__track {
  display: flex;
  gap: 3.5rem;
  width: max-content;
  animation: k-slide 42s linear infinite;
}
.k-ticker:hover .k-ticker__track {
  animation-play-state: paused;
}

.k-ticker span {
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 0.7rem;
}

.k-ticker span::before {
  content: "";
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--primary);
}

@keyframes k-slide {
  to {
    transform: translateX(-50%);
  }
}

/* ════════════════════════════════════════════════════════════════ PIN */

/* The product holds still while its features scroll past it. */
.k-pin {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gut);
  align-items: start;
}

.k-pin__media {
  position: sticky;
  top: 13vh;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border-radius: var(--r-lg);
  background: var(--stage-42);
  border: 1px solid var(--line);
  overflow: hidden;
  grid-template-areas: "shot";
}

/* Every shot sits in the one grid cell, so they overlap and stay centred
   without absolute positioning. Only the active one is visible. */
.k-pin__media img {
  grid-area: shot;
  width: 78%;
  filter: drop-shadow(0 26px 40px rgba(20, 73, 107, 0.22));
  opacity: 0;
  transform: scale(0.94);
  transition:
    opacity 0.6s var(--ease),
    transform 0.9s var(--ease);
}

.k-pin__media img.is-on {
  opacity: 1;
  transform: none;
}

/* Without JS nothing is marked active, so show the first. */
.k-pin__media:not(.is-live) img:first-child {
  opacity: 1;
  transform: none;
}

/* Dim the steps that are not being illustrated — only once the swap is
   actually running, or a no-JS page would sit at 45% forever. */
.k-pin.is-live .k-pin__step {
  opacity: 0.45;
  transition: opacity 0.5s var(--ease);
}

.k-pin.is-live .k-pin__step.is-on {
  opacity: 1;
}

.k-pin__steps {
  display: grid;
  gap: clamp(2rem, 8vh, 5rem);
  padding-block: 7vh;
}
.k-pin__step h3 {
  margin: 0 0 0.9rem;
}
.k-pin__step p {
  color: var(--muted);
  margin: 0;
  max-width: 38ch;
  line-height: 1.6;
}

.k-pin__n {
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  color: var(--primary-ink);
  display: block;
  margin-bottom: 1rem;
}

@media (max-width: 860px) {
  .k-pin {
    grid-template-columns: 1fr;
  }
  .k-pin__media {
    position: relative;
    top: 0;
    aspect-ratio: 4/3;
  }
  .k-pin__steps {
    padding-block: 3rem 0;
    gap: 3rem;
  }
}

/* ═══════════════════════════════════════════════════════════ HOTSPOTS */

/* No overflow:hidden — tooltips extend above the card and were being
   clipped, cutting the bold title off the top of every one of them. The
   rounding lives on the image instead. A stacking context is still needed
   so the tips sit above neighbouring sections. */
.k-spots {
  position: relative;
  border-radius: var(--r-lg);
  background: var(--stage-45);
  border: 1px solid var(--line);
  isolation: isolate;
  z-index: 1;
  padding: clamp(0.6rem, 2.2vw, 1.5rem);
}
/* Wraps the image exactly, so the left/top percentages on the dots land where
   they were measured against the product rather than against the padded box. */
.k-spots__frame {
  position: relative;
}
.k-spots__img {
  display: block;
  width: 100%;
  border-radius: calc(var(--r-lg) - 1px);
}

.k-spot {
  position: absolute;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 0;
  padding: 0;
  cursor: pointer;
  background: var(--paper);
  box-shadow: var(--shadow-md);
  display: grid;
  place-items: center;
  translate: -50% -50%;
  transition: scale 0.3s var(--ease);
  z-index: 4;
}

.k-spot::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--ink);
  transition: background 0.2s;
}

.k-spot::after {
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  border: 1px solid var(--primary);
  opacity: 0;
  animation: k-ping 2.6s var(--ease-io) infinite;
}

@keyframes k-ping {
  0% {
    scale: 0.7;
    opacity: 0.9;
  }
  70%,
  100% {
    scale: 1.5;
    opacity: 0;
  }
}

.k-spot:hover,
.k-spot[aria-expanded="true"] {
  scale: 1.15;
}
.k-spot[aria-expanded="true"]::before {
  background: var(--primary);
}

.k-spot__tip {
  position: absolute;
  z-index: 5;
  width: max-content;
  max-width: 15rem;
  padding: 0.85rem 1rem;
  border-radius: 12px;
  background: var(--ink);
  color: var(--paper);
  font-size: 0.8125rem;
  line-height: 1.5;
  translate: -50% calc(-100% - 24px);
  opacity: 0;
  visibility: hidden;
  transition:
    opacity 0.25s var(--ease),
    translate 0.25s var(--ease);
  pointer-events: none;
}

.k-spot__tip strong {
  display: block;
  margin-bottom: 0.2rem;
}

.k-spot[aria-expanded="true"] + .k-spot__tip {
  opacity: 1;
  visibility: visible;
  translate: -50% calc(-100% - 16px);
}

/* Tips are positioned from their own hotspot, so one anchored at 24% or 76%
   hangs ~42px past the container on a phone. visibility:hidden still takes
   part in layout, so they widened the page even while invisible — this was
   the horizontal scroll. Centre them and let them span the container, which
   also stops a tip rendering half off-screen and unreadable. */
@media (max-width: 640px) {
  .k-spot__tip {
    left: 50% !important;
    width: calc(100% - 1.5rem);
    max-width: none;
  }
}

/* A spot in the top third has no room above it; drop its tip underneath. */
.k-spot__tip.is-below {
  translate: -50% 24px;
}
.k-spot[aria-expanded="true"] + .k-spot__tip.is-below {
  translate: -50% 16px;
}

/* ═══════════════════════════════════════════════════════════════ RAIL */

.k-rail {
  display: flex;
  gap: 1.25rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: 1.5rem;
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}

.k-rail::-webkit-scrollbar {
  height: 4px;
}
.k-rail::-webkit-scrollbar-thumb {
  background: var(--line);
  border-radius: 4px;
}

.k-rail__card {
  flex: 0 0 min(78vw, 380px);
  scroll-snap-align: start;
  border-radius: var(--r);
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
  text-decoration: none;
  color: inherit;
  display: flex;
  flex-direction: column;
  /* No explicit height here on purpose. Both contexts stretch the card for
     free -- the rail is a flex row and the archive's <li> is a grid cell --
     and setting a cross size is what *disables* that stretch, which is how an
     earlier attempt at this left the rail ragged. */
  transition:
    transform 0.4s var(--ease),
    box-shadow 0.4s var(--ease);
}

.k-rail__card:hover {
  transform: translateY(-6px);
  box-shadow: var(--shadow-lg);
}

/* core/post-template's grid makes its own <li> the grid item, so the thing that
   stretches is the wrapper and not the card inside it. Making the wrapper a
   grid passes the stretch down on both axes -- and, unlike flex, it also
   neutralises the card's `flex: 0 0 min(78vw, 380px)`, which belongs to the
   horizontal rail and here forced every card wider than its own column,
   swallowing the gutters and clipping the longer titles. */
.wp-block-post-template.is-layout-grid > li {
  display: grid;
}

.k-rail__shot {
  aspect-ratio: 4/3;
  display: grid;
  place-items: center;
  padding: 1.1rem;
  background: var(--stage-45);
  overflow: hidden;
}
.k-rail__shot img {
  max-height: 100%;
  width: auto;
  transition: transform 0.55s var(--ease);
}
.k-rail__card:hover .k-rail__shot img {
  transform: scale(1.07) translateY(-4px);
}

.k-rail__body {
  padding: 1rem 1.1rem 1.2rem;
  display: grid;
  gap: 0.5rem;
  /* Takes the slack a taller neighbour creates, so the card's white area runs
     to the bottom edge instead of stopping under the last line of copy. */
  flex: 1;
  align-content: start;
}
.k-rail__body :is(h2, h3) {
  font-size: 1.125rem;
  line-height: 1.3;
  margin: 0;
  letter-spacing: -0.025em;
}
.k-rail__body a {
  color: inherit;
  text-decoration: none;
}
.k-rail__body p {
  margin: 0;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.55;
}
.k-rail__meta {
  display: flex;
  gap: 1rem;
  margin-top: 0.4rem;
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  color: var(--muted);
  text-transform: uppercase;
}

/* ══════════════════════════════════════════════════════════ EDITORIAL */

.k-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gut);
  align-items: center;
}
.k-split--offset {
  grid-template-columns: 1.15fr 0.85fr;
}
.k-split--flip > :first-child {
  order: 2;
}
.k-split__media {
  border-radius: var(--r-lg);
  overflow: hidden;
}
.k-split__media img {
  width: 100%;
  display: block;
  aspect-ratio: 4/3;
  object-fit: cover;
  transition: transform 0.9s var(--ease);
}
.k-split__media:hover img {
  transform: scale(1.04);
}
@media (max-width: 820px) {
  .k-split,
  .k-split--offset {
    grid-template-columns: 1fr;
  }
  .k-split--flip > :first-child {
    order: 0;
  }
}

/* ═════════════════════════════════════════════════════════════ PANELS */

/* make_content.py has always emitted `k-band--{tone}` for any tone that is
   not "dark", and nothing ever matched it -- which is why the tonal rhythm
   the generator's docstring promises never appeared. These are that tier.
   With the ground tinted, a section only needs a class where it departs from
   it, so --paper is relief and --tint is an explicit return to the ground
   (useful where a pattern sits inside a paper band). */
.k-band--paper {
  background: var(--paper);
  border: 1px solid var(--line);
}
.k-band--tint {
  background: var(--canvas);
}

/* Whether a band escapes the page gutter depends on how deep it sits, which
   is not something the design should hinge on. WordPress cancels the gutter
   with a negative margin on `.has-global-padding > .alignfull` -- a DIRECT
   child only. Home's sections arrive nested one level deeper (inside
   post-content) so they never escape and sit inside the gutter; every other
   page takes its closing CTA straight from page.html as a direct child of
   main, so there it bled to the viewport edge and had its 36px corners sliced
   off. Same markup, same classes, different depth. Pin them all inside. */
.has-global-padding > .k-sec:is(.k-band, .k-band--paper, .k-band--tint) {
  /* auto rather than 0: cancelling the escape alone left the band filling
     main's whole content box, 1392px against the 1320px every other band on
     the site is capped to. The cap plus auto margins makes a direct child and
     a nested one land in exactly the same place. Below 1320 the max-width is
     inert and the margins collapse to the gutter, which is what mobile wants. */
  margin-inline: auto;
  max-width: 1320px;
}

/* These bands are not full-bleed: the constrained layout caps them at 1320px
   and centres them, so ~53px of ground shows down either side and they read as
   containers rather than as bands. Square corners around a 36px-rounded
   product stage looked like an oversight; matching the radius makes the
   nesting deliberate. The footer is excluded -- it genuinely does reach the
   viewport edge, where a radius would leave two odd notches. */
.k-band--paper,
.k-band--tint,
.k-band {
  border-radius: var(--r-lg);
}

.k-band {
  background: var(--primary-dark);
  color: rgba(255, 255, 255, 0.78);
}
.k-band h1,
.k-band h2,
.k-band h3 {
  color: var(--paper);
}
.k-band p,
.k-band .k-lead {
  color: rgba(255, 255, 255, 0.72);
}
.k-band .k-label {
  color: rgba(255, 255, 255, 0.6);
}
.k-band .k-hair {
  background: rgba(255, 255, 255, 0.16);
}
.k-band a {
  color: #fff;
}

.k-figs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 2.5rem 1.5rem;
}
/* nowrap: the unit belongs to the number. Without it '8,000' and 'm2' split
   across lines once the column got tight on a wide screen. */
.k-fig__v {
  font-size: clamp(2.6rem, 5vw, 4rem);
  font-weight: 560;
  letter-spacing: -0.05em;
  line-height: 0.95;
  margin: 0 0 0.6rem;
  color: #fff;
  white-space: nowrap;
}

/* The unit reads as a suffix, not as part of the figure. */
.k-fig__v em {
  font-style: normal;
  color: var(--primary);
  font-size: 0.78em;
}
.k-fig__l {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.72);
  margin: 0;
  line-height: 1.5;
  max-width: 22ch;
}

/* ═════════════════════════════════════════════════════════════ MOSAIC */

.k-mosaic__head {
  max-width: 46ch;
  margin-bottom: clamp(2rem, 4vw, 3.5rem);
}
.k-mosaic__head h2 {
  margin: 0 0 1rem;
}
.k-mosaic__head .k-lead {
  margin: 0;
}

/* Six columns so a 4 + 2 first row and a 2 + 2 + 2 second row both land on
   the same grid — the establishing shot gets the room, the four supporting
   ones stay equal to each other. */
.k-mosaic {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: clamp(0.75rem, 1.5vw, 1.25rem);
}

.k-mosaic figure {
  margin: 0;
  grid-column: span 2;
  min-width: 0;
  overflow: clip;
}
.k-mosaic figure:first-child {
  grid-column: span 4;
}

.k-mosaic img {
  width: 100%;
  display: block;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--r);
  transition: transform 0.9s var(--ease);
}

.k-mosaic figure:first-child img {
  aspect-ratio: 16 / 9;
}
.k-mosaic figure:hover img {
  transform: scale(1.04);
}

.k-mosaic figcaption {
  margin-top: 0.7rem;
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Two up on a phone, with the establishing shot still spanning the row. */
@media (max-width: 820px) {
  .k-mosaic {
    grid-template-columns: repeat(2, 1fr);
  }
  .k-mosaic figure {
    grid-column: span 1;
  }
  .k-mosaic figure:first-child {
    grid-column: span 2;
  }
}

/* ════════════════════════════════════════════════════════════════ MAP */

.k-map {
  margin: 0;
}

.k-map iframe {
  display: block;
  width: 100%;
  aspect-ratio: 21 / 9;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--paper);
}

.k-map figcaption {
  margin-top: 0.9rem;
  font-size: 0.875rem;
  color: var(--muted);
  line-height: 1.6;
}

.k-map figcaption a {
  color: inherit;
}

/* A wide letterbox is unreadable on a phone; give it height instead. */
@media (max-width: 640px) {
  .k-map iframe {
    aspect-ratio: 4 / 5;
  }
}

/* ═══════════════════════════════════════════════════════════════ TOUR */

/* The Made-in-China 360 walkthrough. Same construction as .k-map above -- a
   figure holding an iframe sized by aspect-ratio, with the caption carrying
   the fallback link. */
.k-tour {
  margin: 0;
}

.k-tour iframe {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--line);
  border-radius: var(--r);
  /* The viewer's own chrome is near-black, so a paper background flashes
     white across the whole band before the panorama paints. */
  background: var(--ink);
}

.k-tour figcaption {
  margin-top: 0.9rem;
  font-size: 0.875rem;
  color: var(--muted);
  line-height: 1.6;
}

.k-tour figcaption a {
  color: var(--primary-ink);
}

/* A 16:9 letterbox leaves a panorama unreadable on a phone; trade width for
   height, the same trade .k-map makes. */
@media (max-width: 640px) {
  .k-tour iframe {
    aspect-ratio: 3 / 4;
  }
}

/* ═══════════════════════════════════════════════════════════ CONTACTS */

/* One hairline grid, same construction as .k-kv: the gap is the background
   showing through, so the cards need no borders of their own.

   The markup carries .alignwide so WordPress's constrained layout gives it
   the 1320px column instead of the 760px reading column. At 760 the three
   cards were 253px each and the e-mail addresses broke mid-word. */
.k-contacts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}

.k-contact {
  background: var(--paper);
  padding: 1.5rem 1.4rem;
}

.k-contact__role {
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 0.35rem;
}

.k-contact__name {
  font-size: 1.25rem;
  letter-spacing: -0.025em;
  margin: 0 0 1.1rem;
}
.k-contact__lines {
  margin: 0;
  display: grid;
  gap: 0.6rem;
}

.k-contact__row {
  display: grid;
  grid-template-columns: 4.25rem 1fr;
  align-items: baseline;
  gap: 0.6rem;
}

.k-contact__row dt {
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.625rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Addresses are long and cards are narrow; break rather than overflow. */
.k-contact__row dd {
  margin: 0;
  font-size: 0.9375rem;
  overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums;
}

.k-contact__row dd a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--line);
}
.k-contact__row dd a:hover {
  border-color: var(--ink);
}

/* ═══════════════════════════════════════════════════════════════ DATA */

/* Two tables, one treatment: the k-data pattern and the comparison table
   the content import writes as a core table block. Eight columns never fit a
   phone, so the wrapper scrolls sideways and every cell stays on one line.
   A sticky model column was tried and removed: model names here are lists
   ("KS-3700B / KS-3700C / ..."), so the pinned cell was either wider than the
   screen or, once capped, eight lines tall. */
.kaisum-compare {
  margin: 0;
}

.k-data,
.kaisum-compare {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}
.k-data table,
.kaisum-compare table {
  border-collapse: collapse;
  width: 100%;
  min-width: 820px;
  font-variant-numeric: tabular-nums;
  font-size: 0.875rem;
}

/* core/table gives every cell `border: 1px solid` with no colour, which
   resolves to the text colour. Collapsed against our light rule that put a
   black line under the header and squared off the rounded corners. */
.k-data th,
.k-data td,
.kaisum-compare th,
.kaisum-compare td {
  border: 0;
}
.k-data thead th,
.kaisum-compare thead th {
  text-align: left;
  padding: 1rem;
  font-weight: 520;
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
  font-family: var(--wp--preset--font-family--mono);
}
.k-data tbody td,
.kaisum-compare tbody td {
  padding: 1rem;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.k-data tbody tr:last-child td,
.kaisum-compare tbody tr:last-child td {
  border-bottom: 0;
}
.k-data tbody tr,
.kaisum-compare tbody tr {
  transition: background 0.2s;
}
.k-data tbody tr:hover,
.kaisum-compare tbody tr:hover {
  background: var(--canvas);
}
.k-data tbody td:first-child,
.kaisum-compare tbody td:first-child {
  font-weight: 560;
}

@media (max-width: 640px) {
  /* Tighter cells fit one more column into the same swipe. */
  .k-data thead th,
  .k-data tbody td,
  .kaisum-compare thead th,
  .kaisum-compare tbody td {
    padding: 0.8rem 0.7rem;
  }
}

/* The content import writes 56 of these -- every Specification, Massage modes,
   Controls and Materials block on every product page -- and nothing in this
   file matched the class, so they fell through to core/table's default: a 1px
   rule around every cell, resolving to the text colour. It was the largest
   untreated surface on the site.

   Same language as .k-data above, but the shape differs: these are two-column
   `th` label / `td` value tables with no thead, and the values are prose that
   must wrap, so they take neither the 820px floor nor `white-space: nowrap`. */
.kaisum-spec-table {
  margin: 0 0 1.5rem;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}

.kaisum-spec-table table {
  border-collapse: collapse;
  width: 100%;
  font-variant-numeric: tabular-nums;
  font-size: 0.9rem;
}

.kaisum-spec-table th,
.kaisum-spec-table td {
  border: 0;
  padding: 0.85rem 1.1rem;
  text-align: left;
  vertical-align: top;
}

/* The label column is half of every spec sheet and never carries the data, so
   it is the one place a table can hold brand colour without competing with
   the numbers next to it. */
.kaisum-spec-table tbody th {
  width: 38%;
  background: var(--canvas);
  color: var(--ink);
  font-weight: 560;
  border-right: 1px solid var(--line);
}

.kaisum-spec-table tbody tr + tr th,
.kaisum-spec-table tbody tr + tr td {
  border-top: 1px solid var(--line);
}

@media (max-width: 640px) {
  .kaisum-spec-table th,
  .kaisum-spec-table td {
    padding: 0.7rem 0.8rem;
  }
  .kaisum-spec-table tbody th {
    width: 42%;
  }
}

.k-kv {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}
.k-kv > div {
  background: var(--paper);
  padding: 1.15rem 1.25rem;
}
.k-kv dt {
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 0.4rem;
}
.k-kv dd {
  margin: 0;
  font-size: 1.125rem;
  font-weight: 540;
  letter-spacing: -0.025em;
  font-variant-numeric: tabular-nums;
}

/* ══════════════════════════════════════════════════════════════ MEDIA */

.k-frame {
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--ink);
}
.k-frame video,
.k-frame img {
  width: 100%;
  display: block;
}
.k-quote {
  font-family: var(--wp--preset--font-family--editorial);
  font-size: clamp(1.6rem, 4vw, 2.6rem);
  line-height: 1.25;
  letter-spacing: -0.02em;
  max-width: 24ch;
  margin: 0;
}

/* ══════════════════════════════════════════════════════════════ CHIPS */

.k-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: center;
}

.k-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.5rem 0.95rem;
  border-radius: 100px;
  background: color-mix(in srgb, var(--paper) 70%, transparent);
  border: 1px solid var(--line);
  backdrop-filter: blur(10px);
  font-size: 0.8125rem;
  font-weight: 480;
  letter-spacing: -0.01em;
  color: var(--ink);
  transition:
    transform 0.3s var(--ease),
    border-color 0.3s var(--ease);
}

.k-chip:hover {
  transform: translateY(-2px);
  border-color: var(--ink);
}
.k-chip svg {
  color: var(--primary);
}

/* ═════════════════════════════════════════════════════════════ LAYOUT */

.k-sec {
  padding-block: clamp(2.5rem, 6vw, 5rem);
}
.k-sec--tight {
  padding-block: clamp(1.5rem, 3.5vw, 2.5rem);
}

/* The hero is one full-width media card. Its slide image is already rounded to
   the same --r-lg as the band around it, so any padding here just draws the
   same corner twice, 25px apart. At zero the two radii coincide and the band
   reads as the image's own frame.

   Both selectors are needed: the block padding comes from .k-sec--tight above,
   but the inline padding is WordPress's own -- theme.json's root padding
   reaching this group through has-global-padding -- so it has to be overridden
   by name rather than simply unset. */
.k-sec--tight:has(.k-slider),
.k-sec--tight.has-global-padding:has(.k-slider) {
  padding: 0;
}

/* theme.json sets one flat 1.5rem root gutter for every width. On a desktop
   that is right; on a 390px phone it spends 48px of the screen before a single
   component has added its own padding, and the hero stacks another 24px on top
   of that. Narrow it on small screens.

   This has to override the custom properties rather than the padding itself.
   `.has-global-padding > .alignfull` cancels the gutter with
   `calc(var(--wp--style--root--padding-left) * -1)`, so a full-bleed section
   only stays flush with the viewport edge while both halves read the same
   value -- setting `padding` directly would move the edges apart. It also has
   to be `body`, not `:root`: WordPress declares these on `body`, and a value
   set on the ancestor loses to the element's own declaration. */
@media (max-width: 640px) {
  body {
    --wp--style--root--padding-left: 1rem;
    --wp--style--root--padding-right: 1rem;
  }
}

@media (max-width: 380px) {
  body {
    --wp--style--root--padding-left: 0.75rem;
    --wp--style--root--padding-right: 0.75rem;
  }
}

/* WordPress's constrained layout puts margin-left/right:auto !important on
   its direct children, so a narrow max-width here centred the whole heading
   block inside the column while the content below it started at the left
   edge. Override the auto margins, and constrain the measure on the heading
   and lead themselves rather than on the box. */
.k-head {
  max-width: 52rem;
  margin-inline: 0 auto !important;
  margin-bottom: clamp(1.5rem, 3vw, 2.25rem);
}

.k-head h2 {
  margin: 0 0 1.25rem;
  text-wrap: balance;
  max-width: 20ch;
}
.k-head .k-lead {
  margin: 0;
}

/* ═════════════════════════════════════════════════════════════ FOOTER */

.k-footer {
  background: var(--primary-dark);
  color: rgba(255, 255, 255, 0.72);
  padding-block: clamp(2.5rem, 5vw, 4rem) 2rem;
  font-size: 0.9rem;
}
.k-footer h3 {
  color: rgba(255, 255, 255, 0.72);
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.625rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  margin: 0 0 1.2rem;
  font-weight: 500;
}
.k-footer a {
  color: rgba(255, 255, 255, 0.75);
  text-decoration: none;
  transition: color 0.2s;
}
.k-footer a:hover {
  color: #fff;
}
/* Decorative oversized wordmark, not read as text — WCAG's incidental-text
   exemption applies, so this alpha is intentionally left low and is
   excluded by name from test_white_text_alphas_on_primary_dark_clear_aa. */
/* The logo heads the brand column, in place of the company name set in the
   body face. The URL is relative to this stylesheet, so it resolves through
   the theme folder without PHP -- which is why this does not need the
   pattern that parts/header.html relies on. */
.k-footer__logo {
  width: clamp(180px, 22vw, 240px);
  aspect-ratio: 608 / 72;
  margin: 0 0 1.25rem;
  background: url("assets/img/logo@4x.png") no-repeat left center / contain;
}
.k-footer__social {
  display: flex;
  gap: 0.7rem;
  margin-top: 1.6rem;
}

.k-footer__social a {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.35);
  display: grid;
  place-items: center;
  color: rgba(255, 255, 255, 0.85);
  transition:
    background-color 0.2s var(--ease),
    border-color 0.2s var(--ease),
    color 0.2s var(--ease);
}

.k-footer__social a:hover {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}
.k-footer__social svg {
  width: 22px;
  height: 22px;
  fill: currentColor;
  display: block;
}

.k-footer__links {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 0.7rem;
}
.k-footer__bar {
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.72);
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
}

/* ═════════════════════════════════════════════════════════════ MOTION */

.k-sec--flush-top {
  padding-top: 0;
}

.k-show__jump {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: clamp(0.5rem, 2vw, 1rem);
}

.k-show__chip {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 0.55rem 0.5rem 1rem;
  border-radius: 100px;
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
  color: var(--ink);
  text-decoration: none;
  font-size: 0.875rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  transition:
    transform 0.3s var(--ease),
    border-color 0.3s var(--ease);
}
.k-show__chip span {
  min-width: 1.75rem;
  padding: 0.15rem 0.45rem;
  border-radius: 100px;
  background: var(--canvas);
  color: var(--primary-ink);
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.6875rem;
  text-align: center;
}
.k-show__chip:hover {
  transform: translateY(-2px);
  border-color: var(--primary);
}
.k-show__chip--quiet {
  padding-right: 1rem;
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  color: var(--primary-ink);
}

.k-show__cat {
  scroll-margin-top: 6rem;
  padding-block: clamp(2rem, 5vw, 3.75rem);
  border-top: 1px solid var(--line);
}
.k-show__jump + .k-show__cat {
  border-top: 0;
  padding-top: clamp(1.25rem, 3vw, 2rem);
}

.k-show__head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-end;
  gap: 1.25rem 3rem;
  margin-bottom: clamp(1.25rem, 3vw, 2rem);
}
.k-show__head .k-label {
  margin-bottom: 0.9rem;
}
.k-show__head h2 {
  margin: 0 0 0.6rem;
  font-size: clamp(1.75rem, 3.4vw, 2.625rem);
  line-height: 1.05;
  letter-spacing: -0.035em;
}
.k-show__blurb {
  margin: 0;
  max-width: 54ch;
  color: var(--muted);
  font-size: 1rem;
  line-height: 1.55;
}

.k-show__all {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.75rem 1.25rem;
  border: 1px solid var(--ink);
  border-radius: 100px;
  color: var(--ink);
  text-decoration: none;
  font-size: 0.875rem;
  font-weight: 500;
  white-space: nowrap;
  transition:
    background 0.3s var(--ease),
    color 0.3s var(--ease);
}
.k-show__all span {
  transition: transform 0.3s var(--ease);
}
.k-show__all:hover {
  background: var(--ink);
  color: var(--paper);
}
.k-show__all:hover span {
  transform: translateX(3px);
}

.k-show__grid {
  display: grid;
  gap: clamp(0.875rem, 1.6vw, 1.25rem);
}
.k-show__grid--3 {
  grid-template-columns: 1.3fr 1fr;
  grid-template-rows: 1fr 1fr;
}
.k-show__grid--3 .k-show__card--lead {
  grid-row: span 2;
}
.k-show__grid--2 {
  grid-template-columns: 1fr 1fr;
}

.k-show__card {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-sm);
  color: var(--ink);
  text-decoration: none;
  transition:
    transform 0.4s var(--ease),
    box-shadow 0.4s var(--ease),
    border-color 0.4s var(--ease);
}
.k-show__card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
  border-color: color-mix(in srgb, var(--primary) 45%, var(--line));
}

.k-show__shot {
  position: relative;
  display: grid;
  place-items: center;
  height: clamp(200px, 20vw, 240px);
  min-height: 0;
  padding: 1.25rem;
  overflow: hidden;
  background: var(--stage-45);
}
.k-show__shot img {
  position: absolute;
  inset: 1.25rem;
  width: calc(100% - 2.5rem);
  height: calc(100% - 2.5rem);
  object-fit: scale-down;
  transition: transform 0.55s var(--ease);
}
.k-show__card:hover .k-show__shot img {
  transform: scale(1.05) translateY(-3px);
}
.k-show__card--lead .k-show__shot {
  flex: 1;
  height: auto;
  min-height: clamp(280px, 30vw, 420px);
  padding: clamp(1.5rem, 3vw, 2.5rem);
}
.k-show__grid--2 .k-show__shot,
.k-show__grid--2 .k-show__card--lead .k-show__shot {
  flex: none;
  height: clamp(240px, 26vw, 340px);
  min-height: 0;
}
.k-show__card--lead .k-show__shot img {
  inset: clamp(1.75rem, 4vw, 3.5rem);
  width: calc(100% - 2 * clamp(1.75rem, 4vw, 3.5rem));
  height: calc(100% - 2 * clamp(1.75rem, 4vw, 3.5rem));
}

.k-show__badge {
  position: absolute;
  top: 1rem;
  left: 1rem;
  z-index: 1;
  padding: 0.35rem 0.75rem;
  border-radius: 100px;
  background: var(--primary-dark);
  color: #fff;
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.k-show__body {
  display: grid;
  gap: 0.55rem;
  align-content: start;
  padding: 1.1rem 1.25rem 1.25rem;
}
.k-show__card--lead .k-show__body {
  padding: 1.4rem 1.6rem 1.6rem;
}
.k-show__body h3 {
  margin: 0;
  font-size: 1.125rem;
  line-height: 1.3;
  letter-spacing: -0.025em;
}
.k-show__card--lead h3 {
  font-size: clamp(1.3rem, 2vw, 1.625rem);
  letter-spacing: -0.03em;
}
.k-show__why {
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.55;
}
.k-show__foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem 1rem;
  margin-top: 0.35rem;
  padding-top: 0.8rem;
  border-top: 1px solid var(--line);
}
.k-show__foot .k-rail__meta {
  margin-top: 0;
}
.k-show__more {
  color: var(--primary-ink);
  font-size: 0.8125rem;
  font-weight: 500;
  white-space: nowrap;
}

.k-show__grid--3 .k-show__card:not(.k-show__card--lead) {
  flex-direction: row;
}
.k-show__grid--3 .k-show__card:not(.k-show__card--lead) .k-show__shot {
  flex: 0 0 42%;
  height: auto;
  min-height: 190px;
}
.k-show__grid--3 .k-show__card:not(.k-show__card--lead) .k-show__body {
  flex: 1;
  align-content: center;
}

.k-show__grid--1 .k-show__card--lead {
  flex-direction: row;
}
.k-show__grid--1 .k-show__card--lead .k-show__shot {
  flex: 1 1 55%;
}
.k-show__grid--1 .k-show__card--lead .k-show__body {
  flex: 1 1 45%;
  align-content: center;
  padding: clamp(1.5rem, 4vw, 3rem);
}

@media (max-width: 900px) {
  .k-show__grid--3 {
    grid-template-columns: 1fr;
    grid-template-rows: none;
  }
  .k-show__grid--3 .k-show__card--lead {
    grid-row: auto;
  }
  .k-show__grid--1 .k-show__card--lead {
    flex-direction: column;
  }
}

@media (max-width: 640px) {
  .k-show__grid--2 {
    grid-template-columns: 1fr;
  }
  .k-show__grid--3 .k-show__card:not(.k-show__card--lead) {
    flex-direction: column;
  }
  .k-show__grid--3 .k-show__card:not(.k-show__card--lead) .k-show__shot {
    flex: none;
    height: 220px;
  }
  .k-show__card--lead .k-show__shot {
    min-height: 260px;
  }
  .k-show__head {
    align-items: flex-start;
  }
}

/* Scroll-driven and native. No IntersectionObserver, no library. */
@supports (animation-timeline: view()) {
  /* Ranges end inside `entry`, so a card has finished arriving by the time it
     is fully on screen. The cover-based ranges this replaces were written for
     a row of three or four; stacked one per row on a phone they left a card
     sitting half-faded in the middle of the viewport, because `cover` is
     measured against the whole scroll past the element rather than its
     arrival. The stagger is a row effect, so it only applies where there is
     a row -- below that the siblings arrive one after another anyway. */
  .k-in,
  .k-in-stagger > * {
    animation: k-rise linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 22%;
  }

  @media (min-width: 781px) {
    .k-in-stagger > :nth-child(2) {
      animation-range: entry 3% cover 26%;
    }
    .k-in-stagger > :nth-child(3) {
      animation-range: entry 6% cover 30%;
    }
    .k-in-stagger > :nth-child(4) {
      animation-range: entry 9% cover 34%;
    }
    .k-in-stagger > :nth-child(5) {
      animation-range: entry 12% cover 38%;
    }
    .k-in-stagger > :nth-child(6) {
      animation-range: entry 15% cover 42%;
    }
  }

  .k-zoom {
    animation: k-settle linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 40%;
  }
}

@keyframes k-rise {
  from {
    opacity: 0;
    transform: translateY(28px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes k-settle {
  from {
    opacity: 0.4;
    transform: scale(1.06);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation: none !important;
    transition-duration: 0.01ms !important;
  }
}

/* ═══════════════════════════════════════════════════════════════ A11Y */

.skip-link {
  position: absolute;
  left: -9999px;
}
.skip-link:focus {
  left: 1rem;
  top: 1rem;
  z-index: 100;
  padding: 0.7rem 1.2rem;
  background: var(--paper);
  border-radius: 100px;
  box-shadow: var(--shadow-md);
}
a:focus-visible,
button:focus-visible,
.wp-block-button__link:focus-visible {
  /* --primary is 2.74:1 on paper and 2.46:1 on canvas -- below the 3:1 a
     non-text control needs. primary-ink clears it on both light grounds. */
  outline: 2px solid var(--primary-ink);
  outline-offset: 3px;
  border-radius: 4px;
}

/* outline-offset puts the ring on the ground, not on the control, so it is the
   ground it has to clear -- and on a navy band that ground is primary-dark,
   where primary-ink is only 1.84:1. --primary is 3.49:1 there, which is the
   mirror of the light case: each is legible exactly where the other is not. */
.k-band :is(a, button, .wp-block-button__link):focus-visible,
.k-footer :is(a, button):focus-visible {
  outline-color: var(--primary);
}

/* ═══════════════════════════════════════════════════════════ BUTTONS */

/* Our patterns write button markup by hand inside core/html blocks, so the
   Button block is never "present" on the page and WordPress never enqueues
   its stylesheet -- the only place `display:inline-block` is declared.
   theme.json supplies the padding and radius regardless, so the pill still
   looks right, but an inline box's vertical padding does not grow the line
   box: the flex item measured 22px while the pill painted 48px. On one line
   nobody notices; as soon as the row wrapped (below ~375px) the second pill
   was laid out 22px + gap below the first and the two overlapped by 15px.
   Restoring core's own value makes the padding count. */
.wp-block-button__link {
  display: inline-block;
  transition:
    transform 0.25s var(--ease),
    background-color 0.25s var(--ease),
    box-shadow 0.25s var(--ease);
}
.wp-block-button__link:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
}
.is-style-outline .wp-block-button__link {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--line);
}
.is-style-outline .wp-block-button__link:hover {
  border-color: var(--ink);
  background: var(--paper);
  box-shadow: none;
}
.k-band .is-style-outline .wp-block-button__link {
  color: var(--paper);
  border-color: rgba(255, 255, 255, 0.25);
}
.k-band .is-style-outline .wp-block-button__link:hover {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.5);
}
.k-band .wp-block-button:not(.is-style-outline) .wp-block-button__link {
  background: var(--paper);
  color: var(--ink);
}

/* ═══════════════════════════════════════════════════════════════ MISC */

.k-crumbs {
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  padding-block: 2rem 0;
}
.k-crumbs a {
  color: var(--muted);
  text-decoration: none;
}
.k-crumbs a:hover {
  color: var(--ink);
}
.k-crumbs span {
  margin-inline: 0.5rem;
  opacity: 0.4;
}

.k-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.k-tag {
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.625rem;
  letter-spacing: 0.1em;
  padding: 0.3rem 0.65rem;
  border: 1px solid var(--line);
  border-radius: 100px;
  color: var(--muted);
}

.k-ticks {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 0.8rem;
}
.k-ticks li {
  position: relative;
  padding-left: 1.9rem;
  line-height: 1.55;
}
.k-ticks li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.45em;
  width: 1.1rem;
  height: 1.1rem;
  border-radius: 50%;
  background: var(--ink)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E")
    center / 0.65rem no-repeat;
}

.k-note {
  border-left: 2px solid var(--primary);
  padding: 0.2rem 0 0.2rem 1.25rem;
  margin-block: 2rem;
  color: var(--muted);
}
.k-note strong {
  color: var(--ink);
}
.k-band .k-note strong {
  color: var(--paper);
}

/* ══════════════════════════════════════════════════════════════ REEL */

/* A product reel instead of a factory film: seven models cross-fading on a
   lit stage. Pure CSS keyframes — no video file, no third-party watermark,
   and nothing on screen that belongs to a client. */

.k-reel {
  position: relative;
  aspect-ratio: 4/3;
  display: grid;
  place-items: center;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  overflow: hidden;
  background: var(--stage-42);
}

.k-reel__slide {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: clamp(1rem, 3vw, 2.25rem);
  opacity: 0;
  animation: k-reel 24.5s linear infinite;
}
.k-reel__slide img {
  max-width: 80%;
  max-height: 80%;
  width: auto;
  object-fit: contain;
  filter: drop-shadow(0 26px 40px rgba(20, 73, 107, 0.24));
}

.k-reel__slide:nth-child(1) {
  animation-delay: 0s;
}
.k-reel__slide:nth-child(2) {
  animation-delay: 3.5s;
}
.k-reel__slide:nth-child(3) {
  animation-delay: 7s;
}
.k-reel__slide:nth-child(4) {
  animation-delay: 10.5s;
}
.k-reel__slide:nth-child(5) {
  animation-delay: 14s;
}
.k-reel__slide:nth-child(6) {
  animation-delay: 17.5s;
}
.k-reel__slide:nth-child(7) {
  animation-delay: 21s;
}

@keyframes k-reel {
  0% {
    opacity: 0;
    transform: scale(0.96) translateY(8px);
  }
  2.5% {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
  14.3% {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
  17% {
    opacity: 0;
    transform: scale(1.02) translateY(-8px);
  }
  100% {
    opacity: 0;
  }
}

.k-reel__name {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 1.25rem;
  text-align: center;
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}
.k-reel__name span {
  position: absolute;
  left: 0;
  right: 0;
  opacity: 0;
  animation: k-reel 24.5s linear infinite;
}
.k-reel__name span:nth-child(1) {
  animation-delay: 0s;
}
.k-reel__name span:nth-child(2) {
  animation-delay: 3.5s;
}
.k-reel__name span:nth-child(3) {
  animation-delay: 7s;
}
.k-reel__name span:nth-child(4) {
  animation-delay: 10.5s;
}
.k-reel__name span:nth-child(5) {
  animation-delay: 14s;
}
.k-reel__name span:nth-child(6) {
  animation-delay: 17.5s;
}
.k-reel__name span:nth-child(7) {
  animation-delay: 21s;
}

@media (prefers-reduced-motion: reduce) {
  .k-reel__slide,
  .k-reel__name span {
    animation: none;
    opacity: 0;
  }
  .k-reel__slide:first-child,
  .k-reel__name span:first-child {
    opacity: 1;
  }
}

/* Brand mark. The scraped logo is 304x36; @2x covers retina. */
.k-brand {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
}
.k-brand img {
  width: clamp(150px, 16vw, 200px);
  height: auto;
  display: block;
}

/* 16vw is only 62px on a phone, so the logo sat on its 150px floor at every
   width below a laptop -- 17.8px tall next to a 41.6px menu button, which read
   as an afterthought rather than the brand. The mark is 304px wide natively and
   the header is a space-between row, so growing it only eats the empty gap
   before the button; nothing reflows. The cap keeps ~54px of clearance at
   320px, the tightest case. */
@media (max-width: 640px) {
  .k-brand img {
    width: clamp(185px, 55vw, 220px);
  }
}

/* ════════════════════════════════════════════════════════════ GALLERY */

.k-gal {
  position: sticky;
  top: 12vh;
}

.k-gal__main {
  aspect-ratio: 4/3;
  display: grid;
  place-items: center;
  padding: clamp(1.5rem, 4vw, 3rem);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--stage-42);
  overflow: hidden;
}

.k-gal__main img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  object-fit: contain;
  filter: drop-shadow(0 24px 38px rgba(20, 73, 107, 0.22));
  animation: k-swap 0.45s var(--ease);
}

@keyframes k-swap {
  from {
    opacity: 0;
    transform: scale(0.97);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.k-gal__thumbs {
  display: flex;
  gap: 0.6rem;
  margin-top: 0.85rem;
  overflow-x: auto;
  padding-bottom: 0.4rem;
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
  scroll-snap-type: x proximity;
}

.k-gal__thumbs::-webkit-scrollbar {
  height: 3px;
}
.k-gal__thumbs::-webkit-scrollbar-thumb {
  background: var(--line);
  border-radius: 3px;
}

.k-gal__thumb {
  flex: 0 0 auto;
  width: 74px;
  height: 60px;
  padding: 0.35rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
  cursor: pointer;
  display: grid;
  place-items: center;
  scroll-snap-align: start;
  transition:
    border-color 0.2s var(--ease),
    transform 0.2s var(--ease);
}

.k-gal__thumb img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  object-fit: contain;
}
.k-gal__thumb:hover {
  border-color: var(--muted);
  transform: translateY(-2px);
}
.k-gal__thumb.is-active {
  border-color: var(--ink);
  box-shadow: 0 0 0 1px var(--ink);
}

.k-gal__count {
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0.75rem 0 0;
}

@media (max-width: 820px) {
  .k-gal {
    position: relative;
    top: 0;
  }
}

/* ══════════════════════════════════════════════════════════════ FIGURE */

.k-figure {
  margin: 0;
  border-radius: var(--r);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--stage-45);
}
.k-figure img {
  width: 100%;
  display: block;
}
.k-figure figcaption {
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 0.85rem 1rem;
  border-top: 1px solid var(--line);
  background: var(--paper);
}

/* Description flow: figures and tables alternate rather than stacking. */
.k-prose {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.5rem);
}
.k-prose h2 {
  margin: 0 0 1.25rem;
  font-size: var(--wp--preset--font-size--x-large);
}

/* ═══════════════════════════════════════════════ IMAGERY, ENLARGED */

/* The product shot leads the page; the copy column supports it. */
.k-split--media {
  grid-template-columns: 1.55fr 1fr;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: start;
}
@media (max-width: 900px) {
  .k-split--media {
    grid-template-columns: 1fr;
  }
}

.k-gal__main {
  aspect-ratio: 5/4;
  padding: clamp(0.6rem, 1.4vw, 1.1rem);
}
.k-gal__main img {
  max-height: 100%;
}
.k-gal__thumb {
  width: 92px;
  height: 74px;
}

/* Figures inside a description run the full content width, not a column. */
.k-prose .k-figure {
  margin-block: 0.5rem;
}
.k-prose .k-figure img {
  width: 100%;
  max-height: min(62vh, 620px);
  object-fit: contain;
  background: var(--stage-45);
  padding: clamp(0.6rem, 1.6vw, 1.25rem);
}

/* The description column is otherwise reading-width; figures break out of it
   so the product is the biggest thing on the page. */
.k-prose {
  --break: clamp(0px, calc((100vw - 100%) / 2 - 1.5rem), 240px);
}
.k-prose .k-figure {
  margin-inline: calc(var(--break) * -1);
}
@media (max-width: 900px) {
  .k-prose .k-figure {
    margin-inline: 0;
  }
}

/* ═══════════════════════════════════════════════════ OVERFLOW CONTAINMENT */

/* Grid and flex children default to min-width:auto, so a child that scrolls
   makes its parent grow to fit the content instead of scrolling. With 16
   thumbnails the gallery column blew past the page. min-width:0 lets the
   track shrink so overflow-x:auto actually engages. */
.k-split > *,
.k-split--media > *,
.k-split--offset > *,
.k-pin > * {
  min-width: 0;
}

.k-gal {
  min-width: 0;
  max-width: 100%;
}
.k-gal__thumbs {
  min-width: 0;
  max-width: 100%;
}

/* Same trap on the horizontal product rail and the wide data tables. */
.k-rail,
.k-data,
.kaisum-compare,
.k-marquee,
.k-ticker {
  min-width: 0;
  max-width: 100%;
}

/* Fade the strip's right edge so it reads as scrollable rather than cut off. */
.k-gal__thumbs {
  mask-image: linear-gradient(
    90deg,
    #000 0,
    #000 calc(100% - 44px),
    transparent 100%
  );
  scroll-padding-inline: 0.5rem;
}

.k-gal__thumbs:only-child,
.k-gal__thumbs.is-complete {
  mask-image: none;
}

/* The viewer was 5:4 — a tall box around a wide, short product, leaving a
   large empty field above and below it. */
.k-gal__main {
  aspect-ratio: 3/2;
}
.k-gal__main img {
  max-height: 100%;
  max-width: 100%;
}

@media (max-width: 900px) {
  .k-gal__main {
    aspect-ratio: 4/3;
  }
}

/* ════════════════════════════════════════════════════ SCROLL CONTROLS */

/* Wrapper is injected by ui.js around any horizontal scroller, so the
   arrows only exist when there is something to scroll to. */
.k-scroll {
  position: relative;
  min-width: 0;
}

.k-scroll__btn {
  position: absolute;
  top: var(--btn-top, 50%);
  translate: 0 -50%;
  z-index: 5;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 100px;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: blur(10px) saturate(160%);
  -webkit-backdrop-filter: blur(10px) saturate(160%);
  color: var(--ink);
  cursor: pointer;
  box-shadow: var(--shadow-md);
  transition:
    opacity 0.28s var(--ease),
    transform 0.28s var(--ease),
    background-color 0.2s var(--ease),
    border-color 0.2s var(--ease);
}

.k-scroll__btn:hover {
  background: var(--paper);
  border-color: var(--ink);
  transform: scale(1.06);
}
.k-scroll__btn:active {
  transform: scale(0.96);
}
.k-scroll__btn--prev {
  left: 0.5rem;
}
.k-scroll__btn--next {
  right: 0.5rem;
}
.k-scroll__btn svg {
  width: 18px;
  height: 18px;
}

/* At an end, or nothing to scroll: gone, and not tabbable. */
.k-scroll__btn[disabled] {
  opacity: 0;
  pointer-events: none;
  transform: scale(0.9);
}

/* Shown on touch as well as pointer devices: swiping works, but the arrows
   are the affordance that tells you there is more to the side. Sized at 40px
   so they stay a comfortable tap target. */
@media (max-width: 600px) {
  .k-scroll__btn {
    width: 40px;
    height: 40px;
  }
  .k-scroll__btn--prev {
    left: 0.35rem;
  }
  .k-scroll__btn--next {
    right: 0.35rem;
  }
  .k-scroll__btn svg {
    width: 16px;
    height: 16px;
  }
}

/* Touch has no hover, so lean on opacity instead of a hover state to keep
   the buttons from competing with the product photography. */
@media (hover: none) {
  .k-scroll__btn {
    background: color-mix(in srgb, var(--paper) 94%, transparent);
  }
  .k-scroll__btn:active {
    transform: scale(0.92);
    background: var(--paper);
  }
}

/* Sit the rail's arrows over the product image, not the card's full height. */
.k-scroll:has(.k-rail) {
  --btn-top: 32%;
}
.k-scroll:has(.k-gal__thumbs) {
  --btn-top: 50%;
}

/* Counting figures need fixed-width digits, or the number jitters sideways
   as it climbs and drags the label with it. */
.k-fig__v {
  font-variant-numeric: tabular-nums;
}
.k-count {
  display: inline-block;
}

/* ═══════════════════════════════════════════════════════════════ CLOSE */

/* The wrapper used to cap at 30ch — about 285px — which is nothing at
   display size, so the headline broke over three lines and orphaned its last
   word. Give it a real measure and let text-wrap:balance split it evenly. */
.k-close {
  text-align: center;
  max-width: 46rem;
  margin-inline: auto !important;
}
.k-close__more {
  margin: 1.5rem 0 0;
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, 0.72);
}

.k-close__more a {
  color: var(--paper);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.k-close .k-label {
  justify-content: center;
}
.k-close h2 {
  margin: 0;
  text-wrap: balance;
}
.k-close .k-lead {
  margin: 1.5rem auto 2.25rem;
  max-width: 42ch;
}

/* ═════════════════════════════════════════════════════════════ SLIDER */

.k-slider {
  position: relative;
  isolation: isolate;
  touch-action: pan-y;
}
/* Every slide shares one grid cell. Inactive slides used to be taken out of
   flow with position:absolute, which left the track only as tall as whichever
   slide happened to be active -- and on mobile, where the copy sits below the
   image instead of over it, the slides differ by up to 104px. The section
   jumped on every advance, and mid-crossfade the outgoing slide overflowed
   the new shorter height and ran under the arrows and dots. Keeping them in
   flow makes the track the height of the tallest slide, once. */
.k-slider__track {
  position: relative;
  display: grid;
}

.k-slide {
  grid-area: 1 / 1;
  position: relative;
  opacity: 0;
  visibility: hidden;
  transition:
    opacity 0.7s var(--ease),
    visibility 0.7s;
}

.k-slide.is-active {
  opacity: 1;
  visibility: visible;
}

.k-slide__img {
  width: 100%;
  aspect-ratio: 2 / 1;
  object-fit: cover;
  display: block;
  border-radius: var(--r-lg);
}

/* The scrim manufactures the text well. Slides are composed with a quiet
   left 40% (see build/make_slides.py), so this stays light enough to keep
   the photograph readable. */
.k-slide__well {
  position: absolute;
  inset: 0 auto 0 0;
  width: min(52%, 40rem);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(1.5rem, 5vw, 4rem);
  border-radius: var(--r-lg) 0 0 var(--r-lg);
  /* 90deg, not 95: at an angle the gradient line runs longer than the box
	   is wide, so the ramp had not reached zero by the right edge and cut off
	   at ~11% white -- a visible vertical seam across the sky. Square to the
	   box, and fully transparent by 88% so the last stretch is clean however
	   the line length rounds. */
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0.96) 0%,
    rgba(255, 255, 255, 0.88) 30%,
    rgba(255, 255, 255, 0.55) 62%,
    rgba(255, 255, 255, 0) 88%
  );
}

.k-slide__well--plate {
  display: none;
}

.k-slide__well--plate .k-slide__head {
  font-weight: 600;
  letter-spacing: -0.035em;
}

.k-slide__head {
  font-size: clamp(1.9rem, 3.2vw, 3.1rem);
  line-height: 1.08;
  margin: 0 0 0.9rem;
  max-width: 18ch;
  text-wrap: balance;
}
.k-slide__head em {
  font-family: var(--wp--preset--font-family--serif);
  font-style: italic;
  font-weight: 400;
}
.k-slide .k-lead {
  margin: 0 0 1.75rem;
  max-width: 38ch;
}
.k-slide__cta {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.k-slider__arrow {
  position: absolute;
  bottom: clamp(0.9rem, 2.6vw, 1.75rem);
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.92);
  color: var(--primary-dark);
  font-size: 1.25rem;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background-color 0.2s var(--ease);
}
.k-slider__arrow:hover {
  background: #fff;
}
.k-slider__arrow--prev {
  right: clamp(4rem, 7vw, 5.25rem);
}
.k-slider__arrow--next {
  right: clamp(0.75rem, 2vw, 1.5rem);
}

.k-slider__dots {
  position: absolute;
  bottom: clamp(1rem, 3vw, 2rem);
  left: 50%;
  translate: -50%;
  display: flex;
  gap: 0.5rem;
}

.k-slider__dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(20, 73, 107, 0.28);
  cursor: pointer;
  transition:
    width 0.3s var(--ease),
    background-color 0.3s var(--ease);
}
.k-slider__dot.is-active {
  width: 22px;
  border-radius: 999px;
  background: var(--primary);
}

/* QA item 9: the cue used to sit under the buttons. */
.k-slider .k-scrollcue {
  bottom: -3.5rem;
}

@media (max-width: 780px) {
  /* The track is now the tallest slide's height, so a short slide has slack
	   below its copy. Let the well take it, or the card ends mid-cell and the
	   controls sit under a rounded edge on bare background. */
  .k-slide {
    display: flex;
    flex-direction: column;
  }

  .k-slide__well {
    position: relative;
    flex: 1;
    width: 100%;
    border-radius: 0 0 var(--r-lg) var(--r-lg);
    background: var(--paper);
    /* The dots are absolutely positioned but the well is in flow here, so
		   nothing reserved room for them and they sat on the CTA row. */
    padding: clamp(0.9rem, 3.5vw, 1.25rem) clamp(0.9rem, 3.5vw, 1.25rem) 3.7rem;
  }

  /* A 2:1 slide cropped to 4/3 and centred cut the product in half: the
	   composited slides place it at 55-99% of the frame by construction, so
	   a centre crop throws away the half that matters. Gentler ratio, and
	   the crop is biased right to keep the product whole. */
  .k-slide--plate {
    justify-content: flex-start;
  }

  .k-slide__well--plate {
    display: flex;
  }

  .k-slide--plate .k-slide__img {
    object-fit: contain;
    background: var(--canvas);
  }

  .k-slide__img {
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    /* The mobile source is already framed for this shape by
		   build/make_slides.py, one crop per slide centred on that slide's
		   own subject. No object-position trickery: a window over the 2:1
		   desktop file is clamped inside it and cannot reach a subject
		   sitting at 77%, which is what left the product stranded right. */
    aspect-ratio: 4 / 3;
  }

  .k-slide__head {
    font-size: clamp(1.55rem, 6.4vw, 2.1rem);
    max-width: none;
  }
  .k-slide .k-lead {
    max-width: none;
    margin-bottom: 1.25rem;
  }

  /* Keep the two CTAs on one line rather than stacking them. */
  .k-slide__cta {
    gap: 0.5rem;
  }
  .k-slide__cta .wp-block-button__link {
    padding-inline: 1.15rem;
    font-size: 0.875rem;
  }

  /* The arrows were hidden here, which left small dots as the only hint
	   that anything slides -- the section read as a static image. They come
	   back, flanking the dots in one control row at the foot of the slide,
	   where there is no copy for them to sit on. Positioned against the
	   centre line rather than the slide edges so the row stays together at
	   any width. */
  .k-slider__arrow {
    display: grid;
    width: 40px;
    height: 40px;
    bottom: 0.55rem;
    font-size: 1.1rem;
  }
  .k-slider__arrow--prev {
    left: auto;
    right: calc(50% + 96px);
  }
  .k-slider__arrow--next {
    right: auto;
    left: calc(50% + 96px);
  }
  .k-slider__dots {
    bottom: 0.75rem;
    gap: 0.25rem;
  }
  .k-slider__dot {
    width: 44px;
    height: 44px;
    border-radius: 0;
    background: none;
    position: relative;
  }
  .k-slider__dot::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    translate: -50% -50%;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(20, 73, 107, 0.28);
    transition:
      width 0.3s var(--ease),
      background-color 0.3s var(--ease);
  }
  .k-slider__dot.is-active {
    width: 44px;
    background: none;
  }
  .k-slider__dot.is-active::after {
    width: 22px;
    border-radius: 999px;
    background: var(--primary);
  }

  .k-slider .k-scrollcue {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .k-slide {
    transition: none;
  }
}



/* ═══════════════════════════════════════════════════════ CATEGORY CARDS */

.k-cats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
}

/* Was --canvas, which is now the page ground -- the card would have dissolved
   into it. Cards paint --surface and let the ground do the separating. */
.k-cat {
  display: grid;
  grid-template-rows: auto 1fr;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  text-decoration: none;
  color: var(--ink);
  box-shadow: var(--shadow-sm);
  transition:
    transform 0.25s var(--ease),
    border-color 0.25s var(--ease),
    box-shadow 0.25s var(--ease);
}
.k-cat:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-3px);
  border-color: var(--primary);
}

/* A definite height, not aspect-ratio. A ratio is only a preferred size: a
   grid item's automatic minimum still lets content push it taller, so the
   portrait head render (472x540 against two landscape siblings) stretched
   its card and shoved the name and blurb out of view. max-height on the
   image could not help either, because it was resolving against a height
   the image itself was setting. */
.k-cat__shot {
  display: grid;
  place-items: center;
  height: clamp(200px, 22vw, 260px);
  min-height: 0;
  overflow: hidden;
  padding: 1.25rem;
  /* The card body used to be canvas against a paper shot; now the card is
     paper throughout, so the shot needs the lit stage to stay distinct from
     the copy under it. Same treatment the rail cards already use. */
  background: var(--stage-45);
}

.k-cat__shot img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}

.k-cat__body {
  display: grid;
  gap: 0.4rem;
  padding: 1.25rem;
  align-content: start;
}
.k-cat__body strong {
  font-size: 1.0625rem;
  letter-spacing: -0.02em;
}
.k-cat__blurb {
  color: var(--muted);
  font-size: 0.875rem;
  line-height: 1.5;
}
.k-cat__more {
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--primary-ink);
  margin-top: 0.35rem;
}

/* ════════════════════════════════════════════════════════════════════ FAQ */

/* Eight question/answer pairs used to sit raw in the 760px column with nothing
   between one and the next. They are panelled here rather than in the markup
   on purpose: inc/schema.php builds the FAQPage rich result by matching
   `</h3>` followed by only comments and whitespace and then a bare `<p>`, so
   putting a wrapper between the two would delete the rich result silently.
   Styling the pair as two halves of one box leaves that adjacency untouched.

   No shadow: the halves would cast onto each other and draw a seam across the
   middle of every panel. White on the tint plus a hairline is enough. */
.k-faq h3 {
  margin: 0;
  padding: 1.15rem 1.35rem 0.7rem;
  font-size: 1.0625rem;
  letter-spacing: -0.025em;
  background: var(--surface);
  border: 1px solid var(--line);
  border-bottom: 0;
  border-radius: var(--r) var(--r) 0 0;
}

.k-faq h3 + p {
  margin: 0 0 1rem;
  padding: 0 1.35rem 1.25rem;
  color: var(--muted);
  line-height: 1.65;
  background: var(--surface);
  border: 1px solid var(--line);
  border-top: 0;
  border-radius: 0 0 var(--r) var(--r);
}

.k-faq h3 + p:last-child {
  margin-bottom: 0;
}



.k-certs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
}

.k-cert {
  display: grid;
  grid-template-rows: auto 1fr;
  margin: 0;
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  transition:
    transform 0.25s var(--ease),
    border-color 0.25s var(--ease),
    box-shadow 0.25s var(--ease);
}

.k-cert:hover {
  transform: translateY(-3px);
  border-color: var(--primary);
  box-shadow: var(--shadow-md);
}

.k-cert__shot {
  position: relative;
  display: grid;
  place-items: center;
  height: clamp(210px, 24vw, 280px);
  min-height: 0;
  overflow: hidden;
  padding: 1rem;
  background: var(--stage-45);
  border-radius: var(--r) var(--r) 0 0;
}

.k-cert__shot img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: 3px;
  box-shadow: var(--shadow-sm);
}

.k-cert__zoom {
  position: absolute;
  right: 0.7rem;
  bottom: 0.7rem;
  padding: 0.25rem 0.6rem;
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--primary-ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 999px;
  opacity: 0;
  transition: opacity 0.25s var(--ease);
}

.k-cert:hover .k-cert__zoom,
.k-cert__shot:focus-visible .k-cert__zoom {
  opacity: 1;
}

.k-cert__meta {
  display: grid;
  gap: 0.4rem;
  align-content: start;
  padding: 1.15rem 1.25rem 1.35rem;
  border-top: 1px solid var(--line);
}

.k-cert__title {
  margin: 0;
  font-size: 1rem;
  line-height: 1.3;
  letter-spacing: -0.02em;
}

.k-cert__lines {
  display: grid;
  gap: 0.35rem;
  margin: 0.2rem 0 0;
  font-size: 0.75rem;
}

.k-cert__lines dt {
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

.k-cert__lines dd {
  margin: 0;
  color: var(--ink);
  line-height: 1.5;
  
  overflow-wrap: anywhere;
}

.k-cert__verify {
  justify-self: start;
  margin-top: 0.5rem;
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--primary-ink);
}

.k-certs--strip {
  grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr));
}
.k-certs--strip .k-cert__shot {
  height: clamp(120px, 14vw, 160px);
  padding: 0.7rem;
}
.k-certs--strip .k-cert__meta {
  gap: 0.1rem;
  padding: 0.7rem 0.85rem 0.9rem;
}
.k-certs--strip .k-cert__title {
  font-size: 0.8125rem;
}
.k-certs--strip .k-cert__issuer {
  font-size: 0.6875rem;
  color: var(--muted);
  margin: 0;
}

@media (max-width: 640px) {
  .k-cert__shot {
    height: clamp(170px, 44vw, 220px);
  }
  .k-certs--strip {
    grid-template-columns: repeat(2, 1fr);
  }
}

.k-lb {
  max-width: 100vw;
  max-height: 100dvh;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: visible;
}

.k-lb::backdrop {
  background: rgba(20, 73, 107, 0.82);
}

.k-lb__inner {
  position: relative;
  display: grid;
  gap: 0.75rem;
  justify-items: center;
  margin: 0;
  min-width: 0;
  padding: clamp(1rem, 4vw, 2.5rem);
}

.k-lb__inner img {
  max-width: min(94vw, 900px);
  max-height: 82dvh;
  width: auto;
  height: auto;
  object-fit: contain;
  background: var(--paper);
  border-radius: var(--r);
  box-shadow: var(--shadow-lg);
}

.k-lb__inner figcaption {
  max-width: 60ch;
  color: var(--paper);
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-align: center;
}

.k-lb__close {
  position: absolute;
  top: clamp(0.25rem, 2vw, 1rem);
  right: clamp(0.25rem, 2vw, 1rem);
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 999px;
  cursor: pointer;
}

@media (prefers-reduced-motion: no-preference) {
  .k-lb[open] .k-lb__inner {
    animation: k-lb-in 0.22s var(--ease) both;
  }
  @keyframes k-lb-in {
    from {
      opacity: 0;
      transform: scale(0.97);
    }
  }
}

.k-cert__all {
  margin: clamp(1.25rem, 2.5vw, 1.75rem) 0 0;
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.kaisum-compare thead th:first-child,
.kaisum-compare tbody td:first-child {
  white-space: normal;
  width: 20ch;
  min-width: 16ch;
  max-width: 24ch;
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--surface);
}

.kaisum-compare thead th:first-child {
  z-index: 2;
}

.kaisum-compare tbody tr:hover td:first-child {
  background: var(--stage-edge);
}

.k-acc {
  display: grid;
  gap: 0.6rem;
}

.k-acc__item {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  transition: border-color 0.25s var(--ease);
}

.k-acc__item[open] {
  border-color: var(--primary);
}

.k-acc__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.1rem 1.35rem;
  font-size: 1.0625rem;
  font-weight: 520;
  letter-spacing: -0.025em;
  color: var(--ink);
  cursor: pointer;
  list-style: none;
}

.k-acc__q::-webkit-details-marker {
  display: none;
}

.k-acc__q:focus-visible {
  outline-offset: -3px;
}

.k-acc__mark {
  flex: none;
  color: var(--primary-ink);
  transition: transform 0.25s var(--ease);
}

.k-acc__item[open] .k-acc__mark {
  transform: rotate(45deg);
}

.k-acc__a {
  padding: 0 1.35rem 1.3rem;
}

.k-acc__a p {
  margin: 0;
  color: var(--muted);
  line-height: 1.65;
  max-width: 68ch;
}

.k-acc__all {
  margin: clamp(1.25rem, 2.5vw, 1.75rem) 0 0;
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

@media (prefers-reduced-motion: no-preference) {
  .k-acc__item[open] .k-acc__a {
    animation: k-acc-in 0.24s var(--ease) both;
  }
  @keyframes k-acc-in {
    from {
      opacity: 0;
      transform: translateY(-4px);
    }
  }
}

.k-cases {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(238px, 100%), 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
}

.k-case {
  display: grid;
  grid-template-rows: auto 1fr;
  margin: 0;
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  transition:
    transform 0.25s var(--ease),
    border-color 0.25s var(--ease),
    box-shadow 0.25s var(--ease);
}

.k-case:hover {
  transform: translateY(-3px);
  border-color: var(--primary);
  box-shadow: var(--shadow-md);
}

.k-case__shot {
  display: block;
  height: clamp(190px, 21vw, 240px);
  background: var(--stage-45);
}

.k-case__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}

.k-case__body {
  display: grid;
  gap: 0.3rem;
  align-content: start;
  padding: 1.15rem 1.25rem 1.35rem;
  border-top: 1px solid var(--line);
}

.k-case__brand {
  margin: 0;
  font-size: 1.0625rem;
  line-height: 1.3;
  letter-spacing: -0.025em;
}

.k-case__market {
  margin: 0;
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

.k-case__custom {
  margin: 0.35rem 0 0;
  font-size: 0.875rem;
  line-height: 1.55;
  color: var(--muted);
}

.k-case__more {
  justify-self: start;
  margin-top: 0.6rem;
  font-family: var(--wp--preset--font-family--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--primary-ink);
}

.k-case__note {
  margin: clamp(1.25rem, 2.5vw, 1.75rem) 0 0;
  font-size: 0.8125rem;
  color: var(--muted);
}

@media (max-width: 780px) {
  .k-cases {
    grid-template-columns: repeat(auto-fill, minmax(min(220px, 100%), 1fr));
  }
  .k-case__shot {
    height: clamp(160px, 40vw, 200px);
  }
}

.k-certs__group {
  margin-top: clamp(2.5rem, 5vw, 4rem);
}
