/* ==========================================================================
   SOLAR SHIELD, Design System
   Blinds. Shades. Solutions.  Kansas City + Peoria / Central Illinois

   Structure
     01  Tokens
     02  Reset & base
     03  Typography
     04  Layout primitives
     05  Motion
     06  Buttons & links
     07  Region switcher
     08  Header & navigation
     09  Hero
     10  Sections & blocks
     11  Cards
     12  Media & video
     13  Proof, reviews, stats
     14  Forms
     15  CTA band & footer
     16  Utilities
   ========================================================================== */

/* ── 01 TOKENS ───────────────────────────────────────────────────────────── */
:root {
  /* Brand teal, sampled from the logo artwork */
  --ss-teal-900: #0A2430;
  --ss-teal-800: #0E3546;
  --ss-teal-700: #155F72;
  --ss-teal-600: #19748B;
  --ss-teal-500: #1E89A4;
  --ss-teal-300: #52ACC2;
  --ss-teal-100: #DCEDF2;

  /* Brand orange, sampled from the sunburst */
  --ss-sun-600: #E5760A;
  --ss-sun-500: #FF8901;
  --ss-sun-400: #FFA940;
  --ss-sun-100: #FFE9D0;

  /* Semantic, not brand. The one thing orange cannot say on a booking page is
     "done", because orange is what the visitor is looking for to find the next
     thing to press. Used only on confirmation ticks. */
  --ss-ok: #17924F;

  /* Paper */
  --ss-sand-50:  #FBF7F1;
  --ss-sand-100: #F5EFE6;
  --ss-sand-200: #EBE1D4;
  --ss-sand-300: #DCCEBB;
  --ss-white: #FFFFFF;

  --ss-line: rgba(10, 36, 48, .12);
  --ss-line-soft: rgba(10, 36, 48, .07);
  --ss-line-dk: rgba(255, 255, 255, .16);

  --ss-text: var(--ss-teal-900);
  --ss-text-mid: #3D5A66;
  /* One shade darker than it was (#6B838D) so small grey text clears the
     WCAG AA 4.5:1 minimum on every light ground: sand 50, 100 and 200 and white. */
  --ss-text-dim: #556870;

  /* Type */
  --font-display: "Manrope", ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-body: "Manrope", ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  /* Spacing, 4px base */
  --sp-1: 4px;   --sp-2: 8px;   --sp-3: 12px;  --sp-4: 16px;
  --sp-5: 24px;  --sp-6: 32px;  --sp-7: 40px;  --sp-8: 56px;
  --sp-9: 72px;  --sp-10: 96px; --sp-11: 128px; --sp-12: 160px; --sp-13: 200px;

  --container: 1280px;
  --gutter: 24px;
  --measure: 68ch;

  /* Radius. Media and cards read cleaner with a real curve than a hairline. */
  --r-sm: 10px;
  --r-md: 14px;
  --r-pill: 999px;

  /* Elevation, one shadow, used consistently */
  --shadow: 0 2px 4px rgba(10, 36, 48, .04), 0 12px 32px -8px rgba(10, 36, 48, .12);
  --shadow-lift: 0 4px 8px rgba(10, 36, 48, .06), 0 20px 48px -12px rgba(10, 36, 48, .20);

  /* Motion */
  --ease-out-expo: cubic-bezier(.16, 1, .30, 1);
  --ease-slat: cubic-bezier(.65, 0, .35, 1);
  --ease-spring: cubic-bezier(.34, 1.4, .64, 1);
  --dur-micro: 180ms;
  --dur-base: 420ms;
  --dur-slow: 720ms;

  --header-h: 76px;
  --switch-h: 48px;
}

@media (min-width: 900px) {
  :root { --gutter: 48px; --header-h: 88px; }
}

/* ── 02 RESET & BASE ─────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + var(--switch-h) + var(--sp-5));
}

body {
  margin: 0;
  background: var(--ss-sand-50);
  color: var(--ss-text);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.65;
  font-weight: 400;
  letter-spacing: -.005em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

body.nav-open { overflow: hidden; }

/* Phones ignore overflow-x on body: one element a few pixels too wide let the
   whole page slide sideways and pushed the fixed menu drawer half off screen
   (Oct 2 2026). clip, unlike hidden, makes no scroll box, so sticky still works. */
main, .footer { overflow-x: clip; }

img, video, svg, picture { display: block; max-width: 100%; }
img, video { height: auto; }

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; padding: 0; }

hr { border: 0; border-top: 1px solid var(--ss-line); margin: var(--sp-8) 0; }

::selection { background: var(--ss-sun-100); color: var(--ss-teal-900); }

