/* ============================================================
   TED Digital - kit components
   Copied from the locked kit page + homepage demo, values tokened.
   hero · section head · buttons · bento · series cards · warm panel
   · feature cards · utility cards · footer strip
   ============================================================ */

/* ---- section rhythm + heading grammar ---- */
.section { padding-block: var(--gap-2xl); }
.section--stone { background: var(--surface-warm); }
.section--dark { background: var(--ted-charcoal); color: var(--ted-white); }
.section--dark .section__label { color: var(--ink-inverse-50); }
.section--dark .split__text > p:not(.section__label) { color: var(--ink-inverse-80); }
.split__media--cutout img { border-radius: 0; }
@media (max-width: 768px) { .section { padding-block: var(--gap-xl); } }

/* ---- text and image (the editorial split; alternates sides) ---- */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-xl); align-items: center; }
.split--reverse .split__media { order: -1; }
.split__text > p:not(.section__label) { color: var(--ink-70); margin-top: var(--gap-sm); }
.split__text .section__title { max-width: 16ch; }
.split__text .btn, .split__text .wp-block-buttons { margin-top: var(--gap-md); }
.split__media img { width: 100%; height: auto; border-radius: var(--radius-lg); display: block; }
.split__media--cutout img { max-height: var(--media-max); object-fit: contain; }
@media (max-width: 900px) { .split { grid-template-columns: 1fr; gap: var(--gap-md); } .split--reverse .split__media { order: 0; } }

/* ---- stat bento: the imagery and the four figures as tiles of different sizes (bento grammar) ----
        3 cols x 140px rows: image 2x2 · tall figure 1x2 beside it · three equal figures along the foot */
.stat-bento { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: minmax(var(--row-stat), auto); gap: var(--gap-sm); }
.stat-bento__img { position: relative; grid-column: span 2; grid-row: span 2; border-radius: var(--radius-lg); overflow: hidden; background: var(--ted-charcoal); }
/* Absolute so the photo's own height never sizes the rows: a portrait image used to stretch them past 140px */
.stat-bento__img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border-radius: 0; }
.stat { border-radius: var(--radius-lg); padding: var(--gap-sm); display: flex; flex-direction: column; justify-content: space-between; }
.stat--dark { background: var(--ted-charcoal); color: var(--ted-white); }
.stat--light { background: var(--surface-raised); border: 1px solid var(--line-soft); color: var(--ink); }
.stat--tall { grid-row: span 2; }
.stat svg { width: var(--icon-sm); height: var(--icon-sm); }
.stat--dark svg { color: var(--ted-white); }
.stat--light svg { color: var(--ted-teal); }
.stat .big { display: block; font-family: var(--font-heading); font-weight: 300; font-size: var(--text-2xl); color: var(--ted-teal); line-height: 1; margin-top: auto; padding-top: var(--gap-xs); }
.stat--tall .big { font-size: var(--text-3xl); }
.stat > :last-child { display: block; font-size: var(--text-xs); line-height: 1.3; margin-top: var(--gap-2xs); }
.stat--dark > :last-child { color: var(--ink-inverse-70); }
.stat--light > :last-child { color: var(--ink-50); }
@media (max-width: 768px) {
  .stat-bento { grid-template-columns: 1fr 1fr; }
  .stat--tall { grid-row: span 1; }
  .stat--tall .big { font-size: var(--text-2xl); }
}

/* ---- reveal on scroll: subtle, once, only when JS is running ---- */
html.js .reveal { opacity: 0; transform: translateY(16px); transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); }
html.js .reveal.is-visible { opacity: 1; transform: none; }
html.js .reveal--stagger > * { opacity: 0; transform: translateY(12px); transition: opacity 0.6s var(--ease), transform 0.6s var(--ease); transition-delay: calc(var(--i, 0) * 80ms); }
html.js .reveal--stagger.is-visible > * { opacity: 1; transform: none; }
.hero__inner { animation: hero-in 0.9s var(--ease) both; }
@keyframes hero-in { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  html.js .reveal, html.js .reveal--stagger > * { opacity: 1; transform: none; transition: none; }
  .hero__inner { animation: none; }
}
.section__label { display: block; font-family: var(--font-heading); font-size: var(--text-xs); font-weight: 500; letter-spacing: 3px; text-transform: uppercase; color: var(--ink-50); }
.section__title { font-family: var(--font-heading); font-weight: 300; letter-spacing: 0.06em; text-transform: uppercase; font-size: var(--text-3xl); line-height: 1.15; margin-top: var(--gap-xs); max-width: 22ch; text-wrap: balance; }
.section .teal-rule { margin-bottom: var(--gap-md); }

/* ---- hero (full screen, Ken Burns drift, video-ready) ---- */
/* Heroes size to their content with a floor, never a fixed box: a long title grows the hero downwards instead of
   climbing under the header. --hero-head-clear = header bar (44px controls + its padding) + air, kept clear on EVERY hero. */
.hero { --hero-head-clear: calc(44px + 2 * var(--gap-sm) + var(--gap-md)); position: relative; min-height: max(560px, 100dvh); overflow: hidden; display: flex; align-items: flex-end; background: var(--ted-black); }
.hero__bg { position: absolute; inset: 0; }
.hero__bg img { width: 100%; height: 100%; object-fit: cover; animation: kenburns 26s ease-in-out infinite alternate; will-change: transform; }
@keyframes kenburns { from { transform: scale(1); } to { transform: scale(1.09) translate(-1.6%, -1%); } }
@media (prefers-reduced-motion: reduce) { .hero__bg img { animation: none; } }
/* Bottom scrim protects the title; top scrim protects the header - needed on light photography (a dark
   image already gives the header contrast for free, but nothing did until Cuba's bright marble hero). */
.hero::after { content: ''; position: absolute; inset: 0; background: linear-gradient(to top, rgba(10, 10, 10, 0.65) 0%, transparent 50%, transparent 72%, rgba(10, 10, 10, 0.62) 100%); }
.hero__content { position: relative; z-index: 2; width: 100%; padding-top: var(--hero-head-clear); padding-bottom: clamp(40px, 7vh, 80px); }
.hero__inner { max-width: 720px; }
.hero__label { display: block; font-family: var(--font-heading); font-size: var(--text-xs); font-weight: 500; letter-spacing: 3px; text-transform: uppercase; color: var(--ted-teal); }
/* A status flag above the title ("Coming soon"): a dark glass pill with the hero's hairline. The 75% backing keeps white text above 9:1 even over a white photograph (the 55% of the play/pause gave 4.4:1). Bottom-anchored hero, so the title never moves when it is absent. */
.hero__flag { display: block; width: fit-content; margin: 0 0 var(--gap-sm); padding: var(--gap-3xs) var(--gap-sm); border: 1px solid var(--line-inverse); border-radius: var(--radius-full); background: var(--ink-70); font-family: var(--font-heading); font-size: var(--text-xs); font-weight: 500; letter-spacing: 2px; line-height: 1.6; text-transform: uppercase; color: var(--ted-white); }
.hero__flag:empty { display: none; }   /* collection pages bind it to the ted_flag meta; no meta, no pill */
.hero__flag:not(:empty) + .hero__title { margin-top: 0; }
.hero__title { font-family: var(--font-heading); font-weight: 300; letter-spacing: 0.05em; text-transform: uppercase; font-size: clamp(36px, 1.4rem + 2.6vw, 60px); line-height: 1.1; color: var(--ted-white); max-width: 15ch; text-wrap: balance; margin-top: var(--gap-sm); }
.hero__sub { color: var(--ink-inverse-80); max-width: 44ch; margin-top: var(--gap-sm); }
.hero__cta { margin-top: var(--gap-md); display: flex; gap: var(--gap-sm); flex-wrap: wrap; }
@media (max-width: 768px) { .hero::after { background: linear-gradient(to top, rgba(10, 10, 10, 0.8) 0%, rgba(10, 10, 10, 0.35) 55%, transparent 72%, rgba(10, 10, 10, 0.62) 100%); } }
/* Inner pages open shorter - two-thirds of the screen - and the featured-image block wears the same frame. */
.hero--page { min-height: clamp(420px, 56dvh, 640px); background: var(--ted-black); }  /* depth, not a full screen. Black until the page's own photo paints: a fallback photo here showed for a moment on every navigation (Richard 30 Oct, "a glimpse of the HERO image" between VENN and CUBA) */
.hero--page .hero__title { max-width: 22ch; font-size: clamp(30px, 1.1rem + 2vw, 48px); }   /* inner pages carry longer titles than the homepage: smaller + wider = fewer lines */
.hero--short { min-height: clamp(320px, 42dvh, 480px); }   /* the dealer pages: the same opener as every inner page, only shorter so the map is in reach */
.section--blank { min-height: 40vh; }
.hero .wp-block-post-featured-image.hero__bg { position: absolute; inset: 0; margin: 0; }
.hero .wp-block-post-featured-image.hero__bg img { width: 100%; height: 100%; object-fit: cover; }
/* Homepage hero video (inc/hero-video.php): the poster is the first frame, the video fades in over
   it once it is actually playing. No Ken Burns here - the drift would jump when the video took over. */
