/* Generated by tools/build.js — do not hand-edit. Edit the source files:
   css/fonts.css, tokens/colors.css, tokens/typography.css, tokens/spacing.css, tokens/effects.css, tokens/base.css, css/chrome.css, css/main.css */

/* ---- css/fonts.css ---- */
/* Generated by tools/self-host-fonts.mjs — do not hand-edit; re-run it instead.
   The brand fonts (Bricolage Grotesque, Hanken Grotesk, Space Mono), served
   from /fonts/ rather than Google Fonts since 2026-09-22. Bundled into every
   content page's CSS by tools/build.js and linked directly by the two tool
   pages (quote, live-data). */
/* vietnamese */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(/fonts/bricolage-grotesque-v9-vietnamese.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(/fonts/bricolage-grotesque-v9-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(/fonts/bricolage-grotesque-v9-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* vietnamese */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 500;
  font-stretch: 100%;
  font-display: swap;
  src: url(/fonts/bricolage-grotesque-v9-vietnamese.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 500;
  font-stretch: 100%;
  font-display: swap;
  src: url(/fonts/bricolage-grotesque-v9-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 500;
  font-stretch: 100%;
  font-display: swap;
  src: url(/fonts/bricolage-grotesque-v9-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* vietnamese */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 600;
  font-stretch: 100%;
  font-display: swap;
  src: url(/fonts/bricolage-grotesque-v9-vietnamese.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 600;
  font-stretch: 100%;
  font-display: swap;
  src: url(/fonts/bricolage-grotesque-v9-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 600;
  font-stretch: 100%;
  font-display: swap;
  src: url(/fonts/bricolage-grotesque-v9-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* vietnamese */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 700;
  font-stretch: 100%;
  font-display: swap;
  src: url(/fonts/bricolage-grotesque-v9-vietnamese.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 700;
  font-stretch: 100%;
  font-display: swap;
  src: url(/fonts/bricolage-grotesque-v9-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 700;
  font-stretch: 100%;
  font-display: swap;
  src: url(/fonts/bricolage-grotesque-v9-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* vietnamese */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 800;
  font-stretch: 100%;
  font-display: swap;
  src: url(/fonts/bricolage-grotesque-v9-vietnamese.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 800;
  font-stretch: 100%;
  font-display: swap;
  src: url(/fonts/bricolage-grotesque-v9-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 800;
  font-stretch: 100%;
  font-display: swap;
  src: url(/fonts/bricolage-grotesque-v9-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* vietnamese */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-vietnamese.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* vietnamese */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-vietnamese.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* vietnamese */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-vietnamese.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* vietnamese */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-vietnamese.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* vietnamese */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-vietnamese.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url(/fonts/hanken-grotesk-v12-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* vietnamese */
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/space-mono-v17-vietnamese-400.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/space-mono-v17-latin-ext-400.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/space-mono-v17-latin-400.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* vietnamese */
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/fonts/space-mono-v17-vietnamese-700.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/fonts/space-mono-v17-latin-ext-700.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/fonts/space-mono-v17-latin-700.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---- tokens/colors.css ---- */
/* Solar Pool Services — Color tokens
 * Palette derived directly from the hand-drawn brand logo (a vermilion sun
 * rising behind a swimmer in teal water, outlined in indigo, yellow cap) and
 * from real SoCal installation photography (blue pools, warm stucco, black mats).
 */
:root {
  /* ── Sun (primary brand) — the vermilion of the logo sun ───────────── */
  --sun-900: #7A2410;
  --sun-800: #A6321A;
  --sun-700: #C43C1E;
  --sun-600: #DC4620; /* PRIMARY brand color */
  --sun-500: #E85A2A;
  --sun-400: #F27B45;
  --sun-300: #F8A277;
  --sun-200: #FBC9AE;
  --sun-100: #FCE4D6;
  --sun-50:  #FDF1EA;

  /* ── Pool (secondary) — the teal water of the logo & real pools ──────── */
  --pool-900: #0F4753;
  --pool-800: #165A69;
  --pool-700: #1E6E7E;
  --pool-600: #268394;
  --pool-500: #2E93A3;
  --pool-400: #57ADB8;
  --pool-300: #8ACBCB; /* aqua highlight */
  --pool-200: #BCE2E0;
  --pool-100: #DEF1EF;
  --pool-50:  #EFF8F7;

  /* ── Indigo (accent) — the wave outline in the logo ──────────────────── */
  --indigo-700: #38316F;
  --indigo-600: #453B8C;
  --indigo-500: #574BA6;
  --indigo-300: #9A91CB;
  --indigo-100: #E4E1F1;

  /* ── Gold (highlight) — the swimmer's cap; sparing use ───────────────── */
  --gold-500: #E8AE13;
  --gold-400: #F4C025;
  --gold-200: #FBE49A;
  --gold-100: #FDF3D2;

  /* ── Warm neutrals — SoCal stucco & sand ─────────────────────────────── */
  --ink-900: #1E1A14; /* warm near-black — primary text */
  --ink-800: #2E281F;
  --ink-700: #423B30;
  --ink-600: #5C5344;
  --ink-500: #746A59;
  --ink-400: #9A8F7C;
  --ink-300: #C0B6A3;
  --sand-200: #E6DCCB;
  --sand-100: #F1EADC;
  --sand-50:  #FAF6EE;
  --white:    #FFFFFF;

  /* ── Semantic status ─────────────────────────────────────────────────── */
  --success-600: #2E7D52;
  --success-100: #DCEEE3;
  --warning-600: #C08A0E;
  --warning-100: #FBEFCF;
  --danger-600:  #C0402A;
  --danger-100:  #F7E0D9;

  /* ═══ Semantic aliases — reference these in components ════════════════ */
  --brand:            var(--sun-600);
  --brand-hover:      var(--sun-700);
  --brand-active:     var(--sun-800);
  --brand-soft:       var(--sun-100);
  --brand-on:         var(--white);

  --accent:           var(--pool-600);
  --accent-hover:     var(--pool-700);
  --accent-soft:      var(--pool-100);
  --accent-on:        var(--white);

  --text-strong:      var(--ink-900);
  --text-body:        var(--ink-700);
  --text-muted:       var(--ink-500);
  --text-faint:       var(--ink-400);
  --text-on-brand:    var(--white);
  --text-link:        var(--pool-700);
  --text-link-hover:  var(--sun-600);

  --surface-page:     var(--sand-50);
  --surface-card:     var(--white);
  --surface-sunk:     var(--sand-100);
  --surface-invert:   var(--ink-900);
  --surface-brand:    var(--sun-600);
  --surface-accent:   var(--pool-700);

  --border-subtle:    var(--sand-200);
  --border-default:   #DED3C0;
  --border-strong:    var(--ink-300);
  --border-focus:     var(--pool-500);
}

/* ---- tokens/typography.css ---- */
/* Solar Pool Services — Typography tokens */
:root {
  /* Families */
  /* No size-matched "fallback" faces between the brand font and system-ui:
     they were built and measured 2026-09-22 and made text paint later with
     no less movement. The why is in tools/self-host-fonts.mjs. */
  --font-display: 'Bricolage Grotesque', 'Hanken Grotesk', system-ui, sans-serif;
  /* The home hero's two big lines skip Hanken (2026-10-26): see .hero-display in css/main.css. */
  --font-display-hero: 'Bricolage Grotesque', system-ui, sans-serif;
  --font-text:    'Hanken Grotesk', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono:    'Space Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* Weights */
  --fw-regular: 400; /* @kind font */
  --fw-medium:  500; /* @kind font */
  --fw-semibold:600; /* @kind font */
  --fw-bold:    700; /* @kind font */
  --fw-black:   800; /* @kind font */

  /* Type scale — display uses tight tracking + line-height; text stays airy */
  --fs-display-xl: 4.5rem;   /* 72 — hero headline           */
  --fs-display-l:  3.375rem; /* 54 — page title              */
  --fs-display-m:  2.5rem;   /* 40 — section header          */
  --fs-display-s:  1.875rem; /* 30 — subsection              */
  --fs-title:      1.5rem;   /* 24 — card / block title      */
  --fs-lead:       1.25rem;  /* 20 — lead paragraph          */
  --fs-body:       1.0625rem;/* 17 — body                    */
  --fs-body-sm:    0.9375rem;/* 15 — secondary body          */
  --fs-caption:    0.8125rem;/* 13 — captions, labels        */
  --fs-overline:   0.75rem;  /* 12 — overline / eyebrow      */

  /* Line heights */
  --lh-tight:   1.04; /* @kind font */
  --lh-snug:    1.18; /* @kind font */
  --lh-heading: 1.28; /* @kind font */
  --lh-body:    1.6;  /* @kind font */
  --lh-relaxed: 1.72; /* @kind font */

  /* Letter spacing */
  --ls-display: -0.02em; /* @kind font */
  --ls-tight:   -0.01em; /* @kind font */
  --ls-normal:  0;       /* @kind font */
  /* eyebrows are UPPERCASE + tracked */
  --ls-overline: 0.14em; /* @kind font */
}

/* Mobile type scale — display sizes only. Desktop (≥641px) keeps the exact
   values above; without this, page titles render 54px on a 375px phone. */
@media (max-width: 640px) {
  :root {
    --fs-display-xl: 3rem;      /* 48 */
    --fs-display-l:  2.25rem;   /* 36 */
    --fs-display-m:  1.75rem;   /* 28 */
    --fs-display-s:  1.5rem;    /* 24 */
  }
}

/* ---- tokens/spacing.css ---- */
/* Solar Pool Services — Spacing & layout tokens
 * 4px base grid. Warm, generous spacing — the brand breathes.
 */
:root {
  --space-0:  0;
  --space-1:  0.25rem; /* 4  */
  --space-2:  0.5rem;  /* 8  */
  --space-3:  0.75rem; /* 12 */
  --space-4:  1rem;    /* 16 */
  --space-5:  1.5rem;  /* 24 */
  --space-6:  2rem;    /* 32 */
  --space-7:  2.5rem;  /* 40 */
  --space-8:  3rem;    /* 48 */
  --space-9:  4rem;    /* 64 */
  --space-10: 5rem;    /* 80 */
  --space-11: 7rem;    /* 112 */

  /* Layout */
  --container-max: 1200px;
  --container-narrow: 760px;
  --section-pad-y: clamp(3rem, 7vw, 7rem);
  --gutter: clamp(1.25rem, 4vw, 3rem); /* @kind spacing */
}

/* ---- tokens/effects.css ---- */
/* Solar Pool Services — Radii, borders, shadows, motion
 * Cards are gently rounded with soft, warm-tinted shadows (never hard/black).
 * Buttons round more. One "sun-ray" accent shadow for hero/brand moments.
 */
:root {
  /* Corner radii — friendly but not bubbly */
  --radius-xs:  4px;
  --radius-sm:  8px;
  --radius-md:  12px;  /* default card / input */
  --radius-lg:  18px;  /* feature cards */
  --radius-xl:  28px;  /* hero panels */
  --radius-pill: 999px;/* pills, tags, CTA buttons */

  /* Borders */
  --border-width: 1px; /* @kind other */
  --border-width-strong: 2px; /* @kind other */

  /* Shadows — warm brown-tinted, soft. Elevation, not drama. */
  --shadow-xs: 0 1px 2px rgba(46, 40, 31, 0.06);
  --shadow-sm: 0 1px 3px rgba(46, 40, 31, 0.08), 0 1px 2px rgba(46, 40, 31, 0.05);
  --shadow-md: 0 4px 14px rgba(46, 40, 31, 0.09), 0 2px 6px rgba(46, 40, 31, 0.05);
  --shadow-lg: 0 14px 34px rgba(46, 40, 31, 0.12), 0 6px 14px rgba(46, 40, 31, 0.07);
  --shadow-xl: 0 28px 60px rgba(46, 40, 31, 0.16), 0 12px 24px rgba(46, 40, 31, 0.08);
  /* Warm glow for brand/CTA hover — a hint of sunlight */
  --shadow-sun: 0 10px 28px rgba(220, 70, 32, 0.30);
  --shadow-focus: 0 0 0 3px rgba(46, 147, 163, 0.35); /* pool-tinted focus ring */

  /* Motion — gentle, no bounce. Trust, not flash. */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);      /* @kind other */
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);   /* @kind other */
  --dur-fast: 120ms; /* @kind other */
  --dur-base: 200ms; /* @kind other */
  --dur-slow: 340ms; /* @kind other */
}

/* ---- tokens/base.css ---- */
/* Solar Pool Services — Base element styles & helpers
 * Resets, base typography, link colors, and a few utility classes.
 */

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

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

body {
  margin: 0;
  font-family: var(--font-text);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-body);
  background: var(--surface-page);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Headings default to the display face */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  color: var(--text-strong);
  font-weight: var(--fw-bold);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-tight);
  margin: 0 0 0.5em;
  text-wrap: balance;
}
h1 { font-size: var(--fs-display-l); line-height: var(--lh-tight); letter-spacing: var(--ls-display); }
h2 { font-size: var(--fs-display-m); }
h3 { font-size: var(--fs-display-s); }
h4 { font-size: var(--fs-title); }

p { margin: 0 0 1em; text-wrap: pretty; }

/* Links — pool-teal by default, sun on hover */
a {
  color: var(--text-link);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-out);
}
a:hover { color: var(--text-link-hover); }

strong, b { font-weight: var(--fw-bold); color: var(--text-strong); }

code, kbd, samp { font-family: var(--font-mono); font-size: 0.92em; }

img { max-width: 100%; display: block; }

::selection { background: var(--sun-200); color: var(--ink-900); }

/* A solid ring, not a glow (2026-09-23). It was `box-shadow: 0 0 0 3px` at 35% teal, which on
   the cream page measured barely off the background and vanished entirely on the orange and dark
   bands. An outline also follows the element's own corner radius, is not clipped by overflow:hidden
   parents, and survives Windows high-contrast mode, where box-shadow is dropped. --focus-ring flips
   to white inside the dark and orange sections (main.css). */
:focus-visible {
  outline: 3px solid var(--focus-ring, var(--pool-600));
  outline-offset: 2px;
}

/* ── Helper classes ─────────────────────────────────────────────────── */
.sps-eyebrow {
  font-family: var(--font-text);
  font-size: var(--fs-overline);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-overline);
  text-transform: uppercase;
  color: var(--brand);
}
.sps-lead {
  font-size: var(--fs-lead);
  line-height: var(--lh-relaxed);
  color: var(--text-body);
}
.sps-mono-spec {
  font-family: var(--font-mono);
  font-size: var(--fs-body-sm);
  letter-spacing: -0.02em;
}
.sps-container { max-width: var(--container-max); margin-inline: auto; padding-inline: var(--gutter); }

/* ---- css/chrome.css ---- */
/* Site chrome (header + footer) — loaded on EVERY page including the two
 * self-contained tool pages (/quote/, /our-data/), which have their own page
 * CSS. Class names here must not collide with tool-page classes — the quote
 * button uses .sps-btn-quote (not .btn) for that reason. */

/* ---------- Header ---------- */
.site-header {
  position: sticky; top: 0; z-index: 50;
  /* Notched phones on pages that opt into viewport-fit=cover (e.g. /our-data/):
     let the blurred bar fill behind the Dynamic Island and push its contents
     below the camera. A no-op everywhere else — the inset resolves to 0. */
  padding-top: env(safe-area-inset-top, 0px);
  background: rgba(255,255,255,0.92);
  -webkit-backdrop-filter: saturate(1.4) blur(8px); backdrop-filter: saturate(1.4) blur(8px);
  border-bottom: 1px solid var(--border-subtle);
  font-family: var(--font-text);
  line-height: 1.5;
}
.header-inner {
  max-width: var(--container-max); margin: 0 auto;
  /* Plain value first: a browser without max()/env() drops the declaration that
     follows entirely, and an unpadded header is worse than an un-inset one. Every
     safe-area rule in this file is paired with its fallback for that reason. */
  padding: 0.7rem var(--gutter);
  padding: 0.7rem max(var(--gutter), env(safe-area-inset-right, 0px)) 0.7rem max(var(--gutter), env(safe-area-inset-left, 0px));
  /* space-4 floor, not space-6: this gap is only the MINIMUM between the three
     clusters (nav's margin-left:auto spreads them on wide screens), and the
     six-link row needs the room — at space-6 the CTA overhung the 1200px
     container's padding box by ~29px. */
  display: flex; align-items: center; gap: var(--space-4);
}
.brand { display: flex; align-items: center; gap: 0.65rem; text-decoration: none; flex-shrink: 0; }
.brand img { height: 44px; width: auto; display: block; }
.brand-name {
  font-family: var(--font-display); font-weight: 800; font-size: 1.05rem;
  line-height: 1.15; color: var(--text-strong); letter-spacing: -0.01em;
}
/* No gap between links — each link's own 0.55rem side padding keeps ~18px
   between labels, and the six-link row is width-constrained (see above). */
.nav-desktop { display: flex; margin-left: auto; align-items: center; }
.nav-item { position: relative; }
.nav-link {
  /* 0.55rem side padding (was 0.65) — six top-level links + phone + CTA sit at
     ~1180px, and the extra 0.1rem per side pushed the row past the 1200px
     container. Keep real slack here: platforms render these fonts ±a few px. */
  display: block; padding: 0.55rem; border-radius: var(--radius-sm);
  font-family: inherit; font-weight: 600; font-size: 0.95rem; color: var(--text-body);
  text-decoration: none; white-space: nowrap;
}
/* Dropdown triggers are <button>s (open on click/touch, not navigation) but
   read as nav links — reset the UA button chrome so they match the <a> links. */
button.nav-link { border: 0; background: none; cursor: pointer; line-height: 1.5; }
.nav-link:hover { background: var(--sand-100); color: var(--brand); }
.nav-link[data-current], .nav-item:has([data-current]) > .nav-link { color: var(--brand); }
.nav-link:focus-visible { outline: 3px solid var(--pool-600); outline-offset: 2px; }
.nav-caret { display: inline-block; font-size: 0.85em; transition: transform var(--dur-fast) var(--ease-out); }
.nav-item:hover .nav-caret, .nav-item.is-open .nav-caret { transform: rotate(180deg); }

.nav-menu {
  position: absolute; top: 100%; left: 0; min-width: 210px; z-index: 20;
  background: #fff; border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
  border: 1px solid var(--border-subtle); padding: 0.4rem;
  display: flex; flex-direction: column;
  /* Hidden by default; fade + 4px slide-down on open. Kept in the DOM (not
     display:none) so the transition can run; visibility flips it off from AT
     and pointer events when closed. */
  opacity: 0; visibility: hidden; transform: translateY(4px);
  transition: opacity var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out),
              visibility 0s linear var(--dur-fast);
}
.nav-item:hover .nav-menu, .nav-item.is-open .nav-menu {
  opacity: 1; visibility: visible; transform: none; transition-delay: 0s;
}
.nav-menu a {
  padding: 0.55rem 0.7rem; border-radius: var(--radius-sm); color: var(--text-body);
  font-weight: 600; font-size: 0.9rem; text-decoration: none; white-space: nowrap;
}
.nav-menu a:hover { background: var(--sand-100); color: var(--brand); }
.nav-menu a[data-current] { color: var(--brand); }
/* Inset, so the ring cannot be clipped by the dropdown panel. */
.nav-menu a:focus-visible { outline: 3px solid var(--pool-600); outline-offset: -3px; }
.header-cta { display: flex; align-items: center; gap: 0.9rem; margin-left: auto; flex-shrink: 0; }
.nav-desktop + .header-cta { margin-left: 0; }
.header-phone {
  font-weight: 700; color: var(--text-strong); white-space: nowrap;
  font-size: 0.95rem; text-decoration: none;
}
.header-phone:hover { color: var(--brand); }
/* Desktop is text-only (no icon) per the nav spec; the icon only appears when
   the number collapses on narrow phones — see the <=640 block below. */
.header-phone-icon { display: none; line-height: 0; }
.sps-btn-quote {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  font-family: var(--font-text); font-weight: 700; font-size: 0.9375rem; line-height: 1;
  padding: 0.5rem 1rem; border-radius: var(--radius-pill);
  background: var(--brand); color: var(--brand-on); border: 2px solid transparent;
  cursor: pointer; text-decoration: none; white-space: nowrap;
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-base) var(--ease-out),
    background var(--dur-fast) var(--ease-out);
}
.sps-btn-quote:hover { background: var(--brand-hover); box-shadow: var(--shadow-sun); color: var(--brand-on); }
.sps-btn-quote:active { transform: translateY(1px) scale(0.99); }
.burger {
  display: none; background: none; border: 0; padding: 0.625rem; cursor: pointer;
  color: var(--text-strong); line-height: 0; border-radius: var(--radius-sm);
}
.burger .burger-close { display: none; }
.burger[aria-expanded="true"] .burger-open { display: none; }
.burger[aria-expanded="true"] .burger-close { display: inline; }
.mobile-menu {
  display: none; flex-direction: column; background: #fff;
  border-top: 1px solid var(--border-subtle); padding: 0.5rem var(--gutter) 1.2rem;
  box-shadow: var(--shadow-lg);
}
.mobile-menu:not([hidden]) { display: flex; }
.mm-link, .mm-sub {
  padding: 0.8rem 0; text-decoration: none; color: var(--text-strong);
  font-weight: 700; border-top: 1px solid var(--sand-100);
}
.mm-sub { padding-left: 1rem; font-weight: 600; color: var(--text-body); }
.mm-group {
  margin-top: 0.8rem; font-size: var(--fs-overline); font-weight: 700;
  letter-spacing: var(--ls-overline); text-transform: uppercase; color: var(--text-muted);
}
.mm-phone { margin-top: 1rem; padding: 0.8rem 0; font-weight: 800; color: var(--brand); text-decoration: none; }
.mm-quote {
  display: flex; align-items: center; justify-content: center; min-height: 48px; margin: 0.5rem 0 0.3rem;
  border-radius: var(--radius-pill, 999px); background: var(--brand); color: var(--brand-on, #fff);
  font-weight: 800; text-decoration: none;
}

@media (prefers-reduced-motion: reduce) {
  .nav-menu { transition: none; }
  .nav-caret { transition: none; }
}

/* ---------- Footer ---------- */
.site-footer { background: var(--ink-900); color: #fff; font-family: var(--font-text); line-height: 1.5; }
.footer-inner {
  max-width: var(--container-max); margin: 0 auto;
  padding: var(--space-9) var(--gutter) var(--space-6);
  padding: var(--space-9) max(var(--gutter), env(safe-area-inset-right, 0px)) calc(var(--space-6) + env(safe-area-inset-bottom, 0px)) max(var(--gutter), env(safe-area-inset-left, 0px));
}
.footer-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1fr 1.2fr; gap: var(--space-7) var(--space-6); }
.footer-col { display: flex; flex-direction: column; gap: 0.6rem; }
.footer-brand { display: flex; align-items: center; gap: 0.6rem; }
.footer-brand img { height: 46px; width: auto; display: block; }
.footer-brand span { font-family: var(--font-display); font-weight: 800; font-size: 1.05rem; line-height: 1.05; }
.footer-blurb { color: rgba(255,255,255,0.72); margin: 0.4rem 0 0; max-width: 30ch; font-size: 0.95rem; }
.footer-head {
  font-size: var(--fs-overline); font-weight: 700; letter-spacing: var(--ls-overline);
  text-transform: uppercase; color: var(--gold-400); margin-bottom: 0.3rem;
}
.site-footer a { color: rgba(255,255,255,0.82); font-size: 0.95rem; text-decoration: none; }
.site-footer a:hover { color: #fff; }
.footer-phone { font-weight: 700; }
.footer-hours { color: rgba(255,255,255,0.72); font-size: 0.9rem; }
.footer-bottom {
  margin-top: var(--space-7); padding-top: var(--space-5);
  border-top: 1px solid rgba(255,255,255,0.14);
  display: flex; justify-content: space-between; align-items: center;
  flex-wrap: wrap; gap: 0.8rem; font-size: 0.85rem; color: rgba(255,255,255,0.6);
}

/* Legal row inside .footer-bottom (privacy / terms / accessibility / choices).
   The 100% lives on the ROW, not the nav, so the build credit can ride its
   right end and cost the page no extra height. */
.footer-legal-row {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 0.4rem 1.4rem;
}
.footer-legal { display: flex; flex-wrap: wrap; gap: 0.4rem 1.4rem; }
.footer-legal a { color: rgba(255,255,255,0.6); text-decoration: none; }
.footer-legal a:hover { color: #FFFFFF; }

/* Build credit, bottom right. Two class names deep because the bare .site-footer
   a rule above is stronger than one — a lone .footer-credit loses the size. */
.footer-bottom .footer-credit {
  margin-left: auto; font-size: 0.8rem; color: rgba(255,255,255,0.45); text-decoration: none;
}
.footer-bottom .footer-credit:hover { color: rgba(255,255,255,0.75); }

/* Inline links in the footer-bottom text (e.g. the CSLB license verify link) */
.footer-bottom > span a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.footer-bottom > span a:hover { color: #FFFFFF; }

/* Skip-to-content link (WCAG 2.4.1) — visually hidden until keyboard focus */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 10000;
  background: var(--surface-card, #FFFFFF); color: var(--text-strong, #1E1A14);
  border: 2px solid var(--border-focus, #2E93A3);
  border-radius: var(--radius-pill, 999px);
  padding: 0.6rem 1.2rem; font-weight: 700; text-decoration: none;
}
.skip-link:focus { left: 12px; top: 12px; }
main:focus { outline: none; }

/* Consent microcopy: centered when it stands alone under a button (the
   quote gate's small print, the review line under a form) */
.form-consent {
  margin: 0.5rem 0 0; font-size: 0.8rem; line-height: 1.5;
  color: var(--text-muted, #746A59); text-align: center;
}
.form-consent a { color: var(--text-link, #1E6E7E); }
/* The fine print directly above a lead form's button: what we do with their
   details, then the texting box. Left-aligned with the fields, so the box
   lines up with the form's other checkboxes. The texting box stays LAST,
   directly above the button: the carriers' registration describes it there
   (worker/tools/phone-10dlc.mjs MessageFlow). */
.form-fine { display: grid; gap: 0.5rem; }
.form-fine .form-consent { margin: 0; text-align: left; }
/* The texting opt-in (A2P 10DLC): an UNCHECKED box, its own line, same muted
   size as the consent line. Carriers reject a pre-ticked one. Its words are
   registered with the carriers word for word: change them only together
   with the campaign (phone-10dlc.mjs). */
.form-texts {
  display: block; position: relative; padding-left: 1.6rem;
  margin: 0; font-size: 0.8rem; line-height: 1.5;
  color: var(--text-muted, #746A59); text-align: left; cursor: pointer;
}
.form-texts input { position: absolute; left: 0; top: 0.2rem; margin: 0; width: 1rem; height: 1rem; accent-color: var(--sun-600, #D9531E); }
.form-texts a { color: var(--text-link, #1E6E7E); }

/* Turnstile slot — js/site.js renders the widget into it (empty = invisible) */
.form-turnstile { display: flex; justify-content: center; }
.form-turnstile:empty { display: none; }

/* ---------- Chrome responsive ---------- */
/* 1280px: the six-link nav (Services · Service Areas · How It Works · Live
   System Data · Resources · Contact) plus brand + phone + Get a Quote measures
   ~1180px, so it needs the full 1200px container a 1280 viewport provides;
   below that, collapse the whole link row into the hamburger panel. (The old
   1024px breakpoint was tuned for a 4-link nav and was already clipping once
   Live System Data made it five.) */
@media (max-width: 1280px) {
  .nav-desktop { display: none; }
  .burger { display: inline-flex; }
  /* Push the phone + CTA + hamburger cluster to the right edge. This needs the
     same selector specificity as the desktop `.nav-desktop + .header-cta`
     (0,2,0) rule that zeroes the margin — a bare `.header-cta` (0,1,0) loses to
     it and the whole cluster collapses to the left. */
  .nav-desktop + .header-cta { margin-left: auto; }
  .sps-btn-quote { min-height: 44px; }
  /* The open menu must never outgrow the screen — scroll inside it instead.
     (The header is sticky, so page scroll can't reveal the menu's bottom links.) */
  /* Three rungs, each one a superset of the last: no env() and no dvh → the first;
     env() but no dvh → the second (which still owes the header its inset-top, or
     the open menu overflows the screen by exactly that inset); both → the third. */
  .mobile-menu:not([hidden]) {
    max-height: calc(100vh - 66px);
    max-height: calc(100vh - 66px - env(safe-area-inset-top, 0px));
    max-height: calc(100dvh - 66px - env(safe-area-inset-top, 0px));
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    padding-bottom: calc(1.2rem + env(safe-area-inset-bottom));
  }
}
@media (max-width: 900px) {
  .footer-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 640px) {
  .brand-name { display: none; }
  /* Not enough room for the full number next to the logo + CTA + hamburger, so
     tap-to-call collapses to an icon button — mobile users are the callers, so
     one-tap dialing stays in the sticky header. */
  .header-phone-num { display: none; }
  .header-phone-icon { display: inline-flex; }
  .header-phone {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 44px; min-height: 44px; color: var(--brand);
  }
  .header-inner { gap: var(--space-4); }
}
@media (max-width: 400px) {
  .sps-btn-quote { padding: 0.5rem 0.75rem; font-size: 0.875rem; }
  .header-cta { gap: 0.4rem; }
}
/* "Get a free quote" (2026-09-23; was "Get a Quote") is 26px longer, which put a 320px phone's header
   7px past the screen edge. */
@media (max-width: 340px) {
  .sps-btn-quote { padding: 0.5rem 0.55rem; font-size: 0.8125rem; }
}
@media (max-width: 560px) {
  /* Link columns stay 2-up rather than stacking — five stacked columns made the
     footer ~1.7 screens tall. The brand/blurb column spans the full width. */
  /* minmax(0,…) so the long support email can't blow one column out; it wraps. */
  .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-6) var(--space-5); }
  .footer-col:first-child { grid-column: 1 / -1; }
  .footer-col a { overflow-wrap: anywhere; }
  .footer-col { gap: 0.2rem; }
  .footer-col a { padding: 0.45rem 0; }
}

/* ---- css/main.css ---- */
/* Solar Pool Services — site styles.
 * Component values ported 1:1 from the design system
 * (design_handoff_solar_pool_website/components/ + ui_kits/website/).
 * Tokens come from /tokens/*.css. */

/* ---------- Layout primitives ---------- */
.section { padding: var(--section-pad-y) 0; background: var(--surface-page); }
.section-sand { background: var(--sand-100); }
.section-ink { background: var(--ink-900); }
.section-pool-900 { background: var(--pool-900); }
.section-pool-800 { background: var(--pool-800); }
.section-sun { background: var(--sun-600); }
.container { max-width: var(--container-max); margin: 0 auto; padding: 0 var(--gutter); }
.container-narrow { max-width: var(--container-narrow); margin: 0 auto; padding: 0 var(--gutter); }
.center { text-align: center; }

.grid { display: grid; gap: var(--space-6); }
.grid-2 { grid-template-columns: 1fr 1fr; align-items: center; }
.grid-3 { grid-template-columns: 1fr 1fr 1fr; }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
.grid-2-uneven { grid-template-columns: 1.1fr 0.9fr; align-items: center; }
.grid-2-uneven-rev { grid-template-columns: 0.9fr 1.1fr; align-items: center; }
.grid-2x3 { grid-template-columns: 1fr 1fr; gap: var(--space-4); }

img { max-width: 100%; height: auto; }
.img-rounded { border-radius: var(--radius-lg); box-shadow: var(--shadow-md); display: block; }
.img-rounded-xl { border-radius: var(--radius-xl); box-shadow: var(--shadow-lg); display: block; }
/* tools/build.js wraps content photos in <picture> to offer WebP (2026-09-22).
   `contents` keeps the wrapper out of layout, so the <img> is still the grid or
   flex item every rule here was written for — and the <source>s must then be
   taken out of layout too, or each one becomes an empty grid cell of its own
   and pushes the photo onto the next row (it did, on every two-column hero).
   Source selection doesn't depend on display, so this changes nothing else. */
picture { display: contents; }
picture > source { display: none; }

/* Gallery grid tiles — uniform 4:3 crop with a caption beneath */
.gallery-item { margin: 0; }
.gallery-item img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: var(--radius-lg); box-shadow: var(--shadow-md); display: block;
}
.gallery-item figcaption {
  margin-top: var(--space-3); color: var(--text-muted); font-size: 0.95rem;
}

/* Before/after pair — matched 16:9 frames, each with a corner tag. Used on
 * /gallery/, /, and /installation/. */
.ba-frame { position: relative; }
.ba-frame img {
  width: 100%; aspect-ratio: 16 / 9; object-fit: cover;
  border-radius: var(--radius-lg); box-shadow: var(--shadow-md); display: block;
}
.ba-tag {
  position: absolute; top: var(--space-3); left: var(--space-3);
  font-family: var(--font-mono); font-size: var(--fs-caption); font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--white);
  padding: 0.3rem 0.75rem; border-radius: var(--radius-pill); box-shadow: var(--shadow-sm);
}
.ba-tag-before { background: var(--pool-700); }
.ba-tag-after  { background: var(--sun-600); }
/* .grid-2 centers its items, so the figure with the shorter caption gets
   nudged down and the two photos stop lining up. Pin both to the top. */
.ba-item { margin: 0; align-self: start; }
.ba-item figcaption { margin-top: var(--space-3); color: var(--text-muted); font-size: 0.95rem; }

/* (Header + footer chrome styles live in chrome.css, shared with the
 * self-contained tool pages at /quote/ and /our-data/.) */

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  font-family: var(--font-text); font-weight: 700; line-height: 1;
  border-radius: var(--radius-pill); white-space: nowrap; text-decoration: none;
  cursor: pointer; border: 2px solid transparent;
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-base) var(--ease-out),
    background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
  padding: 12px 24px; font-size: 1.0625rem;
}
.btn-sm { padding: 8px 16px; font-size: 0.9375rem; }
.btn-lg { padding: 16px 32px; font-size: 1.1875rem; }
.btn:active { transform: translateY(1px) scale(0.99); }
.btn-primary { background: var(--brand); color: var(--brand-on); }
.btn-primary:hover { background: var(--brand-hover); box-shadow: var(--shadow-sun); color: var(--brand-on); }
.btn-secondary { background: var(--pool-700); color: #fff; }
.btn-secondary:hover { box-shadow: var(--shadow-md); color: #fff; }
.btn-outline { background: transparent; color: var(--text-strong); border-color: var(--border-strong); }
.btn-outline:hover { border-color: var(--brand); color: var(--brand); }
.btn-outline-white { background: transparent; color: #fff; border-color: rgba(255,255,255,0.75); }
.btn-outline-white:hover { border-color: #fff; color: #fff; background: rgba(255,255,255,0.1); }
.btn-full { width: 100%; }
.btn-row { display: flex; gap: var(--space-3); flex-wrap: wrap; }

/* ---------- Eyebrow / Badge / Stat ---------- */
.eyebrow {
  display: inline-flex; align-items: center; gap: 0.6rem;
  font-size: var(--fs-overline); font-weight: 700; letter-spacing: var(--ls-overline);
  /* sun-800, not --brand: at overline size, sun-600 is ~3.9–4.3:1 on white/sand
     (WCAG AA needs 4.5:1 for small text); sun-800 clears 5.6:1 on every surface
     up to sand-100. CTAs and large type keep --brand. */
  text-transform: uppercase; color: var(--sun-800); margin: 0 0 var(--space-3);
}
.eyebrow::before { content: ""; width: 28px; height: 2px; border-radius: 2px; background: currentColor; }
.eyebrow-gold { color: var(--gold-400); }
.eyebrow-center { justify-content: center; }

.badge {
  display: inline-flex; align-items: center; gap: 0.35rem; font-weight: 700;
  letter-spacing: 0.01em; border-radius: var(--radius-pill); line-height: 1.2;
  white-space: nowrap; padding: 5.6px 12.8px; font-size: var(--fs-caption);
}
.badge-brand { background: var(--sun-100); color: var(--sun-800); }
.badge-pool { background: var(--pool-100); color: var(--pool-800); }
.badge-indigo { background: var(--indigo-100); color: var(--indigo-700); }
.badge-gold { background: var(--gold-100); color: var(--warning-600); }
.badge-success { background: var(--success-100); color: var(--success-600); }
.badge-neutral { background: var(--sand-100); color: var(--ink-700); }
.badge-neutral-solid { background: var(--ink-800); color: #fff; }
.badge-row { display: flex; gap: var(--space-2); flex-wrap: wrap; }
/* Badges that link out (the CSLB license lookup) keep the badge's own color
   rather than picking up the body link palette. */
a.badge { text-decoration: none; transition: filter 160ms ease-out; }
a.badge:hover { filter: brightness(0.96); }

.stat { display: flex; flex-direction: column; gap: 0.15rem; }
.stat-value {
  font-family: var(--font-display); font-weight: 800; font-size: var(--fs-display-m);
  line-height: 1; letter-spacing: var(--ls-display); color: var(--brand);
}
.stat-pool .stat-value { color: var(--pool-700); }
.stat-indigo .stat-value { color: var(--indigo-600); }
.stat-label { font-weight: 700; font-size: var(--fs-body); color: var(--text-strong); }
.stat-sublabel { font-size: var(--fs-body-sm); color: var(--text-muted); }

/* ---------- Cards ---------- */
.card {
  background: var(--surface-card); border-radius: var(--radius-lg);
  border: 1px solid var(--border-subtle); box-shadow: var(--shadow-md);
  padding: var(--space-6); position: relative; overflow: hidden;
}
.card-accent-top { border-top: 4px solid var(--sun-600); }

.service-card {
  display: flex; flex-direction: column; gap: var(--space-3);
  background: var(--surface-card); border-radius: var(--radius-lg);
  border: 1px solid var(--border-subtle); box-shadow: var(--shadow-md);
  padding: var(--space-6); text-decoration: none; color: inherit;
  transition: box-shadow var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
.service-card:hover { box-shadow: var(--shadow-lg); transform: translateY(-3px); }
.icon-chip {
  width: 52px; height: 52px; border-radius: var(--radius-md);
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  background: var(--sun-100); color: var(--sun-700);
}
.icon-chip-pool { background: var(--pool-100); color: var(--pool-700); }
.icon-chip-indigo { background: var(--indigo-100); color: var(--indigo-600); }
.icon-chip-sm { width: 40px; height: 40px; }
.icon-chip-sm svg { width: 20px; height: 20px; }
.service-card h2, .service-card h3 { font-size: var(--fs-title); margin: 0; }
.service-card p { margin: 0; flex-grow: 1; color: var(--text-body); }
.service-card .card-cta {
  display: inline-flex; align-items: center; gap: 0.4rem; font-weight: 700;
  color: var(--brand); margin-top: var(--space-2);
}
.service-card .card-cta svg { transition: transform var(--dur-base) var(--ease-out); }
.service-card:hover .card-cta svg { transform: translateX(3px); }

.benefit-card {
  background: var(--surface-card); border-radius: var(--radius-lg);
  border: 1px solid var(--border-subtle); box-shadow: var(--shadow-sm);
  padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-2);
}
.benefit-card h3 { font-size: var(--fs-body); font-family: var(--font-text); font-weight: 700; margin: 0; }
.benefit-card p { margin: 0; font-size: var(--fs-body-sm); color: var(--text-muted); }

/* ---------- Steps ---------- */
.step { display: flex; gap: var(--space-4); }
.step-marker-col { display: flex; flex-direction: column; align-items: center; flex: none; }
.step-marker {
  width: 48px; height: 48px; border-radius: var(--radius-pill); background: var(--brand);
  color: #fff; display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-weight: 800; font-size: 1.375rem;
}
.step-rail { width: 2px; flex: 1; min-height: 16px; margin-top: var(--space-2); background: var(--border-default); }
.step-body { padding-bottom: var(--space-5); }
.step:last-child .step-body { padding-bottom: 0; }
.step-body h3 { font-size: var(--fs-title); margin: 0 0 0.35rem; }
.step-body p { margin: 0; color: var(--text-body); }

/* ---------- Testimonials ---------- */
.testimonial {
  display: flex; flex-direction: column; gap: var(--space-4); margin: 0;
  background: var(--surface-card); border-radius: var(--radius-lg);
  border: 1px solid var(--border-subtle); box-shadow: var(--shadow-md); padding: var(--space-6);
}
.testimonial .stars { display: flex; gap: 2px; color: var(--gold-400); }
.testimonial .stars svg { width: 20px; height: 20px; fill: currentColor; stroke: currentColor; }
.testimonial blockquote {
  margin: 0; font-size: var(--fs-lead); line-height: var(--lh-relaxed);
  color: var(--text-strong); font-weight: 500;
}
.testimonial figcaption { margin-top: auto; }
.testimonial .author { font-weight: 700; color: var(--text-strong); }
.testimonial .location { display: block; font-size: var(--fs-body-sm); color: var(--text-muted); }
/* Clickable testimonial cards (link out to the Google review). */
a.testimonial-link { display: flex; text-decoration: none; }
a.testimonial-link > .testimonial {
  flex: 1 1 auto;
  transition: box-shadow var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
a.testimonial-link:hover > .testimonial { box-shadow: var(--shadow-lg); transform: translateY(-3px); }

/* ---------- Reviews page ----------
   This was a horizontal rail with prev/next buttons. Sideways scrolling on the
   one page whose entire job is reading reviews meant most of them were never
   seen — you had to work a scrollbar to get past card three. Now every review
   is on the page at once: one featured pull-quote, then the rest in a masonry
   column layout that packs the wildly different quote lengths with no dead
   space. No JS at all — CSS columns do the packing. */

/* Trust numbers under the intro. Left-aligned stats, centered as a row. */
.review-stats {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--space-6) var(--space-9); margin-top: var(--space-8);
}
.review-stats .stat { text-align: center; align-items: center; }
.review-stats .stat-label { font-weight: 600; color: var(--text-body); }

/* Featured pull-quote — sits straight on the pool-900 section with no card, so
   it reads as a headline instead of "the first review". */
.review-feature {
  display: block; max-width: 860px; margin: 0 auto var(--space-9);
  text-align: center; text-decoration: none;
}
.review-feature .review-mark {
  display: block; font-family: var(--font-display); font-weight: 800;
  font-size: 4rem; line-height: 0.75; color: var(--gold-400);
  margin-bottom: var(--space-3);
}
.review-feature blockquote {
  margin: 0; color: #fff;
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.5rem, 3.2vw, 2.25rem);
  line-height: var(--lh-snug); letter-spacing: var(--ls-tight);
}
.review-feature .stars {
  display: flex; justify-content: center; gap: 3px;
  color: var(--gold-400); margin: var(--space-5) 0 var(--space-3);
}
.review-feature .stars svg { width: 22px; height: 22px; fill: currentColor; stroke: currentColor; }
.review-feature .review-byline {
  display: block; font-size: var(--fs-body-sm); font-weight: 600;
  color: rgba(255,255,255,0.8);
}
.review-feature .review-byline .author { color: #fff; font-weight: 700; }
.review-feature .review-source { color: var(--gold-400); }
.review-feature:hover .review-source { color: var(--gold-200); text-decoration: underline; }
.review-feature:focus-visible { outline: 2px solid #fff; outline-offset: 8px; border-radius: var(--radius-md); }

/* Masonry: CSS columns, not grid — grid would either stretch every card to the
   tallest in its row or leave ragged gaps. break-inside keeps a card whole. */
.review-grid { columns: 3; column-gap: var(--space-5); }
.review-grid > * {
  display: block; margin: 0 0 var(--space-5);
  break-inside: avoid; -webkit-column-break-inside: avoid;
}
.review-grid .testimonial { position: relative; padding: var(--space-5); }
/* Decorative open-quote in the corner the stars leave empty. */
.review-grid .testimonial::after {
  content: "\201C"; position: absolute; top: 2px; right: var(--space-4);
  font-family: var(--font-display); font-weight: 800; font-size: 3.5rem;
  line-height: 1; color: var(--sand-200); pointer-events: none;
}
.review-grid blockquote { font-size: var(--fs-body); line-height: var(--lh-body); }
.review-grid figcaption {
  display: flex; align-items: center; gap: var(--space-3);
  margin-top: auto; padding-top: var(--space-4);
  border-top: 1px solid var(--border-subtle);
}
.review-avatar {
  flex: none; width: 40px; height: 40px; border-radius: var(--radius-pill);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-weight: 800; font-size: 0.875rem;
  background: var(--pool-100); color: var(--pool-800);
}
/* Rotate the avatar tints so a column doesn't read as one flat block of teal. */
.review-grid > *:nth-child(4n+2) .review-avatar { background: var(--sun-100); color: var(--sun-800); }
.review-grid > *:nth-child(4n+3) .review-avatar { background: var(--indigo-100); color: var(--indigo-700); }
.review-grid > *:nth-child(4n+4) .review-avatar { background: var(--gold-100); color: var(--warning-600); }
.review-who { display: flex; flex-direction: column; min-width: 0; }
.review-grid .author, .review-grid .location { display: block; }
.review-grid .review-source {
  margin-left: auto; flex: none; display: inline-flex; color: var(--text-link);
  transition: transform var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
}
.review-grid .testimonial-link:hover .review-source { transform: translateX(3px); color: var(--brand); }
/* pool-900 behind the cards swallows the teal focus ring. */
.review-grid .testimonial-link:focus-visible { outline: 2px solid #fff; outline-offset: 3px; border-radius: var(--radius-lg); }

.review-outro { text-align: center; margin-top: var(--space-8); }
.review-outro p { margin: 0 0 var(--space-5); color: rgba(255,255,255,0.75); font-size: var(--fs-body-sm); }
.review-outro-cta { margin: var(--space-6) 0 0 !important; font-size: var(--fs-body) !important; color: rgba(255,255,255,0.9) !important; }
.review-outro-cta a { color: #fff; text-decoration: underline; }
.review-outro-cta a:hover { color: var(--gold-400); }

/* ---------- Accordion ---------- */
.accordion { border-top: 1px solid var(--border-subtle); }
.accordion-item { border-bottom: 1px solid var(--border-subtle); }
.accordion-q {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-4); background: none; border: 0; cursor: pointer; text-align: left;
  padding: var(--space-5) 0; font-family: var(--font-display); font-weight: 700;
  font-size: var(--fs-title); color: var(--text-strong);
  transition: color var(--dur-fast) var(--ease-out);
}
.accordion-item.open .accordion-q { color: var(--brand); }
.accordion-q .acc-icon {
  flex: none; color: var(--brand); line-height: 0;
  transition: transform var(--dur-base) var(--ease-out);
}
.accordion-item.open .acc-icon { transform: rotate(45deg); }
.accordion-a {
  max-height: 0; opacity: 0; overflow: hidden;
  transition: max-height var(--dur-slow) var(--ease-out), opacity var(--dur-base) var(--ease-out);
}
.accordion-item.open .accordion-a { max-height: 100vh; opacity: 1; }
.accordion-a p { margin: 0; padding: 0 0 var(--space-5); max-width: 60ch; color: var(--text-body); }

/* ---------- Forms ---------- */
.field { display: flex; flex-direction: column; gap: 0.4rem; }
.field > label { font-weight: 600; font-size: var(--fs-body-sm); color: var(--text-strong); }
.field .req { color: var(--brand); }
.field .hint { font-size: var(--fs-caption); color: var(--text-muted); }
.field .error-msg { font-size: var(--fs-caption); color: var(--danger-600); }
/* Soft qualifier inside a group label, e.g. "Service details (check all that apply)" */
.field .hint-inline { font-weight: 400; color: var(--text-muted); }
/* Checkbox group (service details). Wraps to as many rows as it needs. */
.lf-checks { display: flex; flex-wrap: wrap; gap: 0.5rem var(--space-4); }
.lf-checks label {
  display: inline-flex; align-items: center; gap: 0.45rem; cursor: pointer;
  font-size: var(--fs-body-sm); color: var(--text-body);
}
.lf-checks input[type="checkbox"] { accent-color: var(--brand); width: 16px; height: 16px; cursor: pointer; }
.lf-checks input[type="checkbox"]:focus-visible { outline: 2px solid var(--border-focus); outline-offset: 2px; }
.input, .select, .textarea {
  width: 100%; font-family: var(--font-text); font-size: var(--fs-body);
  color: var(--text-strong); background: #fff; border: 1.5px solid var(--border-default);
  border-radius: var(--radius-md); padding: 0.7rem 0.9rem; outline: none; box-sizing: border-box;
  transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.input:focus, .select:focus, .textarea:focus { border-color: var(--border-focus); box-shadow: var(--shadow-focus); }
.input.invalid, .select.invalid, .textarea.invalid { border-color: var(--danger-600); }
.select-wrap { position: relative; }
.select { appearance: none; padding-right: 2.4rem; cursor: pointer; }
.select-wrap::after {
  content: ""; position: absolute; right: 0.9rem; top: 50%; width: 10px; height: 10px;
  border-right: 2.5px solid var(--text-muted); border-bottom: 2.5px solid var(--text-muted);
  transform: translateY(-70%) rotate(45deg); pointer-events: none;
}
.textarea { resize: vertical; min-height: 120px; line-height: var(--lh-body); }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); }
.form-grid .full { grid-column: 1 / -1; }
.honeypot { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ---------- Misc patterns ---------- */
.chip {
  display: inline-flex; align-items: center; gap: 0.45rem; padding: 0.5rem 0.9rem;
  background: var(--sand-100); border-radius: var(--radius-pill);
  font-weight: 600; font-size: var(--fs-body-sm); color: var(--text-strong);
}
.chip svg { color: var(--sun-600); }
.chip-ghost { background: transparent; border: 1.5px dashed var(--border-strong); color: var(--text-muted); }
.chip-row { display: flex; flex-wrap: wrap; gap: var(--space-2); }
/* Chips that navigate (the /services/ jump row): same look, quiet hover. */
a.chip {
  text-decoration: none;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
a.chip:hover { background: var(--sand-200); color: var(--text-strong); }

.check-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.check-list li { display: flex; gap: 0.6rem; align-items: flex-start; color: var(--text-body); }
.check-list svg { flex: none; color: var(--pool-600); margin-top: 2px; }
.check-list-success svg { color: var(--success-600); }

.pricing-table {
  width: 100%; border-collapse: collapse; background: var(--surface-card);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-md); overflow: hidden;
}
/* overflow-x:auto (not hidden): on narrow phones the table pans inside its own
   wrapper instead of the price column getting clipped off unreachable. */
.pricing-wrap { border-radius: var(--radius-lg); overflow-x: auto; overflow-y: hidden; box-shadow: var(--shadow-md); }
.pricing-table th {
  background: var(--ink-900); color: #fff; text-align: left; font-weight: 700;
  font-size: var(--fs-body-sm); padding: var(--space-4) var(--space-5);
}
.pricing-table td { padding: var(--space-4) var(--space-5); border-top: 1px solid var(--border-subtle); }
.pricing-table tbody tr:nth-child(even) { background: var(--sand-50); }
.pricing-table .price { text-align: right; font-family: var(--font-mono); color: var(--pool-700); font-weight: 700; white-space: nowrap; }
.pricing-table th:last-child { text-align: right; }
/* Top-down pool glyphs in the size column, drawn to relative scale (√ of surface area) */
.pricing-table .size-label { display: inline-flex; align-items: center; gap: var(--space-3); white-space: nowrap; }
.pricing-table .pool-glyph { flex: none; width: 56px; height: 28px; }
.pricing-table .pool-glyph rect { fill: var(--pool-300); stroke: var(--pool-600); stroke-width: 2; }

/* ---------- Hero patterns ---------- */
.hero-dark { position: relative; background: var(--ink-900); overflow: hidden; }
.hero-dark .hero-bg {
  position: absolute; inset: 0; background-size: cover; background-position: center;
  opacity: 0.55;
}
.hero-bg-home {
  background-image: url('/assets/install-crew.jpg');
  /* WebP where the browser takes it (2026-09-22); the line above is the fallback.
     tools/build.js preloads the same two files — change them together. */
  background-image: image-set(url('/assets/install-crew.webp') type('image/webp'), url('/assets/install-crew.jpg') type('image/jpeg'));
}
.hero-dark .hero-scrim {
  position: absolute; inset: 0;
  background: linear-gradient(rgba(30,26,20,0.35), rgba(30,26,20,0.55) 55%, rgba(30,26,20,0.85));
}
.hero-dark .container { position: relative; }
.hero-content { max-width: 720px; padding: clamp(3.5rem, 8vw, 7rem) 0; }
.hero-pill {
  display: inline-flex; align-items: center; gap: 0.5rem;
  background: rgba(255,255,255,0.14); color: #fff; border-radius: var(--radius-pill);
  padding: 0.45rem 1rem; font-weight: 600; font-size: var(--fs-body-sm);
  margin-bottom: var(--space-5);
}
.hero-pill svg { color: var(--gold-400); }
a.hero-pill { text-decoration: none; transition: background var(--dur-base) var(--ease-out); }
a.hero-pill:hover { background: rgba(255,255,255,0.24); }
.hero-dark h1 { color: #fff; font-size: clamp(2.15rem, 6vw, 4.5rem); line-height: var(--lh-tight); margin: 0 0 var(--space-4); }
.hero-dark .lead { color: rgba(255,255,255,0.88); }
.hero-sub { margin-top: var(--space-5); color: rgba(255,255,255,0.75); font-size: var(--fs-body-sm); }
.hero-sub a { color: var(--gold-400); font-weight: 700; }
.hero-sub a:hover { color: var(--gold-200); }

.lead { font-size: var(--fs-lead); line-height: var(--lh-relaxed); color: var(--text-body); }
.on-dark, .on-dark h1, .on-dark h2, .on-dark h3 { color: #fff; }
.on-dark .lead, .on-dark p { color: rgba(255,255,255,0.9); }
/* The focus ring (tokens/base.css) turns white wherever the ground is dark or orange: teal on the
   sun-600 bands measured about 1.6:1, i.e. invisible. White clears 3:1 on all of them. */
.hero-dark, .on-dark, .section-sun, .section-ink, .section-pool-900, .section-pool-800, .how-stage, .site-footer { --focus-ring: #fff; }

.stats-band { display: flex; justify-content: space-between; gap: var(--space-5); flex-wrap: wrap; }
.stats-band .stat-value, .stats-band .stat-label { color: #fff; }
.stats-band .stat-label { font-weight: 600; opacity: 0.9; }

.section-head { max-width: 720px; margin: 0 auto var(--space-7); text-align: center; }
.section-head h2 { margin: 0 0 var(--space-3); }
.section-head .lead { margin: 0; }

.info-row { display: flex; gap: var(--space-4); align-items: center; }
.info-row > div { min-width: 0; }
.info-row .info-value { overflow-wrap: anywhere; }
.info-row .icon-chip { width: 42px; height: 42px; }
.info-row .info-label {
  font-size: var(--fs-overline); font-weight: 700; letter-spacing: var(--ls-overline);
  text-transform: uppercase; color: var(--text-muted);
}
.info-row .info-value { font-weight: 700; color: var(--text-strong); }
.info-row .info-value a { color: var(--text-strong); text-decoration: none; }
.info-row .info-value a:hover { color: var(--brand); }

.success-state { text-align: center; padding: var(--space-6) 0; }
.success-check {
  width: 64px; height: 64px; border-radius: 50%; margin: 0 auto var(--space-4);
  background: var(--success-100); color: var(--success-600);
  display: flex; align-items: center; justify-content: center;
}

/* ---------- Home page (2026-09-22) ---------- */
/* The repair shortcut under the hero buttons — same gold as the licence link. */
.hero-urgent { margin: var(--space-4) 0 0; font-weight: 700; }
.hero-urgent a { color: var(--gold-400); text-decoration: none; }
.hero-urgent a:hover { color: var(--gold-200); text-decoration: underline; }
.hero-urgent + .hero-sub { margin-top: var(--space-3); }
/* The H1 is the search phrase, set small; the big line under it is the pitch,
   styled exactly as the H1 used to be. Google weighs the heading, the customer
   reads the big line, and the title tag leads with the same words. (0,2,1) so it
   beats .hero-dark h1, which every other dark hero still uses as-is. */
.hero-dark h1.hero-kicker {
  font-family: var(--font-display-hero);
  font-size: var(--fs-lead); line-height: var(--lh-snug); letter-spacing: normal;
  color: var(--gold-400); margin: 0 0 var(--space-3);
}
/* The hero's two big lines go from the phone's own font straight to Bricolage, never through Hanken
   (--font-display-hero, 2026-10-26). Hanken lands about half a second before Bricolage on a slow phone and
   is narrower, so these lines went system font (3 lines at 412px) -> Hanken (2) -> Bricolage (3 again),
   moving everything under them twice: layout shift 0.25 on the 1.6 Mbps test, 3 runs of 3
   (writeups/SEO-AUDIT-2026-10-26.md). Windows' system font wraps like Bricolage there, so nothing moves;
   Android's Roboto wraps like Hanken at 412px, so it moves once, as before, never twice. Measured
   360-1350px: the system font never wraps worse than Hanken did. */
.hero-display {
  font-family: var(--font-display-hero); font-weight: var(--fw-bold); color: #fff;
  font-size: clamp(2.15rem, 6vw, 4.5rem); line-height: var(--lh-tight);
  letter-spacing: var(--ls-display); margin: 0 0 var(--space-4); text-wrap: balance;
}

/* Swim season: two bars on a Jan–Dec track. The bars carry no text; the label
   beside each one says the same months, so the chart reads in greyscale and to
   a screen reader (role="img" + aria-label on .season). */
.season { max-width: 880px; margin: 0 auto; }
.season-row { display: grid; grid-template-columns: 11rem 1fr; gap: var(--space-4); align-items: center; }
.season-row + .season-row { margin-top: var(--space-3); }
.season-label { display: flex; flex-direction: column; font-size: var(--fs-body-sm); color: var(--text-muted); line-height: 1.3; }
.season-label strong { color: var(--text-strong); font-size: var(--fs-body); }
.season-ticks { display: grid; grid-template-columns: repeat(12, 1fr); text-align: center; font-size: var(--fs-caption); color: var(--text-muted); }
.season-track {
  position: relative; height: 2.25rem; background: var(--surface-card);
  border: 1px solid var(--border-subtle); border-radius: var(--radius-pill);
}
.season-bar {
  position: absolute; top: 3px; bottom: 3px; border-radius: var(--radius-pill);
  left: calc(var(--from) / 12 * 100%); width: calc((var(--to) - var(--from)) / 12 * 100%);
}
.season-bar-cold { background: var(--pool-300); }
.season-bar-warm { background: var(--sun-600); }
.season-note { max-width: 720px; margin: var(--space-5) auto 0; text-align: center; font-size: var(--fs-body-sm); color: var(--text-muted); }
.season-stats { margin-top: var(--space-7); text-align: center; }
.season-stats .stat { align-items: center; }

/* Service-area cards: the heading is the link to the area page; city names
   inside the text may link to their own pages, so the card itself cannot. */
.area-card h3 { font-size: var(--fs-title); margin: 0 0 var(--space-2); }
.area-card h3 a { color: var(--text-strong); text-decoration: none; display: inline-flex; align-items: center; gap: 0.4rem; }
.area-card h3 a svg { color: var(--brand); flex: none; transition: transform var(--dur-base) var(--ease-out); }
.area-card h3 a:hover { color: var(--brand); }
.area-card h3 a:hover svg { transform: translateX(3px); }
.area-card p { margin: 0; color: var(--text-body); }

/* ---------- Home page (2026-09-23): the combined page ---------- */
/* Text links that end in an arrow stay INLINE, with the icon on the last line of the text. As
   inline-flex, a wrapped link became a full-width box and its arrow floated off to the far right. */
.hero-urgent a svg, .how-more a svg, .how-skip a svg, .area-list h3 a svg {
  display: inline-block; vertical-align: -0.2em; margin-left: 0.3em;
}
/* Trust band: the Google rating is the one item that links (to the profile). */
.stats-band .stat-link { text-decoration: none; color: #fff; }
.stats-band .stat-link .stat-value { display: inline-flex; align-items: center; gap: 0.3rem; }
.stats-band .stat-link svg { width: 0.72em; height: 0.72em; fill: var(--gold-400); stroke: var(--gold-400); }
.stats-band .stat-link:hover .stat-label { text-decoration: underline; text-underline-offset: 3px; }

/* The 3D "how it works" section and the phone call bar live in css/how.css (2026-10-26): only the two
   pages that carry the section load them. */

.live-proof {
  display: flex; align-items: center; justify-content: center; gap: var(--space-3); flex-wrap: wrap;
  margin: var(--space-7) auto 0; max-width: 720px; text-align: center; font-weight: 600; color: var(--text-strong);
}
.live-proof svg { color: var(--brand); flex: none; }

.rating-link { color: var(--gold-400); font-weight: 700; text-decoration: none; }
.rating-link:hover { color: var(--gold-200); text-decoration: underline; text-underline-offset: 3px; }

.extras {
  list-style: none; margin: var(--space-6) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-5);
}
.extras li { font-size: var(--fs-body-sm); color: var(--text-body); padding-left: var(--space-4); border-left: 3px solid var(--sun-200); }
.extras strong { display: block; color: var(--text-strong); font-size: var(--fs-body); }

.certs { margin-top: var(--space-7); padding-top: var(--space-6); border-top: 1px solid var(--border-subtle); }
.certs-head {
  margin: 0 0 var(--space-5); text-align: center; font-family: var(--font-mono); font-size: var(--fs-overline);
  font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-muted);
}
.certs-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-5); }
.certs-list li { display: flex; align-items: center; gap: var(--space-3); font-size: var(--fs-body-sm); color: var(--text-body); }
.certs-list img, .certs-mark { width: 52px; height: 52px; object-fit: contain; flex: none; }
.certs-mark {
  display: flex; align-items: center; justify-content: center; border-radius: 50%;
  background: var(--ink-800); color: #fff; font-family: var(--font-mono); font-weight: 700; font-size: 0.75rem;
}
.certs-list strong { display: block; color: var(--text-strong); }

.area-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); }
.area-list li {
  background: var(--surface-card); border: 1px solid var(--border-subtle); border-radius: var(--radius-md);
  padding: var(--space-4) var(--space-5);
}
.area-list h3 { margin: 0 0 0.2rem; font-size: 1.125rem; }
.area-list h3 a { color: var(--text-strong); text-decoration: none; }
.area-list h3 a svg { color: var(--brand); transition: transform var(--dur-base) var(--ease-out); }
.area-list h3 a:hover { color: var(--brand); }
.area-list h3 a:hover svg { transform: translateX(3px); }
.area-list p { margin: 0; font-size: var(--fs-body-sm); color: var(--text-body); }

.next-steps {
  list-style: none; counter-reset: step; margin: var(--space-6) auto 0; padding: 0; text-align: left;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4);
}
.next-steps li {
  counter-increment: step; position: relative; padding: var(--space-4) var(--space-4) var(--space-4) 3.25rem;
  background: rgba(255, 255, 255, 0.1); border-radius: var(--radius-md);
}
.next-steps li::before {
  content: counter(step); position: absolute; left: var(--space-4); top: var(--space-4);
  width: 1.6rem; height: 1.6rem; border-radius: 50%; background: #fff; color: var(--sun-700);
  display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 0.9rem;
}
.next-steps strong { display: block; color: #fff; line-height: var(--lh-snug); }
.next-steps span { display: block; margin-top: 0.2rem; font-size: var(--fs-body-sm); color: rgba(255, 255, 255, 0.9); }
.quote-proof { margin: var(--space-5) 0 0; font-size: var(--fs-body-sm); color: rgba(255, 255, 255, 0.88); }

@media (max-width: 900px) {
  .extras { grid-template-columns: 1fr; gap: var(--space-4); }
  .certs-list { grid-template-columns: repeat(2, 1fr); }
  .area-list { grid-template-columns: repeat(2, 1fr); }
  .next-steps { grid-template-columns: 1fr; max-width: 420px; }
}
@media (max-width: 640px) {
  /* A plain divided list on a phone: five cards' borders, shadows and gaps were ~150px of chrome. */
  .area-list { grid-template-columns: 1fr; gap: 0; background: var(--surface-card); border: 1px solid var(--border-subtle); border-radius: var(--radius-md); }
  .area-list li { padding: var(--space-3) var(--space-4); border: 0; border-radius: 0; background: none; }
  .area-list li + li { border-top: 1px solid var(--border-subtle); }
  .page-home #services .service-card { padding: var(--space-5); gap: var(--space-2); }
  .page-home #services .icon-chip { width: 40px; height: 40px; }
  .certs-list { gap: var(--space-4) var(--space-3); }
  .certs-list li { flex-direction: column; align-items: flex-start; gap: var(--space-2); font-size: var(--fs-caption); }
  .certs-list img, .certs-mark { width: 40px; height: 40px; }
  /* The outcome figures sit three across even on a phone; the one-line explanations under them go,
     because the section's lead and note already say each of those things in a sentence. */
  .grid.season-stats { grid-template-columns: repeat(3, 1fr); gap: var(--space-3); margin-top: var(--space-6); }
  .season-stats .stat-value { font-size: 1.6rem; }
  .season-stats .stat-label { font-size: var(--fs-caption); line-height: 1.3; }
  .season-stats .stat-sublabel { display: none; }
  /* Reviews become a row you swipe, the next card peeking in from the edge so it reads as more. Every
     card is still in the page and reachable by keyboard; nothing is hidden, only side by side. */
  #reviews .grid-3 {
    display: flex; overflow-x: auto; scroll-snap-type: x mandatory; gap: var(--space-4);
    margin: 0 calc(-1 * var(--gutter)); padding: 4px var(--gutter) var(--space-3); scrollbar-width: none;
  }
  #reviews .grid-3::-webkit-scrollbar { display: none; }
  #reviews .grid-3 > .testimonial-link { flex: 0 0 86%; scroll-snap-align: center; }
  .extras li { padding-left: var(--space-3); }
}

/* ---------- Responsive (breakpoints per design: 980/900/640/560) ---------- */
@media (max-width: 980px) {
  .review-grid { columns: 2; }
}
@media (max-width: 900px) {
  .grid-2, .grid-3, .grid-4, .grid-2-uneven, .grid-2-uneven-rev { grid-template-columns: 1fr; }
  .grid-2x3 { grid-template-columns: 1fr 1fr; }
  .form-grid { grid-template-columns: 1fr; }
  .stats-band { justify-content: flex-start; gap: var(--space-6); }
}
@media (max-width: 640px) {
  .br-lg { display: none; }
  .hero-bg-home {
    background-image: url('/assets/install-crew-800.jpg');
    background-image: image-set(url('/assets/install-crew-800.webp') type('image/webp'), url('/assets/install-crew-800.jpg') type('image/jpeg'));
  }
  .review-grid { columns: 1; }
  .review-stats { gap: var(--space-5) var(--space-7); }
}
@media (max-width: 560px) {
  .season-row { grid-template-columns: 1fr; gap: var(--space-2); }
  .season-months .season-label { display: none; }
  .season-label { flex-direction: row; gap: 0.5rem; align-items: baseline; flex-wrap: wrap; }
  .season-ticks { font-size: 0.68rem; }
  .grid-2x3 { grid-template-columns: 1fr; }
  .btn-row .btn { width: 100%; }
  .pricing-table th, .pricing-table td { padding: var(--space-3); font-size: var(--fs-body-sm); }
  .pricing-table .price { white-space: normal; }
  .pricing-table .pool-glyph { width: 44px; height: 22px; }
}
@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* ---------- More Info (article hub + article pages) ---------- */
.article-meta {
  display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap;
  font-size: var(--fs-body-sm); font-weight: 600; color: var(--text-muted);
}
.article-meta span { display: inline-flex; align-items: center; gap: 0.4rem; }
.article-meta svg { color: var(--sun-600); flex: none; }
.article-card .article-meta { font-size: var(--fs-caption); }

.back-link {
  display: inline-flex; align-items: center; gap: 0.45rem;
  font-weight: 700; font-size: var(--fs-body-sm); color: var(--pool-700);
  /* padding + negative margin: ~44px tap target, pixel-identical position */
  padding: 0.6rem 0.25rem;
  margin: -0.6rem -0.25rem calc(var(--space-5) - 0.6rem);
}
.back-link svg { flex: none; transform: rotate(180deg); transition: transform var(--dur-base) var(--ease-out); }
.back-link:hover { color: var(--brand); }
.back-link:hover svg { transform: rotate(180deg) translateX(3px); }

.article-body h2 { margin: var(--space-7) 0 var(--space-3); }
.article-body h3 { margin: var(--space-5) 0 var(--space-2); }
.article-body p { color: var(--text-body); }
.article-body ul, .article-body ol {
  margin: var(--space-3) 0 var(--space-4); padding-left: 1.3rem;
  display: flex; flex-direction: column; gap: var(--space-2); color: var(--text-body);
}
.article-body a { font-weight: 600; }
.article-body a:hover { color: var(--brand); }

/* ---------- Buying-guide article blocks ---------- */
.article-figure { margin: var(--space-6) 0 0; }
.article-figure img {
  width: 100%; aspect-ratio: 21 / 9; object-fit: cover; display: block;
  border-radius: var(--radius-xl); box-shadow: var(--shadow-lg);
}
.article-figure figcaption {
  margin-top: var(--space-3); text-align: center;
  font-size: var(--fs-caption); color: var(--text-muted);
}

/* "Look for: … / Avoid: …" verdict line closing a component card */
.verdict { margin: 0; font-size: var(--fs-body-sm); }
.verdict .look { font-weight: 700; color: var(--pool-700); }
.verdict .avoid { font-weight: 700; color: var(--sun-700); margin-left: var(--space-2); }

/* Mono label above a card title ("Best for · most new installations").
   sun-800/pool-800 rather than --brand for the same reason .eyebrow uses
   sun-800: at caption size sun-600 misses 4.5:1 on white and sand.
   These live on <p>, so they are element-qualified to clear `.article-body p`
   (0,1,1) — a bare class selector loses that fight and inherits body color. */
p.card-label {
  font-family: var(--font-mono); font-weight: 700; font-size: var(--fs-caption);
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--sun-800); margin: 0 0 var(--space-2);
}
p.card-label-pool { color: var(--pool-800); }
p.card-sub {
  font-family: var(--font-mono); font-size: var(--fs-caption);
  color: var(--text-muted); margin: 0.25rem 0 var(--space-2);
}
.card-title-row { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.card-title-row h3 { margin: 0; }

/* Pool-tinted callout with an action parked on the right */
.callout {
  background: var(--pool-50); border: 1px solid var(--pool-200);
  border-radius: var(--radius-lg); padding: var(--space-5) var(--space-6);
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-4); flex-wrap: wrap;
}
.callout h3 { margin: 0 0 0.35rem; font-size: var(--fs-title); }
.callout p { margin: 0; font-size: var(--fs-body-sm); max-width: 46ch; }

/* Display-weight closing statement, and the brand-ruled pull quote */
p.pull {
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-title);
  line-height: var(--lh-heading); color: var(--text-strong); text-wrap: pretty;
}
.pullquote {
  border-left: 3px solid var(--brand);
  padding: 0.2rem 0 0.2rem var(--space-5); margin: var(--space-6) 0;
}
.pullquote p {
  font-family: var(--font-display); font-weight: 600; font-size: var(--fs-title);
  line-height: var(--lh-relaxed); color: var(--text-strong); margin: 0;
}

/* Footnote marker + note. The strikethrough and the "*" are both purely visual,
   so the struck heading carries an .sr-only phrase — a screen reader announces
   neither line-through nor a bare asterisk. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.fn-mark { color: var(--sun-800); font-weight: 700; }
.benefit-card h3 s { text-decoration-thickness: 2px; text-decoration-color: var(--sun-700); }
p.footnote {
  margin: var(--space-4) 0 0; font-size: var(--fs-body-sm); color: var(--text-muted);
}

/* Two-up ✗/✓ diagram pair (one-piece C-clamp vs two-piece header bracket).
   Tiles carry their own flex-basis, so they drop to one column on narrow
   screens without a media query. The ✗/✓ reads in brand sun/pool rather than
   the danger/success tokens, to match the .verdict line closing each card. */
.clamp-figs { display: flex; flex-wrap: wrap; gap: var(--space-4); margin: var(--space-4) 0; }
.clamp-fig { flex: 1 1 260px; margin: 0; }
.clamp-frame {
  position: relative; background: var(--sand-50);
  border: 1px solid var(--border-subtle); border-radius: var(--radius-md);
  overflow: hidden;
}
/* Child combinator: the badge icon is also inside .clamp-frame, and must keep
   its own 16px intrinsic size rather than stretch to the frame width. */
.clamp-frame > svg { display: block; width: 100%; height: auto; }
.clamp-badge {
  position: absolute; top: var(--space-3); left: var(--space-3); z-index: 2;
  width: 34px; height: 34px; border-radius: var(--radius-pill);
  display: flex; align-items: center; justify-content: center;
  color: var(--white); box-shadow: var(--shadow-sm);
}
.clamp-badge-no { background: var(--sun-700); }
.clamp-badge-yes { background: var(--pool-700); }
.clamp-cap {
  display: flex; gap: 0.5rem; align-items: flex-start;
  margin-top: var(--space-3);
  font-size: var(--fs-body-sm); color: var(--text-body);
}
.clamp-cap svg { flex: none; margin-top: 2px; }
.clamp-cap strong { color: var(--text-strong); }
.clamp-cap-no svg { color: var(--sun-700); }
.clamp-cap-yes svg { color: var(--pool-700); }

@media (max-width: 640px) {
  .callout { justify-content: flex-start; }
}

/* ---------- Repair guides ----------
   Responsive video slot for the optional per-guide embed. aspect-ratio rather
   than the old padding-top hack, so the iframe needs no wrapper of its own. */
.guide-video {
  aspect-ratio: 16 / 9; border-radius: var(--radius-lg); overflow: hidden;
  box-shadow: var(--shadow-md); background: var(--ink-800);
}
.guide-video iframe { width: 100%; height: 100%; border: 0; display: block; }

/* ---------- Print ----------
   The printable "doc" half of a repair guide is this rule, and nothing else:
   the page IS the handout, so a guide's written steps and its printout are the
   same text and can never drift apart. Drops the site chrome and anything
   screen-only (.no-print), flattens the section rhythm, and forces the FAQ
   accordions open — a collapsed <div> prints as an empty box, which on paper
   reads as a missing answer rather than a closed one. Applies site-wide because
   every page here is worth printing cleanly, not just the guides. */
@media print {
  .site-header, .site-footer, .mobile-menu, .skip-link,
  #sps-staging-flag, .no-print { display: none !important; }

  html, body { background: #fff !important; }
  .section { padding: 0 0 var(--space-6) !important; background: #fff !important; }
  .section.on-dark, .section.on-dark h1, .section.on-dark h2,
  .section.on-dark h3, .section.on-dark p { color: #000 !important; }
  .container, .container-narrow { max-width: none; padding: 0; }
  .section-head { max-width: none; text-align: left; }
  .eyebrow-center { justify-content: flex-start; }

  .card, .benefit-card, .service-card, .callout {
    box-shadow: none !important; border: 1px solid #bbb !important;
    background: #fff !important;
  }
  .card, .benefit-card, .service-card, .callout, .step, figure, img {
    break-inside: avoid;
  }
  h1, h2, h3 { break-after: avoid; }

  /* Collapsed by a max-height/opacity transition on screen — both have to be
     unwound or the answers print as blank space. */
  .accordion-a { max-height: none !important; opacity: 1 !important; }

  /* The brand marks still read in greyscale; solid fills waste toner. */
  .step-marker { background: #444 !important; color: #fff !important; }
  .icon-chip { background: #eee !important; color: #333 !important; }
}