:focus-visible {
  outline: 2px solid var(--ss-sun-500);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip-link {
  position: absolute; left: 50%; top: -80px; transform: translateX(-50%);
  z-index: 200; padding: var(--sp-3) var(--sp-5);
  background: var(--ss-teal-900); color: #fff; border-radius: 0 0 var(--r-sm) var(--r-sm);
  font-weight: 700; font-size: 14px; text-decoration: none;
  transition: top var(--dur-micro) var(--ease-out-expo);
}
.skip-link:focus { top: 0; }

/* ── 03 TYPOGRAPHY ───────────────────────────────────────────────────────── */

/* The "Yes!" brand mark.
   Not a second typeface for the site. It is one word, set the way the company
   already sets it in its own marketing, and it appears in exactly one place:
   the YES Experience headline. The file is a four glyph subset, Y e s and the
   exclamation mark, 1.2KB, self hosted so there is no third party request and
   nothing to fall back to badly. Everything else on every page stays Manrope. */
@font-face {
  font-family: 'Yellowtail';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/yellowtail.woff2") format("woff2");
  unicode-range: U+21, U+59, U+65, U+73;
}
/* Inside a button the script sits on a fixed line box, so it takes a smaller
   step up and a nudge rather than the headline treatment. */
.btn .yes-script { font-size: 1.35em; margin-inline: 2px; transform: translateY(1px); }
/* The Yes! logotype inside a button, drawn as generated content. It is part of
   the brand mark, which WCAG 1.4.3 exempts from contrast, and the words are
   still in the button for screen readers (.vh). Drawn this way so automated
   checkers do not report the logo as a failure. */
.yes-script--mark::before { content: "Yes!"; content: "Yes!" / ""; }

.yes-script {
  font-family: 'Yellowtail', cursive;
  font-weight: 400;
  font-size: 1.28em;
  letter-spacing: 0;
  color: var(--ss-sun-500);
  /* A brush script hangs below its baseline and the exclamation leans hard
     right, so it needs room on that side or it touches the next word. The
     inline-block plus nudge sits it on the same line as the Manrope around it
     without the descender pushing the line box open. */
  display: inline-block;
  line-height: .78;
  padding-inline: .05em .26em;
  transform: translateY(.03em);
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -.035em;
  margin: 0 0 var(--sp-5);
  text-wrap: balance;
}

h1 { font-size: clamp(2.375rem, 5.6vw, 4.25rem); letter-spacing: -.04em; line-height: 1.02; }
h2 { font-size: clamp(1.875rem, 4vw, 3rem); letter-spacing: -.035em; line-height: 1.06; }
h3 { font-size: clamp(1.3125rem, 2vw, 1.625rem); letter-spacing: -.025em; line-height: 1.2; }
h4 { font-size: 1.1875rem; font-weight: 700; letter-spacing: -.02em; line-height: 1.3; }

p { margin: 0 0 var(--sp-5); }
p:last-child { margin-bottom: 0; }

.lead {
  font-size: clamp(1.0625rem, 1.6vw, 1.25rem);
  line-height: 1.55;
  letter-spacing: -.01em;
  color: var(--ss-text-mid);
}

.eyebrow {
  display: inline-flex; align-items: flex-end; gap: 10px;
  font-size: 15px; font-weight: 700; letter-spacing: -.005em;
  color: var(--ss-teal-600);
  margin: 0 0 var(--sp-4);
}
/* The rising sun from the logo, in place of the generic orange dash. */
.eyebrow::before {
  content: ""; width: 30px; height: 15px; flex: none; margin-bottom: .22em;
  background: url("/assets/brand/sun-mark.svg") center bottom / contain no-repeat;
}
.eyebrow.is-plain::before { display: none; }

.prose { max-width: var(--measure); }
/* Headings inside a reading column step down from the section scale, otherwise
   a migrated H2 arrives at display size and outweighs the page H1. */
.prose h2 {
  margin-top: var(--sp-9); margin-bottom: var(--sp-4);
  font-size: clamp(1.4375rem, 2.2vw, 1.8125rem); letter-spacing: -.03em; line-height: 1.18;
}
.prose h3 {
  margin-top: var(--sp-7); margin-bottom: var(--sp-3);
  font-size: clamp(1.125rem, 1.6vw, 1.3125rem); letter-spacing: -.022em; line-height: 1.3;
}
.prose > :first-child { margin-top: 0; }
.prose ul, .prose ol { margin: 0 0 var(--sp-5); padding-left: var(--sp-5); }
.prose li { margin-bottom: var(--sp-2); }
.prose li::marker { color: var(--ss-sun-500); font-weight: 700; }
.prose strong { font-weight: 700; color: var(--ss-teal-900); }
.prose blockquote {
  margin: var(--sp-7) 0; padding: var(--sp-2) 0 var(--sp-2) var(--sp-6);
  border-left: 3px solid var(--ss-sun-500);
  font-family: var(--font-display); font-size: 1.1875rem; line-height: 1.45;
  font-weight: 600; letter-spacing: -.02em;
}
/* Who said it. Sits under the quote at body scale so the name reads as a
   credit rather than as another line of the quotation. */
.prose blockquote > footer {
  display: block; margin-top: var(--sp-3);
  font-family: var(--font-body); font-size: 14px; font-weight: 600;
  letter-spacing: 0; line-height: 1.4;
  color: var(--ss-text-mid);
}
.prose blockquote > footer::before { content: "\2014\00a0"; }

/* Text colours on dark grounds */
.on-dark { color: #fff; }
.on-dark h1, .on-dark h2, .on-dark h3, .on-dark h4 { color: #fff; }
.on-dark .lead { color: rgba(255, 255, 255, .78); }
.on-dark .eyebrow { color: var(--ss-sun-400); }

/* ── 04 LAYOUT PRIMITIVES ────────────────────────────────────────────────── */
.container {
  width: 100%; max-width: var(--container);
  margin-inline: auto; padding-inline: var(--gutter);
}
.container--narrow { max-width: 940px; }
.container--wide { max-width: 1560px; }

.section { padding-block: var(--sp-10); }
@media (min-width: 900px) { .section { padding-block: var(--sp-12); } }
.section--tight { padding-block: var(--sp-9); }
.section--flush-top { padding-top: 0; }

.section--sand { background: var(--ss-sand-100); }
.section--white { background: var(--ss-white); }
.section--ink { background: var(--ss-teal-900); color: #fff; }
.section--teal { background: var(--ss-teal-700); color: #fff; }

/* Dark sections. They used to carry an angled band of faint orange stripes
   (sun through a blind); Tim asked on Sep 30 for it to go everywhere, as it
   read as haze over the dark tiles. The stacking below is kept because
   section layouts were built on it. */
.section--ink, .section--teal { position: relative; overflow: hidden; }
.section--ink > *, .section--teal > * { position: relative; z-index: 1; }

/* Louver rule, the slat motif, used as a divider */
.louver {
  height: 14px; width: 100%;
  background: repeating-linear-gradient(
    to bottom,
    var(--ss-line) 0 1px,
    transparent 1px 4px
  );
  opacity: .8;
}
.louver--dark { background: repeating-linear-gradient(to bottom, var(--ss-line-dk) 0 1px, transparent 1px 4px); }

.grid { display: grid; gap: var(--sp-5); }
@media (min-width: 640px)  { .g-sm-2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 900px)  {
  .g-md-2 { grid-template-columns: repeat(2, 1fr); }
  .g-md-3 { grid-template-columns: repeat(3, 1fr); }
  .g-md-4 { grid-template-columns: repeat(4, 1fr); }
  .g-md-5 { grid-template-columns: repeat(5, 1fr); }
  .grid { gap: var(--sp-6); }
}
@media (min-width: 1180px) { .g-lg-5 { grid-template-columns: repeat(5, 1fr); } }

/* Asymmetric editorial split: heading hangs left, body indents */
.split {
  display: grid; gap: var(--sp-6);
  align-items: start;
}
@media (min-width: 900px) {
  .split { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: var(--sp-9); }
  .split--wide-left { grid-template-columns: minmax(0, 6fr) minmax(0, 5fr); }
  .split--sticky > :first-child { position: sticky; top: calc(var(--header-h) + var(--sp-8)); }
  /* Two columns of unequal height read as an accident when both hang from the
     top. Centring the shorter one against the taller is what the client asked
     for, and a sticky column has to stay at the top to work at all. */
  .split:not(.split--sticky) { align-items: center; }
}

/* Alternating feature rows. Words one side, photography the other, and the
   sides swap row to row so the eye is walked down the page instead of being
   asked to read two columns at once.
   On a phone both rows read heading first, then picture, which is why the copy
   comes first in the markup and the media is moved by order, not by source. */
.altrow { display: grid; gap: var(--sp-6); align-items: center; }
.altrow + .altrow { margin-top: var(--sp-9); }
@media (min-width: 900px) {
  .altrow { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-9); }
  .altrow + .altrow { margin-top: var(--sp-11); }
  .altrow--media-left .altrow__media { order: -1; }
}
@media (min-width: 1180px) { .altrow { gap: var(--sp-10); } }
.altrow__copy .lead { margin-bottom: 0; }
.altrow__media { min-width: 0; }
/* One shared crop, so both rows sit on the same rhythm */
.altrow .slider__slide img, .altrow .baslider img { aspect-ratio: 4/3; }
@media (min-width: 900px) { .altrow .slider__slide img { aspect-ratio: 4/3; } }
/* Product name only. The long caption belongs on the product page. */
.altrow .slider__cap { padding: var(--sp-9) var(--sp-5) var(--sp-5); }
.altrow .slider__cap span { display: none; }
/* No dot rail under the frame. It cost forty pixels of photograph and said
   nothing the arrows and the counter do not. The counter moves inside. */
.altrow .slider__count {
  position: absolute; z-index: 3;
  right: var(--sp-4); bottom: var(--sp-4);
  padding: 5px var(--sp-3); border-radius: var(--r-pill);
  background: rgba(10, 36, 48, .62);
  color: #fff; font-size: 12px;
}
.altrow .baslider { box-shadow: var(--shadow-lift); }

/* Slat list. Used wherever a paragraph needs three facts pulled out of it
   without turning into another card grid. Hairline rules at an even interval,
   the louver rhythm, rather than a tick on every line. The ticks are kept for
   the Carefree Guarantee only, where they mean "promised in writing". */
.checks {
  list-style: none; margin: var(--sp-6) 0 0; padding: 0;
  display: grid; gap: 0;
}
.checks li {
  position: relative; padding: 11px 0;
  border-top: 1px solid var(--ss-line);
  font-size: 16px; line-height: 1.5; color: var(--ss-text-mid);
}
.checks li:last-child { border-bottom: 1px solid var(--ss-line); }
/* Plain framed photograph. No caption, no overlay, just a picture doing its
   job next to some words. Opens with the slat wipe like the rest of the
   photography on the page. */
.figbox {
  position: relative; overflow: hidden;
  border-radius: var(--r-md);
  box-shadow: var(--shadow);
  background: var(--ss-sand-200);
}
.figbox img, .figbox video { width: 100%; display: block; aspect-ratio: 16/10; object-fit: cover; }
.figbox.slat-reveal::after { border-radius: var(--r-md); }
.mb-5 { margin-bottom: var(--sp-5); }

/* Small caps heading for a block inside a section, below the h2 but above a
   list or a grid. Not a heading scale of its own, just a label. */
.mini-head {
  margin: 0 0 var(--sp-4);
  font-size: 14px; font-weight: 700; letter-spacing: -.005em;
  color: var(--ss-teal-600);
}
/* A ticked point that leads with a bold phrase then explains it */
.checks li b { color: var(--ss-teal-900); font-weight: 800; }

/* Where a list is carrying six facts rather than three, tighten it so the
   block still reads as one thing instead of a column of separate lines. */
.checks--tight { margin-top: var(--sp-5); gap: 0; }
.checks--tight li { font-size: 15.5px; }
/* Same list on a dark band */
.checks--dark li { color: rgba(255, 255, 255, .82); border-color: var(--ss-line-dk); }
/* Six points in a page header run two up once there is room, so the list does
   not push the buttons under the fold. */
@media (min-width: 700px) {
  .checks--2col { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--sp-6); }
  .checks--2col li:nth-last-child(2):nth-child(odd) { border-bottom: 1px solid var(--ss-line); }
  .checks--2col.checks--dark li:nth-last-child(2):nth-child(odd) { border-color: var(--ss-line-dk); }
}

/* The mirror of .checks. Used where the point is what goes wrong, so the mark
   is a muted dash rather than an orange tick. Reading a list of problems with
   approving orange ticks beside them is the wrong signal. */
.drawbacks {
  list-style: none; margin: var(--sp-5) 0 0; padding: 0;
  display: grid; gap: 0;
}
.drawbacks li {
  position: relative; padding: 11px 0;
  border-top: 1px solid var(--ss-line);
  font-size: 16px; line-height: 1.5; color: var(--ss-text-mid);
}
.drawbacks li:last-child { border-bottom: 1px solid var(--ss-line); }

.section-head { margin-bottom: var(--sp-8); max-width: 760px; }
.section-head--center { margin-inline: auto; text-align: center; }
/* For headings that carry a location and need the room to stay on two lines */
.section-head--wide { max-width: 980px; }
.section-head--center .eyebrow { justify-content: center; }
@media (min-width: 900px) { .section-head { margin-bottom: var(--sp-9); } }

/* Header row with an action pushed right */
/* The button follows the heading instead of being pinned opposite it. A
   head on the left with an outlined pill hard right, repeated section after
   section, is the most template looking row a page can have. */
.head-row {
  display: flex; flex-direction: column; gap: var(--sp-5);
  align-items: flex-start;
  margin-bottom: var(--sp-8);
}
.head-row .section-head { margin-bottom: 0; }

/* ── 05 MOTION ───────────────────────────────────────────────────────────── */
/* Reveals are opt-in, not opt-out. Content is visible by default and only
   hides once the inline head script confirms JS is running and motion is
   allowed. If the script or stylesheet fails, the page still reads. */
/* Slat open, image reveals like a blind lifting */
.slat-reveal { position: relative; overflow: hidden; }
html:not(.js-reveal) .slat-reveal::after { display: none; }
.slat-reveal::after {
  content: ""; position: absolute; inset: 0; z-index: 2;
  background: repeating-linear-gradient(
    to bottom,
    var(--ss-sand-50) 0 calc(100% / 7),
    transparent calc(100% / 7) calc(100% / 7)
  );
  background-size: 100% calc(100% / 7);
  transform-origin: top;
  transition: transform var(--dur-slow) var(--ease-slat), opacity var(--dur-base) linear;
  pointer-events: none;
}
.slat-reveal.is-in::after { transform: scaleY(0); opacity: 0; }
/* The dark variant has to replace the gradient, not sit a colour behind it.
   The base gradient is opaque sand, so setting background-color alone left the
   wipe flashing cream across a dark section on its way up. */
.slat-reveal--dark::after {
  background-image: repeating-linear-gradient(
    to bottom,
    var(--ss-teal-900) 0 calc(100% / 7),
    transparent calc(100% / 7) calc(100% / 7)
  );
  background-color: var(--ss-teal-900);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
  .slat-reveal::after { display: none; }
}

/* ── 06 BUTTONS & LINKS ──────────────────────────────────────────────────── */
a { color: var(--ss-teal-600); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--ss-teal-800); }
/* Buttons are excluded. Without the :not() this rule paints the label of a
   primary button sun orange on top of a sun orange pill, and turns the white
   label of a ghost button orange as well. A button carries its own colour. */
.on-dark a:not(.btn) { color: var(--ss-sun-400); }

.link-arrow {
  display: inline-block;
  font-weight: 700; font-size: 15px;
  color: var(--ss-teal-600);
  text-decoration: underline; text-decoration-thickness: 2px;
  text-decoration-color: var(--ss-sun-500); text-underline-offset: 5px;
  transition: color var(--dur-micro) var(--ease-out-expo);
}
.link-arrow:hover { color: var(--ss-teal-900); }
.on-dark .link-arrow { color: var(--ss-sun-400); }
.on-dark .link-arrow:hover { color: #fff; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: 48px; padding: 0 var(--sp-6);
  border-radius: var(--r-pill);
  font-weight: 700; font-size: 15px; letter-spacing: .02em;
  text-decoration: none; white-space: nowrap;
  border: 1.5px solid transparent;
  transition:
    background-color var(--dur-micro) var(--ease-out-expo),
    border-color var(--dur-micro) var(--ease-out-expo),
    color var(--dur-micro) var(--ease-out-expo),
    transform var(--dur-micro) var(--ease-out-expo),
    box-shadow var(--dur-micro) var(--ease-out-expo);
}
@media (min-width: 900px) { .btn { min-height: 52px; } }
/* Reflow (WCAG 1.4.10). On a narrow screen, or zoomed to 400%, a long label
   wraps inside its pill instead of pushing the page sideways. Only buttons
   that do not fit are affected; everything else looks as before. */
@media (max-width: 599px) {
  .btn { white-space: normal; text-align: center; max-width: 100%; padding-block: 10px; line-height: 1.3; }
}
/* Grid and flex children may shrink below their longest word. Without this a
   single long button set the width of the whole column on a phone. */
.split > *, .feature > *, .guarantee > *, .guarantee__grid > *, .videoblock > * { min-width: 0; }

.btn:active { transform: translateY(0); }

.btn--primary {
  background: var(--ss-sun-500);
  color: var(--ss-teal-900);
  box-shadow: 0 2px 0 rgba(10, 36, 48, .10);
}
.btn--primary:hover {
  background: var(--ss-sun-400); color: var(--ss-teal-900);
  box-shadow: 0 2px 0 rgba(10, 36, 48, .10);
}

.btn--secondary {
  border-color: var(--ss-teal-600); color: var(--ss-teal-700); background: transparent;
}
.btn--secondary:hover {
  background: var(--ss-teal-100); border-color: var(--ss-teal-800);
  color: var(--ss-teal-900);
}

.btn--ghost { border-color: var(--ss-line-dk); color: #fff; background: rgba(255,255,255,.04); }
.btn--ghost:hover { background: rgba(255,255,255,.12); border-color: rgba(255,255,255,.5); color: #fff; }

.btn--lg { min-height: 56px; padding: 0 var(--sp-7); font-size: 16px; }
.btn--block { width: 100%; }

.btn-row { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.btn-row--center { justify-content: center; }

/* Phone button carries the handset glyph */
.btn-tel::before {
  content: ""; width: 16px; height: 16px; flex: none; background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6.6 10.8a15.1 15.1 0 0 0 6.6 6.6l2.2-2.2c.3-.3.7-.4 1-.2 1.2.4 2.4.6 3.7.6.6 0 1 .4 1 1V20c0 .6-.4 1-1 1A17 17 0 0 1 3 4c0-.6.4-1 1-1h3.5c.6 0 1 .4 1 1 0 1.2.2 2.5.6 3.6.1.4 0 .8-.2 1.1l-2.3 2.1z'/%3E%3C/svg%3E") no-repeat center/contain;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6.6 10.8a15.1 15.1 0 0 0 6.6 6.6l2.2-2.2c.3-.3.7-.4 1-.2 1.2.4 2.4.6 3.7.6.6 0 1 .4 1 1V20c0 .6-.4 1-1 1A17 17 0 0 1 3 4c0-.6.4-1 1-1h3.5c.6 0 1 .4 1 1 0 1.2.2 2.5.6 3.6.1.4 0 .8-.2 1.1l-2.3 2.1z'/%3E%3C/svg%3E") no-repeat center/contain;
}

/* The number takes texts as well as calls, so every headline phone spot says so.
   Three shapes: inline on a button, stacked over a compact number, and a small
   caps label above a large one. */
.btn-tel__lbl { font-weight: 700; opacity: .88; }
@media (max-width: 380px) { .btn-tel__lbl { display: none; } }

.tel-stack { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; line-height: 1.15; }
.tel-stack__lbl {
  font-size: 11.5px; font-weight: 700;
  opacity: .78;
}

.tel-label {
  display: block; font-size: 12.5px; font-weight: 700;
  opacity: .78; margin-bottom: 2px;
}

/* ── 07 REGION SWITCHER ──────────────────────────────────────────────────── */
/* The switcher and the nav under it stick as one block, see .topbar */
.regionbar {
  background: var(--ss-teal-900);
  border-bottom: 1px solid rgba(255, 255, 255, .08);
  position: relative; z-index: 60;
}
.regionbar__inner {
  min-height: var(--switch-h);
  display: flex; align-items: center; justify-content: center;
  gap: var(--sp-4); padding-block: var(--sp-2);
  position: relative;
}
.regionbar__label {
  font-size: 13px; font-weight: 700;
  color: rgba(255, 255, 255, .55);
  display: none;
}
@media (min-width: 780px) { .regionbar__label { display: block; } }

.rswitch {
  position: relative; display: inline-flex; align-items: center;
  padding: 3px; gap: 2px;
  background: rgba(255, 255, 255, .07);
  border: 1px solid rgba(255, 255, 255, .16);
  border-radius: var(--r-pill);
}
.rswitch__thumb {
  position: absolute; top: 3px; bottom: 3px; left: 3px;
  border-radius: var(--r-pill);
  background: var(--ss-sun-500);
  transition:
    transform 420ms var(--ease-out-expo),
    width 420ms var(--ease-out-expo);
  will-change: transform, width;
  pointer-events: none;
}
.rswitch__opt {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 34px; padding: 0 var(--sp-4);
  border-radius: var(--r-pill);
  font-size: 13px; font-weight: 700; letter-spacing: .01em;
  color: rgba(255, 255, 255, .72);
  white-space: nowrap;
  transition: color var(--dur-micro) var(--ease-out-expo);
}
/* The options are links to the other region's page; they read as a toggle,
   not as text links, so no underline. */
.rswitch__opt, .rswitch__opt:hover, .rswitch__opt:focus-visible { text-decoration: none; }
.rswitch__opt:hover { color: #fff; }
.rswitch__opt[aria-current="true"] { color: var(--ss-teal-900); }
/* Until the script has placed the thumb, the current option carries the
   orange itself, so every page opens with the right area already lit and
   the thumb never slides in on page load. */
.rswitch:not(.is-ready) .rswitch__thumb { visibility: hidden; transition: none; }
.rswitch:not(.is-ready) .rswitch__opt[aria-current="true"] { background: var(--ss-sun-500); }
.rswitch__opt svg { width: 13px; height: 13px; flex: none; }

@media (max-width: 420px) {
  .rswitch__opt { padding: 0 var(--sp-3); font-size: 12px; }
  .rswitch__opt svg { display: none; }
}

/* Region-bound content cross-fade */
[data-region-swap] { transition: opacity 220ms var(--ease-out-expo); }
html.region-swapping [data-region-swap] { opacity: 0; }

/* Region specific fragments. Kansas City is the default, because a first time
   visitor has nothing in storage and the pre-paint script only stamps
   data-region when a choice has been made. Hiding both variants in that case
   would have left the sentence with a hole in it. */
/* !important is deliberate. Component rules like `.slider__cap span` are more
   specific than an attribute selector, and one of them was forcing the Illinois
   town back into view inside a Kansas City slider caption. Showing a visitor
   the wrong branch's towns is a correctness failure, not a styling preference,
   so this rule has to win everywhere without hunting down each override. */
[data-region-only="il"] { display: none !important; }
html[data-region="il"] [data-region-only="il"] { display: revert !important; }
html[data-region="il"] ul.chiplist[data-region-only="il"] { display: flex !important; }
/* Sections and block wrappers restore their own display, not an inline one. */
html[data-region="il"] section[data-region-only="il"],
html[data-region="il"] div[data-region-only="il"] { display: block !important; }
html[data-region="il"] [data-region-only="kc"] { display: none !important; }

/* ── 08 HEADER & NAVIGATION ──────────────────────────────────────────────── */
.header {
  position: relative; z-index: 50;
  background: var(--ss-sand-50);
  border-bottom: 1px solid var(--ss-line-soft);
  transition: box-shadow var(--dur-micro) var(--ease-out-expo),
              border-color var(--dur-micro) var(--ease-out-expo);
}
.header.is-stuck { box-shadow: 0 1px 0 var(--ss-line), 0 8px 24px -16px rgba(10,36,48,.35); }

/* The area switcher and the nav stick together as one block. Sticking them as
   a pair rather than separately means no measured offset to keep in step with
   the bar's real height, which changes with the type and the breakpoint. */
.topbar { position: sticky; top: 0; z-index: 60; }
/* Once the page has moved, the bar tightens so it gives the content more of
   the screen back. Nothing leaves, it just takes up less room. */
/* One duration and one curve across everything that moves, so the bar reads as
   a single object settling rather than four parts easing at their own pace. */
.regionbar__inner {
  transition: min-height 300ms var(--ease-out-expo),
              padding-block 300ms var(--ease-out-expo);
}
.header__inner { transition: min-height 300ms var(--ease-out-expo); }
.brand img { transition: height 300ms var(--ease-out-expo); }
.rswitch {
  transition: padding 300ms var(--ease-out-expo);
}
.rswitch__opt {
  transition: color 300ms var(--ease-out-expo),
              min-height 300ms var(--ease-out-expo),
              padding 300ms var(--ease-out-expo),
              font-size 300ms var(--ease-out-expo);
}
.topbar.is-compact .regionbar__inner { min-height: 38px; padding-block: 3px; }
.topbar.is-compact .rswitch__opt { min-height: 28px; padding-inline: var(--sp-3); }
.topbar.is-compact .header__inner { min-height: 62px; }
.topbar.is-compact .brand img { height: 38px; }
@media (min-width: 900px) {
  .topbar.is-compact .header__inner { min-height: 68px; }
  .topbar.is-compact .brand img { height: 44px; }
}
/* While the bar is resizing the thumb is redrawn every frame to stay glued to
   the button under it, so its own easing is taken off for the duration. */
.rswitch.is-tracking .rswitch__thumb { transition: none; }
@media (prefers-reduced-motion: reduce) {
  .regionbar__inner, .header__inner, .brand img, .rswitch, .rswitch__opt { transition: none; }
}

.header__inner {
  min-height: var(--header-h);
  display: flex; align-items: center; gap: var(--sp-5);
}

.brand { display: flex; align-items: center; gap: var(--sp-3); flex: none; text-decoration: none; }
.brand img { width: auto; height: 46px; }
@media (min-width: 900px) { .brand img { height: 54px; } }

.nav { display: none; margin-left: auto; }
@media (min-width: 1280px) { .nav { display: flex; align-items: center; gap: var(--sp-1); } }

.nav__item { position: relative; }
.nav__link {
  display: inline-flex; align-items: center; gap: 5px;
  padding: var(--sp-3) 10px;
  font-size: 14.5px; font-weight: 600; letter-spacing: -.01em;
  color: var(--ss-teal-900); text-decoration: none;
  white-space: nowrap;
  border-radius: var(--r-sm);
  transition: color var(--dur-micro) var(--ease-out-expo);
}
@media (min-width: 1320px) { .nav__link { padding: var(--sp-3) var(--sp-3); font-size: 15px; } }
.nav__link::after {
  /* Spans the whole nav item, chevron included. Inset to the text alone read
     as a rule that had been cut short. */
  content: ""; position: absolute; left: 0; right: 0; bottom: 6px;
  height: 2px; background: var(--ss-sun-500);
  transform: scaleX(0); transform-origin: right;
  transition: transform 340ms var(--ease-out-expo);
}
.nav__link:hover, .nav__item:focus-within > .nav__link { color: var(--ss-teal-600); }
.nav__link:hover::after,
.nav__item:hover > .nav__link::after,
.nav__link[aria-current="page"]::after,
.nav__link[data-section="active"]::after { transform: scaleX(1); transform-origin: left; }

/* You are on this page, or somewhere inside this section. */
.nav__link[aria-current="page"],
.nav__link[data-section="active"] { color: var(--ss-teal-600); }
/* The section you are inside reads at full strength, same as the hover. */

.drawer__sub[aria-current="page"] { color: var(--ss-sun-600); font-weight: 700; }
.drawer__toggle[data-section="active"] { color: var(--ss-teal-600); }
.nav__link .chev {
  width: 9px; height: 9px; flex: none;
  transition: transform var(--dur-micro) var(--ease-out-expo);
}
.nav__item:hover .chev { transform: rotate(180deg); }

/* Dropdown */
.nav__panel {
  position: absolute; top: calc(100% - 4px); left: 50%;
  transform: translateX(-50%) translateY(-6px);
  min-width: 280px; padding: var(--sp-3);
  background: var(--ss-white);
  border: 1px solid var(--ss-line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lift);
  opacity: 0; visibility: hidden;
  transition: opacity var(--dur-micro) var(--ease-out-expo),
              transform var(--dur-micro) var(--ease-out-expo),
              visibility 0s linear var(--dur-micro);
}
.nav__item:hover > .nav__panel,
.nav__item:focus-within > .nav__panel {
  opacity: 1; visibility: visible;
  transform: translateX(-50%) translateY(0);
  transition-delay: 0s;
}
.nav__panel--wide { min-width: 560px; display: grid; grid-template-columns: 1fr 1fr; gap: 2px; }

.nav__sub {
  display: block; padding: var(--sp-3) var(--sp-4);
  font-size: 14.5px; font-weight: 600; line-height: 1.3;
  color: var(--ss-teal-900); text-decoration: none;
  border-radius: var(--r-sm);
  transition: background-color 220ms var(--ease-out-expo),
              color 220ms var(--ease-out-expo);
}
.nav__sub small { display: block; font-weight: 400; font-size: 12.5px; color: var(--ss-text-dim); margin-top: 2px; }

/* The rule sits under the whole item, below the description line, rather than
   between the two lines where it read as an underline on the title alone.
   It wipes in from the left and retracts to the right, matching the top level. */
.nav__sub { position: relative; }
.nav__sub__t { display: block; }
.nav__sub::after {
  content: ""; position: absolute;
  left: var(--sp-4); right: var(--sp-4); bottom: calc(var(--sp-3) - 4px);
  height: 2px; background: var(--ss-sun-500);
  transform: scaleX(0); transform-origin: right;
  transition: transform 340ms var(--ease-out-expo);
}
.nav__sub:hover { background: var(--ss-sand-100); color: var(--ss-teal-900); }
.nav__sub:hover::after,
.nav__sub:focus-visible::after,
.nav__sub[aria-current="page"]::after {
  transform: scaleX(1); transform-origin: left;
}
.nav__sub[aria-current="page"] { background: var(--ss-sand-100); }

/* Product menu. A thumbnail of the real thing beside every name, because ten
   lines of text all beginning with a fabric type is slow to scan. Desktop only:
   the phone drawer is a plain list and stays that way.

   This sits after the .nav__sub rules on purpose. Both selectors carry the same
   weight, so declared earlier the display:block above would win and the layout
   would collapse back to a stack of full width photographs. */
.nav__panel--products {
  min-width: 720px; gap: var(--sp-1); padding: var(--sp-3);
  /* Anchored left rather than centred. Centred on a link near the start of the
     bar, a 720px panel hangs off the side of the window. */
  left: 0; transform: translateX(0) translateY(-6px);
}
.nav__item:hover > .nav__panel--products,
.nav__item:focus-within > .nav__panel--products { transform: translateX(0) translateY(0); }
/* Escape puts an open dropdown away until the pointer or focus leaves. */
.nav__item.is-dismissed > .nav__panel { opacity: 0 !important; visibility: hidden !important; }

.nav__sub--img { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-3); }
.nav__thumb {
  flex: none; width: 72px; height: 56px;
  border-radius: var(--r-sm); overflow: hidden;
  background: var(--ss-sand-200);
}
.nav__thumb img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform var(--dur-base) var(--ease-out-expo);
}
.nav__sub--img:hover .nav__thumb img { }
.nav__sub__c { min-width: 0; }
.nav__sub--img .nav__sub__t { font-size: 14.5px; }
/* The rule clears the thumbnail rather than starting under it */
.nav__sub--img::after {
  left: calc(72px + var(--sp-3) + var(--sp-3)); right: var(--sp-3);
  bottom: calc(var(--sp-2) - 2px);
}

@media (prefers-reduced-motion: reduce) {
  .nav__sub::after { transition: none; }
}

/* Two booking buttons plus the phone number leaves very little slack in a
   1280 bar, and a few pixels of font variance was enough to tip the row onto
   a second line. Nothing in here shrinks or wraps now, and the gap is tighter
   so there is real room rather than fifteen pixels of it. */
.header__actions {
  display: flex; flex-wrap: nowrap; align-items: center;
  gap: var(--sp-2); margin-left: auto; flex: none;
}
@media (min-width: 1280px) { .header__actions { margin-left: var(--sp-4); } }
.header__tel {
  display: none; align-items: center; gap: var(--sp-2); flex: none;
  font-weight: 800; font-size: 15.5px; letter-spacing: -.01em;
  color: var(--ss-teal-900); text-decoration: none;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.header__tel:hover { color: var(--ss-teal-600); }
@media (min-width: 780px) { .header__tel { display: inline-flex; } }
.header__cta { display: none; flex: none; white-space: nowrap; padding-inline: var(--sp-5); }
@media (min-width: 900px) { .header__cta { display: inline-flex; } }
/* Both booking buttons show from tablet width up (Tim, Oct 2 2026: Schedule
   Now vanished on tablets and small laptops). The full menu needs the bar's
   room, so it stays in the burger drawer until 1280px; at that width the
   menu, the phone number and both buttons fit. */
.header__cta--wide { display: none; }
@media (min-width: 900px) { .header__cta--wide { display: inline-flex; } }

/* Burger */
.burger {
  width: 44px; height: 44px; flex: none;
  display: grid; place-items: center;
  border: 1px solid var(--ss-line); border-radius: var(--r-sm);
  background: var(--ss-white);
}
@media (min-width: 1280px) { .burger { display: none; } }
.burger span {
  display: block; width: 20px; height: 2px; background: var(--ss-teal-900);
  border-radius: 2px; position: relative;
  transition: transform var(--dur-micro) var(--ease-out-expo),
              background-color var(--dur-micro) linear;
}
.burger span::before, .burger span::after {
  content: ""; position: absolute; left: 0; width: 20px; height: 2px;
  background: var(--ss-teal-900); border-radius: 2px;
  transition: transform var(--dur-base) var(--ease-out-expo), top var(--dur-micro) var(--ease-out-expo);
}
.burger span::before { top: -6px; }
.burger span::after { top: 6px; }
.burger[aria-expanded="true"] span { background: transparent; }
.burger[aria-expanded="true"] span::before { top: 0; transform: rotate(45deg); }
.burger[aria-expanded="true"] span::after { top: 0; transform: rotate(-45deg); }

/* Mobile drawer */
.drawer {
  position: fixed; inset: 0; z-index: 90;
  background: var(--ss-sand-50);
  display: flex; flex-direction: column;
  transform: translateX(100%);
  transition: transform var(--dur-base) var(--ease-out-expo);
  overflow-y: auto; overscroll-behavior: contain;
}
.drawer.is-open { transform: none; }
/* Off screen is not enough: closed, its links were still reachable with Tab and
   announced by screen readers. visibility waits for the slide out to finish. */
.drawer:not(.is-open) { visibility: hidden; transition: transform var(--dur-base) var(--ease-out-expo), visibility 0s linear var(--dur-base); }
@media (min-width: 1280px) { .drawer { display: none; } }
.drawer__top {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4); padding: var(--sp-4) var(--gutter);
  border-bottom: 1px solid var(--ss-line);
  position: sticky; top: 0; background: var(--ss-sand-50); z-index: 2;
}
.drawer__body { padding: var(--sp-5) var(--gutter) var(--sp-10); }
.drawer__group + .drawer__group { border-top: 1px solid var(--ss-line-soft); }
.drawer__toggle {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4); padding: var(--sp-4) 0;
  font-family: var(--font-display); font-size: 1.375rem; font-weight: 800; letter-spacing: -.03em;
  letter-spacing: -.02em; color: var(--ss-teal-900); text-align: left;
  text-decoration: none;
}
.drawer__toggle .chev { width: 12px; height: 12px; flex: none; transition: transform var(--dur-base) var(--ease-out-expo); }
.drawer__toggle[aria-expanded="true"] .chev { transform: rotate(180deg); }
.drawer__panel {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-base) var(--ease-out-expo);
}
.drawer__panel > div { overflow: hidden; }
.drawer__toggle[aria-expanded="true"] + .drawer__panel { grid-template-rows: 1fr; }
.drawer__sub {
  display: block; padding: var(--sp-3) 0 var(--sp-3) var(--sp-4);
  border-left: 2px solid var(--ss-line);
  font-size: 15px; font-weight: 600; color: var(--ss-text-mid); text-decoration: none;
}
.drawer__sub:hover { border-left-color: var(--ss-sun-500); color: var(--ss-teal-900); }
.drawer__foot { margin-top: var(--sp-7); display: grid; gap: var(--sp-3); }

/* Sticky mobile call bar */
.callbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
  display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
  background: var(--ss-line-dk);
  border-top: 1px solid rgba(255,255,255,.12);
  transform: translateY(100%);
  transition: transform var(--dur-base) var(--ease-out-expo);
  padding-bottom: env(safe-area-inset-bottom);
}
.callbar.is-visible { transform: none; }
@media (min-width: 900px) { .callbar { display: none; } }
/* The Podium text bubble pins itself to the bottom right corner, which on a
   phone is where the call bar's Book button sits. While the bar is showing,
   lift the bubble and its prompt above it. */
@media (max-width: 899px) {
  body:has(.callbar.is-visible) #podium-bubble,
  body:has(.callbar.is-visible) #podium-prompt {
    bottom: calc(58px + env(safe-area-inset-bottom)) !important;
    transition: bottom var(--dur-base) var(--ease-out-expo);
  }
}
.callbar a {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: 56px; font-weight: 700; font-size: 15px; text-decoration: none;
}
.callbar__tel { background: var(--ss-teal-900); color: #fff; font-variant-numeric: tabular-nums; }
.callbar__tel .tel-stack { align-items: center; }
.callbar__book { background: var(--ss-sun-500); color: var(--ss-teal-900); }

/* ── 09 HERO ─────────────────────────────────────────────────────────────── */
.hero {
  position: relative; color: #fff;
  background: var(--ss-teal-900);
  overflow: hidden;
}
/* Media and scrim stack above the section background, content above both. */
.hero__media { position: absolute; inset: 0; z-index: 0; }
.hero__media img, .hero__media video { width: 100%; height: 100%; object-fit: cover; }
/* Heavy on the left where the headline sits, light on the right so the
   installed work stays readable. Text contrast measured at the worst point. */
.hero__scrim {
  position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(96deg,
      rgba(10,36,48,.96) 0%,
      rgba(10,36,48,.94) 30%,
      rgba(10,36,48,.86) 47%,
      rgba(10,36,48,.48) 65%,
      rgba(10,36,48,.20) 83%,
      rgba(10,36,48,.13) 100%),
    linear-gradient(to top, rgba(10,36,48,.55) 0%, transparent 38%);
}
@media (max-width: 899px) {
  /* No room for a two-column read on a phone, so darken the whole frame */
  .hero__scrim {
    background:
      linear-gradient(to bottom, rgba(10,36,48,.86) 0%, rgba(10,36,48,.78) 45%, rgba(10,36,48,.90) 100%);
  }
}
.hero > .container { position: relative; z-index: 2; }
.hero__inner {
  position: relative;
  padding-block: var(--sp-9) var(--sp-10);
  max-width: 780px;
}
@media (min-width: 900px) { .hero__inner { padding-block: var(--sp-11) var(--sp-11); } }

/* The eyebrow is the product name on six of the seven hero slides, so it is
   doing real work and 12px was too quiet for it. Larger, with the tracking
   eased back a touch so the extra size does not stretch the line. */
.hero .eyebrow {
  font-size: 16px; gap: var(--sp-3);
  margin-bottom: var(--sp-6);
  color: var(--ss-teal-300);   /* the lighter teal: 6:1 on the hero, AA (was 3:1) */
}
@media (min-width: 900px) { .hero .eyebrow { font-size: 17px; } }
.hero .eyebrow::before { width: 34px; height: 17px; }

/* Held a step below the global h1 scale. At the full 4.25rem a headline with a
   place name in it ran to three lines, and because the deck is sized by its
   tallest slide every other slide then carried that extra height as a hole
   between its buttons and the line underneath. */
.hero h1, .hero .hero__h {
  font-size: clamp(2.25rem, 4.8vw, 3.75rem);
  margin-bottom: var(--sp-6);
  text-shadow: 0 2px 24px rgba(10, 36, 48, .45);
}
/* Held to 48 characters so the line never runs into the bright side of the photo */
.hero .lead {
  max-width: 48ch; margin-bottom: var(--sp-8);
  line-height: 1.62;
  color: rgba(255, 255, 255, .90);
  text-shadow: 0 1px 16px rgba(10, 36, 48, .55);
}

/* ── 09b HERO PRODUCT SLIDER ─────────────────────────────────────────────
   Six products sharing one frame. Photography cross fades underneath while
   the copy above it swaps on its own, slightly faster curve, so the words
   land before the picture has finished settling. The product rail along the
   bottom is both the control and a plain list of what the company sells.
   ------------------------------------------------------------------------ */
.hero--slider { display: flex; flex-direction: column; }
.hero--slider > .container { flex: 1 0 auto; }
/* The rail carries its own height and the deck is sized by the tallest slide,
   so the copy gives some of its padding back. The whole hero plus the rail has
   to clear a 900px laptop viewport, otherwise the products fall below the fold
   and the rail stops doing the one job it has. */
.hero--slider .hero__inner { padding-block: var(--sp-8) var(--sp-7); }
@media (min-width: 900px) {
  .hero--slider .hero__inner { padding-block: var(--sp-10) var(--sp-9); }
}

.hero__stage { position: absolute; inset: 0; z-index: 0; }
.hero__slide {
  position: absolute; inset: 0;
  opacity: 0; visibility: hidden;
  transition: opacity 900ms var(--ease-out-expo), visibility 0s linear 900ms;
}
.hero__slide.is-active {
  opacity: 1; visibility: visible;
  transition: opacity 900ms var(--ease-out-expo), visibility 0s linear 0s;
}
.hero__slide img { width: 100%; height: 100%; object-fit: cover; }
/* A slow drift rather than a keyframed pan. The resting state is the zoomed
   frame, so a slide that leaves eases back over eight seconds and never pops
   while it is fading.

   No will-change here on purpose. Six full bleed images each holding a
   promoted compositor layer costs more than the drift is worth, and the
   scrim above them stops compositing cleanly over the top. */
.hero__slide img {
  transform: scale(1.07);
  transition: transform 8600ms linear;
}
.hero__slide.is-active img { transform: scale(1); }

/* Every block of copy occupies the same grid cell, so the hero is sized once
   by the tallest slide and nothing below it moves as the copy changes. */
.hero__deck { display: grid; }
.hero__copy {
  grid-area: 1 / 1;
  visibility: hidden; pointer-events: none;
  transition: visibility 0s linear 620ms;
}
.hero__copy.is-active, .hero__copy.is-leaving { visibility: visible; transition-delay: 0s; }
.hero__copy.is-active { pointer-events: auto; }

/* The stagger. Eyebrow, headline, paragraph and buttons arrive in that order,
   about eighty milliseconds apart, which reads as one movement rather than
   four separate ones. */
.hero__copy > * {
  opacity: 0; transform: translateY(18px);
  transition:
    opacity 520ms var(--ease-out-expo),
    transform 680ms var(--ease-out-expo);
}
.hero__copy.is-active > * { opacity: 1; transform: none; }
.hero__copy.is-active > *:nth-child(1) { transition-delay: 140ms; }
.hero__copy.is-active > *:nth-child(2) { transition-delay: 220ms; }
.hero__copy.is-active > *:nth-child(3) { transition-delay: 300ms; }
.hero__copy.is-active > *:nth-child(4) { transition-delay: 380ms; }
/* Leaving copy lifts and clears together, quicker than it arrived */
.hero__copy.is-leaving > * {
  opacity: 0; transform: translateY(-12px);
  transition-duration: 300ms, 340ms;
  transition-delay: 0s;
}

/* Slides two through six use a paragraph rather than a heading, so the page
   keeps one h1. Matched to the h1 scale by hand. */
.hero__h {
  font-family: var(--font-display);
  font-size: clamp(2.375rem, 5.6vw, 4.25rem);
  font-weight: 800; line-height: 1.02; letter-spacing: -.04em;
  text-wrap: balance;
  margin: 0 0 var(--sp-5);
}

.hero__foot {
  margin-top: var(--sp-7); margin-bottom: 0;
  font-size: 14px; color: rgba(255,255,255,.66);
}
.hero__foot strong { color: #fff; font-weight: 700; }
.hero__tel {
  color: #fff; font-weight: 700; text-decoration: none;
  font-variant-numeric: tabular-nums;
  border-bottom: 1px solid rgba(255,255,255,.34);
  transition: border-color var(--dur-micro) var(--ease-out-expo);
}
.hero__tel:hover { border-bottom-color: #fff; }

/* Product rail */
.hero__rail {
  position: relative; z-index: 2;
  border-top: 1px solid rgba(255,255,255,.14);
  background: linear-gradient(to top, rgba(10,36,48,.42), transparent);
}
.hero__tabs {
  display: flex; gap: 0;
  overflow-x: auto; scrollbar-width: none;
  scroll-snap-type: x proximity;
  margin-inline: calc(var(--gutter) * -1);
  padding-inline: var(--gutter);
}
.hero__tabs::-webkit-scrollbar { display: none; }
@media (min-width: 900px) { .hero__tabs { margin-inline: 0; padding-inline: 0; } }

.hero__tab {
  flex: 0 0 auto; scroll-snap-align: start;
  display: block; text-align: left;
  background: none; border: 0; padding: 0 var(--sp-6) var(--sp-6) 0;
  font: inherit; font-size: 13px; font-weight: 700; letter-spacing: .01em;
  color: rgba(255,255,255,.7);   /* was .58, 4.5:1 minimum over the photo */
  cursor: pointer;
  transition: color var(--dur-micro) var(--ease-out-expo);
}
@media (min-width: 900px) { .hero__tab { flex: 1 1 0; padding-right: var(--sp-5); } }
.hero__tab:hover { color: rgba(255,255,255,.92); }
.hero__tab[aria-current="true"] { color: #fff; }
.hero__tab:focus-visible { outline: 2px solid var(--ss-sun-400); outline-offset: 3px; }

/* The rule above each label is the timer. It fills over the dwell, which
   tells the visitor a change is coming instead of surprising them with it. */
.hero__tab-line {
  display: block; height: 2px; margin-bottom: var(--sp-5);
  min-width: 84px;
  background: rgba(255,255,255,.18);
  overflow: hidden;
}
.hero__tab-line i {
  display: block; height: 100%;
  background: var(--ss-sun-500);
  transform: scaleX(0); transform-origin: left center;
}
.hero__tab-txt { display: block; white-space: nowrap; }

/* No autoplay, no drift, no stagger. The slider still works on click. */
@media (prefers-reduced-motion: reduce) {
  .hero__slide, .hero__slide img, .hero__copy, .hero__copy > * { transition: none !important; }
  .hero__slide img { transform: none; }
  .hero__slide.is-active img { transform: none; }
}

/* Page hero, the shorter interior variant */
/* Interior page hero. The photograph is the product, so it gets shown rather
   than buried under a dark scrim: text on the ink ground to the left, the
   picture bleeding off the right edge with nothing laid over it. It opens
   with the slat wipe, a blind lifting, once. On a phone the picture sits on
   top as a band and the words follow on the ink. */
.pagehero { position: relative; background: var(--ss-teal-900); color: #fff; overflow: hidden; }
.pagehero__media { position: relative; z-index: 0; height: min(58vw, 46vh); background: var(--ss-teal-800); }
.pagehero__media img,
.pagehero__media video { width: 100%; height: 100%; object-fit: cover; display: block; }
.pagehero__scrim { display: none; }
.pagehero__media::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: repeating-linear-gradient(to bottom,
    var(--ss-teal-900) 0 calc(100% / 7), transparent calc(100% / 7) calc(100% / 7));
  background-size: 100% calc(100% / 7);
  transform-origin: top;
  animation: pagehero-slats 1.1s var(--ease-slat, cubic-bezier(.7, 0, .2, 1)) .15s both;
}
@keyframes pagehero-slats { to { transform: scaleY(0); } }
@media (prefers-reduced-motion: reduce) { .pagehero__media::after { display: none; } }

.pagehero > .container { position: relative; z-index: 2; }
.pagehero__inner { padding-block: var(--sp-7) var(--sp-9); max-width: 760px; }
@media (min-width: 900px) {
  .pagehero { display: flex; align-items: center; min-height: min(78vh, 720px); }
  .pagehero__media { position: absolute; inset: 0 0 0 56%; height: auto; }
  /* A thin sun rule where the photograph meets the ink. */
  .pagehero__media::before {
    content: ""; position: absolute; left: 0; top: 0; bottom: 0; z-index: 2;
    width: 3px; background: var(--ss-sun-500);
  }
  .pagehero > .container { width: 100%; }
  .pagehero__inner {
    padding-block: var(--sp-10);
    max-width: calc(56vw - max(var(--gutter), (100vw - var(--container)) / 2 + var(--gutter)) - var(--sp-8));
  }
  .pagehero .btn--lg { padding-inline: var(--sp-6); }
}
.pagehero h1 { font-size: clamp(2.25rem, 4.2vw, 3.5rem); }
.pagehero .eyebrow { color: var(--ss-sun-400); }
.pagehero .lead {
  max-width: 46ch; color: rgba(255,255,255,.84);
}
/* Sun coloured standfirst, closed off with a short rule. Used under the one
   headline that carries the Yes! mark, so the two orange elements read as one
   piece rather than as decoration scattered through the hero. */
.pagehero .lead--sun {
  color: var(--ss-sun-400); font-weight: 600; max-width: 34ch;
  margin-bottom: var(--sp-6);
}
.pagehero .lead--sun::after {
  content: ""; display: block;
  width: 96px; height: 3px; margin-top: var(--sp-6);
  background: rgba(255, 255, 255, .28);
}

.breadcrumb {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  font-size: 13px; font-weight: 600; margin-bottom: var(--sp-5);
  color: rgba(255,255,255,.62); list-style: none; padding: 0;
}
.breadcrumb a { color: rgba(255,255,255,.78); text-decoration: none; }
.breadcrumb a:hover { color: #fff; text-decoration: underline; }
.breadcrumb li + li::before { content: "/"; margin-right: var(--sp-2); opacity: .5; }

/* On a light ground. The default is written for a photographic hero, so a page
   that leads straight into its content needs the crumb the other way up. */
.breadcrumb--light { color: var(--ss-text-dim); }
.breadcrumb--light a { color: var(--ss-teal-600); }
.breadcrumb--light a:hover { color: var(--ss-teal-900); }

/* Compact page header for pages with no photographic hero, where the job is to
   name the page and get out of the way of the thing the visitor came to do.
   Only the top padding is reduced. Collapsing the bottom too leaves whatever
   ends the section sitting flush against the band underneath it. */
.section.pagehead { padding-top: var(--sp-8); }
@media (min-width: 900px) { .section.pagehead { padding-top: var(--sp-9); } }
.pagehead h1 { margin-bottom: var(--sp-4); }
.pagehead .lead { max-width: 58ch; color: var(--ss-text-mid); text-wrap: pretty; }

/* Elevate wordmark. The logo file carries its own teal ground, so it sits
   directly on the page with no chip behind it. */
.elevatemark {
  display: inline-block; margin: 0 0 var(--sp-5);
}
.elevatemark img { display: block; width: 190px; height: auto; border-radius: var(--r-sm); }

/* The two pull quotes on Elevate carry a paragraph rather than a line, so they
   read at body size on their own band instead of in a three across row. */
.quote.quote--lead p { font-size: clamp(1.25rem, 2vw, 1.75rem); line-height: 1.55; }
.quote--lead { flex-direction: column; }

/* Trust strip riding under the hero */
/* ── TRUST STRIP ─────────────────────────────────────────────────────────
   Light band under the hero. Four proofs, each led by a real picture: the
   award badge as supplied, a drawn five star rating, and round crops of the
   owners and the building. The rule above each item is the same device the
   stat rows on the interior pages use, so the two read as one family.
   ---------------------------------------------------------------------- */
.trustbar { background: var(--ss-white); }
.trustbar__inner {
  display: grid; gap: var(--sp-7) var(--sp-6);
  grid-template-columns: repeat(2, minmax(0, 1fr));
  padding-block: var(--sp-8);
}
@media (min-width: 900px) {
  .trustbar__inner { grid-template-columns: repeat(4, minmax(0, 1fr)); padding-block: var(--sp-9); }
}
/* Centred, and without the rule over the top. Four rules across a white band
   fenced the items off from each other when the point is that they read as one
   run of proof. */
.trustbar__item { text-align: center; }

/* One band of fixed height for the visual, so four different kinds of picture
   still line their headlines up. */
.trustbar__vis {
  display: flex; align-items: center; justify-content: center;
  height: 96px; margin-bottom: var(--sp-4);
}
.trustbar__vis img { width: 96px; height: 96px; object-fit: contain; display: block; }
/* Scoped to beat the contain above, which was letterboxing the photographs
   inside their own circle and leaving four transparent corners. */
.trustbar__vis .trustbar__photo {
  border-radius: 50%; object-fit: cover;
  border: 2px solid var(--ss-sand-200);
}
.trustbar__stars { width: 150px; height: 30px; color: var(--ss-sun-500); display: block; }

.trustbar__n {
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 1.9vw, 1.5rem); font-weight: 800; line-height: 1.15;
  letter-spacing: -.03em; color: var(--ss-teal-900);
  text-wrap: balance;
}
.trustbar__t { font-size: 13.5px; line-height: 1.45; color: var(--ss-text-mid); margin-top: var(--sp-2); }

/* ── 10 SECTIONS & BLOCKS ────────────────────────────────────────────────── */

/* Feature row, image bleeds one edge, text opposite */
.feature { display: grid; gap: var(--sp-6); align-items: center; }
@media (min-width: 900px) {
  .feature { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--sp-10); }
  .feature--flip .feature__media { order: 2; }
  .feature + .feature { margin-top: var(--sp-11); }
}
.feature__media { border-radius: var(--r-sm); overflow: hidden; position: relative; }
.feature__media img, .feature__media video { width: 100%; aspect-ratio: 4/3; object-fit: cover; }
.feature__body h3 { margin-bottom: var(--sp-4); }

/* Process steps */
.steps { counter-reset: step; display: grid; gap: var(--sp-6); }
@media (min-width: 900px) { .steps { grid-template-columns: repeat(4, 1fr); gap: var(--sp-6); } }
.step { position: relative; padding-top: var(--sp-6); border-top: 1px solid var(--ss-line); }
.step::before {
  counter-increment: step; content: "0" counter(step);
  position: absolute; top: var(--sp-5); right: 0;
  font-family: var(--font-display); font-size: 2.375rem; font-weight: 800;
  line-height: 1; color: var(--ss-sand-300); letter-spacing: -.05em;
}
/* Six rungs rather than four. Two rows of three reads as a ladder; six across
   squeezes each rung into two words and a hyphen. */
@media (min-width: 900px) { .steps--six { grid-template-columns: repeat(3, 1fr); row-gap: var(--sp-8); } }
/* Two rungs across rather than four, for the Elevate page, where the numbered
   list sits in one half of a split beside a full height photograph. Four
   columns in half the width leaves each rung two words wide. */
@media (min-width: 900px) { .steps--pair { grid-template-columns: repeat(2, 1fr); row-gap: var(--sp-8); } }
.step h3 { font-size: 1.25rem; margin-bottom: var(--sp-3); padding-right: var(--sp-8); }
.step p { font-size: 15.5px; color: var(--ss-text-mid); }
.on-dark .step { border-top-color: var(--ss-line-dk); }
.on-dark .step::before { color: rgba(255,255,255,.18); }
.on-dark .step p { color: rgba(255,255,255,.72); }

/* Guarantee panel */
.guarantee {
  display: grid; gap: var(--sp-5);
  padding: var(--sp-7); border-radius: var(--r-sm);
  background: var(--ss-white); border: 1px solid var(--ss-line);
}
@media (min-width: 900px) { .guarantee { padding: var(--sp-9); } }
.guarantee__head h3 {
  margin: 0 0 var(--sp-2); font-size: clamp(1.375rem, 2.2vw, 1.75rem);
  letter-spacing: -.03em; color: var(--ss-teal-900);
}
.guarantee__head p { margin: 0; max-width: 60ch; color: var(--ss-text-mid); font-size: 16px; }

.guarantee__grid { display: grid; gap: var(--sp-6) var(--sp-7); }
@media (min-width: 640px)  { .guarantee__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1000px) { .guarantee__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* A panel holding only two promises should not leave a third of itself empty. */
@media (min-width: 1000px) { .guarantee__grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* One promise. The tick is on the name, the sentence hangs under it on the
   same left edge as the words, not the bullet. */
.pact b {
  display: flex; align-items: center; gap: var(--sp-3);
  font-family: var(--font-display); font-size: 1.0625rem; font-weight: 800;
  letter-spacing: -.02em; color: var(--ss-teal-900);
}
.pact b::before {
  content: ""; width: 22px; height: 22px; flex: none;
  border-radius: 50%; background: var(--ss-sun-500);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18'%3E%3Cpath fill='%230A2430' d='m7.6 12.3-3-3 1.1-1.1 1.9 1.9 4.7-4.7 1.1 1.1z'/%3E%3C/svg%3E");
  background-size: contain;
}
.pact p {
  margin: var(--sp-2) 0 0; padding-left: calc(22px + var(--sp-3));
  font-size: 15px; line-height: 1.55; color: var(--ss-text-mid);
}

.guarantee__foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4) var(--sp-6);
  padding-top: var(--sp-6); border-top: 1px solid var(--ss-line);
}

.guarantee__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
@media (min-width: 640px) { .guarantee__list { grid-template-columns: 1fr 1fr; gap: var(--sp-3) var(--sp-6); } }
.guarantee__list li {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  font-weight: 600; font-size: 15.5px; line-height: 1.4;
}
.guarantee__list li::before {
  content: ""; width: 18px; height: 18px; flex: none; margin-top: 2px;
  border-radius: 50%; background: var(--ss-sun-500);
  -webkit-mask: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18'%3E%3Cpath fill='%230A2430' d='m7.6 12.3-3-3 1.1-1.1 1.9 1.9 4.7-4.7 1.1 1.1z'/%3E%3C/svg%3E");
  background-size: contain;
}

/* FAQ accordion */
.faq { border-top: 1px solid var(--ss-line); }
.faq__item { border-bottom: 1px solid var(--ss-line); }
.faq__q {
  width: 100%; display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--sp-5); padding: var(--sp-5) 0; text-align: left;
  font-family: var(--font-display); font-size: 1.125rem; font-weight: 700;
  letter-spacing: -.015em; line-height: 1.3; color: var(--ss-teal-900);
}
.faq__q .plus { position: relative; width: 16px; height: 16px; flex: none; margin-top: 5px; }
.faq__q .plus::before, .faq__q .plus::after {
  content: ""; position: absolute; inset: 0; margin: auto;
  background: var(--ss-sun-500); border-radius: 1px;
}
.faq__q .plus::before { width: 16px; height: 2px; }
.faq__q .plus::after { width: 2px; height: 16px; transition: transform var(--dur-base) var(--ease-out-expo); }
.faq__q[aria-expanded="true"] .plus::after { transform: scaleY(0); }
.faq__a { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--dur-base) var(--ease-out-expo); }
.faq__a > div { overflow: hidden; }
.faq__q[aria-expanded="true"] + .faq__a { grid-template-rows: 1fr; }
.faq__a p { padding-bottom: var(--sp-5); color: var(--ss-text-mid); max-width: var(--measure); }

/* ── 11 CARDS ────────────────────────────────────────────────────────────── */
.card {
  position: relative; display: flex; flex-direction: column;
  background: var(--ss-white);
  border: 1px solid var(--ss-line);
  border-radius: var(--r-sm);
  overflow: hidden;
  text-decoration: none; color: inherit;
  transition: transform var(--dur-base) var(--ease-out-expo),
              box-shadow var(--dur-base) var(--ease-out-expo),
              border-bottom-width var(--dur-base) var(--ease-out-expo);
}
/* The orange rule marks a card you can click. Info cards go without. */
a.card { border-bottom: 3px solid var(--ss-sun-500); }
a.card:hover { border-bottom-width: 5px; }
.card__media { position: relative; overflow: hidden; background: var(--ss-sand-200); }
.card__media img, .card__media video {
  width: 100%; aspect-ratio: 4/3; object-fit: cover;
  transition: transform var(--dur-slow) var(--ease-out-expo);
}

.card__body { padding: var(--sp-5); display: flex; flex-direction: column; flex: 1; gap: var(--sp-3); }
@media (min-width: 900px) { .card__body { padding: var(--sp-6); } }
/* Dark sections set colour on everything beneath them, which turned card
   headings white on a white card. The card owns its own palette. */
.card { color: var(--ss-text); }
.card__body h3, .card__body .card__title { margin: 0; font-size: 1.25rem; color: var(--ss-teal-900); }
/* Same look as the h3 cards where a card title has to be an h2 to keep the
   heading outline in order (a page whose cards come straight after its h1). */
.card__body .card__title { line-height: 1.2; letter-spacing: -.01em; }
.card__body p { font-size: 15px; color: var(--ss-text-mid); margin: 0; }
.card__body .link-arrow { margin-top: auto; padding-top: var(--sp-2); }
/* French Doors: a product button pinned to the bottom of each tile. */
.card__body .card__cta { margin-top: auto; align-self: flex-start; }

/* City hub product shelf. Ten products as photographs with a line under
   each, five across, instead of ten boxed cards leaving one alone on the last
   row. */
.product-shelf { gap: var(--sp-7) var(--sp-5); }
@media (min-width: 1100px) { .product-shelf { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
.product-shelf .card, .product-shelf a.card, .product-shelf a.card:hover {
  border: 0; border-radius: 0; background: none; overflow: visible;
}
.product-shelf .card__media { border-radius: var(--r-sm); }
.product-shelf .card__body { padding: var(--sp-3) 0 0; gap: var(--sp-2); }
.product-shelf .card__body h3 { font-size: 1.125rem; }
.product-shelf .card__body p { font-size: 14px; }
.product-shelf .card__body .link-arrow { font-size: 13.5px; }
.product-shelf a.card:hover h3 {
  text-decoration: underline; text-decoration-color: var(--ss-sun-500);
  text-decoration-thickness: 2px; text-underline-offset: 5px;
}

/* Product card, image-led with a text overlay, echoing the tile grid they liked */
.tile {
  position: relative; display: block; overflow: hidden;
  border-radius: var(--r-sm); text-decoration: none; color: #fff;
  background: var(--ss-teal-900);
  min-height: 320px;
}
.tile img, .tile video {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transition: transform var(--dur-slow) var(--ease-out-expo);
}
/* The legibility gradient lives on ::before. On ::after it shared a layer
   with the slat reveal, and the reveal's end state (scaled to nothing) took
   the gradient with it, leaving white titles on bare photographs. */
.tile::before {
  content: ""; position: absolute; inset: 0; z-index: 1;   /* above the photo, below the words */
  background: linear-gradient(to top, rgba(10,36,48,.92) 4%, rgba(10,36,48,.55) 38%, rgba(10,36,48,.10) 72%);
  transition: background var(--dur-base) var(--ease-out-expo);
}
.tile:hover img, .tile:hover video { }
.tile:hover::before { background: linear-gradient(to top, rgba(10,36,48,.95) 10%, rgba(10,36,48,.62) 48%, rgba(21,95,114,.28) 100%); }
.tile__body {
  position: relative; z-index: 2;
  height: 100%; display: flex; flex-direction: column; justify-content: flex-end;
  padding: var(--sp-5);
  min-height: 320px;
}
.tile__body h3 { color: #fff; font-size: 1.375rem; margin: 0 0 var(--sp-2); }
.tile__body p {
  font-size: 14.5px; line-height: 1.45; color: rgba(255,255,255,.82); margin: 0;
  max-height: 0; opacity: 0; overflow: hidden;
  transition: max-height var(--dur-base) var(--ease-out-expo), opacity var(--dur-base) var(--ease-out-expo),
              margin var(--dur-base) var(--ease-out-expo);
}
.tile:hover p, .tile:focus-visible p { max-height: 8em; opacity: 1; margin-top: var(--sp-1); }
/* Retired: the small orange dash on every tile. Markup left in place. */
.tile__rule { display: none; }
@media (max-width: 899px) {
  .tile__body p { max-height: 8em; opacity: 1; margin-top: var(--sp-1); }
}

/* Small link card, used for solutions and locations.
   Markup: <a class="linkcard"><span>Title<small>sub</small></span></a>
   The span is required. A bare text node becomes its own flex item and the
   subtitle ends up beside the title instead of under it. */
.linkcard {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  padding: 12px 0; text-decoration: none; color: var(--ss-teal-700);
  background: none; border: 0; border-bottom: 1px solid var(--ss-line); border-radius: 0;
  font-weight: 700; font-size: 16px; line-height: 1.3;
  transition: border-color var(--dur-micro) var(--ease-out-expo),
              background-color var(--dur-micro) var(--ease-out-expo),
              transform var(--dur-micro) var(--ease-out-expo);
}
.linkcard > span { display: block; min-width: 0; }
.linkcard:hover { color: var(--ss-sun-600); border-bottom-color: var(--ss-sun-500); }
.linkcard small { display: block; font-weight: 400; font-size: 13px; color: var(--ss-text-dim); margin-top: 3px; }

/* ── 12 MEDIA & VIDEO ────────────────────────────────────────────────────── */
.media { border-radius: var(--r-sm); overflow: hidden; background: var(--ss-sand-200); }
.media img, .media video { width: 100%; object-fit: cover; }
.media--16x9 img, .media--16x9 video { aspect-ratio: 16/9; }
.media--4x3 img, .media--4x3 video { aspect-ratio: 4/3; }
.media--3x4 img, .media--3x4 video { aspect-ratio: 3/4; }
.media--1x1 img, .media--1x1 video { aspect-ratio: 1/1; }

figure { margin: 0; }
figcaption {
  font-size: 13.5px; color: var(--ss-text-dim); margin-top: var(--sp-3);
  padding-left: var(--sp-3); border-left: 2px solid var(--ss-sun-500);
  line-height: 1.45;
}

/* Video block, media paired with a text column, never text over video */
.videoblock { display: grid; gap: var(--sp-6); align-items: center; }
@media (min-width: 900px) {
  .videoblock { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--sp-9); }
  .videoblock--flip > :first-child { order: 2; }
}
/* Wide variant. The clip is the proof on this block, so on a large screen it
   takes the bigger share of a wider container and a taller crop. */
@media (min-width: 900px) {
  .videoblock--wide { grid-template-columns: minmax(0, 8fr) minmax(0, 5fr); }
}
.videoblock__media { position: relative; border-radius: var(--r-sm); overflow: hidden; background: var(--ss-teal-900); }
.videoblock__media video { width: 100%; aspect-ratio: 16/9; object-fit: cover; display: block; }
.videoblock--wide .videoblock__media video { aspect-ratio: 16/10; }
/* French Doors: a portrait clip shown at its own 9:16 in a narrow column. */
.videoblock--portrait .videoblock__media { width: 100%; max-width: 420px; justify-self: center; }
.videoblock--portrait .videoblock__media video { aspect-ratio: 9/16; }
@media (min-width: 900px) {
  .videoblock--portrait.videoblock--flip { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
}
/* The copy column here is capped at roughly 460px, so a heading of more than a
   few words lands on three ragged lines. This one notch down lets a longer
   heading sit on two full lines without touching the layout. */
.videoblock h2.h2--long { font-size: clamp(1.75rem, 3.4vw, 2.5rem); }
/* The clip's label sits in a strip under the frame, right aligned (the clips
   carry our logo watermark bottom left). It used to ride the footage on its
   own shade; Tim asked on Sep 30 for nothing to be written over the videos. */
.videoblock__media:has(> .videoblock__badge) { display: flex; flex-direction: column; }
.videoblock__media > video { flex: none; }
.videoblock__badge {
  order: 2;
  display: block; text-align: right;
  padding: var(--sp-3) var(--sp-4);
  border-top: 3px solid var(--ss-sun-500);
  color: rgba(255, 255, 255, .78); font-size: 13px; font-weight: 600;
}

/* A customer's own words inside a text column: a sun rule and a step up in
   size, no box. */
.custquote {
  margin: 0; padding-left: var(--sp-5);
  border-left: 3px solid var(--ss-sun-500);
}
.custquote p { font-size: 1.1875rem; line-height: 1.55; color: var(--ss-teal-900); font-weight: 500; }

/* An Instagram reel standing in for a clip we do not have as a file yet.
   Instagram sizes its own frame; this keeps it to a phone width column. */
.igembed { width: 100%; max-width: 420px; justify-self: center; }
.igembed .instagram-media { margin: 0 !important; min-width: 0 !important; width: 100% !important; }

/* Gallery grid with a mosaic rhythm */
.mosaic { display: grid; gap: var(--sp-3); grid-template-columns: repeat(2, 1fr); }
@media (min-width: 900px) { .mosaic { grid-template-columns: repeat(4, 1fr); gap: var(--sp-4); } }
.mosaic > * { border-radius: var(--r-sm); overflow: hidden; }
.mosaic img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 1/1; transition: transform var(--dur-slow) var(--ease-out-expo); }
.mosaic > *:hover img { }
@media (min-width: 900px) {
  .mosaic > *:nth-child(1) { grid-column: span 2; grid-row: span 2; }
  .mosaic > *:nth-child(1) img { aspect-ratio: 1/1; }
}

/* Four picture collage beside a headline, as on the Elevate page. .mosaic is
   built for five images across a full width container, with the first spanning
   two by two, so in half of a split it packs into one big tile and three
   scraps. This is the plain two by two the client's own page uses. */
.collage { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); }
@media (min-width: 900px) { .collage { gap: var(--sp-4); } }
.collage > figure { margin: 0; border-radius: var(--r-sm); overflow: hidden; }
.collage img {
  width: 100%; height: 100%; display: block; object-fit: cover; aspect-ratio: 4/5;
  transition: transform var(--dur-slow) var(--ease-out-expo);
}
.collage > figure:hover img { }

/* Before / after slider */
.baslider { position: relative; border-radius: var(--r-sm); overflow: hidden; touch-action: pan-y; user-select: none; }
.baslider img { width: 100%; aspect-ratio: 16/10; object-fit: cover; display: block; }
.baslider__after { position: absolute; inset: 0; width: var(--pos, 50%); overflow: hidden; }
.baslider__after img { width: var(--baw, 100%); max-width: none; height: 100%; }
.baslider__handle {
  position: absolute; top: 0; bottom: 0; left: var(--pos, 50%);
  width: 3px; background: var(--ss-sun-500); transform: translateX(-1.5px);
  cursor: ew-resize;
}
.baslider__handle::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
  border-radius: 50%; background: var(--ss-sun-500);
  box-shadow: 0 4px 16px rgba(10,36,48,.35);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%230A2430' d='M8.5 7 4 12l4.5 5V7zm7 0v10l4.5-5-4.5-5z'/%3E%3C/svg%3E");
  background-size: 26px; background-repeat: no-repeat; background-position: center;
}
.baslider__tag {
  position: absolute; bottom: var(--sp-4); z-index: 2;
  padding: 5px var(--sp-3); border-radius: var(--r-pill);
  background: rgba(10,36,48,.75); color: #fff;
  font-size: 12px; font-weight: 700;
}
.baslider__tag--b { left: var(--sp-4); }
.baslider__tag--a { right: var(--sp-4); }

/* Standing notice. Used where a service is paused or limited, so it has to be
   read before anything below it and must not look like a marketing callout. */
.notice {
  border: 1px solid var(--ss-line);
  border-left: 4px solid var(--ss-sun-500);
  border-radius: var(--r-sm);
  background: var(--ss-sand-50, #FBF7F2);
  padding: var(--sp-5) var(--sp-6);
}
.notice p { margin: 0; font-size: 15px; line-height: 1.6; color: var(--ss-text-mid); }
.notice b { color: var(--ss-teal-900); }

/* ── FLIPBOOK ─────────────────────────────────────────────────────────────
   A print guide, on the web, that still reads as a book.

   Two pages side by side on a wide screen with a gutter shadow down the
   middle, one page on a phone. Turning rotates the leaf on its spine edge,
   which is the whole reason it reads as paper rather than a slideshow.

   The text of the guide is not in here. It is written into the page as
   ordinary copy underneath, because a picture of a sentence is not content. */
/* The book runs straight on from whatever introduces it. Two stacked section
   paddings left a screen of nothing between the title and the thing the page
   exists for. Set on the section itself rather than as an adjacency rule,
   which is easier to reason about and does not depend on what precedes it. */
/* The book is the first thing on the page, so it needs a little air under the
   navigation and nothing else above it. */
.flipbook-section { padding-top: var(--sp-7); }

.flipbook {
  position: relative;
  max-width: 1180px; margin-inline: auto;
  perspective: 2600px;
}
.flipbook__stage {
  position: relative;
  display: grid; grid-template-columns: 1fr;
  aspect-ratio: var(--book-aspect, .7727);
  margin-inline: auto; width: min(100%, 560px);
  transform-style: preserve-3d;
}
.flipbook__leaf {
  grid-area: 1 / 1;
  width: 100%; height: 100%; object-fit: contain;
  border-radius: 3px;
  box-shadow: 0 12px 40px rgba(10,36,48,.22);
  background: #fff;
  visibility: hidden;
  transform-origin: left center;
  backface-visibility: hidden;
}
.flipbook__leaf[data-on] { visibility: visible; }
/* The leaf being turned. Rotating on the spine edge, with the shadow easing
   off as it lifts, is what sells it as paper. */
.flipbook__leaf[data-turning="fwd"] { animation: leaf-fwd .5s cubic-bezier(.4,0,.2,1) both; z-index: 3; }
.flipbook__leaf[data-turning="back"] { animation: leaf-back .5s cubic-bezier(.4,0,.2,1) both; z-index: 3; }
@keyframes leaf-fwd {
  from { transform: rotateY(0deg); box-shadow: 0 12px 40px rgba(10,36,48,.22); }
  to   { transform: rotateY(-105deg); box-shadow: 0 2px 10px rgba(10,36,48,0); }
}
@keyframes leaf-back {
  from { transform: rotateY(-105deg); box-shadow: 0 2px 10px rgba(10,36,48,0); }
  to   { transform: rotateY(0deg); box-shadow: 0 12px 40px rgba(10,36,48,.22); }
}

@media (min-width: 900px) {
  /* Open book: two leaves at once, and a gutter shadow so the spine reads. */
  .flipbook__stage {
    width: 100%;
    grid-template-columns: 1fr 1fr;
    aspect-ratio: calc(var(--book-aspect, .7727) * 2);
  }
  .flipbook__leaf { grid-area: 1 / 1; }
  .flipbook__leaf[data-side="right"] { grid-area: 1 / 2; transform-origin: left center; }
  .flipbook__leaf[data-side="left"]  { grid-area: 1 / 1; transform-origin: right center; }
  .flipbook__stage::after {
    content: ""; position: absolute; inset: 0 calc(50% - 12px); z-index: 4;
    pointer-events: none; border-radius: 2px;
    background: linear-gradient(90deg, rgba(10,36,48,0), rgba(10,36,48,.16), rgba(10,36,48,0));
  }
}

.flipbook__nav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 5;
  width: 46px; height: 46px; border-radius: 50%; border: 0;
  background: var(--ss-teal-900); color: #fff; font-size: 19px;
  box-shadow: 0 6px 18px rgba(10,36,48,.28);
}
.flipbook__nav:hover { background: var(--ss-sun-500); color: var(--ss-teal-900); }
.flipbook__nav:disabled { opacity: .28; cursor: default; }
.flipbook__nav--prev { left: -10px; }
.flipbook__nav--next { right: -10px; }
@media (min-width: 1260px) {
  .flipbook__nav--prev { left: -58px; }
  .flipbook__nav--next { right: -58px; }
}

.flipbook__bar {
  display: flex; flex-wrap: wrap; gap: var(--sp-4) var(--sp-6);
  align-items: center; justify-content: center;
  margin-top: var(--sp-6); font-size: 14px; color: var(--ss-text-mid);
}
.flipbook__count b { color: var(--ss-teal-900); font-variant-numeric: tabular-nums; }

/* The guide as a web page: each printed page beside the words that are on it.
   The picture is the layout the client designed, the text next to it is what a
   search engine and a screen reader get. Pages that are pure photography have
   no text and stand on their own. */
.bookprose { max-width: 1100px; margin-inline: auto; }
/* Centred against the page beside it. Most of these blocks are shorter than
   an A4 page is tall, and top aligning them left the copy stranded at the top
   of a column of nothing. */
.bookpage { display: grid; gap: var(--sp-5); align-items: center; }
.bookpage + .bookpage { margin-top: var(--sp-9); }
@media (min-width: 820px) {
  .bookpage { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: var(--sp-8); }
  /* Alternate which side the page sits on, so a long run of them does not
     read as a list. */
  .bookpage:nth-child(even) .bookpage__img { order: 2; }
}
.bookpage__img { margin: 0; }
.bookpage__img img {
  width: 100%; height: auto; display: block; border-radius: 3px;
  box-shadow: 0 8px 28px rgba(10,36,48,.16);
}
/* A full bleed photograph page has nothing beside it, so it sits on its own
   and centred rather than stranded in one column. */
.bookpage--plate { grid-template-columns: 1fr; max-width: 620px; margin-inline: auto; }
/* Set in the same card the rest of the site uses: white on the sand ground,
   hairline border, sun coloured rule along the bottom. Same device as the
   product cards and the guarantee panel, so the guide reads as part of the
   site rather than as something pasted into it. */
.bookpage__text {
  background: var(--ss-white);
  border: 1px solid var(--ss-line);
  border-radius: var(--r-sm);
  padding: var(--sp-6);
}
@media (min-width: 820px) { .bookpage__text { padding: var(--sp-7); } }
.bookpage__text p { margin: 0 0 var(--sp-4); color: var(--ss-text-mid); }
.bookpage__text p:last-child { margin-bottom: 0; }
/* First sentence of a card is the heading in the printed original, so it gets
   a little more weight here to keep that structure. */
.bookpage__text p:first-child { color: var(--ss-text); }

@media (prefers-reduced-motion: reduce) {
  .flipbook__leaf[data-turning] { animation-duration: .01ms; }
}

/* ── 13 PROOF, REVIEWS ───────────────────────────────────────────────────── */

.stars { display: inline-flex; gap: 2px; }
.stars svg { width: 16px; height: 16px; fill: var(--ss-sun-500); }

.quote {
  display: flex; flex-direction: column; gap: var(--sp-4);
  padding: var(--sp-6); border-radius: var(--r-sm);
  background: var(--ss-teal-800); color: #fff;
  height: 100%;
}
.quote__mark {
  font-family: var(--font-display); font-size: 3rem; line-height: .6;
  color: var(--ss-sun-500); height: 26px;
}
.quote p { font-size: 15.5px; line-height: 1.55; color: rgba(255,255,255,.90); margin: 0; flex: 1; }
.quote__by { font-size: 14px; font-weight: 700; color: var(--ss-sun-400); }
.quote__by small { display: block; font-weight: 400; font-size: 12.5px; color: rgba(255,255,255,.55); margin-top: 2px; }

/* Horizontal scroller for proof rows */
.scroller {
  display: grid; grid-auto-flow: column; grid-auto-columns: 84%;
  gap: var(--sp-4); overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; padding-bottom: var(--sp-4);
  scrollbar-width: thin;
}
.scroller > * { scroll-snap-align: start; }
@media (min-width: 640px) { .scroller { grid-auto-columns: 46%; } }
@media (min-width: 1100px) { .scroller { grid-auto-columns: 31%; } }

/* Award badge row */
/* The badges used to bunch up on the left of a very wide row. They now share
   the width evenly, sitting under the reviews as a band rather than a huddle,
   with a rule above so the row reads as its own statement. */
.badges {
  display: grid; grid-template-columns: repeat(3, 1fr);
  align-items: center; justify-items: center;
  gap: var(--sp-6) var(--sp-5);
  padding-top: var(--sp-7);
  border-top: 1px solid var(--ss-line);
}
@media (min-width: 720px) { .badges { grid-template-columns: repeat(5, 1fr); gap: var(--sp-6); } }
.badges img {
  height: 68px; width: auto; opacity: .95;
  transition: transform var(--dur-base) var(--ease-out-expo), opacity var(--dur-base) var(--ease-out-expo);
}
@media (min-width: 900px) { .badges img { height: 88px; } }
.badges img:hover { opacity: 1; }

/* Elfsight reviews widget (third party). Its review count and review dates
   ship in #858585 on #F8F8F8, 3.5:1. The widget renders into our page, so the
   two greys are corrected here to #666, 5.5:1, WCAG AA. Nothing else in the
   widget changes. */
.reviews-embed .es-header-rating-reviews-count,
.reviews-embed .es-review-info-date-container,
.reviews-embed .es-review-info-date-container * { color: #666 !important; }

/* ── 14 FORMS ────────────────────────────────────────────────────────────── */
.field { display: grid; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.field label { font-size: 13.5px; font-weight: 700; letter-spacing: .01em; }
.field label .req { color: var(--ss-sun-600); }
.field input, .field select, .field textarea {
  width: 100%; min-height: 50px; padding: var(--sp-3) var(--sp-4);
  background: var(--ss-white);
  border: 1px solid var(--ss-line); border-radius: var(--r-sm);
  font-size: 16px; color: var(--ss-teal-900);
  transition: border-color var(--dur-micro) var(--ease-out-expo),
              box-shadow var(--dur-micro) var(--ease-out-expo);
}
.field textarea { min-height: 120px; padding-top: var(--sp-3); resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--ss-teal-500);
  box-shadow: 0 0 0 3px rgba(30, 137, 164, .16);
}
.field input::placeholder, .field textarea::placeholder { color: var(--ss-text-dim); }
.field__hint { font-size: 12.5px; color: var(--ss-text-dim); }

.formcard {
  background: var(--ss-white); border: 1px solid var(--ss-line);
  border-radius: var(--r-sm); padding: var(--sp-6);
}
@media (min-width: 900px) { .formcard { padding: var(--sp-8); } }

.checkgrid { display: grid; gap: var(--sp-2); grid-template-columns: 1fr 1fr; }
.checkgrid label {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3); border: 1px solid var(--ss-line); border-radius: var(--r-sm);
  font-size: 14px; font-weight: 600; cursor: pointer;
  transition: border-color var(--dur-micro) var(--ease-out-expo), background-color var(--dur-micro) var(--ease-out-expo);
}
.checkgrid label:has(input:checked) { border-color: var(--ss-sun-500); background: var(--ss-sun-100); }
/* The shared .field input rule sets a 50px min-height so text inputs are
   comfortable to hit. A checkbox inherits that and each row grows to 74px of
   mostly empty box, so it is reset here. */
.checkgrid input {
  width: 16px; height: 16px; min-height: 0; padding: 0;
  accent-color: var(--ss-sun-600); flex: none;
}

/* ── 15 CTA BAND & FOOTER ────────────────────────────────────────────────── */
.ctaband { background: var(--ss-teal-700); color: #fff; position: relative; overflow: hidden; }
.ctaband > .container { position: relative; z-index: 1; }
.ctaband__inner {
  display: grid; gap: var(--sp-6); align-items: center;
  padding-block: var(--sp-9);
}
@media (min-width: 900px) {
  .ctaband__inner { grid-template-columns: minmax(0, 1fr) auto; gap: var(--sp-9); padding-block: var(--sp-10); }
}
.ctaband h2 { font-size: clamp(1.875rem, 3.4vw, 2.75rem); margin-bottom: var(--sp-3); }
.ctaband p { color: rgba(255,255,255,.82); margin: 0; max-width: 58ch; }

.footer { background: var(--ss-teal-900); color: rgba(255,255,255,.72); font-size: 14.5px; }
.footer__top { padding-block: var(--sp-10); display: grid; gap: var(--sp-8); }
@media (min-width: 780px) { .footer__top { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .footer__top { grid-template-columns: 1.6fr 1fr 1fr 1.3fr; gap: var(--sp-7); } }
/* Footer column titles are h2 for a correct outline (they follow the page's
   h2s), set to the same small size they always had. */
.footer h4, .footer .footer__h {
  font-family: var(--font-body); font-size: 12px; font-weight: 700;
  letter-spacing: -.005em; color: #fff;
  line-height: 1.3;
  margin-bottom: var(--sp-4);
}
.footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.footer a { color: rgba(255,255,255,.72); text-decoration: none; }
.footer a:hover { color: var(--ss-sun-400); }
.footer__logo { height: 62px; width: auto; margin-bottom: var(--sp-5); }
.footer__nap { display: grid; gap: var(--sp-3); }
.footer__nap strong { color: #fff; display: block; font-size: 15px; }
.footer__nap a[href^="tel"] { font-size: 20px; font-weight: 800; color: #fff; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
.footer__nap a[href^="tel"] .tel-label { color: rgba(255,255,255,.8); }
.footer__nap a[href^="tel"]:hover { color: var(--ss-sun-400); }
.footer__social { display: flex; gap: var(--sp-2); margin-top: var(--sp-4); }
.footer__social a {
  width: 40px; height: 40px; display: grid; place-items: center;
  border: 1px solid var(--ss-line-dk); border-radius: 50%;
  transition: background-color var(--dur-micro) var(--ease-out-expo),
              border-color var(--dur-micro) var(--ease-out-expo),
              transform var(--dur-micro) var(--ease-out-expo);
}
.footer__social a:hover { background: var(--ss-sun-500); border-color: var(--ss-sun-500); }
.footer__social svg { width: 17px; height: 17px; fill: #fff; }
.footer__social a:hover svg { fill: var(--ss-teal-900); }
.footer__bottom {
  border-top: 1px solid rgba(255,255,255,.10);
  padding-block: var(--sp-5) calc(var(--sp-5) + 64px);
  display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-5);
  align-items: center; justify-content: space-between;
  font-size: 13px;
}
@media (min-width: 900px) { .footer__bottom { padding-bottom: var(--sp-5); } }
.footer__legal { display: flex; flex-wrap: wrap; gap: var(--sp-4); }
.footer__credit { margin: 0; color: rgba(255,255,255,.55); }
.footer__credit a { color: rgba(255,255,255,.82); text-decoration: none; font-weight: 700; }
.footer__credit a:hover { color: var(--ss-sun-400); text-decoration: underline; }

/* ── 16 UTILITIES ────────────────────────────────────────────────────────── */
/* Lead forms. The honeypot is off screen for people and still filled by
   bots; the status line says what happened when the form is sent. */
.hp { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
.form-status { margin-top: var(--sp-4); font-weight: 600; }
.form-status--error { color: #b3261e; }

.vh {
  position: absolute !important; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }
/* The scale ran 5 to 8 only, so mt-4 and mt-9 in the markup were doing nothing
   at all and the spacing they were meant to set fell back to whatever the
   surrounding gap happened to be. */
.mt-3 { margin-top: var(--sp-3); }
.mt-4 { margin-top: var(--sp-4); }
.mt-5 { margin-top: var(--sp-5); }
.mt-6 { margin-top: var(--sp-6); }
.mt-7 { margin-top: var(--sp-7); }
.mt-8 { margin-top: var(--sp-8); }
.mt-9 { margin-top: var(--sp-9); }
.mb-7 { margin-bottom: var(--sp-7); }
.mb-8 { margin-bottom: var(--sp-8); }
.mt-10 { margin-top: var(--sp-10); }
.tc { text-align: center; }
.nowrap { white-space: nowrap; }
.tnum { font-variant-numeric: tabular-nums; }
.measure { max-width: var(--measure); }
.dim { color: var(--ss-text-dim); }

/* ── 17 SHOWREEL & MEDIA-LED BLOCKS ──────────────────────────────────────
   Added after client review: the home page read as text on paper. These are
   the blocks that carry the work rather than describe it.
   ---------------------------------------------------------------------- */

/* Full-bleed cinematic video band */
/* Full bleed video band. The clip plays clear across the top and the words
   follow underneath in their own box on the ink. Tim asked for this on Sep 30:
   laid over the footage, the headline and the shade it needed covered most of
   the frame on a phone, so the video could not be watched. Nothing sits on
   the clip now but the pause (and, on a spoken clip, sound) control. */
.showreel {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column;
  background: var(--ss-teal-900);
}
/* Written as a child selector on purpose: two class names beat the flat
   `.showreel__media` rule further down whatever the order. */
.showreel > .showreel__media {
  position: relative; z-index: 0;
  aspect-ratio: 16 / 9;
  background: var(--ss-teal-800);
}
@media (min-width: 900px) {
  .showreel > .showreel__media { aspect-ratio: auto; height: min(78vh, 56.25vw); }
}
.showreel__media video, .showreel__media img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
/* Clips sharing the frame, cross fading. Kept inside the showreel block so the
   absolute stacking always wins over the flat rules above. */
[data-vidrotate] video {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0;
  transition: opacity 900ms var(--ease-out-expo);
}
[data-vidrotate] video.is-active { opacity: 1; }
@media (prefers-reduced-motion: reduce) { [data-vidrotate] video { transition: none; } }
/* No shade over the footage any more: nothing is written on it. */
.showreel__scrim { display: none; }

/* A sun rule along the join between the footage and the text box. */
.showreel > .showreel__media { border-bottom: 3px solid var(--ss-sun-500); }
/* The label under the clip, right aligned like a caption. */
.showreel__badge {
  display: block; text-align: right;
  padding: var(--sp-3) max(var(--gutter), (100vw - var(--container)) / 2 + var(--gutter)) 0;
  color: rgba(255, 255, 255, .72); font-size: 13px; font-weight: 600;
}
.showreel > .container { position: relative; z-index: 2; }
.showreel__inner { padding-block: var(--sp-7) var(--sp-9); }
.showreel__badge + .container .showreel__inner { padding-top: var(--sp-3); }
/* On a wide screen the headline and the paragraph sit side by side, so the
   box under the clip stays short. */
@media (min-width: 900px) {
  .showreel__inner {
    display: grid; grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
    column-gap: var(--sp-10); align-items: end;
    padding-block: var(--sp-6) var(--sp-10);
  }
  .showreel__inner > * { grid-column: 1; }
  .showreel__inner > p:not(.eyebrow) { grid-column: 2; grid-row: 1 / span 2; align-self: end; }
}
.showreel h2 {
  color: #fff; max-width: 18ch;
  font-size: clamp(2rem, 4.4vw, 3.5rem);
  margin-bottom: var(--sp-4);
}
@media (min-width: 900px) { .showreel h2 { margin-bottom: 0; } }
.showreel p {
  color: rgba(255,255,255,.86); max-width: 46ch;
  font-size: clamp(1rem, 1.5vw, 1.1875rem); line-height: 1.55;
}

/* Light variant: the text box sits on white, for a band that would otherwise
   run straight into another dark section (KC home, Oct 2 2026). */
.showreel--light { background: var(--ss-white); }
.showreel--light h2 { color: var(--ss-teal-900); max-width: 22ch; }
.showreel--light p { color: var(--ss-text-mid); }
.showreel--light .eyebrow { color: var(--ss-teal-600); }

/* Process step with a photograph */
.step--photo { border-top: 0; padding-top: 0; }
.step--photo .step__img {
  border-radius: var(--r-sm); overflow: hidden; margin-bottom: var(--sp-5);
}
.step--photo .step__img img {
  width: 100%; aspect-ratio: 5/4; object-fit: cover; display: block;
  transition: transform var(--dur-slow) var(--ease-out-expo);
}
.step--photo:hover .step__img img { }
/* The numeral rides the corner of the photograph as a solid badge.
   It used to be positioned off its static position with a negative margin,
   which put all four numbers up in the section heading instead of on the
   cards. Anchored to the card box now, so it cannot drift. */
.step--photo::before {
  position: absolute; z-index: 2;
  top: var(--sp-4); left: var(--sp-4); right: auto; bottom: auto;
  margin: 0;
  display: grid; place-items: center;
  width: 42px; height: 42px; border-radius: 50%;
  background: var(--ss-sun-500);
  color: var(--ss-teal-900); text-shadow: none;
  font-size: 1.0625rem; letter-spacing: -.03em;
  box-shadow: 0 2px 10px rgba(10,36,48,.28);
}
.step--photo h3 { padding-right: 0; }

/* ── OFFICES ─────────────────────────────────────────────────────────────
   Kansas City has two locations, each with its own Google Business Profile and
   the same phone number, so they are given identical cards rather than one
   being made the branch and the other a footnote. Illinois has one office and
   gets the single column variant.
   ---------------------------------------------------------------------- */
.offices { display: grid; gap: var(--sp-6); }
@media (min-width: 820px) { .offices { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-7); } }
.offices--one { max-width: 560px; }
@media (min-width: 820px) { .offices--one { grid-template-columns: minmax(0, 1fr); } }

.office {
  display: flex; flex-direction: column;
  padding: var(--sp-5);
  background: var(--ss-white);
  border: 1px solid var(--ss-line);
  border-radius: var(--r-md);
}
@media (min-width: 900px) { .office { padding: var(--sp-6); } }
.office__label {
  margin: 0 0 var(--sp-2);
  font-family: var(--font-display); font-size: 1.375rem; font-weight: 800;
  letter-spacing: -.035em; color: var(--ss-teal-900);
}
.office__addr { margin: 0 0 var(--sp-2); font-size: 15.5px; line-height: 1.5; color: var(--ss-text-mid); }
.office__tel { margin: 0 0 var(--sp-5); }
.office__tel a {
  font-weight: 800; font-size: 1.1875rem; text-decoration: none;
  font-variant-numeric: tabular-nums;
}
.office__map {
  position: relative; overflow: hidden;
  border-radius: var(--r-sm); aspect-ratio: 16/10;
  background: var(--ss-sand-200);
  margin-bottom: var(--sp-4);
}
.office__map iframe { width: 100%; height: 100%; border: 0; display: block; }
.office .link-arrow { margin-top: auto; }

/* ── TOWN COVERAGE ─────/* ── TOWN COVERAGE ───────────────────────────────────────────────────────
   Every town the branch works in, split by state so somebody can find their
   own in one pass. A town with a page of its own is a link and reads as one.
   A town without a page is plain body text, so nobody clicks into nothing. */
.towns { display: grid; gap: var(--sp-6) var(--sp-7); }
@media (min-width: 520px) { .towns { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.towns__head {
  font-size: 14px; font-weight: 700; letter-spacing: -.005em;
  color: var(--ss-teal-600); margin: 0 0 var(--sp-3);
  padding-bottom: var(--sp-3); border-bottom: 1px solid var(--ss-line);
}
.towns__list {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--sp-2);
  font-size: 15.5px; line-height: 1.35; color: var(--ss-text-mid);
}
.towns__list a {
  color: var(--ss-teal-700); font-weight: 700; text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-micro) var(--ease-out-expo);
}
.towns__list a:hover { border-bottom-color: var(--ss-teal-600); }
/* Overflow disclosure. Native details, so it needs no script and the hidden
   towns are still in the markup for search. */
.more { margin-top: var(--sp-3); }
.more > summary {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: 13px; font-weight: 700; color: var(--ss-teal-600);
  cursor: pointer; list-style: none; padding-block: var(--sp-1);
}
.more > summary::-webkit-details-marker { display: none; }
.more > summary::after {
  content: ""; width: 9px; height: 9px; flex: none;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--dur-micro) var(--ease-out-expo);
}
.more[open] > summary::after { transform: translateY(1px) rotate(-135deg); }
.more > summary:hover { color: var(--ss-teal-800); }
.more > summary:focus-visible { outline: 2px solid var(--ss-sun-500); outline-offset: 3px; }
.more .more__off, .more[open] .more__on { display: none; }
.more[open] .more__off { display: inline; }
.more .towns__list { margin-top: var(--sp-3); }

/* Local proof band */
/* Photographs on one side, the words on the other. The two sides are stretched
   to the same height rather than centred against each other, so the picture
   block finishes on the same line as the copy instead of floating in the
   middle of a much taller column. */
.localband { display: grid; gap: var(--sp-6); }
@media (min-width: 900px) {
  .localband { grid-template-columns: minmax(0, 6fr) minmax(0, 5fr); gap: var(--sp-9); align-items: stretch; }
  .localband > * { min-width: 0; }
}
.localband__grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); }
.localband__grid figure { border-radius: var(--r-sm); overflow: hidden; margin: 0; }
.localband__grid img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 4/3; display: block; }
@media (min-width: 640px) { .localband__grid > :first-child { grid-column: span 2; } }
/* On a wide screen the pictures fill the row: the big shot takes whatever is
   left after the two below it, so the block ends level with the copy. */
@media (min-width: 900px) {
  .localband__grid { height: 100%; grid-template-rows: 1fr auto; }
  .localband__grid img { aspect-ratio: auto; }
  .localband__grid > :nth-child(n + 2) img { aspect-ratio: 4/3; }
}

/* Before / after section wrapper */
.compare { display: grid; gap: var(--sp-6); }
@media (min-width: 900px) { .compare { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: var(--sp-9); align-items: center; } }
.compare__hint {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: 13px; font-weight: 700; color: var(--ss-text-dim);
  margin-top: var(--sp-4);
}
.compare__hint::before {
  content: ""; width: 26px; height: 14px; background: var(--ss-sun-500);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M8.5 7 4 12l4.5 5V7zm7 0v10l4.5-5-4.5-5z'/%3E%3C/svg%3E") no-repeat center/contain;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M8.5 7 4 12l4.5 5V7zm7 0v10l4.5-5-4.5-5z'/%3E%3C/svg%3E") no-repeat center/contain;
}
/* Same hint under a vertical slider, arrows turned to match the drag. */
.compare__hint--v::before { width: 14px; height: 26px; transform: rotate(90deg); }

/* Lead transformation block. Sits directly under the hero, so the slider is
   the widest thing on the page and reads as the first real proof. */
.compare-lead { max-width: 1100px; margin-inline: auto; }
.baslider--lead { box-shadow: var(--shadow-lift); }
.baslider--lead img { aspect-ratio: 16/9; }
.baslider--lead .baslider__handle { width: 4px; }
.baslider--lead .baslider__handle::after { width: 56px; height: 56px; background-size: 32px; }
.baslider--lead .baslider__tag { font-size: 12px; padding: 7px var(--sp-4); }

/* Vertical variant of the same slider. Wipes top to bottom instead of left to
   right, which is how an exterior shade actually moves. Written after the
   --lead rules on purpose, since both carry the same specificity and the
   vertical axis has to win.

   touch-action is pan-x here rather than pan-y, and on touch the drag only
   starts from the handle, so a thumb swiped across the photograph still
   scrolls the page instead of being swallowed by the slider. */
.baslider--v { touch-action: pan-x; }
.baslider--v .baslider__after { width: 100%; height: var(--pos, 50%); }
.baslider--v .baslider__after img { width: 100%; max-width: none; }
.baslider--v .baslider__handle {
  top: var(--pos, 50%); bottom: auto; left: 0; right: 0;
  width: auto; height: 3px; transform: translateY(-1.5px);
  cursor: ns-resize;
}
.baslider--lead.baslider--v .baslider__handle { width: auto; height: 4px; }
.baslider--v .baslider__handle::after {
  top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(90deg);
}
/* The clipped layer here holds the "after", hanging from the top edge and
   growing downward, so dragging the handle down is the shade closing. That
   puts After above the line and Before below it, and the tags follow. */
.baslider--v .baslider__tag--a { top: var(--sp-4); bottom: auto; left: var(--sp-4); right: auto; }
.baslider--v .baslider__tag--b { bottom: var(--sp-4); top: auto; right: var(--sp-4); left: auto; }
/* Honeycomb page. The closed photograph was shot from a step further back
   than the open one, so it is scaled and lifted a touch to put both sills on
   the same line where the wipe crosses them. */
.baslider--hcfit .baslider__after img { transform: translateY(-4.5%) scale(1.03); transform-origin: 50% 50%; }
/* Banded Shades page. A portrait pair of a two storey great room, shown at its
   own shape in a feature column rather than cropped to 16:9. */
.baslider--lead.baslider--tall img { aspect-ratio: 1600 / 2324; }
.baslider--tall { max-width: 520px; margin-inline: auto; }

/* ── PILLARS ─────────────────────────────────────────────────────────────
   Three promises on a white ground. Cards rather than a dark band, because the
   palette is sand, teal and sun orange and a black panel is none of those.

   The motion carries the section instead of the colour. Cards arrive staggered
   by the delay the script writes onto siblings, the icon draws itself stroke by
   stroke, and the orange rule grows out along the floor of the card. One pass,
   nothing repeats, and all of it stops under prefers-reduced-motion.
   ---------------------------------------------------------------------- */
.pillar {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; gap: var(--sp-3);
  padding: var(--sp-6);
  border-radius: var(--r-md);
  background: var(--ss-white);
  border: 1px solid var(--ss-line);
  transition: border-color var(--dur-micro) var(--ease-out-expo);
}
@media (min-width: 900px) { .pillar { padding: var(--sp-7); } }
.pillar:hover { border-color: var(--ss-sand-300); }

/* The rule along the floor of the card, the same signature as .card */
.pillar::before {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
  background: var(--ss-sun-500);
}

/* Numeral sits opposite the icon, large and quiet */
.pillar__n {
  position: absolute; top: var(--sp-5); right: var(--sp-6);
  font-family: var(--font-display); font-size: 3rem; font-weight: 800;
  letter-spacing: -.05em; line-height: 1;
  color: var(--ss-sand-200);
  transition: color var(--dur-base) var(--ease-out-expo);
}
.pillar:hover .pillar__n { color: var(--ss-sand-300); }

.pillar__icon {
  width: 44px; height: 44px; flex: none;
  color: var(--ss-sun-500);
  margin-bottom: var(--sp-1);
}

.pillar h3 {
  margin: 0; font-size: 1.3125rem; letter-spacing: -.025em;
  color: var(--ss-teal-700);
}
.pillar p { margin: 0; font-size: 15px; line-height: 1.6; color: var(--ss-text-mid); }
.pillar__list {
  margin: 0; padding: 0; list-style: none;
  display: grid; gap: var(--sp-2);
  font-size: 14.5px; line-height: 1.4; color: var(--ss-text-mid);
}
.pillar__list li { position: relative; padding-left: var(--sp-5); }
.pillar__list li::before {
  content: ""; position: absolute; left: 0; top: .46em;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--ss-sun-500);
}
/* Seven guarantees would run the first card a long way past the other two, so
   that one list sits in two columns and all three cards finish together. */
@media (min-width: 560px) {
  .pillar__list--two { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--sp-4); }
}
/* The arrow sits on the floor of the card so three cards of different lengths
   still line their links up. */