.hero__media picture { display: contents; }
.hero__media .hero__poster, .hero__video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; animation: none; }
.hero__video { opacity: 0; transition: opacity 0.6s var(--ease); }
.hero__media.is-playing .hero__video { opacity: 1; }
.hero__toggle { position: absolute; z-index: 3; right: var(--gap-md); bottom: var(--gap-md); width: calc(var(--icon-sm) * 2); height: calc(var(--icon-sm) * 2); display: grid; place-items: center; padding: 0; border: 1px solid var(--line-inverse); border-radius: var(--radius-circle); background: var(--ink-50); color: var(--ted-white); cursor: pointer; transition: border-color 0.3s var(--ease), color 0.3s var(--ease); }
.hero__toggle[hidden] { display: none; }
.hero__toggle:hover { border-color: var(--ted-teal); color: var(--ted-teal); }
.hero__toggle svg { width: var(--icon-xs); height: var(--icon-xs); }
.hero__toggle[data-state="playing"] .hero__toggle-play, .hero__toggle[data-state="paused"] .hero__toggle-pause { display: none; }
@media (max-width: 768px) { .hero__toggle { right: var(--gap-sm); bottom: var(--gap-sm); } }
@media (prefers-reduced-motion: reduce) { .hero__video, .hero__toggle { transition: none; } }

/* ---- page head: the stone opener for archives (label, H1, rule, one line) ---- */
.page-head { padding-top: calc(var(--gap-2xl) + var(--gap-xl)); }
.page-head__lede { color: var(--ink-70); max-width: 50ch; margin-top: var(--gap-sm); }
.page-head__link { margin-top: var(--gap-sm); }

/* ---- query loops wear the kit grids: the <li> wrapper steps aside, the card inside is the grid item ---- */
.wp-block-post-template { list-style: none; margin: 0; padding: 0; }
.wp-block-post-template > .wp-block-post { display: contents; }
.series-card .wp-block-post-featured-image.series-card__img { margin: 0; }
.series-card__name a { color: inherit; text-decoration: none; }
.series-card__name a:focus-visible { outline: none; }
.series-card .wp-block-post-featured-image.series-card__img img { border-radius: 0; }
.util-card .wp-block-post-title { font-family: var(--font-heading); font-size: var(--text-base); font-weight: 500; letter-spacing: 0; text-transform: none; margin-bottom: var(--gap-3xs); }
.util-card .wp-block-post-title a { color: inherit; text-decoration: none; }
.util-card .wp-block-post-excerpt p { font-size: var(--text-sm); color: var(--ink-50); }
.wp-block-query-pagination { display: flex; justify-content: space-between; gap: var(--gap-sm); margin-top: var(--gap-md); font-family: var(--font-heading); font-size: var(--text-sm); font-weight: 500; letter-spacing: 2px; text-transform: uppercase; }
.wp-block-query-pagination a { color: var(--ink-70); text-decoration: none; }
.wp-block-query-pagination a:hover { color: var(--ink); }

/* ---- buttons: always pills; black = workhorse, teal = the one conversion moment.
        .btn = hand-written markup; .wp-block-button__link = the Buttons block, variant via its Styles panel ---- */
.wp-block-buttons { display: flex; flex-wrap: wrap; gap: var(--gap-sm); }
.prose + .wp-block-buttons, .prose + .btn { margin-top: var(--gap-md); }   /* a button row after running text (the video pages' All videos): theme.json sets no block gap, so the step is written here (30 Oct) */
.container > * + .wp-block-buttons, .section__lede + .util-grid, .section__lede + .wp-block-group { margin-top: var(--gap-md); }   /* 2 Nov sweep: a button row after anything in a section (WYSE: Enquire sat on the price table) and a card grid after a section lede (Contact) */
.btn, .wp-block-button > .wp-block-button__link {
  font-family: var(--font-heading); font-size: var(--text-sm); font-weight: 500;
  letter-spacing: 2px; text-transform: uppercase;
  height: 52px; padding: 0 var(--gap-md); border-radius: var(--radius-full);
  cursor: pointer; text-decoration: none; display: inline-flex; align-items: center;
  border: 1px solid transparent;
  transition: color 0.2s var(--ease), background-color 0.2s var(--ease), border-color 0.2s var(--ease), transform 0.2s var(--ease);
}
.btn--primary, .btn--teal, .is-style-black .wp-block-button__link, .is-style-teal .wp-block-button__link { position: relative; overflow: hidden; }
.btn--primary::after, .btn--teal::after, .is-style-black .wp-block-button__link::after, .is-style-teal .wp-block-button__link::after {
  content: ''; position: absolute; top: 0; left: -70%; width: 45%; height: 100%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.28), transparent);
  transform: skewX(-20deg); transition: left 0.5s var(--ease);
}
.btn--primary:hover::after, .btn--teal:hover::after, .is-style-black .wp-block-button__link:hover::after, .is-style-teal .wp-block-button__link:hover::after { left: 120%; }
.btn--primary, .wp-block-button > .wp-block-button__link, .is-style-black .wp-block-button__link { background: var(--ted-black); color: var(--ted-white); }
.btn--primary:hover, .is-style-black .wp-block-button__link:hover { background: var(--ted-charcoal); transform: translateY(-1px); }
.btn--teal, .is-style-teal .wp-block-button__link { background: var(--ted-teal); color: var(--ted-black); }
.btn--teal:hover, .is-style-teal .wp-block-button__link:hover { background: var(--ted-teal-dark); transform: translateY(-1px); }
.btn--outline, .is-style-outline .wp-block-button__link { background: transparent; color: var(--ink); border-color: var(--ink-50); }
.btn--outline:hover, .is-style-outline .wp-block-button__link:hover { border-color: var(--ted-black); transform: translateY(-1px); }
.btn--glass, .is-style-glass .wp-block-button__link { background: transparent; color: var(--ted-white); border-color: var(--line-inverse); }
.btn--glass:hover, .is-style-glass .wp-block-button__link:hover { border-color: var(--ted-white); transform: translateY(-1px); }
.btn--ghost, .is-style-ghost .wp-block-button__link { background: transparent; color: var(--ink-70); padding-left: 0; padding-right: 0; }
.btn--ghost:hover, .is-style-ghost .wp-block-button__link:hover { color: var(--ink); }
.btn--ghost::after, .is-style-ghost .wp-block-button__link::after { content: " \2192"; display: inline-block; margin-left: var(--gap-2xs); transition: transform 0.25s var(--ease); }
.btn--ghost:hover::after, .is-style-ghost .wp-block-button__link:hover::after { transform: translateX(4px); }
.section--dark .is-style-ghost .wp-block-button__link { color: var(--ink-inverse-80); }
.section--dark .is-style-ghost .wp-block-button__link:hover { color: var(--ted-white); }

/* ---- bento (Quooker front-page pattern) with + popups ---- */
.bento { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: var(--row-bento); gap: var(--gap-sm); }
.bento__tile { position: relative; border-radius: var(--radius-lg); overflow: hidden; display: block; text-decoration: none; color: inherit; }
.bento__tile.is-linked { cursor: pointer; }
.bento__tile:focus-within { outline: 2px solid var(--ted-teal); outline-offset: 3px; }
.bento__img { position: absolute; inset: 0; }
.bento__img img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.6s var(--ease); }
.bento__tile:hover .bento__img img, .bento__tile:focus-within .bento__img img { transform: scale(1.05); }
/* Focal point: the BubbleSpa handset sits left of frame, so narrow crops (4:5 cards) anchor left of centre */
img[src*="bubblespa-cover"] { object-position: 10% 50%; }
img[src*="home-cover-shower"] { object-position: 50% 53%; }
@media (max-width: 768px) { img[src*="home-cover-shower"] { object-position: 100% 50%; } }
img[src*="togo-kit-brass"] { object-position: 50% 78%; }
@media (max-width: 768px) { img[src*="retrofit-header-retro-oval"] { object-position: 88% 50%; } }   /* the Retro Oval sits at 73% across the 16:10 frame; anchoring the cover crop at 88% lands it about 62% across a 390px phone, in frame and clear of the title on the left (worked from the crop maths 30 Oct; confirm on the eyeball) */
.bento__tile:hover .bento__plus, .bento__tile:focus-within .bento__plus { background: var(--ted-teal); transform: rotate(90deg) scale(1.1); }
.bento__label a, .bento__tile--text h3 a { color: inherit; text-decoration: none; }
.bento__label a:focus-visible, .bento__tile--text h3 a:focus-visible { outline: none; }
.bento__tile--lg { grid-column: span 2; grid-row: span 2; }
.bento__tile--wide { grid-column: span 2; }
.bento__tile--text { background: var(--surface-warm); padding: var(--gap-sm); display: flex; flex-direction: column; justify-content: flex-end; }
.bento__tile--text h3 { font-family: var(--font-heading); font-weight: 300; letter-spacing: 0.05em; text-transform: uppercase; font-size: var(--text-xl); text-wrap: balance; }
.bento__label { position: absolute; left: var(--gap-sm); bottom: var(--gap-sm); color: var(--ted-white); font-family: var(--font-heading); font-weight: 500; font-size: var(--text-sm); letter-spacing: 2px; text-transform: uppercase; text-shadow: 0 1px 8px rgba(0, 0, 0, 0.5); }
.bento__plus {
  position: absolute; right: var(--gap-xs); bottom: var(--gap-xs); z-index: 2;
  width: 36px; height: 36px; border-radius: var(--radius-circle); border: none; cursor: pointer;
  background: rgba(255, 255, 255, 0.92); color: var(--ted-black);
  font-size: var(--text-xl); line-height: 1; display: flex; align-items: center; justify-content: center;
  transition: transform 0.6s var(--ease-spring), background-color 0.2s var(--ease);
}
.bento__plus:hover { background: var(--ted-teal); }
/* Hover: a quarter turn with a spring, so the + wakes up and settles. Open: the + becomes a x. */
.bento__tile.open .bento__plus, .bento__tile.open:hover .bento__plus, .bento__tile.open:focus-within .bento__plus { transform: rotate(45deg); }
.bento__pop {
  position: absolute; inset: 0; z-index: 1; padding: var(--gap-sm);
  background: rgba(243, 239, 233, 0.96); opacity: 0; pointer-events: none;
  transition: opacity 0.25s var(--ease); display: flex; flex-direction: column; justify-content: center;
}
.bento__tile.open .bento__pop { opacity: 1; pointer-events: auto; }
.bento__pop h4 { font-family: var(--font-heading); font-weight: 500; font-size: var(--text-base); margin-bottom: var(--gap-2xs); }
.bento__pop p { font-size: var(--text-sm); color: var(--ink-70); }
@media (max-width: 768px) { .bento { grid-template-columns: repeat(2, 1fr); } }

/* ---- product series cards (the dark photographic moments) ---- */
.card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--gap-sm); }
/* Six collections sit three by two - never five and an orphan */
.card-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 900px) { .card-grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .card-grid--3 { grid-template-columns: minmax(0, 1fr); } }
.series-card { position: relative; border-radius: var(--radius-lg); overflow: hidden; aspect-ratio: 4 / 5; display: flex; flex-direction: column; justify-content: flex-end; padding: var(--gap-sm); background: var(--ted-charcoal); }
.series-card__img { position: absolute; inset: 0; }
.series-card__img img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.6s var(--ease); }
.series-card:hover .series-card__img img, .series-card:focus-within .series-card__img img { transform: scale(1.05); }
.series-card::after { content: ''; position: absolute; inset: 0; background: linear-gradient(to top, rgba(10, 10, 10, 0.6) 0%, transparent 55%); }
.series-card__name { position: relative; z-index: 1; font-family: var(--font-heading); font-weight: 300; letter-spacing: 0.08em; text-transform: uppercase; font-size: var(--text-xl); color: var(--ted-white); }
/* The subtext is folded away at rest; on hover (or keyboard focus) it unfolds beneath the name, which rises to make room. */
.series-card__name small, .series-card__sub { position: relative; z-index: 1; display: block; font-family: var(--font-body); font-weight: 400; font-size: var(--text-sm); line-height: 1.3; color: var(--ink-inverse-70); letter-spacing: 0; text-transform: none; }
.series-card__sub { max-height: 0; overflow: hidden; opacity: 0; transform: translateY(var(--gap-tight)); margin-top: 0; transition: max-height 0.5s var(--ease), opacity 0.4s var(--ease), transform 0.5s var(--ease), margin-top 0.5s var(--ease); }
.series-card:hover .series-card__sub, .series-card:focus-within .series-card__sub { max-height: calc(4 * 1.3em); opacity: 1; transform: none; margin-top: var(--gap-2xs); }
@media (hover: none) { .series-card__sub { max-height: calc(4 * 1.3em); opacity: 1; transform: none; margin-top: var(--gap-2xs); } }
.series-card .wp-block-buttons { position: relative; z-index: 1; margin-top: var(--gap-sm); }
.series-card__cta, .is-style-card .wp-block-button__link { position: relative; z-index: 1; isolation: isolate; overflow: hidden; height: auto; background: transparent; font-size: var(--text-xs); color: var(--ted-white); border: 1px solid var(--line-inverse); border-radius: var(--radius-full); padding: var(--gap-2xs) var(--gap-sm); font-family: var(--font-heading); font-weight: 500; letter-spacing: 2px; text-transform: uppercase; text-decoration: none; transition: color 0.3s var(--ease), border-color 0.3s var(--ease); }
.series-card__cta { margin-top: var(--gap-sm); align-self: flex-start; }
/* Teal fill swipes in from the left - the card's whole surface is the trigger, as is the pill itself. */
.series-card__cta::before, .is-style-card .wp-block-button__link::before { content: ''; position: absolute; inset: 0; z-index: -1; background: var(--ted-teal); transform: translateX(-101%); transition: transform 0.4s var(--ease); }
.series-card:hover .series-card__cta, .series-card:focus-within .series-card__cta, .series-card__cta:hover,
.series-card:hover .is-style-card .wp-block-button__link, .series-card:focus-within .is-style-card .wp-block-button__link, .is-style-card .wp-block-button__link:hover { border-color: var(--ted-teal); color: var(--ted-black); transform: none; }
.series-card:hover .series-card__cta::before, .series-card:focus-within .series-card__cta::before, .series-card__cta:hover::before,
.series-card:hover .is-style-card .wp-block-button__link::before, .series-card:focus-within .is-style-card .wp-block-button__link::before, .is-style-card .wp-block-button__link:hover::before { transform: none; }
.series-card.is-linked { cursor: pointer; }

/* ---- range carousel: static wrapping .card-grid by default; components.js promotes it to a slow,
   looping, swipeable step carousel (one range every 8s) when JS runs and the visitor allows motion.
   Nav arrows + the toggle's progress ring are user-driven chrome, so they still work under
   prefers-reduced-motion - only the automatic timer and its ring animation are gated on that. ---- */
.range-carousel__viewport { position: relative; overflow: hidden; touch-action: pan-y; }
.range-carousel.is-live { display: flex; flex-wrap: nowrap; transition: transform 0.9s var(--ease); will-change: transform; }
.range-carousel.is-live.is-jumping, .range-carousel.is-live.is-dragging { transition: none; }
.range-carousel.is-live > .series-card { flex: 0 0 calc((100% - 2 * var(--gap-sm)) / 3); }
@media (max-width: 900px) { .range-carousel.is-live > .series-card { flex-basis: calc((100% - var(--gap-sm)) / 2); } }
@media (max-width: 560px) { .range-carousel.is-live > .series-card { flex-basis: 100%; } }