.pillar .link-arrow { margin-top: auto; padding-top: var(--sp-4); }

/* ── 18 TEAM ─────────────────────────────────────────────────────────────
   The About page carries seventeen people, grouped by department. Portraits
   are square so a mixed set of source crops still lines up on a grid.
   ---------------------------------------------------------------------- */
.team-group {
  font-size: 14px; font-weight: 700; letter-spacing: -.005em;
  color: var(--ss-teal-600); margin: var(--sp-9) 0 var(--sp-5);
  padding-bottom: var(--sp-3); border-bottom: 1px solid var(--ss-line);
  font-family: var(--font-body);
}
.team-group:first-of-type { margin-top: 0; }

.team-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-5); }
@media (min-width: 640px)  { .team-grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 900px)  { .team-grid { grid-template-columns: repeat(4, 1fr); gap: var(--sp-6); } }
@media (min-width: 1180px) { .team-grid { grid-template-columns: repeat(5, 1fr); } }

.person { margin: 0; }
.person__img {
  border-radius: var(--r-md); overflow: hidden; background: var(--ss-sand-200);
}
/* Source headshots run 0.71 to 0.83 wide-to-tall, so 3:4 keeps almost the whole
   frame. Anchoring to the top means a taller original loses shirt, never a face. */
.person__img img {
  width: 100%; aspect-ratio: 3/4; object-fit: cover; object-position: center top;
  display: block;
  transition: transform var(--dur-slow) var(--ease-out-expo);
}
.person:hover .person__img img { }
.person figcaption {
  margin-top: var(--sp-3); padding: 0; border: 0;
  font-size: 15px; line-height: 1.3;
}
.person figcaption b { display: block; font-weight: 800; letter-spacing: -.02em; color: var(--ss-teal-900); }
.person figcaption span { display: block; font-size: 13px; color: var(--ss-text-dim); margin-top: 3px; }