/* Edge nav: a slim hit zone at each side; on hover of the carousel each arrow slides in from its
   own edge (Richard, 24 Sept: subtle, not the cursor-follow). Touch uses swipe instead. */
.range-carousel__nav {
  position: absolute; z-index: 2; top: 0; bottom: 0; width: 15%; min-width: 56px; max-width: 120px;
  padding: 0; border: 0; background: none; cursor: pointer; overflow: hidden;
  display: flex; align-items: center; opacity: 0; transition: opacity 0.45s var(--ease);
}
.range-carousel__nav--prev { left: 0; justify-content: flex-start; }
.range-carousel__nav--next { right: 0; justify-content: flex-end; }
.range-carousel__nav svg {
  width: 40px; height: 40px; margin: var(--gap-sm); padding: 10px; box-sizing: border-box;
  border-radius: var(--radius-circle); border: 1px solid var(--line-inverse); background: rgba(10, 10, 10, 0.4);
  color: var(--ted-white); transition: border-color 0.2s var(--ease), background 0.2s var(--ease), transform 0.45s var(--ease);
}
.range-carousel__nav--prev svg { transform: translateX(-16px); }
.range-carousel__nav--next svg { transform: translateX(16px); }
.range-carousel__nav:hover svg, .range-carousel__nav:focus-visible svg { border-color: var(--ted-white); background: rgba(10, 10, 10, 0.6); }
.range-carousel__viewport:hover .range-carousel__nav, .range-carousel__nav:focus-visible { opacity: 1; }
.range-carousel__viewport:hover .range-carousel__nav svg, .range-carousel__nav:focus-visible svg { transform: translateX(0); }
@media (hover: none) { .range-carousel__nav { display: none; } }

/* Toggle: a plain ticking ring, no icon, no button chrome - Richard's call, 21 Sept. Still gates
   the automatic advance under prefers-reduced-motion and still pauses on hover/focus/hidden-tab. */
.range-carousel__toggle {
  position: absolute; z-index: 2; top: var(--gap-sm); right: var(--gap-sm);
  width: 36px; height: 36px; padding: 0; border-radius: var(--radius-circle);
  border: none; background: none; cursor: pointer;
}
.range-carousel__ring { display: block; width: 36px; height: 36px; transform: rotate(-90deg); pointer-events: none; }
.range-carousel__ring circle { fill: none; stroke-width: 2; }
.range-carousel__ring-track { stroke: var(--line-inverse); }
.range-carousel__ring-fill { stroke: var(--ted-teal); stroke-linecap: round; stroke-dasharray: 81.68; stroke-dashoffset: 81.68; }
.range-carousel__ring-fill.is-ticking { animation: range-carousel-tick 8s linear forwards; }
.range-carousel__toggle.is-paused .range-carousel__ring-fill { animation-play-state: paused; }
@keyframes range-carousel-tick { to { stroke-dashoffset: 0; } }
.range-carousel__icon { display: none !important; }

/* ---- warm stone editorial panel ---- */
.panel-warm { background: var(--surface-warm); border-radius: var(--radius-lg); padding: var(--gap-md); display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-md); align-items: center; }
.panel-warm img { width: 100%; height: auto; border-radius: var(--radius); display: block; }
.panel-warm h2, .panel-warm h3 { font-family: var(--font-heading); font-weight: 300; letter-spacing: 0.06em; text-transform: uppercase; font-size: var(--text-2xl); line-height: 1.15; text-wrap: balance; }
.panel-warm p { color: var(--ink-70); margin-top: var(--gap-sm); max-width: 50ch; }
.panel-warm .btn { margin-top: var(--gap-md); }
@media (max-width: 720px) { .panel-warm { grid-template-columns: 1fr; padding: var(--gap-sm); } }

/* ---- feature cards (the Quooker move: oversized light figures in brand colour) ---- */
.feature-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gap-sm); margin-top: var(--gap-md); }
@media (max-width: 900px) { .feature-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .feature-cards { grid-template-columns: 1fr; } }
.feature-card { background: var(--surface-warm); border-radius: var(--radius-lg); padding: var(--gap-md) var(--gap-sm); }
.feature-card .big { font-family: var(--font-heading); font-weight: 300; font-size: var(--text-3xl); color: var(--ted-teal); line-height: 1; }
.feature-card h3 { font-family: var(--font-heading); font-weight: 500; font-size: var(--text-base); letter-spacing: 0; text-transform: none; margin-top: var(--gap-sm); }
.feature-card p { font-size: var(--text-sm); color: var(--ink-50); margin-top: var(--gap-3xs); }
.feature-card svg { width: var(--icon-md); height: var(--icon-md); color: var(--ted-teal); display: block; }
.feature-card p.big { margin-top: 0; }
.section--stone .feature-card { background: var(--surface-raised); }

/* ---- call to action: one charcoal panel on stone in three columns - title · copy · the three pills ---- */
.cta-panel { background: var(--ted-charcoal); color: var(--ted-white); border-radius: var(--radius-lg); padding: var(--gap-lg) var(--gap-md); display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr) auto; gap: var(--gap-lg); align-items: center; }
.cta-panel .section__label { color: var(--ted-teal); }
.cta-panel .section__title { max-width: 16ch; }
.cta-panel .cta-panel__copy > p { color: var(--ink-inverse-80); }
.cta-panel .wp-block-buttons { flex-direction: column; align-items: stretch; gap: var(--gap-xs); justify-self: end; }
.cta-panel .wp-block-button__link { width: 100%; justify-content: center; }
@media (max-width: 900px) { .cta-panel { grid-template-columns: 1fr; gap: var(--gap-sm); padding: var(--gap-md) var(--gap-sm); } .cta-panel .wp-block-buttons { justify-self: stretch; margin-top: var(--gap-sm); } }

/* ---- trade partners: distributor logos on white cards ---- */
.partner-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--gap-sm); margin-top: var(--gap-md); }
.partner-card { background: var(--surface-raised); border: 1px solid var(--line-soft); border-radius: var(--radius); padding: var(--gap-md) var(--gap-sm); display: grid; place-items: center; gap: var(--gap-sm); }
.partner-card__logo { margin: 0; width: 100%; max-width: 220px; }
.partner-card__logo img { width: 100%; height: auto; }
.partner-card__link { font-family: var(--font-heading); font-size: var(--text-xs); font-weight: 500; letter-spacing: 2px; text-transform: uppercase; }
.partner-card__link a { color: var(--ink-70); text-decoration: none; }
.partner-card__link a:hover { color: var(--ink); }

/* ---- support utility cards ---- */
.util-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--gap-sm); }
.util-card { display: flex; flex-direction: column; text-decoration: none; color: inherit; background: var(--surface-raised); border: 1px solid var(--line-soft); border-radius: var(--radius); padding: var(--gap-sm); transition: border-color 0.2s var(--ease); }
.util-card .download { margin-top: auto; padding-top: var(--gap-xs); }
.util-card:hover, .util-card:focus-within { border-color: var(--ted-teal); }
.util-card.is-linked { cursor: pointer; }
.util-card svg { width: var(--icon-md); height: var(--icon-md); display: block; margin-bottom: var(--gap-xs); color: var(--ted-teal); }
.util-card h3 { font-family: var(--font-heading); font-size: var(--text-base); font-weight: 500; letter-spacing: 0; text-transform: none; margin-bottom: var(--gap-3xs); }
.util-card h3 a { color: inherit; text-decoration: none; }
.util-card h3 a:focus-visible { outline: none; }
.util-card p { font-size: var(--text-sm); color: var(--ink-50); }
.util-card__all { display: inline-block; margin-top: var(--gap-2xs); font-size: var(--text-sm); color: var(--ink-50); text-decoration: none; transition: color 0.2s var(--ease); }
.util-card__all::after { content: " \27F6"; display: inline-block; margin-left: var(--gap-2xs); transition: transform 0.25s var(--ease); }
.util-card__all:hover, .util-card__all:focus-visible { color: var(--ted-teal); }
.util-card__all:hover::after, .util-card__all:focus-visible::after { transform: translateX(4px); }

/* ---- footer: charcoal, four columns of clear links, legal strip ---- */
.site-footer { background: var(--ted-charcoal); color: var(--ink-inverse-80); padding-block: var(--gap-xl) var(--gap-md); }
.site-footer a { color: inherit; text-decoration: none; transition: color 0.2s var(--ease); }
.site-footer a:hover { color: var(--ted-teal); }
.site-footer__grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: var(--gap-lg) var(--gap-md); }
.site-footer__brand img { height: 34px; width: auto; }
.site-footer__brand p { margin-top: var(--gap-sm); max-width: 44ch; font-size: var(--text-sm); color: var(--ink-inverse-70); }
.site-footer__contact { list-style: none; margin-top: var(--gap-sm); display: grid; gap: var(--gap-2xs); font-size: var(--text-sm); }
.site-footer__contact li { display: flex; align-items: flex-start; gap: var(--gap-xs); }
.site-footer__contact svg { flex: none; width: var(--icon-xs); height: var(--icon-xs); color: var(--ted-teal); margin-top: calc((1.6em - var(--icon-xs)) / 2); }
.site-footer__contact a { color: var(--ted-white); }
.site-footer__credit { margin-left: var(--gap-sm); }
/* Socials: two quiet 36px targets under the contact lines. Marque: hairline-weight credential beside the copyright. */
.site-footer ul.site-footer__social { list-style: none; display: flex; gap: var(--gap-xs); margin-top: var(--gap-md); }
.site-footer__social a { display: grid; place-items: center; width: 36px; height: 36px; border: 1px solid var(--line-inverse-soft); border-radius: var(--radius-circle); color: var(--ink-inverse-70); transition: color 0.2s var(--ease), border-color 0.2s var(--ease); }
.site-footer__social a:hover, .site-footer__social a:focus-visible { color: var(--ted-teal); border-color: var(--ted-teal); }
.site-footer__social svg { width: var(--icon-xs); height: var(--icon-xs); }
.site-footer__legal { display: flex; align-items: center; gap: var(--gap-sm); }
.site-footer__marque { height: var(--icon-md); width: auto; opacity: 0.6; }
.site-footer h2 { font-family: var(--font-heading); font-size: var(--text-xs); font-weight: 500; letter-spacing: 2px; text-transform: uppercase; color: var(--ted-teal); margin-bottom: var(--gap-sm); }
.site-footer ul { list-style: none; display: grid; gap: var(--gap-xs); font-size: var(--text-sm); }
.site-footer__meta { margin-top: var(--gap-xl); padding-top: var(--gap-sm); border-top: 1px solid var(--line-inverse-soft); display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: var(--gap-sm); font-size: var(--text-xs); color: var(--ink-inverse-50); }
.site-footer__meta nav { display: flex; flex-wrap: wrap; gap: var(--gap-sm); }
@media (max-width: 900px) { .site-footer__grid { grid-template-columns: 1fr 1fr; } .site-footer__brand { grid-column: 1 / -1; } }
@media (max-width: 560px) { .site-footer__grid { grid-template-columns: 1fr; } .site-footer { padding-top: var(--gap-lg); } }

/* ---- product cutout cards (kit contract): white card, hairline, cutout image contained at 220px, teal border + gentle scale on hover.
        --photo = a photograph filling 4:3 (case studies, spray modes) ---- */