/* Alternating media/text rows used on The YES Experience */
.yes-list { display: grid; gap: var(--sp-9); }
.yes-item { display: grid; gap: var(--sp-5); align-items: center; }
@media (min-width: 900px) {
  .yes-item { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: var(--sp-9); }
  .yes-item:nth-child(even) .yes-item__media { order: 2; }
}
.yes-item__media { border-radius: var(--r-md); overflow: hidden; background: var(--ss-sand-200); }
.yes-item__media img {
  width: 100%; aspect-ratio: 4/3; object-fit: cover; display: block;
  transition: transform var(--dur-slow) var(--ease-out-expo);
}
.yes-item:hover .yes-item__media img { }
.yes-item__body h3 { margin-bottom: var(--sp-4); }
.yes-item__body p { color: var(--ss-text-mid); }
.yes-item__body .link-arrow { margin-top: var(--sp-2); }

/* Numbered rail. Five rows of the same shape read as five identical slabs
   unless something counts them, so the row opens with its number, the thing
   it is about, and a slat rule running out to the margin. */
.yes-item__label {
  display: flex; align-items: center; gap: var(--sp-4);
  margin-bottom: var(--sp-4);
}
/* Decorative ordinals, drawn as generated content: they carry no meaning the
   heading beside them does not, and are hidden from assistive tech. */