.product-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--gap-sm); margin-top: var(--gap-md); }
.product-grid--wide { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.product-grid--two { grid-template-columns: repeat(2, minmax(0, 1fr)); }   /* kit cards: room for the thumbnails under the picture; one across on a phone, below */
.product-grid--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 900px) { .product-grid--three { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Three across, then four (Retrofit's seven models): a 12-column track, the first row's cards span 4, the rest span 3. */
@media (min-width: 901px) {
  .product-grid--three-four { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  .product-grid--three-four > * { grid-column: span 3; }
  .product-grid--three-four > :nth-child(-n + 3) { grid-column: span 4; }
  /* The wider first row letterboxes the 4:3 photos; their ground is --ted-black, so the frame matches it. */
  .product-grid--three-four .wp-block-image img { background: var(--ted-black); }
}
@media (min-width: 561px) and (max-width: 900px) { .product-grid--three-four { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .product-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .product-grid--wide, .product-grid--two, .product-grid--three { grid-template-columns: 1fr; } }
.product-card { background: var(--surface-raised); border: 1px solid var(--line-soft); border-radius: var(--radius); padding: var(--gap-sm); display: flex; flex-direction: column; transition: border-color 0.2s var(--ease); }
.product-card:hover, .product-card:focus-within { border-color: var(--ted-teal); }
.product-card .wp-block-image { margin: 0 0 var(--gap-xs); overflow: hidden; border-radius: var(--radius); }
.product-card .wp-block-image img { width: 100%; height: 220px; object-fit: contain; display: block; transition: transform 0.4s var(--ease), opacity 0.22s var(--ease); }
.product-card .wp-block-image img.is-swapping { opacity: 0; }   /* tedSwapImage (components.js): out, swap, in */
.product-card:hover .wp-block-image img { transform: scale(1.04); }
.product-card--photo .wp-block-image img { aspect-ratio: 4 / 3; height: auto; object-fit: cover; }
.product-card h3 { font-family: var(--font-heading); font-weight: 500; font-size: var(--text-base); letter-spacing: 0; text-transform: none; }
.product-card p { font-size: var(--text-sm); color: var(--ink-70); margin-top: var(--gap-3xs); }
.product-card .product-card__code { font-size: var(--text-xs); color: var(--ink-50); letter-spacing: 1px; text-transform: uppercase; }
.product-card .product-card__price { font-family: var(--font-heading); font-weight: 300; font-size: var(--text-xl); color: var(--ink); margin-top: auto; padding-top: var(--gap-xs); }
.product-card .product-card__step { font-family: var(--font-heading); font-weight: 300; font-size: var(--text-2xl); color: var(--ted-teal); line-height: 1; margin: 0 0 var(--gap-2xs); }
.product-card .wp-block-buttons { margin-top: var(--gap-sm); }
.product-card .wp-block-button__link { height: 44px; padding: 0 var(--gap-sm); font-size: var(--text-xs); }
/* Data sheet: a quiet text link under the price and basket button - the spec-downloads grammar (label, arrow, underline on hover).
   Sentence case so it fits the two-up cards on a phone; there the arrow gives way to a resting underline. */
.product-card .product-card__sheet-row { margin-top: var(--gap-xs); }
.product-card__sheet { display: inline-flex; align-items: center; min-height: calc(var(--gap-sm) + var(--gap-3xs)); padding-block: var(--gap-3xs); font-family: var(--font-heading); font-size: var(--text-xs); font-weight: 500; color: var(--ink-70); text-decoration: none; text-underline-offset: var(--gap-3xs); transition: color 0.2s var(--ease); }
.product-card__sheet::after { content: " \27F6"; content: " \27F6" / ""; display: inline-block; margin-left: var(--gap-2xs); transition: transform 0.25s var(--ease); }
.product-card__sheet:hover, .product-card__sheet:focus-visible { color: var(--ink); text-decoration: underline; }
@media (prefers-reduced-motion: no-preference) { .product-card__sheet:hover::after, .product-card__sheet:focus-visible::after { transform: translateX(var(--gap-3xs)); } }
@media (max-width: 560px) { .product-card__sheet { text-decoration: underline; } .product-card__sheet::after { display: none; } }
/* ---- what's in the box (patterns/products.php + assets/js/kit.js, b03): a kit card's parts, a captioned picture each. Without
        script: a small grid under the card. With kit.js: the parts fold into a row of thumbnails under the card's picture, which
        swipes through the kit and its parts, the current caption on one line. Kit grids sit two across (product-grid--two). ---- */
.product-card .kit-box { margin-top: var(--gap-xs); }
.product-card .kit-box__label { font-size: var(--text-xs); color: var(--ink-50); letter-spacing: 1px; text-transform: uppercase; margin: 0 0 var(--gap-2xs); }
.product-card .kit-box__list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gap-2xs); }
@media (max-width: 560px) { .product-card .kit-box__list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.product-card .kit-box.is-enhanced .kit-box__list { display: none; }   /* the thumbnails carry the pictures and their names once kit.js has built them; a script that never ran leaves the list */
.product-card .kit-box__list .wp-block-image { margin: 0; }
.product-card .kit-box__list .wp-block-image img, .product-card:hover .kit-box__list .wp-block-image img { aspect-ratio: 1; height: auto; object-fit: contain; background: var(--surface-raised); transform: none; }
.product-card .kit-box__list .wp-element-caption { margin-top: var(--gap-3xs); font-size: var(--text-xs); color: var(--ink-70); text-align: left; }
.product-card .kit-box__note, .product-card .kit-box__also { margin-top: var(--gap-xs); font-size: var(--text-xs); color: var(--ink-70); }
.product-card .kit-box__current { min-height: 1lh; margin: 0 0 var(--gap-2xs); font-size: var(--text-sm); color: var(--ink-70); }
.product-card .finishes + .kit-box__label, .product-card .wp-block-image + .kit-box__label { margin-top: var(--gap-2xs); }   /* the label kit.js brings up under the picture (or the finish row) */
.product-card .kit-strip + .kit-box__note, .product-card .kit-strip + .kit-box__also, .product-card .kit-box__note + .kit-box__also { margin: 0 0 var(--gap-xs); }   /* the lines that qualify the thumbnails sit right under them */
.product-card .wp-block-image.is-part img, .product-card--photo .wp-block-image.is-part img { object-fit: contain; background: var(--surface-raised); }   /* a part is a cut-out or a white-ground photo: shown whole on white, never cropped like the room photo */
.product-card .wp-block-image { touch-action: pan-y pinch-zoom; }   /* kit.js reads sideways drags on the picture; up and down, and pinch, stay the browser's */
html.is-zoomed .product-card .wp-block-image, html.is-zoomed .lightbox { touch-action: auto; }   /* pinch-zoomed in: every drag pans, nothing steps */
.kit-strip { display: flex; flex-wrap: wrap; gap: var(--gap-2xs); margin: 0 0 var(--gap-xs); animation: ted-fade-in 0.3s var(--ease) both; }   /* arrives softly once kit.js has built it */
@keyframes ted-fade-in { from { opacity: 0; } to { opacity: 1; } }
.kit-strip__thumb { width: calc(var(--icon-md) * 2); height: calc(var(--icon-md) * 2); padding: var(--gap-3xs); border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-raised); cursor: pointer; transition: border-color 0.2s var(--ease), box-shadow 0.2s var(--ease); }
.kit-strip__thumb img { display: block; width: 100%; height: 100%; object-fit: contain; border-radius: calc(var(--radius) - var(--gap-3xs)); }
.kit-strip__thumb:hover { border-color: var(--ink-50); }
.kit-strip__thumb[aria-pressed="true"] { border-color: var(--ink); box-shadow: 0 0 0 1px var(--ink); }
.kit-strip__thumb:focus-visible { outline: 2px solid var(--ted-teal); outline-offset: 2px; }
.section--dark .product-card .kit-box__label { color: var(--ink-inverse-50); }
.section--dark .product-card .kit-box__list .wp-element-caption, .section--dark .product-card .kit-box__note, .section--dark .product-card .kit-box__also, .section--dark .product-card .kit-box__current { color: var(--ink-inverse-80); }
.section--dark .kit-strip__thumb { background: var(--ted-black); border-color: var(--line-inverse-soft); }
.section--dark .kit-strip__thumb[aria-pressed="true"] { border-color: var(--ted-white); box-shadow: 0 0 0 1px var(--ted-white); }
@media (prefers-reduced-motion: reduce) { .kit-strip { animation: none; } .kit-strip__thumb { transition: none; } }   /* a fade is not motion: the picture swap keeps its fade; nothing slides or scales */
/* ---- finish picker (inc/finishes.php + assets/js/finishes.js): thumbnails under a card's photo swap it to that finish.
   Chips are the TOGO button close-ups; a finish without one shows the product. */
.finishes { display: none; margin: 0 0 var(--gap-xs); }
html.js .finishes { display: block; }   /* set in the head before paint: the row holds its space from the first frame */
.product-card .finishes__now { font-size: var(--text-xs); color: var(--ink-70); margin: 0 0 var(--gap-2xs); }
.finishes__label { color: var(--ink-50); letter-spacing: 1px; text-transform: uppercase; margin-right: var(--gap-3xs); }
.finishes__chips { display: flex; flex-wrap: wrap; gap: var(--gap-2xs); }
.finishes__chip { width: var(--icon-md); height: var(--icon-md); padding: calc(var(--gap-3xs) / 2); border: 1px solid var(--line); border-radius: var(--radius-circle); background: var(--surface-raised); cursor: pointer; transition: border-color 0.2s var(--ease), box-shadow 0.2s var(--ease); }
.finishes__chip img { display: block; width: 100%; height: 100%; border-radius: var(--radius-circle); object-fit: contain; }
.finishes__chip--material img { object-fit: cover; object-view-box: inset(6% 34% 66% 34%); }   /* the plain metal above the icon; without support, the whole close-up */
.finishes__chip:hover { border-color: var(--ink-50); }
.finishes__chip[aria-pressed="true"] { border-color: var(--ink); box-shadow: 0 0 0 1px var(--ink); }
.section--dark .finishes__chip { background: var(--ted-black); border-color: var(--line-inverse-soft); }
.section--dark .finishes__chip:hover { border-color: var(--line-inverse); }
.section--dark .finishes__chip[aria-pressed="true"] { border-color: var(--ted-white); box-shadow: 0 0 0 1px var(--ted-white); }
.section--dark .product-card .finishes__now { color: var(--ink-inverse-80); }
.section--dark .finishes__label { color: var(--ink-inverse-50); }

.section--stone .product-card, .section--stone .util-card { border-color: transparent; }
.section--stone .product-card:hover, .section--stone .util-card:hover { border-color: var(--ted-teal); }

/* ---- finish swatches (ted/swatches): square colour tiles, the finish named beneath. Small tiles stretch to fill the row
        (seven sit across on desktop); large tiles hold their size, left to right. Tablets take fixed columns so a row
        never ends on a lone tile: three across, or four (--quad) for counts that three would orphan, like seven. Phones: two across. ---- */
.swatch-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: var(--gap-sm); margin-top: var(--gap-md); }
.swatch-grid--lg { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
@media (max-width: 960px) {
  .swatch-grid:not(.swatch-grid--lg) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .swatch-grid.swatch-grid--quad { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .swatch-grid:not(.swatch-grid--lg), .swatch-grid.swatch-grid--quad, .swatch-grid--lg { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.swatch .wp-block-image { margin: 0; border: 1px solid var(--line-soft); border-radius: var(--radius); overflow: hidden; }
.swatch .wp-block-image img { width: 100%; height: auto; aspect-ratio: 1; object-fit: cover; display: block; transition: transform 0.4s var(--ease); }
@media (prefers-reduced-motion: no-preference) { .swatch:hover .wp-block-image img { transform: scale(1.04); } }
.swatch h3 { margin-top: var(--gap-xs); font-family: var(--font-heading); font-size: var(--text-sm); font-weight: 500; line-height: 1.3; letter-spacing: 0; text-transform: none; }
.swatch .swatch__code { margin-top: var(--gap-3xs); font-size: var(--text-xs); color: var(--ink-70); letter-spacing: 1px; text-transform: uppercase; }
.swatch-grid--lg .swatch h3 { font-size: var(--text-base); }
.section--dark .swatch .wp-block-image { border-color: var(--line-inverse-soft); }
.section--dark .swatch h3 { color: var(--ted-white); }
.section--dark .swatch .swatch__code { color: var(--ink-inverse-70); }

/* ---- specification list: "Key: value" rows on hairlines, two columns wide ---- */
.spec-list { list-style: none; margin: var(--gap-md) 0 var(--gap-md); padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--gap-md); }
@media (max-width: 768px) { .spec-list { grid-template-columns: 1fr; } }
.spec-list li { padding: var(--gap-xs) 0; border-bottom: 1px solid var(--line-soft); font-size: var(--text-sm); color: var(--ink-70); }
.spec-list li strong { display: block; font-family: var(--font-heading); font-weight: 500; font-size: var(--text-xs); letter-spacing: 1px; text-transform: uppercase; color: var(--ink); margin-bottom: var(--gap-3xs); }

/* ---- data-sheet content brought onto the product page: pack contents, warranty badge, pressure/flow table, dimension + installation diagrams ---- */
.spec-subhead { font-family: var(--font-heading); font-size: var(--text-xs); font-weight: 500; letter-spacing: 1px; text-transform: uppercase; color: var(--ink-50); margin: var(--gap-lg) 0 var(--gap-xs); }
.spec-warranty { display: inline-flex; align-items: center; gap: var(--gap-2xs); margin-top: var(--gap-sm); padding: var(--gap-3xs) var(--gap-sm); border-radius: var(--radius-full); background: var(--ted-teal); font-family: var(--font-heading); font-size: var(--text-xs); font-weight: 500; letter-spacing: 1px; text-transform: uppercase; color: var(--ted-black); }
.data-table { margin-top: var(--gap-sm); overflow-x: auto; }
.data-table table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.data-table th, .data-table td { padding: var(--gap-2xs) var(--gap-xs) var(--gap-2xs) 0; border-bottom: 1px solid var(--line-soft); text-align: left; color: var(--ink-70); }
.data-table th { font-family: var(--font-heading); font-weight: 500; letter-spacing: 1px; text-transform: uppercase; font-size: var(--text-xs); color: var(--ink-50); }
.data-table tbody th { font-family: inherit; font-weight: 400; letter-spacing: normal; text-transform: none; font-size: inherit; color: var(--ink); }   /* row labels: body text, one step darker than the values */
.section--specs .split { align-items: start; }   /* a long spec beside drawings: both columns start at the top, no floating gap */
.section--specs .split__text > .wp-block-list:not(.spec-list):not(.spec-downloads) { margin: 0; padding-left: var(--gap-sm); font-size: var(--text-sm); color: var(--ink-70); }
.spec-diagrams { display: grid; gap: var(--gap-sm); }
.spec-diagrams figure { margin: 0; border: 1px solid var(--line); border-radius: var(--radius); padding: var(--gap-sm); background: var(--ted-white); }
.spec-diagrams img { width: 100%; height: auto; display: block; }
.spec-diagrams figcaption { margin-top: var(--gap-xs); font-family: var(--font-heading); font-size: var(--text-xs); font-weight: 500; letter-spacing: 1px; text-transform: uppercase; color: var(--ink-50); text-align: center; }
/* one data sheet per model: the files as rows on the spec-list hairlines, arrow like the support cards' "All files" */
.spec-downloads { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--gap-md); }
@media (max-width: 768px) { .spec-downloads { grid-template-columns: minmax(0, 1fr); } }
.spec-downloads li { border-bottom: 1px solid var(--line-soft); font-size: var(--text-sm); }
.spec-downloads a { display: block; padding: var(--gap-xs) 0; color: var(--ink); text-decoration: none; text-underline-offset: var(--gap-3xs); }   /* the whole row is the target */
.spec-downloads a::after { content: " \27F6"; display: inline-block; margin-left: var(--gap-2xs); transition: transform 0.25s var(--ease); }
.spec-downloads a:hover, .spec-downloads a:focus-visible { text-decoration: underline; }
.spec-downloads a:hover::after, .spec-downloads a:focus-visible::after { transform: translateX(var(--gap-3xs)); }

/* ---- finish feature (ted/finish-feature): one finish shown off on the dark tone - a tall room beside the words,
        a close-up under them. The room fills its column's height, so both columns finish together. ---- */
.finish-feature { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-xl); align-items: stretch; }
.finish-feature__room { position: relative; min-height: var(--media-max); }
.finish-feature__room .wp-block-image { position: absolute; inset: 0; }
.finish-feature__room img { width: 100%; height: 100%; object-fit: cover; border-radius: var(--radius-lg); }
.finish-feature__body { display: flex; flex-direction: column; justify-content: center; }
.finish-feature__detail { margin-top: var(--gap-lg); }
.finish-feature__detail img { width: 100%; height: auto; border-radius: var(--radius-lg); }
.split__text .finish-feature__codes { font-size: var(--text-xs); letter-spacing: 1px; text-transform: uppercase; }
@media (max-width: 900px) {
  .finish-feature { grid-template-columns: 1fr; gap: var(--gap-md); }
  .finish-feature__room { min-height: 0; }
  .finish-feature__room .wp-block-image { position: static; }
  .finish-feature__room img { height: auto; aspect-ratio: 4 / 5; }
}

/* ---- price table (the kit's spec-table grammar): hairline rows, first column left, the rest centred ---- */
.price-table { margin: var(--gap-md) 0 0; overflow-x: auto; }
.price-table table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); color: var(--ink-70); }
.price-table th, .price-table td { padding: var(--gap-xs); border-bottom: 1px solid var(--line-soft); text-align: center; }
.price-table th { font-family: var(--font-heading); font-weight: 500; font-size: var(--text-xs); letter-spacing: 1px; text-transform: uppercase; color: var(--ink); }
.price-table th:first-child, .price-table td:first-child { text-align: left; }
.price-table tr:last-child td { border-bottom: none; }
.price-table figcaption { text-align: left; font-size: var(--text-xs); color: var(--ink-50); margin-top: var(--gap-xs); }

/* ---- questions and answers: native details, hairline rows, a teal + that turns ---- */
.faq { margin-top: var(--gap-md); border-top: 1px solid var(--line-soft); }
.faq .wp-block-details { border-bottom: 1px solid var(--line-soft); }
.faq summary { list-style: none; cursor: pointer; padding: var(--gap-sm) 0; display: flex; justify-content: space-between; align-items: center; gap: var(--gap-sm); font-family: var(--font-heading); font-weight: 500; font-size: var(--text-base); color: var(--ink); }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: '+'; flex: none; width: var(--icon-sm); height: var(--icon-sm); border-radius: var(--radius-circle); border: 1px solid var(--line); display: grid; place-items: center; font-weight: 300; color: var(--ted-teal); transition: transform 0.3s var(--ease-spring), background 0.2s var(--ease); }
.faq details[open] summary::after { transform: rotate(45deg); background: var(--ted-teal); color: var(--ted-black); border-color: var(--ted-teal); }
.faq summary:hover::after { border-color: var(--ted-teal); }
.faq summary:focus-visible { outline: 2px solid var(--ted-teal); outline-offset: 4px; }
/* Smooth open and close (30 Oct 2026, Richard: "any accordions should be smooth, with ease in and out"). Where the browser can
   animate a details element (Chrome 131+: interpolate-size + ::details-content) this is the whole mechanism; elsewhere
   components.js animates the height by hand on the same token. Both paths stand down under prefers-reduced-motion:
   a height ease moves everything below the row, which is motion (WCAG 2.3.3). Richard's Windows reports reduce. */
@media (prefers-reduced-motion: no-preference) {
  :root { interpolate-size: allow-keywords; }
  .wp-block-details::details-content { height: 0; overflow: clip; transition: height 0.3s var(--ease-in-out), content-visibility 0.3s var(--ease-in-out) allow-discrete; }
  .wp-block-details[open]::details-content { height: auto; }
}
.faq .wp-block-details > :not(summary) { padding-bottom: var(--gap-sm); color: var(--ink-70); max-width: 65ch; }
.faq .wp-block-details > p + p { margin-top: 0; padding-top: 0; }

/* ---- section lede + the dark tone's ink ---- */
.section__lede { color: var(--ink-70); max-width: 60ch; margin-top: var(--gap-sm); }
.section--dark .section__lede { color: var(--ink-inverse-80); }
.section--dark .section__label { color: var(--ted-teal); }
.section--dark .product-card { background: var(--ted-black); border-color: var(--line-inverse-soft); }
.section--dark .product-card h3, .section--dark .product-card .product-card__price { color: var(--ted-white); }
.section--dark .product-card p { color: var(--ink-inverse-70); }
.section--dark .product-card__sheet { color: var(--ink-inverse-80); }
.section--dark .product-card__sheet:hover, .section--dark .product-card__sheet:focus-visible { color: var(--ted-white); }
.section--dark .spec-list li { color: var(--ink-inverse-70); border-color: var(--line-inverse-soft); }
.section--dark .spec-list li strong { color: var(--ted-white); }