.yes-item__n::before { content: attr(data-n); }
.yes-item__n {
  font-family: var(--font-display); font-weight: 800;
  font-size: 2.125rem; line-height: 1; letter-spacing: -.05em;
  font-variant-numeric: tabular-nums;
  color: var(--ss-sand-300); flex: none;
}
.on-dark .yes-item__n { color: rgba(255, 255, 255, .28); }
.yes-item__label .eyebrow { margin: 0; }
.yes-item__label .louver { flex: 1; min-width: 32px; }

/* Pull quote. A customer's own sentence, given the weight of a headline
   rather than tucked into a paragraph where it reads as filler. */
.pullquote {
  margin: 0; padding-left: var(--sp-6);
  border-left: 3px solid var(--ss-sun-500);
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(1.5rem, 3.4vw, 2.5rem);
  letter-spacing: -.035em; line-height: 1.2;
  color: var(--ss-teal-900);
}
.on-dark .pullquote { color: #fff; }

/* ── 19 FRAMED FIGURE ────────────────────────────────────────────────────
   The treatment the client picked out on the team grid: rounded media, a
   3px orange rule along the bottom, caption sitting underneath rather than
   over the image. Generalised here so every image-plus-label block matches.
   Markup: <figure class="fig"><div class="fig__img"><img></div>
             <figcaption><b>Title</b><span>Detail</span></figcaption></figure>
   ---------------------------------------------------------------------- */
.fig { margin: 0; display: flex; flex-direction: column; }
.fig__img {
  border-radius: var(--r-md); overflow: hidden;
  background: var(--ss-sand-200);
  transition: border-bottom-width var(--dur-base) var(--ease-out-expo);
}
.fig__img img, .fig__img video {
  width: 100%; aspect-ratio: 4/3; object-fit: cover; display: block;
  transition: transform var(--dur-slow) var(--ease-out-expo);
}
/* A graphic or chart keeps its own proportions instead of being cropped to 4/3. */
.fig__img--natural img { aspect-ratio: auto; height: auto; object-fit: contain; }
.fig:hover .fig__img img, .fig:hover .fig__img video { }
.fig:hover .fig__img { border-bottom-width: 5px; }

.fig--portrait .fig__img img { aspect-ratio: 3/4; object-position: center top; }
.fig--square   .fig__img img { aspect-ratio: 1/1; }
.fig--wide     .fig__img img { aspect-ratio: 16/9; }

/* Reset the generic figcaption rule. The orange already lives on the bottom
   rule of the image, so a second orange bar on the caption is one too many. */
.fig figcaption {
  margin-top: var(--sp-4); font-size: 15px; line-height: 1.4;
  padding-left: 0; border-left: 0; color: inherit;
}
.fig figcaption b {
  display: block; font-family: var(--font-display); font-weight: 800;
  font-size: 1.0625rem; letter-spacing: -.025em; color: var(--ss-teal-900);
}
.fig figcaption span { display: block; font-size: 14px; color: var(--ss-text-mid); margin-top: 5px; }
.on-dark .fig figcaption b { color: #fff; }
.on-dark .fig figcaption span { color: rgba(255, 255, 255, .72); }

/* Anchor variant, for figures that link somewhere */
a.fig { text-decoration: none; color: inherit; }
a.fig:hover figcaption b { color: var(--ss-teal-600); }
.on-dark a.fig:hover figcaption b { color: var(--ss-sun-400); }

/* The team grid is now just the portrait variant of the same component */
.person { margin: 0; display: flex; flex-direction: column; }

/* Framed mosaic tiles pick up the same rule */
.mosaic--framed > figure {
  border-radius: var(--r-md);
}

/* ── 20 GALLERY ──────────────────────────────────────────────────────────
   Product install galleries. The client supplied 24 to 102 photographs per
   product, so this needs to hold real volume without becoming a wall.
   ---------------------------------------------------------------------- */
.gallery {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 700px)  { .gallery { grid-template-columns: repeat(3, 1fr); gap: var(--sp-4); } }
@media (min-width: 1100px) { .gallery { grid-template-columns: repeat(4, 1fr); } }
.gallery figure {
  margin: 0; border-radius: var(--r-md); overflow: hidden;
  background: var(--ss-sand-200);
  border-bottom: 3px solid transparent;
  transition: border-bottom-color var(--dur-base) var(--ease-out-expo),
              transform var(--dur-base) var(--ease-out-expo),
              box-shadow var(--dur-base) var(--ease-out-expo);
}
.gallery figure:hover { border-bottom-color: var(--ss-sun-500); }
.gallery img {
  width: 100%; aspect-ratio: 4/3; object-fit: cover; display: block;
  transition: transform var(--dur-slow) var(--ease-out-expo);
}
.gallery figure:hover img { }

/* Every third tile runs tall so the grid does not read as a spreadsheet */
@media (min-width: 700px) {
  .gallery figure:nth-child(7n+1) { grid-row: span 2; }
  .gallery figure:nth-child(7n+1) img { aspect-ratio: 4/5; height: 100%; }
}

/* ── 21 SHOWCASE GALLERY ─────────────────────────────────────────────────
   Replaces the flat 4-up grid. Bigger tiles, a deliberate size rhythm, video
   interleaved with stills, and a lightbox. Built to make the client's own
   photography the reason somebody calls.
   ---------------------------------------------------------------------- */
.showcase {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(2, 1fr);
  grid-auto-flow: dense;
}
@media (min-width: 760px)  { .showcase { grid-template-columns: repeat(3, 1fr); gap: var(--sp-4); } }
@media (min-width: 1200px) { .showcase { grid-template-columns: repeat(4, 1fr); gap: var(--sp-5); } }

.shot {
  position: relative; margin: 0; overflow: hidden;
  border-radius: var(--r-md);
  background: var(--ss-sand-200);
  background-clip: padding-box;
  border-bottom: 3px solid transparent;
  cursor: zoom-in;
  transition: border-bottom-color var(--dur-base) var(--ease-out-expo),
              transform var(--dur-base) var(--ease-out-expo),
              box-shadow var(--dur-base) var(--ease-out-expo);
}
.shot img, .shot video {
  width: 100%; height: 100%; object-fit: cover; display: block;
  aspect-ratio: 4/3;
  transition: transform var(--dur-slow) var(--ease-out-expo);
}
.shot:hover { border-bottom-color: var(--ss-sun-500); }
.shot:hover img, .shot:hover video { }

/* Caption rides in from the bottom on hover, carries the local keyword */
.shot figcaption {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: var(--sp-7) var(--sp-4) var(--sp-4);
  margin: 0; border: 0;
  color: #fff; font-size: 13.5px; line-height: 1.35; font-weight: 600;
  background: linear-gradient(to top, rgba(10,36,48,.92) 18%, rgba(10,36,48,.78) 62%, transparent);
  opacity: 0; transform: translateY(8px);
  transition: opacity var(--dur-base) var(--ease-out-expo), transform var(--dur-base) var(--ease-out-expo);
}
.shot:hover figcaption, .shot:focus-within figcaption { opacity: 1; transform: none; }
/* The real control that opens the viewer. A transparent button over the tile,
   so the figure itself is not a button wrapped around the sound and pause
   buttons (nested controls are unusable with a screen reader). */
.shot__open {
  position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%;
  padding: 0; margin: 0; border: 0; background: none; cursor: zoom-in;
  border-radius: inherit;
}
.shot__open:focus-visible { outline: 3px solid var(--ss-sun-500); outline-offset: 3px; }
@media (hover: none) { .shot figcaption { opacity: 1; transform: none; } }

/* One feature and five tiles fill three columns exactly. At four columns the
   sixth tile sat alone on a row of its own, so that set stays at three. */
@media (min-width: 1200px) {
  .showcase:has(> .shot--feature:first-child):has(> .shot:nth-child(6):last-child) {
    grid-template-columns: repeat(3, 1fr);
  }
  .showcase:has(> .shot:nth-child(6):last-child) > .shot--feature img { aspect-ratio: 4/3; }
}

/* Two columns on a phone: an odd tile at the end spans both rather than
   leaving a hole beside it. */
@media (max-width: 759px) {
  .showcase > .shot:last-child:nth-child(odd) { grid-column: span 2; }
}

/* Size rhythm. Feature tiles are twice the size, tall tiles break the rows. */
@media (min-width: 760px) {
  .shot--feature { grid-column: span 2; grid-row: span 2; }
  .shot--feature img, .shot--feature video { aspect-ratio: 1/1; }
  .shot--tall { grid-row: span 2; }
  .shot--tall img, .shot--tall video { aspect-ratio: 3/4; }
  .shot--wide { grid-column: span 2; }
  .shot--wide img, .shot--wide video { aspect-ratio: 16/9; }
}

/* Video tiles get a play marker so they read as motion */
.shot--video::after {
  content: ""; position: absolute; top: var(--sp-4); left: var(--sp-4); z-index: 2;
  width: 34px; height: 34px; border-radius: 50%;
  background: rgba(10,36,48,.72) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23FF8901' d='M8 5v14l11-7z'/%3E%3C/svg%3E") no-repeat center/18px;
  border: 1px solid rgba(255,255,255,.25);
}
@media (hover: hover) {
  .shot--video::after { opacity: 0; transition: opacity var(--dur-base) var(--ease-out-expo); }
  .shot--video:hover::after { opacity: 1; }
}

/* ── Lightbox ──────────────────────────────────────────────────────────── */
.lightbox {
  position: fixed; inset: 0; z-index: 120;
  background: rgba(6, 22, 30, .94);
  display: grid; place-items: center;
  padding: var(--sp-6);
  opacity: 0; visibility: hidden;
  transition: opacity var(--dur-base) var(--ease-out-expo), visibility 0s linear var(--dur-base);
}
.lightbox.is-open { opacity: 1; visibility: visible; transition-delay: 0s; }
.lightbox__stage { max-width: min(1400px, 94vw); max-height: 84vh; position: relative; }
.lightbox__stage img, .lightbox__stage video {
  max-width: 100%; max-height: 84vh; width: auto; height: auto;
  border-radius: var(--r-md); display: block;
  box-shadow: 0 24px 80px -20px rgba(0,0,0,.7);
}
.lightbox__cap {
  color: rgba(255,255,255,.86); font-size: 14.5px; text-align: center;
  margin-top: var(--sp-4); max-width: 70ch; margin-inline: auto;
}
.lightbox__count { color: rgba(255,255,255,.5); font-size: 13px; font-variant-numeric: tabular-nums; }
.lightbox button {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 52px; height: 52px; border-radius: 50%;
  background: rgba(255,255,255,.10); border: 1px solid rgba(255,255,255,.22);
  display: grid; place-items: center; color: #fff;
  transition: background-color var(--dur-micro) var(--ease-out-expo);
}
.lightbox button:hover { background: var(--ss-sun-500); color: var(--ss-teal-900); border-color: var(--ss-sun-500); }
.lightbox__prev { left: calc(-1 * var(--sp-9)); }
.lightbox__next { right: calc(-1 * var(--sp-9)); }
@media (max-width: 900px) {
  .lightbox__prev { left: var(--sp-2); }
  .lightbox__next { right: var(--sp-2); }
}
.lightbox__close {
  position: fixed; top: var(--sp-5); right: var(--sp-5); transform: none;
  width: 48px; height: 48px;
}
.lightbox svg { width: 20px; height: 20px; fill: currentColor; }

/* ── 22 TRIPTYCH & TWO COLUMN READ ───────────────────────────────────────
   Used under a product lead. Three large photographs break the copy before
   it becomes a wall, and the remaining paragraphs run in two columns so no
   single measure runs longer than the eye wants to track.
   ---------------------------------------------------------------------- */
.triptych {
  display: grid; gap: var(--sp-3);
  grid-template-columns: 1fr;
}
@media (min-width: 700px) { .triptych { grid-template-columns: repeat(3, 1fr); gap: var(--sp-4); align-items: start; } }
@media (min-width: 1100px) { .triptych { gap: var(--sp-5); } }
.triptych .shot img { aspect-ratio: 4/3; }
@media (min-width: 700px) {
  .triptych .shot--tall { margin-top: var(--sp-8); }
  .triptych .shot--tall img { aspect-ratio: 3/4; }
}

.twocol { columns: 1; }
@media (min-width: 900px) { .twocol { columns: 2; column-gap: var(--sp-9); } }
.twocol p { margin: 0 0 var(--sp-5); break-inside: avoid; color: var(--ss-text-mid); }
.twocol p:last-child { margin-bottom: 0; }

/* ── 23 STORY SLIDER ─────────────────────────────────────────────────────
   Sits directly under the hero on every interior page. Large photography
   carries the first impression, and video moves further down the page.
   ---------------------------------------------------------------------- */
.slider { position: relative; }
.slider__frame {
  position: relative; overflow: hidden;
  border-radius: var(--r-md);
  background: var(--ss-teal-900);
  box-shadow: var(--shadow-lift);
}
/* The slide itself is quick. At 620ms the photograph was still travelling
   long after the eye had arrived, which read as sluggish rather than smooth. */
.slider__track {
  display: flex;
  transition: transform 380ms var(--ease-out-expo);
  will-change: transform;
}
.slider__slide { flex: 0 0 100%; position: relative; min-width: 0; }
.slider__slide img {
  width: 100%; display: block;
  aspect-ratio: 3/2; object-fit: cover;
}
@media (min-width: 900px) { .slider__slide img { aspect-ratio: 16/9; } }
/* A slider in a half width column, where 16:9 would crop the windows. */
.slider--4-3 .slider__slide img { aspect-ratio: 4/3; }
/* Drapery page: wide line drawing strips of the cornice styles, shown whole on
   white with room at the sides for the arrows. */
.slider--strip .slider__frame { background: #fff; box-shadow: none; border: 1px solid var(--ss-sand-300); }
.slider--strip .slider__slide { padding: var(--sp-5) var(--sp-4); }
.slider--strip .slider__slide img { aspect-ratio: 7/2; object-fit: contain; }
@media (min-width: 900px) { .slider--strip .slider__slide { padding: var(--sp-6) 88px; } }
/* Drapery page: the Roman shade style drawings, shown whole rather than cropped to 4:3. */
.card__media--drawing img { aspect-ratio: 26/22; object-fit: contain; }

.slider__cap {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: var(--sp-10) var(--sp-6) var(--sp-6);
  background: linear-gradient(to top, rgba(10,36,48,.92) 10%, rgba(10,36,48,.6) 55%, transparent);   /* AA over bright frames */
  color: #fff;
}
@media (min-width: 900px) { .slider__cap { padding: var(--sp-11) var(--sp-8) var(--sp-7); } }
.slider__cap b {
  display: block; font-weight: 800; letter-spacing: -.025em;
  font-size: clamp(1.0625rem, 1.7vw, 1.375rem); line-height: 1.2;
}
.slider__cap span {
  display: block; margin-top: var(--sp-2);
  font-size: 14px; color: rgba(255,255,255,.78); line-height: 1.4;
}

/* Controls */
.slider__nav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
  width: 48px; height: 48px; border-radius: 50%;
  background: rgba(10,36,48,.62); border: 1px solid rgba(255,255,255,.28);
  display: grid; place-items: center; color: #fff;
  transition: background-color var(--dur-micro) var(--ease-out-expo),
              border-color var(--dur-micro) var(--ease-out-expo),
              transform var(--dur-micro) var(--ease-out-expo);
}
.slider__nav:hover {
  background: var(--ss-sun-500); border-color: var(--ss-sun-500);
  color: var(--ss-teal-900);
}
.slider__nav svg { width: 20px; height: 20px; fill: currentColor; }
.slider__prev { left: var(--sp-4); }
.slider__next { right: var(--sp-4); }
@media (min-width: 900px) { .slider__prev { left: var(--sp-6); } .slider__next { right: var(--sp-6); } }

/* Counter and progress dots */
.slider__bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-5); margin-top: var(--sp-5);
}
.slider__dots { display: flex; gap: 7px; flex-wrap: wrap; }
.slider__dot {
  width: 28px; height: 4px; border-radius: 2px;
  background: var(--ss-sand-300);
  transition: background-color var(--dur-micro) var(--ease-out-expo), width var(--dur-base) var(--ease-out-expo);
}
.slider__dot[aria-current="true"] { background: var(--ss-sun-500); width: 44px; }
.on-dark .slider__dot { background: rgba(255,255,255,.28); }
.on-dark .slider__dot[aria-current="true"] { background: var(--ss-sun-500); }
.slider__count {
  font-size: 13px; font-weight: 700; color: var(--ss-text-dim);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.on-dark .slider__count { color: rgba(255,255,255,.6); }

@media (prefers-reduced-motion: reduce) { .slider__track { transition-duration: 1ms; } }

/* ── 24 STORY BLOCK ──────────────────────────────────────────────────────
   Heading and scannable points that give the under-hero slider context.
   ---------------------------------------------------------------------- */
/* The eyebrow sits above the grid rather than inside the left column, so the
   points on the right align to the top of the headline instead of to the
   eyebrow. Doing it structurally beats nudging with a margin that would drift
   as the eyebrow wraps at other breakpoints. */
.storyhead__grid { display: grid; gap: var(--sp-6); align-items: start; }
@media (min-width: 900px) {
  .storyhead__grid { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: var(--sp-9); }
}
.storyhead h2 { margin-bottom: var(--sp-4); }
.storyhead .lead { margin-bottom: 0; }
.storyhead .lead + .lead { margin-top: var(--sp-4); }

/* Prose in the right hand column of a storyhead, for the pages where the copy
   runs as paragraphs rather than as four short points. Same colour as the
   points it stands in for, a touch larger so it reads as body copy. */
.storycopy { color: var(--ss-text-mid); }
.storycopy p { font-size: 16px; line-height: 1.6; margin-bottom: var(--sp-4); }
.storycopy p:last-child { margin-bottom: 0; }

.storypoints { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-4); }
/* .storypoints zeroes its margin, which beats the mt utilities on source
   order, so a spaced variant is needed where the points follow copy. */
.storypoints--spaced { margin-top: var(--sp-8); }
@media (min-width: 640px) { .storypoints { grid-template-columns: 1fr 1fr; gap: var(--sp-5) var(--sp-6); } }
/* Each point hangs under a hairline, the same slat rule as the lists, in
   place of an orange square bullet. */
.storypoints li { position: relative; padding-top: var(--sp-3); border-top: 1px solid var(--ss-line); }
.storypoints b {
  display: block; font-weight: 800; letter-spacing: -.02em;
  font-size: 1rem; color: var(--ss-teal-900); line-height: 1.25;
}
.storypoints span {
  display: block; margin-top: 5px; font-size: 14.5px; line-height: 1.45;
  color: var(--ss-text-mid);
}

/* ── 25 VIDEO GRID ───────────────────────────────────────────────────────
   Footage rows. Two up rather than three, so the frame is large enough to
   read what is happening, and the caption sits on its own gradient instead
   of dark text on a dark section.
   ---------------------------------------------------------------------- */
.videogrid { display: grid; gap: var(--sp-4); grid-template-columns: 1fr; }
@media (min-width: 760px)  { .videogrid { grid-template-columns: repeat(2, 1fr); gap: var(--sp-5); } }
@media (min-width: 1300px) { .videogrid { gap: var(--sp-6); } }

.videogrid .shot img, .videogrid .shot video { aspect-ratio: 16/9; }
/* A phone clip in the grid keeps its own portrait shape, centred, instead of
   being cropped into a widescreen tile. */
.videogrid .shot--portrait { max-width: 440px; margin-inline: auto; width: 100%; }
.videogrid .shot--portrait video { aspect-ratio: 9/16; }

/* An odd number of clips left the last one stranded in a half width column
   with a hole beside it. The final tile spans the row when it would otherwise
   sit alone, which covers both the single video case and three. */
@media (min-width: 760px) {
  .videogrid > :last-child:nth-child(odd) { grid-column: 1 / -1; }
}

/* Footage captions stay visible. They carry the location keyword and the
   viewer should not have to hover to find out what they are looking at. They
   sit in a box under the clip rather than on it (Tim, Sep 30: on a phone the
   caption and its shade covered most of the frame). The tile takes the box
   colour, so tiles of unequal caption length still line up as one row. */
.videogrid .shot {
  display: flex; flex-direction: column;
  background: var(--ss-teal-800);
}
.videogrid .shot img, .videogrid .shot video { height: auto; flex: none; }
.videogrid .shot figcaption {
  position: static; flex: 1 0 auto;
  opacity: 1; transform: none;
  background: none;
  font-size: 14.5px; line-height: 1.4;
  padding: var(--sp-4) var(--sp-5) var(--sp-5);
}
@media (min-width: 900px) { .videogrid .shot figcaption { font-size: 15px; } }

/* Child Safe marker on operating system cards */
.tag-safe {
  display: inline-block; vertical-align: middle;
  margin-left: var(--sp-2); padding: 3px var(--sp-3);
  border-radius: var(--r-sm);
  background: var(--ss-sun-100); color: #9C4E07; /* 5:1 on sun 100, AA */
  font-family: var(--font-body); font-size: 12px; font-weight: 700;
}

/* Named option ranges: colours, systems, frames */
.chiplist { list-style: none; margin: var(--sp-4) 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.chiplist li {
  padding: 7px var(--sp-4); border-radius: var(--r-sm);
  background: var(--ss-white); border: 1px solid var(--ss-line);
  font-size: 14px; font-weight: 600; color: var(--ss-teal-900);
}

/* ── 26 SECTION SEAMS ────────────────────────────────────────────────────
   Two sections sharing a background stack their vertical padding, which on a
   desktop viewport meant up to 232px of empty ground between a slider and the
   copy under it. Where the background does not change there is no seam to
   express, so the following section drops its top padding.
   ---------------------------------------------------------------------- */
/* Where the background does change, the colour break is doing the separating
   already, so a full 160px on top of the previous section's 160px reads as a
   hole rather than as breathing room. */
.section + .section { padding-top: var(--sp-9); }
@media (min-width: 900px) { .section + .section { padding-top: var(--sp-10); } }

.section--sand  + .section--sand,
.section--white + .section--white,
.section--ink   + .section--ink,
.section--teal  + .section--teal { padding-top: 0; }

/* Plain sections inherit the page ground, so two in a row are the same case. */
.section:not(.section--sand):not(.section--white):not(.section--ink):not(.section--teal)
+ .section:not(.section--sand):not(.section--white):not(.section--ink):not(.section--teal) {
  padding-top: 0;
}

/* A section that opens with its own heading still needs breathing room, just
   not a full section's worth on top of the previous one's. */
.section--tight + .section > .container > .section-head:first-child,
.section--tight + .section > .container > .head-row:first-child { padding-top: var(--sp-6); }

/* ── 27 PORTRAIT FIGURE ──────────────────────────────────────────────────
   The client shot a lot of footage on a phone, so it is 9:16. Dropping that
   into the 4:3 figure used elsewhere letterboxed it into a sliver, so a
   portrait figure gets its own ratio and a width that keeps it beside the
   copy rather than towering over it.
   ---------------------------------------------------------------------- */
/* The two column point list is for a full width block. Inside the narrower
   feature column it orphans the third point, so it runs as one column. */
.feature__body .storypoints { grid-template-columns: 1fr; gap: var(--sp-5); }

/* Three points across a full width block rather than beside a figure. */
.storypoints--wide { max-width: 1100px; }
@media (min-width: 900px) { .storypoints--wide { grid-template-columns: repeat(3, 1fr); gap: var(--sp-7); } }
.moredetail--wide { max-width: 820px; }
.feature__body h2 { margin-bottom: var(--sp-6); }
.feature__body h2.h2--long { font-size: clamp(1.5rem, 2.6vw, 2.125rem); line-height: 1.12; }

.fig--tall .fig__img video { aspect-ratio: 9 / 16; width: 100%; object-fit: cover; }
.fig--tall { max-width: 380px; margin-inline: auto; }
@media (min-width: 900px) { .fig--tall { margin-inline: 0; } }

/* Scannable by default, with the full explanation one click away. The prose is
   in the DOM either way, so nothing is lost to search, but a reader who only
   wants the three points is not made to wade through it. */
.moredetail { margin-top: var(--sp-6); border-top: 1px solid var(--ss-line); }
.moredetail > summary {
  cursor: pointer; list-style: none;
  padding: var(--sp-4) 0 0;
  font-size: 14.5px; font-weight: 600; color: var(--ss-teal-600);
  display: flex; align-items: center; gap: 8px;
}
.moredetail > summary::-webkit-details-marker { display: none; }
.moredetail > summary::after {
  content: ""; width: 8px; height: 8px; flex: none;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--dur-micro) var(--ease-out-expo);
}
.moredetail[open] > summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.moredetail > summary:hover { color: var(--ss-sun-600); }
.moredetail > p { font-size: 15px; color: var(--ss-text-mid); margin-top: var(--sp-4); }

/* The crew shots are a mix of orientations, some taken on a phone in portrait.
   Anchoring the crop to the top keeps faces in frame rather than cutting heads
   off, which is what a centred crop does to a tall group photo. */
.peopleband .feature__media img { aspect-ratio: 4 / 3; object-fit: cover; object-position: center top; }
/* A tall portrait cropped from the top frames a wall and cuts the people
   off, so a variant can carry its own object-position inline. */

/* ── 28 SOUND CONTROL ────────────────────────────────────────────────────
   Clips autoplay muted because browsers require it, so the button is the only
   way a visitor discovers there is sound at all. Two real speaker glyphs,
   swapped by state: the first attempt drew them out of CSS borders and read as
   a smudge at this size.
   ---------------------------------------------------------------------- */
/* The button anchors to whatever wraps the video, so those wrappers have to
   establish a containing block. Without this it positions against the page and
   lands outside the figure, which clips it away entirely. Deleted once by
   accident while restyling the icon, hence the note. */
/* .showreel__media is not in this list: the showreel block positions it with
   a stronger selector, and it has to stay that way for the cross fade. */
.fig__img, .card__media, .videoblock__media { position: relative; }

.soundbtn {
  position: absolute; top: var(--sp-4); right: var(--sp-4); z-index: 3;
  width: 36px; height: 36px; padding: 0;
  display: grid; place-items: center;
  border: 0; border-radius: 50%;
  background: rgba(10, 36, 48, .55);
  color: #fff; cursor: pointer;
  transition: background-color var(--dur-micro) var(--ease-out-expo),
              transform var(--dur-micro) var(--ease-out-expo);
}
.soundbtn:hover { background: var(--ss-sun-500); color: var(--ss-teal-900); }
.soundbtn:focus-visible { outline: 2px solid var(--ss-sun-500); outline-offset: 3px; }

.soundbtn__ico { width: 19px; height: 19px; grid-area: 1 / 1; fill: currentColor; }
.soundbtn__ico--on { opacity: 0; }
.soundbtn.is-on { background: var(--ss-sun-500); color: var(--ss-teal-900); }
.soundbtn.is-on .soundbtn__ico--off { opacity: 0; }
.soundbtn.is-on .soundbtn__ico--on { opacity: 1; }
/* Where there is a pointer, the button waits for it instead of sitting on
   every frame. Touch screens keep it showing. */