/* ---- video: self-hosted poster and one play control; the player iframe arrives only on request ---- */
.video { position: relative; aspect-ratio: 16 / 9; border-radius: var(--radius-lg); overflow: hidden; background: var(--ted-charcoal); margin-top: var(--gap-md); }
.video img, .video iframe { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border: 0; }
.video__play { position: absolute; inset: 0; display: grid; place-items: center; background: linear-gradient(to top, rgba(10, 10, 10, 0.55), transparent 60%); color: var(--ted-white); }
.video__play > span:first-child { width: 72px; height: 72px; border-radius: var(--radius-circle); background: var(--ted-teal); color: var(--ted-black); display: grid; place-items: center; transition: transform 0.3s var(--ease-spring); }
.video__play svg { width: var(--icon-sm); height: var(--icon-sm); margin-left: 3px; }
.video__play:hover > span:first-child, .video__play:focus-visible > span:first-child { transform: scale(1.08); }
.video__play:focus-visible { outline: 2px solid var(--ted-teal); outline-offset: -6px; }
.video-card .wp-block-post-featured-image { margin: 0 0 var(--gap-xs); border-radius: var(--radius); overflow: hidden; aspect-ratio: 16 / 9; background: var(--ted-charcoal); }
.video-card .wp-block-post-featured-image img { width: 100%; height: 100%; object-fit: cover; }

/* ---- archive cards: range term, code, contained thumbnail, download pills ---- */
.download { display: flex; flex-wrap: wrap; gap: var(--gap-2xs); margin-top: var(--gap-sm); }
.download a { display: inline-flex; align-items: center; gap: var(--gap-2xs); height: 40px; padding: 0 var(--gap-sm); border-radius: var(--radius-full); border: 1px solid var(--line); font-family: var(--font-heading); font-size: var(--text-xs); font-weight: 500; letter-spacing: 1px; text-transform: uppercase; color: var(--ink); text-decoration: none; transition: border-color 0.2s var(--ease), background 0.2s var(--ease); }
.download a:hover, .download a:focus-visible { border-color: var(--ted-teal); background: var(--ted-teal); }
.download a small { font-weight: 400; letter-spacing: 0; text-transform: none; color: var(--ink-50); }
.download a:hover small { color: var(--ink-70); }
.util-card .product-card__code { font-size: var(--text-xs); color: var(--ink-50); letter-spacing: 1px; text-transform: uppercase; margin-bottom: var(--gap-3xs); }
.util-card .wp-block-post-featured-image { margin: 0 0 var(--gap-xs); border-radius: var(--radius); overflow: hidden; background: var(--surface-warm); }
.util-card .wp-block-post-featured-image img { width: 100%; height: 160px; object-fit: contain; }
.util-card .wp-block-post-terms { font-size: var(--text-xs); color: var(--ted-teal); letter-spacing: 1px; text-transform: uppercase; margin-bottom: var(--gap-3xs); }
.util-card .wp-block-post-terms a { color: inherit; text-decoration: none; }
.util-card p a { color: var(--ink); text-decoration: none; }
.util-card p a:hover { color: var(--ted-teal); }
.section__label a { color: inherit; text-decoration: none; }

/* ---- click to enlarge, and step through a set (assets/js/lightbox.js): every product grid, any .zoomable group and any gallery
        block open full size in a dialog. The frame is white (cutouts are not transparent-safe on the dark), the picture fades in
        once it has loaded. A set (lightbox--set) adds previous / next and a caption; on a phone the arrows sit along the bottom
        so they never cover the picture. ---- */
.zoom-trigger { display: block; width: 100%; padding: 0; border: 0; border-radius: inherit; background: none; cursor: zoom-in; }
.zoom-trigger:focus-visible { outline-offset: calc(var(--gap-3xs) * -1); }   /* inside the box: the figure around it clips an outer ring */
html.lightbox-open { overflow: hidden; scrollbar-gutter: stable; }   /* the page behind does not shift when its scrollbar goes */
.lightbox { position: fixed; inset: 0; width: 100%; height: 100%; max-width: none; max-height: none; margin: 0; padding: var(--gap-xl) var(--gap-sm); border: 0; background: transparent; touch-action: pan-y pinch-zoom; }
.lightbox[open] { display: grid; place-items: center; animation: lightbox-in 0.3s var(--ease) both; }
.lightbox::backdrop { background: var(--ink-70, rgba(10, 10, 10, 0.75)); }   /* ::backdrop only inherits custom properties in newer browsers: the fallback is the token's own value */
@keyframes lightbox-in { from { opacity: 0; } to { opacity: 1; } }
.lightbox__frame { display: grid; justify-items: center; gap: var(--gap-xs); margin: 0; max-width: 100%; transition: opacity 0.22s var(--ease), transform 0.22s var(--ease); }   /* the same length as a card's picture swap: a step reads as one movement, not two */
.lightbox.is-loading .lightbox__frame { opacity: 0; transform: translateX(calc(var(--lightbox-dir, 0) * -1 * var(--gap-sm))); }   /* out the way we are going; in from the other side (lightbox.js flips --lightbox-dir while unseen) */
.lightbox__frame.is-jumping { transition: none; }
.lightbox__img { max-width: 100%; max-height: calc(100dvh - 2 * var(--gap-xl)); width: auto; height: auto; padding: var(--gap-xs); border-radius: var(--radius-lg); background: var(--surface-raised); }
.lightbox--set .lightbox__img { max-height: calc(100dvh - 2 * var(--gap-xl) - var(--gap-xs) - var(--lightbox-caption, var(--gap-lg))); }
.lightbox__caption { display: none; max-width: 65ch; padding: var(--gap-xs) var(--gap-sm); border-radius: var(--radius); background: var(--ink-70); color: var(--ted-white); font-size: var(--text-sm); line-height: 1.5; text-align: center; text-wrap: balance; }   /* its own backing: the page's words show through the backdrop otherwise */
.lightbox--set .lightbox__caption { display: block; }
.lightbox__live { display: block; }
.lightbox__title { display: block; font-family: var(--font-heading); font-weight: 500; font-size: var(--text-base); }
.lightbox__text { display: block; margin-top: var(--gap-3xs); color: var(--ink-inverse-80); }
.lightbox__text:empty { display: none; }
.lightbox__note { display: block; margin-top: var(--gap-2xs); color: var(--ink-inverse-80); }   /* a kit's "Also in the box" line, under every slide of that kit */
.lightbox__note:empty { display: none; }
.lightbox__count { display: block; margin-top: var(--gap-2xs); color: var(--ink-inverse-80); font-size: var(--text-xs); letter-spacing: 1px; text-transform: uppercase; }
.lightbox__close, .lightbox__prev, .lightbox__next { position: absolute; z-index: 1; width: calc(var(--icon-sm) * 2); height: calc(var(--icon-sm) * 2); display: grid; place-items: center; padding: 0; border: 1px solid var(--line-inverse); border-radius: var(--radius-circle); background: var(--ink-70); color: var(--ted-white); cursor: pointer; transition: border-color 0.3s var(--ease), color 0.3s var(--ease); }   /* 48px targets; the 75% backing keeps them readable over a white cut-out */
.lightbox__close { top: var(--gap-sm); right: var(--gap-sm); }
.lightbox__prev, .lightbox__next { display: none; top: 50%; transform: translateY(-50%); }
.lightbox--set .lightbox__prev, .lightbox--set .lightbox__next { display: grid; }
.lightbox__prev { left: var(--gap-sm); }
.lightbox__next { right: var(--gap-sm); }
.lightbox__close:hover, .lightbox__prev:hover, .lightbox__next:hover { border-color: var(--ted-teal); color: var(--ted-teal); }
.lightbox__close:focus-visible, .lightbox__prev:focus-visible, .lightbox__next:focus-visible { outline: 2px solid var(--ted-teal); outline-offset: 3px; }
.lightbox__close svg, .lightbox__prev svg, .lightbox__next svg { width: var(--icon-sm); height: var(--icon-sm); }
@media (max-width: 768px) {
  .lightbox--set { padding-bottom: calc(var(--gap-xl) + var(--gap-md)); }
  .lightbox--set .lightbox__img { max-height: calc(100dvh - 2 * var(--gap-xl) - var(--gap-md) - var(--gap-xs) - var(--lightbox-caption, var(--gap-lg))); }
  .lightbox__prev, .lightbox__next { top: auto; bottom: var(--gap-sm); transform: none; }
}
@media (prefers-reduced-motion: reduce) { .lightbox[open] { animation: none; } .lightbox.is-loading .lightbox__frame { transform: none; } }   /* a fade stays; the slide does not */