@media (hover: hover) {
  .soundbtn { opacity: 0; transition: opacity var(--dur-base) var(--ease-out-expo), background-color var(--dur-micro) var(--ease-out-expo); }
  *:hover > .soundbtn, .soundbtn:focus-visible, .soundbtn.is-on { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .soundbtn { transition: none; }
  .soundbtn:hover { transform: none; }
}

/* Pause control (WCAG 2.2.2). Same look and behaviour as the sound button:
   top right, showing on hover or keyboard focus and always on touch. Sits to
   the left of the sound button where a clip has both. */
.pausebtn {
  position: absolute; top: var(--sp-4); right: var(--sp-4); z-index: 3;
  width: 36px; height: 36px; padding: 0;
  display: grid; place-items: center;
  border: 0; border-radius: 50%;
  background: rgba(10, 36, 48, .55);
  color: #fff; cursor: pointer;
  transition: background-color var(--dur-micro) var(--ease-out-expo);
}
.pausebtn svg { width: 18px; height: 18px; fill: currentColor; }
.pausebtn:hover { background: var(--ss-sun-500); color: var(--ss-teal-900); }
.pausebtn:focus-visible { outline: 2px solid var(--ss-sun-500); outline-offset: 3px; }
.soundbtn ~ .pausebtn { right: calc(var(--sp-4) + 44px); }
.showreel > .pausebtn { top: var(--sp-6); right: var(--sp-6); }
.pagehero__media > .pausebtn { z-index: 3; }
@media (hover: hover) {
  .pausebtn { opacity: 0; transition: opacity var(--dur-base) var(--ease-out-expo), background-color var(--dur-micro) var(--ease-out-expo); }
  *:hover > .pausebtn, .pausebtn:focus-visible { opacity: 1; }
}

/* Captions on the four clips with speech. Set in the site's body face, on a
   dark band, so they read over any frame. */
video::cue {
  font-family: var(--font-body); font-size: .92em; line-height: 1.35;
  color: #fff; background: rgba(10, 36, 48, .78);
}

/* ── 29 TEXT ON DARK SECTIONS ────────────────────────────────────────────
   A dark section sets colour on itself, but every component that sets its own
   dark colour ignores that and stays dark. The guarantee band on the service
   pages was a teal panel with near black body copy on it: the bold lead-ins
   were readable and every explanation under them was not.

   Anything that carries its own muted colour is re-stated here for the dark
   backgrounds. Cards are excluded, because a white card on a dark section
   keeps its own light palette.
   ---------------------------------------------------------------------- */
.section--ink :is(p, li, span, .lead, dd, td):not(.card *):not(.tag-safe):not(.chip),
.section--teal :is(p, li, span, .lead, dd, td):not(.card *):not(.tag-safe):not(.chip) {
  color: rgba(255, 255, 255, .82);
}
.section--ink :is(h1, h2, h3, h4, b, strong):not(.card *),
.section--teal :is(h1, h2, h3, h4, b, strong):not(.card *) { color: #fff; }

.section--ink .storypoints b, .section--teal .storypoints b { color: #fff; }
.section--ink .storypoints li, .section--teal .storypoints li { border-color: var(--ss-line-dk); }
.section--ink .storypoints span, .section--teal .storypoints span { color: rgba(255, 255, 255, .78); }
.section--ink .eyebrow, .section--teal .eyebrow { color: rgba(255, 255, 255, .72); }

/* Links have to stay findable against the dark ground. */
.section--ink a:not(.btn):not(.card), .section--teal a:not(.btn):not(.card) { color: #fff; }
.section--ink .link-arrow, .section--teal .link-arrow { color: var(--ss-sun-500); }

/* Town lists on the service pages, matching the branch panel on the home page.
   A town we have written a page for links to it; the rest still appear, because
   the coverage claim is the point, but they are not dressed up as links. */
.townwrap { margin-top: var(--sp-7); }
.townwrap__more {
  margin-top: var(--sp-5); font-size: 14.5px; color: var(--ss-text-dim);
}
.linkcard--plain { cursor: default; color: var(--ss-text-mid); }
.linkcard--plain:hover { transform: none; box-shadow: none; border-color: var(--ss-line); }
html[data-region="il"] .townwrap[data-region-only="il"] { display: block !important; }

/* ── 24 BOOKING FLOW ──────────────────────────────────────────────────────
   /schedule-now. Three steps on one page: who, when, details. The visual job
   is to make a free in-home appointment feel like three small decisions
   rather than one form, so each step shows only its own question and the
   summary on the right keeps the answers already given in view.
   ---------------------------------------------------------------------- */

/* A class with a display value beats the user agent's [hidden] rule, so any
   row we toggle from script needs this or it stays on screen with an empty
   value under its label. */
[hidden] { display: none !important; }

.booking { margin-top: var(--sp-8); }
/* The step panels differ in height by hundreds of pixels, so swapping them
   collapses the document under the scroll position and the browser yanks the
   page. Script pins this column at the old height and moves it to the new one;
   the transition that makes that a movement rather than a snap has to be
   declared here, not inline, or it does not start. */
.booking__main { transition: min-height 340ms var(--ease-out-expo); }
@media (prefers-reduced-motion: reduce) { .booking__main { transition: none; } }
.booking__layout { display: grid; gap: var(--sp-8); align-items: start; }
@media (min-width: 1000px) {
  .booking__layout { grid-template-columns: minmax(0, 1fr) 340px; gap: var(--sp-10); }
  .booking__aside { position: sticky; top: calc(var(--header-h) + var(--sp-6)); }
}

/* Progress rail. Three numbers, the current one filled. */
.bksteps {
  display: flex; align-items: center; gap: var(--sp-3);
  list-style: none; margin: 0 0 var(--sp-7); padding: 0; flex-wrap: wrap;
}
.bksteps__item {
  display: flex; align-items: center; gap: var(--sp-3);
  font-size: 13.5px; font-weight: 700; color: var(--ss-text-dim);
}
.bksteps__item + .bksteps__item::before {
  content: ""; width: 28px; height: 2px; background: var(--ss-line);
}
.bksteps__num {
  width: 26px; height: 26px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--ss-sand-200); color: var(--ss-text-mid);
  font-size: 13px; font-variant-numeric: tabular-nums;
}
.bksteps__item.is-active { color: var(--ss-teal-900); }
.bksteps__item.is-active .bksteps__num { background: var(--ss-sun-500); color: var(--ss-teal-900); }
.bksteps__item.is-done .bksteps__num { background: var(--ss-teal-600); color: #fff; }

.bkstep__head { margin-bottom: var(--sp-6); }
.bkstep__head h2 { margin-bottom: var(--sp-3); }
.bkstep__sub { color: var(--ss-text-mid); max-width: 60ch; margin: 0; }

/* The people. A photograph and a real sentence beside it, because the choice
   being offered is a person coming to your house, not a dropdown value. */
.speclist { display: grid; gap: var(--sp-4); margin-bottom: var(--sp-7); }
.speccard {
  display: grid; grid-template-columns: 72px 1fr auto; gap: var(--sp-5);
  align-items: center; text-align: left; width: 100%;
  padding: var(--sp-5); border-radius: var(--r-md);
  background: var(--ss-white); border: 1px solid var(--ss-line);
  /* Grey until chosen, orange once it is. It has to stay a visible 3px either
     way: a transparent bottom border leaves the box looking cut off along the
     bottom edge rather than looking unselected. */
  border-bottom: 3px solid var(--ss-line);
  transition: border-color var(--dur-micro) var(--ease-out-expo),
              box-shadow var(--dur-micro) var(--ease-out-expo),
              transform var(--dur-micro) var(--ease-out-expo);
  cursor: pointer;
}
@media (min-width: 600px) { .speccard { grid-template-columns: 84px 1fr auto; } }
.speccard:hover { border-color: var(--ss-teal-300); }
/* Pressing settles the card back onto the page rather than shrinking it. A 4%
   scale reads as tactile on a 48px button and as a glitch on a 700px card. */

.speccard.is-selected { border-color: var(--ss-teal-300); border-bottom-color: var(--ss-sun-500); }
.speccard__photo {
  width: 72px; height: 72px; border-radius: 50%; overflow: hidden;
  background: var(--ss-sand-200); flex: none;
  /* Pure black at low opacity. A tinted neutral would pick up the sand behind
     it and read as dirt on the edge of the photograph. */
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1);
}
@media (min-width: 600px) { .speccard__photo { width: 84px; height: 84px; } }
.speccard__photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.speccard__photo--any { display: grid; place-items: center; color: var(--ss-teal-600); }
.speccard__photo--any svg { width: 34px; height: 34px; }
.speccard__name {
  display: block; font-family: var(--font-display); font-weight: 800;
  font-size: 1.125rem; letter-spacing: -.025em; color: var(--ss-teal-900);
}
.speccard__role {
  display: block; font-size: 13px; font-weight: 700;
  color: var(--ss-teal-600); margin-top: 2px;
}
.speccard__bio { margin: var(--sp-3) 0 0; font-size: 15px; line-height: 1.5; color: var(--ss-text-mid); }
.speccard__tick {
  width: 24px; height: 24px; border-radius: 50%; flex: none;
  border: 2px solid var(--ss-line); position: relative;
}
.speccard.is-selected .speccard__tick { border-color: var(--ss-sun-500); background: var(--ss-sun-500); }
.speccard.is-selected .speccard__tick::after {
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 12px; height: 9px;
  background: var(--ss-teal-900);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 13'%3E%3Cpath d='M6.5 13 0 6.5l1.8-1.8 4.7 4.7L16.2 0 18 1.8z'/%3E%3C/svg%3E") no-repeat center/contain;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 13'%3E%3Cpath d='M6.5 13 0 6.5l1.8-1.8 4.7 4.7L16.2 0 18 1.8z'/%3E%3C/svg%3E") no-repeat center/contain;
}
.speccard input { position: absolute; opacity: 0; pointer-events: none; }

/* Days rail. A horizontal strip beats a month grid here: every pill shown is
   a day that actually has a slot, so there is nothing to hunt for. */
.dayrail {
  display: flex; gap: var(--sp-3); overflow-x: auto;
  padding-bottom: var(--sp-2); scroll-snap-type: x proximity;
  /* Four weeks of days do not fit, so the right edge fades to say so. A grey
     scrollbar track running the width of the rail said the same thing far more
     loudly than it needed to. */
  scrollbar-width: none;
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 56px), transparent 100%);
  mask-image: linear-gradient(to right, #000 calc(100% - 56px), transparent 100%);
}
.dayrail::-webkit-scrollbar { height: 0; }
.daypill {
  flex: none; scroll-snap-align: start;
  display: grid; gap: 2px; justify-items: center;
  min-width: 72px; padding: var(--sp-4) var(--sp-3);
  border-radius: var(--r-md); border: 1px solid var(--ss-line);
  background: var(--ss-white); cursor: pointer;
  transition: border-color var(--dur-micro) var(--ease-out-expo),
              background var(--dur-micro) var(--ease-out-expo);
}
.daypill:hover { border-color: var(--ss-teal-300); }
.daypill:active { scale: .96; }
.daypill__dow, .daypill__mon { font-size: 11.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--ss-text-dim); }
.daypill__num { font-family: var(--font-display); font-size: 1.375rem; font-weight: 800; letter-spacing: -.03em; color: var(--ss-teal-900); font-variant-numeric: tabular-nums; }
.daypill.is-active { background: var(--ss-teal-900); border-color: var(--ss-teal-900); }
.daypill.is-active .daypill__dow, .daypill.is-active .daypill__mon { color: rgba(255,255,255,.7); }
.daypill.is-active .daypill__num { color: #fff; }

.slots { margin-top: var(--sp-7); }
.slots__day { font-family: var(--font-display); font-weight: 800; font-size: 1.125rem; letter-spacing: -.025em; color: var(--ss-teal-900); margin: 0 0 var(--sp-5); }
.slots__group + .slots__group { margin-top: var(--sp-6); }
.slots__label { font-size: 13px; font-weight: 700; color: var(--ss-teal-600); margin: 0 0 var(--sp-3); }
.slots__none { margin: 0; font-size: 15px; color: var(--ss-text-dim); }
.slots__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: var(--sp-3); }
.slotbtn {
  padding: var(--sp-4) var(--sp-3); border-radius: var(--r-md);
  border: 1px solid var(--ss-line); background: var(--ss-white);
  font-weight: 700; font-size: 15px; color: var(--ss-teal-900);
  font-variant-numeric: tabular-nums; cursor: pointer;
  transition: border-color var(--dur-micro) var(--ease-out-expo),
              background var(--dur-micro) var(--ease-out-expo),
              transform var(--dur-micro) var(--ease-out-expo);
}
.slotbtn:hover { border-color: var(--ss-sun-500); background: var(--ss-sun-100); }
.slotbtn:active { scale: .96; }

/* Slots arrive as a set when a day is chosen, so they come in staggered rather
   than all at once. A run-once sequence, which is what keyframes are for. The
   delay is set per button from script. */
@keyframes slot-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.slots__grid .slotbtn {
  animation: slot-in 260ms var(--ease-out-expo) backwards;
  animation-delay: calc(var(--i, 0) * 22ms);
}
@media (prefers-reduced-motion: reduce) {
  .slots__grid .slotbtn { animation-duration: 1ms; animation-delay: 0ms; }
}

/* Shown when live times cannot load. Not an error page: three routes that all
   work, stated plainly. */
.bookfall {
  padding: var(--sp-6); border-radius: var(--r-md);
  background: var(--ss-sand-100); border: 1px solid var(--ss-line);
}
.bookfall__lead { margin: 0 0 var(--sp-5); font-weight: 700; color: var(--ss-teal-900); }
.bookfall__or { margin: var(--sp-5) 0 0; font-size: 14.5px; color: var(--ss-text-mid); }

/* Summary card. Holds the answers already given so nobody has to scroll back
   up to check who they picked. */
.bksummary {
  padding: var(--sp-6); border-radius: var(--r-md);
  background: var(--ss-white); border: 1px solid var(--ss-line);
  border-bottom: 3px solid var(--ss-sun-500);
}
.bksummary__brand {
  display: flex; align-items: center; gap: var(--sp-4);
  padding-bottom: var(--sp-5); margin-bottom: var(--sp-5);
  border-bottom: 1px solid var(--ss-line);
}
.bksummary__brand img { width: 52px; height: auto; flex: none; }
.bksummary__title { margin: 0; font-family: var(--font-display); font-weight: 800; font-size: 1.0625rem; letter-spacing: -.02em; color: var(--ss-teal-900); }
.bksummary dl { margin: 0; display: grid; gap: var(--sp-4); }
.bksummary__row { display: grid; gap: 2px; }
.bksummary__row dt {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: 12.5px; font-weight: 700;
  color: var(--ss-text-dim);
}
.bksummary__row dd { margin: 0; font-weight: 700; color: var(--ss-teal-900); font-variant-numeric: tabular-nums; }

/* Confirmation tick. Green because it means done, which is the one thing on
   this page orange should not be saying: orange is the colour of the next
   thing to press. It only ever appears beside a choice already made. */
.bkcheck {
  width: 15px; height: 15px; flex: none;
  display: grid; place-items: center;
  border-radius: 50%; background: var(--ss-ok);
  opacity: 0; transform: scale(.25); filter: blur(4px);
  transition: opacity 220ms cubic-bezier(0.2, 0, 0, 1),
              transform 220ms cubic-bezier(0.2, 0, 0, 1),
              filter 220ms cubic-bezier(0.2, 0, 0, 1);
}
.bksummary__row.is-confirmed .bkcheck { opacity: 1; transform: scale(1); filter: blur(0); }
.bkcheck svg { width: 9px; height: 7px; fill: #fff; display: block; }
@media (prefers-reduced-motion: reduce) {
  .bkcheck { transition-duration: 1ms; filter: none; }
}
.bksummary__facts { list-style: none; margin: var(--sp-6) 0 0; padding: var(--sp-5) 0 0; border-top: 1px solid var(--ss-line); display: grid; gap: var(--sp-3); }
.bksummary__facts li { position: relative; padding-left: var(--sp-6); font-size: 14.5px; color: var(--ss-text-mid); }
.bksummary__facts li::before {
  content: ""; position: absolute; left: 0; top: .42em; width: 14px; height: 10px;
  background: var(--ss-sun-500);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 13'%3E%3Cpath d='M6.5 13 0 6.5l1.8-1.8 4.7 4.7L16.2 0 18 1.8z'/%3E%3C/svg%3E") no-repeat center/contain;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 13'%3E%3Cpath d='M6.5 13 0 6.5l1.8-1.8 4.7 4.7L16.2 0 18 1.8z'/%3E%3C/svg%3E") no-repeat center/contain;
}

.bkback { margin-top: var(--sp-6); }
.bkback button {
  background: none; border: 0; padding: 0; cursor: pointer;
  font-weight: 700; font-size: 14.5px; color: var(--ss-teal-600);
}
.bkback button:hover { color: var(--ss-teal-900); text-decoration: underline; }

.bkstatus {
  margin-top: var(--sp-5); padding: var(--sp-4) var(--sp-5);
  border-radius: var(--r-md); background: var(--ss-sun-100);
  border: 1px solid var(--ss-sun-400); color: var(--ss-teal-900);
  font-size: 15px; font-weight: 600;
}

/* Booked. */
.bkdone { text-align: center; padding: var(--sp-9) var(--sp-6); }
.bkdone__mark {
  width: 64px; height: 64px; margin: 0 auto var(--sp-6);
  border-radius: 50%; background: var(--ss-sun-500);
  display: grid; place-items: center;
}
.bkdone__mark svg { width: 30px; height: 22px; fill: var(--ss-teal-900); }
.bkdone dl { display: inline-grid; gap: var(--sp-4); text-align: left; margin: var(--sp-7) 0 0; }

/* ── 30 OPTION AND SWATCH IMAGERY ────────────────────────────────────────
   Swatch charts and option diagrams are documents, not photographs. Cropping
   them to a fixed ratio cut the fabric names off the bottom of every awning
   colour card, which is the one thing a visitor is trying to read. They are
   contained rather than covered, on a neutral ground so the trimmed edges do
   not look like a mistake.
   ---------------------------------------------------------------------- */
.fig--doc .fig__img { background: var(--ss-white); border: 1px solid var(--ss-line); }
.fig--doc .fig__img img { aspect-ratio: auto; object-fit: contain; width: 100%; height: auto; }
/* The SA Tracks sheet is a tall portrait graphic; held narrower so it does
   not run twice the height of the copy beside it. */
.fig--satrack { max-width: 440px; width: 100%; margin-inline: auto; }
/* Exterior Shade Solutions: the four protection icons are light artwork on a
   transparent background, drawn for a dark band, so they sit on one. */
.fig--iconband .fig__img { background: var(--ss-teal-900); padding: var(--sp-5) var(--sp-6); }
@media (min-width: 900px) { .fig--iconband .fig__img { padding: var(--sp-6) var(--sp-10); } }
/* Skylight Windows: the skylight is overhead, at the top of every photo, so
   crops anchor to the top of the frame instead of cutting it off. */
.crop-top img { object-position: center top; }

/* Landscape footage in the same slot as the portrait phone clips. It keeps its
   own 16:9 rather than being forced into a 9:16 frame it would be cropped to
   pieces by. */
.fig--wideclip .fig__img video { aspect-ratio: 16 / 9; width: 100%; object-fit: cover; }

/* A call to action part way down a long page, on the sand ground rather than
   the closing band's darker one, so it reads as a pause and not as the end. */
.ctaband--mid { background: var(--ss-sand-100); color: var(--ss-text); }
.ctaband--mid h2 { color: var(--ss-teal-900); }
.ctaband--mid p { color: var(--ss-text-mid); }

/* The ghost button is drawn for a dark band. On the light mid page one it was
   white on sand, which made the phone number all but invisible. */
.ctaband--mid .btn--ghost {
  color: var(--ss-teal-900);
  border-color: rgba(10, 36, 48, .28);
  background: transparent;
}
.ctaband--mid .btn--ghost:hover {
  background: var(--ss-teal-900); color: #fff; border-color: var(--ss-teal-900);
}
.ctaband--mid .btn--ghost svg { fill: currentColor; }

/* ── 30 PRODUCT PICKER ────────────────────────────────────────────────────
   "What are you looking at?" on the booking form. A checkbox beside a word is
   a form control; this is a choice between products, and people recognise the
   shape of a shutter faster than they read the word. Tiles, an icon each, and
   an Other that opens a box to type in.
   ---------------------------------------------------------------------- */
.pickgrid {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-top: var(--sp-2);
}
@media (min-width: 560px) { .pickgrid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.pick {
  position: relative;
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-3);
  padding: var(--sp-4); min-height: 92px;
  border: 1px solid var(--ss-line); border-radius: var(--r-sm);
  background: var(--ss-white); cursor: pointer;
  font-size: 14.5px; font-weight: 700; line-height: 1.25; color: var(--ss-teal-900);
  transition: border-color var(--dur-micro) var(--ease-out-expo),
              background-color var(--dur-micro) var(--ease-out-expo),
              box-shadow var(--dur-micro) var(--ease-out-expo);
}
.pick:hover { border-color: var(--ss-teal-300); }
.pick:active { scale: .96; }
.pick:has(input:focus-visible) { outline: 2px solid var(--ss-sun-500); outline-offset: 2px; }
.pick input { position: absolute; opacity: 0; width: 0; height: 0; margin: 0; min-height: 0; }

.pick__ico {
  width: 26px; height: 26px; flex: none;
  color: var(--ss-teal-600);
  transition: color var(--dur-micro) var(--ease-out-expo);
}
.pick__ico svg { width: 100%; height: 100%; display: block; }

.pick:has(input:checked) {
  border-color: var(--ss-sun-500); background: var(--ss-sun-100);
  box-shadow: inset 0 0 0 1px var(--ss-sun-500);
}
.pick:has(input:checked) .pick__ico { color: var(--ss-sun-600); }

/* The tick rides in the top right, on the same scale, opacity and blur curve
   as the confirmation ticks in the summary card. */
.pick__tick {
  position: absolute; top: var(--sp-3); right: var(--sp-3);
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--ss-sun-500); display: grid; place-items: center;
  opacity: 0; transform: scale(.25); filter: blur(4px);
  transition: opacity 200ms cubic-bezier(0.2, 0, 0, 1),
              transform 200ms cubic-bezier(0.2, 0, 0, 1),
              filter 200ms cubic-bezier(0.2, 0, 0, 1);
}
.pick:has(input:checked) .pick__tick { opacity: 1; transform: scale(1); filter: blur(0); }
.pick__tick svg { width: 9px; height: 7px; fill: var(--ss-teal-900); display: block; }

/* Opens under the grid when Other is ticked. */
.pickother { margin-top: var(--sp-3); }
.pickother[hidden] { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  .pick__tick { transition-duration: 1ms; filter: none; }
  .pick:active { scale: 1; }
}

/* Each step fades up as it opens. The container height is animated from
   script at the same time, so the two read as one movement. */
@keyframes bkstep-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
[data-step].is-entering { animation: bkstep-in 300ms var(--ease-out-expo) backwards; }
@media (prefers-reduced-motion: reduce) {
  [data-step].is-entering { animation-duration: 1ms; }
}

/* Skeleton shapes for the diary while it loads. Same footprint as the real
   controls so the column does not resize when the times arrive. */
.daypill.is-skeleton, .slotbtn.is-skeleton {
  pointer-events: none; border-color: transparent;
  background: linear-gradient(90deg, var(--ss-sand-100) 25%, var(--ss-sand-200) 37%, var(--ss-sand-100) 63%);
  background-size: 400% 100%;
  animation: bkshimmer 1400ms ease-in-out infinite;
}
.daypill.is-skeleton { height: 88px; }
.slotbtn.is-skeleton { height: 51px; }
.slots__day--skeleton {
  width: 220px; height: 20px; border-radius: 4px;
  background: var(--ss-sand-100);
}
@keyframes bkshimmer {
  from { background-position: 100% 0; }
  to   { background-position: 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .daypill.is-skeleton, .slotbtn.is-skeleton { animation: none; }
}

/* ── 30 COMPARE SWITCHER (TEMPORARY) ─────────────────────────────────────
   A review tool for the solutions cluster, not part of the finished site.
   Delete this whole section, initCompare() in main.js and the panes in
   src/pages/solutions before launch.
   ---------------------------------------------------------------------- */
[hidden] { display: none !important; }

.cmpbar {
  position: fixed; z-index: 200;
  /* Bottom, not top. At the top it sat straight over the branch switcher.
     Lifted clear of the sticky call bar on a phone. */
  bottom: calc(var(--sp-4) + 64px); left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 6px 6px 6px var(--sp-4);
  border-radius: var(--r-pill);
  background: rgba(10, 36, 48, .94);
  border: 1px solid rgba(255, 255, 255, .18);
  box-shadow: 0 8px 28px -8px rgba(10, 36, 48, .55);
}
.cmpbar__lbl {
  font-size: 12px; font-weight: 700;
  color: rgba(255, 255, 255, .55);
}
.cmpbar__opt {
  padding: 7px var(--sp-4); border: 0; border-radius: var(--r-pill);
  font: inherit; font-size: 13px; font-weight: 700;
  color: rgba(255, 255, 255, .72); background: transparent; cursor: pointer;
  transition: background-color var(--dur-micro) var(--ease-out-expo),
              color var(--dur-micro) var(--ease-out-expo);
}
.cmpbar__opt:hover { color: #fff; background: rgba(255, 255, 255, .10); }
.cmpbar__opt[aria-pressed="true"] { background: var(--ss-sun-500); color: var(--ss-teal-900); }
.cmpbar__opt:focus-visible { outline: 2px solid var(--ss-sun-400); outline-offset: 2px; }
@media (min-width: 900px) { .cmpbar { bottom: var(--sp-5); } }

/* The reproduced live page. Same copy and the same photographs as the live
   site, set in this site's type and layout so the two versions can be compared
   on what they say rather than on how they look. */
.livepage__h1 {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(2rem, 4.4vw, 3rem); line-height: 1.06; letter-spacing: -.035em;
  color: var(--ss-teal-900); margin: 0 0 var(--sp-4);
  text-wrap: balance;
}
/* Live photography is a mix of portrait and landscape phone shots, so it keeps
   its own proportions instead of being forced into a crop it was never framed
   for. The gallery below is square by design. */
/* Several of the live site's section media are autoplay clips rather than
   stills, so the frame has to size video the same way it sizes a photograph.
   The poster is kept on each one, which is what shows before it plays and what
   shows under prefers-reduced-motion. */
.figbox--auto img, .figbox--auto video { aspect-ratio: auto; height: auto; }
.figbox video { background: var(--ss-sand-200); }

/* ── 31 BRAND GUIDE PANE (TEMPORARY) ─────────────────────────────────────
   The third compare pane. Same live copy, same new layout, but re-tokenised
   to the Solar Shield Blinds Brand Guide v.2026.01 rather than to this site's
   own palette and type.

   It works by overriding the design tokens inside one scope, so every existing
   component picks up the brand values without being rewritten. Nothing here
   changes the rest of the site.

   From the guide:
     #155E70  Solar Shield Blue     primary dark, and the colour for text
     #FFFFFF  Solar Shield White    the preferred base for web
     #FF8900  Solar Shield Orange   accent only
     #F7FFFE  Solar Shield Light Blue
     Source Sans Pro, regular / bold / italic
   ---------------------------------------------------------------------- */
.bg3 {
  --ss-teal-900: #155E70;
  --ss-teal-800: #155E70;
  --ss-teal-700: #155E70;
  --ss-teal-600: #155E70;
  --ss-teal-500: #2C7C90;
  --ss-teal-300: #7FB3BF;
  --ss-teal-100: #E3F1F3;

  --ss-sun-600: #E67C00;
  --ss-sun-500: #FF8900;
  --ss-sun-400: #FFA340;
  --ss-sun-100: #FFE8CE;

  /* White is the base. The light blue takes the place of the sand tints. */
  --ss-white: #FFFFFF;
  --ss-sand-50:  #FFFFFF;
  --ss-sand-100: #F7FFFE;
  --ss-sand-200: #E8F4F5;
  --ss-sand-300: #CFE4E7;

  --ss-line: rgba(21, 94, 112, .16);
  --ss-line-soft: rgba(21, 94, 112, .09);

  /* The guide is explicit that blue is the text colour. */
  --ss-text: #155E70;
  --ss-text-mid: #3D7A8A;
  --ss-text-dim: #6D9AA6;

  --font-display: "Source Sans 3", "Source Sans Pro", ui-sans-serif, system-ui, sans-serif;
  --font-body: "Source Sans 3", "Source Sans Pro", ui-sans-serif, system-ui, sans-serif;

  color: var(--ss-text);
  font-family: var(--font-body);
}
/* Source Sans is a quieter face than Manrope and carries less weight at the
   same size, so the display sizes come up and the tracking comes back toward
   neutral rather than the tight negative the geometric face wanted. */
.bg3 h1, .bg3 h2, .bg3 h3, .bg3 h4, .bg3 .livepage__h1 { letter-spacing: -.015em; font-weight: 700; }
.bg3 .lead { color: var(--ss-text-mid); }
.bg3 .eyebrow { color: var(--ss-sun-500); letter-spacing: .12em; }
/* White is the base, per the guide. A plain .section inherits the body colour,
   which is this site's sand, so inside the brand scope it is painted white and
   the light blue takes the alternating role the sand tint used to have. */
.bg3 .section { background: #FFFFFF; }
.bg3 .section--sand { background: var(--ss-sand-100); }
.bg3 .section--white { background: #FFFFFF; }
/* A dark band brought across from the new-design pane keeps its own ground.
   Without this the white base above repaints it and the reversed heading
   disappears against white. */
.bg3 .section--ink { background: var(--ss-teal-900); color: #fff; }
.bg3 .section--teal { background: var(--ss-teal-700); color: #fff; }
.bg3 .section--ink .lead, .bg3 .section--teal .lead { color: rgba(255, 255, 255, .82); }
/* Trademark mark, small and raised, per the guide's first prominent use rule */
.bg3 .tm { font-size: .5em; vertical-align: super; line-height: 0; font-weight: 400; }

/* Steps stacked in a column rather than across four. Used beside a form, where
   the four-across rhythm has nowhere to go. */
.steps--stack { grid-template-columns: 1fr; gap: var(--sp-6); }
@media (min-width: 900px) { .steps--stack { grid-template-columns: 1fr; gap: var(--sp-6); } }

/* The other route out of the summary card, for somebody who would rather be
   called back than pick a slot themselves. */
.bksummary__alt {
  margin: var(--sp-5) 0 0; padding-top: var(--sp-5);
  border-top: 1px solid var(--ss-line);
  font-size: 14px; line-height: 1.45; color: var(--ss-text-mid);
}

/* ── 32 OPTION CARD (TEMPORARY, compare panes) ───────────────────────────
   The live product pages present their control and design options as a photo
   with a name and a line of copy. This is that, in this site's card language.
   Goes when the compare panes go.
   ---------------------------------------------------------------------- */
.optcard {
  display: flex; flex-direction: column;
  background: var(--ss-white);
  border: 1px solid var(--ss-line);
  border-radius: var(--r-md);
  overflow: hidden;
  box-shadow: var(--shadow);
  transition: transform var(--dur-base) var(--ease-out-expo),
              box-shadow var(--dur-base) var(--ease-out-expo);
}
.optcard:hover { border-color: var(--ss-teal-300); }
.optcard__media { background: var(--ss-sand-200); }
.optcard__media img, .optcard__media video {
  width: 100%; display: block; aspect-ratio: 4/3; object-fit: cover;
}
.optcard__body { padding: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-2); }
.optcard__body h3 { margin: 0; font-size: 1.125rem; letter-spacing: -.02em; color: var(--ss-teal-700); }
.optcard__body p { margin: 0; font-size: 14.5px; line-height: 1.55; color: var(--ss-text-mid); }
.livepage__sub {
  margin: 0 0 var(--sp-4); font-family: var(--font-display);
  font-size: clamp(1.125rem, 1.8vw, 1.375rem); font-weight: 700;
  letter-spacing: -.02em; color: var(--ss-teal-700);
}

/* A note or label sitting between photographs in a reproduced gallery. It spans
   the whole row so the grid stays dense, instead of closing the grid and
   leaving a single orphaned photograph on the line after it. */
.livepage__note { grid-column: 1 / -1; margin: var(--sp-4) 0 0; color: var(--ss-text-mid); font-size: 16px; }
.livepage__note--head {
  font-family: var(--font-display); font-weight: 700; letter-spacing: -.02em;
  font-size: clamp(1.125rem, 1.8vw, 1.375rem); color: var(--ss-teal-700);
  margin-top: var(--sp-5);
}

/* ── 33 REPRODUCTION PANE RHYTHM (TEMPORARY) ─────────────────────────────
   The reproduced pages are long runs of short sections. At the site's normal
   rhythm the padding under one section, the margin under its heading and the
   padding above the next stacked to about 144px of nothing between a heading
   and the block it introduces. Everything here is scoped to a reproduction
   pane and goes when the panes go.
   ---------------------------------------------------------------------- */
[data-cmp="live"] .section,
[data-cmp="brand"] .section,
[data-cmp="combined"] .section { padding-block: var(--sp-6); }
@media (min-width: 900px) {
  [data-cmp="live"] .section,
  [data-cmp="brand"] .section,
  [data-cmp="combined"] .section { padding-block: var(--sp-7); }
}
[data-cmp="live"] .section--tight,
[data-cmp="brand"] .section--tight,
[data-cmp="combined"] .section--tight { padding-block: var(--sp-6); }
[data-cmp="live"] .section--flush-top,
[data-cmp="brand"] .section--flush-top,
[data-cmp="combined"] .section--flush-top { padding-top: 0; }

/* A heading sat as far from its own content as from the section above it */
[data-cmp="live"] .section-head,
[data-cmp="brand"] .section-head,
[data-cmp="combined"] .section-head { margin-bottom: var(--sp-5); }
/* and when the heading is all the section holds, its margin is dead space */
[data-cmp="live"] .section-head:last-child,
[data-cmp="brand"] .section-head:last-child,
[data-cmp="combined"] .section-head:last-child { margin-bottom: 0; }
/* With a lead under the heading, an equal gap above and below it leaves the
   sentence stranded between the two. It belongs to the heading, so it sits
   close to it and the room goes underneath instead. */
[data-cmp="live"] .section-head .lead,
[data-cmp="brand"] .section-head .lead,
[data-cmp="combined"] .section-head .lead { margin-bottom: var(--sp-7); }

/* Body copy runs the full width of the column it sits in. A reading measure is
   usually right, but under a full width block of photography a paragraph half
   the width of the media above it reads as a mistake. */
[data-cmp="live"] .prose,
[data-cmp="brand"] .prose,
[data-cmp="combined"] .prose { max-width: none; }
[data-cmp="live"] .prose p,
[data-cmp="brand"] .prose p,
[data-cmp="combined"] .prose p { max-width: none; }
/* and the copy needs room from the media it sits under */
[data-cmp="live"] .grid + .prose,
[data-cmp="brand"] .grid + .prose,
[data-cmp="combined"] .grid + .prose { margin-top: var(--sp-6); }
[data-cmp="live"] .container--narrow,
[data-cmp="brand"] .container--narrow,
[data-cmp="combined"] .container--narrow { max-width: 1100px; }

/* ── 34 REPRODUCTION HERO AND ACCENTS (TEMPORARY) ────────────────────────
   The live product and solution pages open on a full bleed clip with the title
   over it, and set their section media against an orange edge bar. Both are
   rebuilt here in brand guide colour rather than copied, so the Combined pane
   reads like their site without borrowing their stylesheet.
   ---------------------------------------------------------------------- */
.livehero {
  position: relative; overflow: hidden;
  min-height: clamp(300px, 46vh, 460px);
  display: grid; place-items: center;
  background-color: var(--ss-teal-700);
  background-size: cover;
  background-position: center;
}
@media (min-width: 900px) { .livehero { min-height: clamp(460px, 60vh, 700px); } }
/* The live pages lay a near white sheet at half opacity over the picture, with
   a teal cast under it, so the photograph reads pale rather than darkened. This
   is that wash, with the teal taken from the brand guide instead of theirs. */
.livehero__wash {
  position: absolute; inset: 0; z-index: 1;
  background:
    radial-gradient(60% 58% at 50% 50%, rgba(8, 38, 49, .34), rgba(8, 38, 49, 0) 72%),
    linear-gradient(rgba(247, 247, 247, .34), rgba(247, 247, 247, .34)),
    linear-gradient(rgba(21, 94, 112, .5), rgba(21, 94, 112, .5));
}
/* The New design opens on moving footage. The same clip runs here, under the
   wash, with the still it was cut from left on the section as the backdrop so
   there is never a blank frame while the video loads. */
.livehero__video {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; object-fit: cover;
  pointer-events: none;
}
.livehero > .container { position: relative; z-index: 2; text-align: center; }
.livehero__title {
  margin: 0; color: #fff;
  font-family: var(--font-display); font-weight: 700; text-transform: uppercase;
  font-size: clamp(1.9rem, 5.2vw, 4.5rem); line-height: 1.14; letter-spacing: -.01em;
  text-shadow: 0 2px 16px rgba(10, 36, 48, .38);
}
/* Their headline always sits on two lines, the product on one and the
   by line under it, rather than wrapping wherever the width runs out. */
.livehero__title .by { display: block; color: var(--ss-sun-500); }
/* Where they carry a service line under the name, it drops to 48px on its own
   row rather than running on at headline size */
.livehero__title .sub {
  display: block; color: #fff; font-weight: 700;
  font-size: clamp(1.25rem, 3.4vw, 3rem); line-height: 1.2; margin-top: .12em;
}
/* The trademarked company name, which used to sit alone in a band of its own
   under the hero looking like something left behind */
.livehero__lockup {
  margin: var(--sp-4) 0 0; color: #fff; font-size: 16px; font-weight: 600;
  letter-spacing: .05em; text-transform: uppercase; text-shadow: 0 1px 10px rgba(10, 36, 48, .45);
}
.livehero__crumb {
  margin: var(--sp-3) 0 0; font-size: 14px; color: rgba(255, 255, 255, .92);
  text-shadow: 0 1px 10px rgba(10, 36, 48, .45);
}
.livehero__crumb b { color: var(--ss-sun-400); font-weight: 600; }

/* The orange edge bar the live pages put against their section photography */

/* ---------------------------------------------------------------------------
   34b. Combined pane, laid out the way the live product pages are laid out.
   TEMPORARY, goes with the rest of the compare scaffolding.
   --------------------------------------------------------------------------- */

/* The live pages open on a teal band: sun mark, orange rule, then the product
   title and intro centred in a narrow column with the lead photograph under it */
.lvband {
  color: #fff; padding: var(--sp-9) 0;
  background-color: var(--ss-teal-700);
  /* Their own hatch, which is what stops the band reading as a flat slab */
  background-image: url("https://irp.cdn-website.com/d01edfbe/dms3rep/multi/opt/background-pattern-2880w.png");
  background-repeat: repeat;
}
.lvmark { display: flex; flex-direction: column; align-items: center; gap: 22px; margin: 0 0 var(--sp-8); }
.lvmark img { width: clamp(110px, 14vw, 170px); height: auto; }
.lvmark i { display: block; width: min(1080px, 92%); height: 8px; background: var(--ss-sun-500); }
.lvcopy { max-width: 1200px; margin: 0 auto; text-align: center; }
.lvcopy h2 { color: #fff; font-size: 24px; line-height: 2; margin: 0 0 var(--sp-4); }
.lvcopy p, .lvband .lvcopy .lead { color: rgba(255, 255, 255, .93); font-size: 20px; line-height: 2; margin: 0 0 var(--sp-5); }
.lvcopy p:last-child { margin-bottom: 0; }
.lvlead { max-width: 860px; margin: var(--sp-8) auto 0; }
.lvlead img, .lvlead video { display: block; width: 100%; height: auto; }

/* Their section headings run centred in two tones, the qualifier in orange */
.lvh {
  margin: 0 0 var(--sp-7); text-align: center;
  font-family: var(--font-display); font-weight: 700; line-height: 1.2;
  font-size: clamp(1.5rem, 3.2vw, 2.25rem); line-height: 1.3; color: var(--ss-teal-700);
}
.lvh em { font-style: normal; color: var(--ss-sun-500); }
.lvh--caps { text-transform: uppercase; letter-spacing: .01em; }

/* Option cards run four across on their site, picture on top, text centred */
.lvopts { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
@media (min-width: 960px) { .lvopts { grid-template-columns: repeat(4, 1fr); } }
.lvopts .optcard__body { text-align: center; padding: 14px 14px 20px; }
.lvopts .optcard__body h3 { font-size: 16px; color: var(--ss-teal-700); margin: 0 0 8px; }
.lvopts .optcard__body p { font-size: 13.5px; line-height: 1.7; }

/* The installed gallery is a tight four across */
.lvgal { display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px; }
@media (min-width: 760px) { .lvgal { grid-template-columns: repeat(4, 1fr); } }
.lvgal__i { overflow: hidden; }
.lvgal__i img, .lvgal__i video { display: block; width: 100%; height: auto; }
/* Only the installed photo gallery crops to an even grid, the way their page
   does. Option screenshots carry their label inside the picture, so cropping
   those would cut the wording off. */
.lvgal--tiles .lvgal__i img, .lvgal--tiles .lvgal__i video { aspect-ratio: 4 / 3; object-fit: cover; }
/* A gallery note stops the run of pictures and speaks across the full width */
.lvgal__note {
  grid-column: 1 / -1; margin: var(--sp-7) auto var(--sp-5); max-width: 820px; text-align: center;
  font-weight: 600; color: var(--ss-teal-700); font-size: 17px;
}

/* Three clips across, as on their pages */
.lvvids { display: flex; flex-wrap: wrap; justify-content: center; gap: 16px; }
.lvvids__i { flex: 1 1 100%; }
/* A third of the row each, so a pair sits centred rather than stranded left */
@media (min-width: 820px) { .lvvids__i { flex: 0 1 calc(33.333% - 11px); } }
.lvvids__i img, .lvvids__i video { display: block; width: 100%; height: auto; }

/* One clip on its own, the full width of the column, the way they close a page.
   Capping it narrower than the gallery above left it inset and looking stranded. */
.lvsolo { width: 100%; margin: 0 auto; }
/* Air between the blocks in a section. Without it a clip butts straight up
   against the bottom row of the gallery and the two read as one smear. */
.lvgal, .lvsolo, .lvvids, .lvopts { margin-bottom: var(--sp-8); }
.lvgal:last-child, .lvsolo:last-child, .lvvids:last-child, .lvopts:last-child { margin-bottom: 0; }
.lvsolo img, .lvsolo video { display: block; width: 100%; height: auto; }
/* The same centred column, used on the pale sections rather than the teal band */
.lvcopy--dark p { color: var(--ink-700); font-size: 20px; line-height: 2; }
.lvcopy--dark h2 { color: var(--ss-teal-700); }
/* A heading that introduces the sections beneath it, so it sits close to them */
.lvsec--intro { padding-bottom: 0; }
.lvsec--intro .lvh { margin-bottom: 0; }
/* The steps they list on the drapery page, kept as the list it reads as */
.lvlist {
  max-width: 640px; margin: 0 auto; padding: 0; list-style: none;
  display: grid; gap: 10px;
}
.lvlist li {
  position: relative; padding-left: 26px;
  font-size: 20px; line-height: 2; color: var(--ink-700);
}
.lvlist li::before {
  content: ""; position: absolute; left: 4px; top: .62em;
  width: 8px; height: 8px; border-radius: 50%; background: var(--ss-sun-500);
}

/* The installed work gallery on a Combined page.

   It is the one block down there with no section-head to space it, so the
   heading and its line of copy sat straight on the photographs: forty pixels
   under the title, nothing at all under the copy, and the lead running the
   full width of the container so it broke with two words stranded on a second
   line. Air above the heading, a readable measure for the lead, and air under
   it before the grid starts.

   !important is deliberate: two plain sections in a row are collapsed to no
   top padding at all by the rule in section 26, which is ten classes deep and
   wins on specificity. On the pages where the gallery follows a plain section
   that left the heading sitting on the block above it. */
[data-cmp="combined"] .section:has(> .container > .lvh + .lvcopy + .showcase) {
  padding-block-start: var(--sp-8) !important;
}
@media (min-width: 760px) {
  [data-cmp="combined"] .section:has(> .container > .lvh + .lvcopy + .showcase) {
    padding-block-start: var(--sp-9) !important;
  }
}
.lvh:has(+ .lvcopy + .showcase) { margin-bottom: var(--sp-5); }
.lvcopy:has(+ .showcase) { margin-bottom: var(--sp-7); }
.lvcopy:has(+ .showcase) p { max-width: 760px; margin-inline: auto; text-wrap: balance; }

/* ---------------------------------------------------------------------------
   34c. Type in the Combined pane.

   The brand guide names Source Sans Pro, and the Brand tab still shows it. The
   client's own live site, though, sets every piece of type in Manrope, h1 to
   body, and so does this site. Combined is meant to read as their page, so it
   follows the live site here. If the client wants the guide's face honoured,
   deleting this block puts it back.
   TEMPORARY, goes with the rest of the compare scaffolding.
   --------------------------------------------------------------------------- */
.bg3[data-cmp="combined"] {
  --font-display: "Manrope", ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-body: "Manrope", ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
/* The FAQ and the closing block come from the new design and arrived with its
   heading scale, which towered over the live layout headings above them and
   sat left while everything else sat centred. Brought onto one scale. */
[data-cmp="combined"] .section-head { text-align: center; }
[data-cmp="combined"] .section-head h2 { font-size: clamp(1.5rem, 3.2vw, 2.25rem); line-height: 1.3; }

/* A section lifted wholesale out of the New view and dropped into one of the
   compare views. The brand scope repaints the palette, swaps the typeface and
   centres headings, which is right for the brand guide and wrong for a band
   that is meant to look exactly as it does in New. This puts the site's own
   values back inside that one section, so it reads identically either side of
   the switcher. Add the class to the section, nothing else. */
.cmp-pane .section--asnew {
  --ss-teal-900: #0A2430;
  --ss-teal-800: #0E3546;
  --ss-teal-700: #155F72;
  --ss-teal-600: #19748B;
  --ss-teal-500: #1E89A4;
  --ss-teal-300: #52ACC2;
  --ss-teal-100: #DCEDF2;
  --ss-sand-50:  #FBF7F1;
  --ss-sand-100: #F5EFE6;
  --ss-sand-200: #EBE1D4;
  --ss-sand-300: #DCCEBB;
  --ss-line: rgba(10, 36, 48, .12);
  --ss-line-soft: rgba(10, 36, 48, .07);
  --ss-text: #0A2430;
  --ss-text-mid: #3D5A66;
  --ss-text-dim: #6B838D;
  --font-display: "Manrope", ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-body: "Manrope", ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-family: var(--font-body);
}
.cmp-pane .section--asnew.section--ink { background: var(--ss-teal-900); color: #fff; }
.cmp-pane .section--asnew .section-head { text-align: left; margin-bottom: var(--sp-9); }
.cmp-pane .section--asnew .section-head h2 { font-size: clamp(1.75rem, 4vw, 3rem); line-height: 1.06; letter-spacing: -.03em; }
.cmp-pane .section--asnew .section-head .lead { margin-bottom: 0; color: rgba(255, 255, 255, .82); }
.cmp-pane .section--asnew .eyebrow { justify-content: flex-start; }
[data-cmp="combined"] .faq__q { font-size: 17px; }
[data-cmp="combined"] .faq__a p { font-size: 16px; }

/* Peoria blog posts (src/regions/il/pages/<post>.html): the live post's own photo inside the reading column. */
.prose .post-fig { margin: var(--sp-7) 0; }
.prose .post-fig--upright { max-width: 440px; }

/* Peoria about-us: six team members, so the grid runs three up, then six up in one row. */
@media (min-width: 900px)  { .team-grid--six { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1180px) { .team-grid--six { grid-template-columns: repeat(6, 1fr); } }
/* Peoria about-us, why-solar-shield, 5-star-reviews: six Angi badges sit in one row. */
@media (min-width: 720px) { .badges--six { grid-template-columns: repeat(6, 1fr); } }
