/* 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;
  --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); }

:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus);
  border-radius: var(--radius-xs);
}

/* ── 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: none; box-shadow: var(--shadow-focus); }
.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); }
.nav-menu a:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
.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; }

@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 under every lead-form submit button */
.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); }

/* 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; }
}
@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); }

.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;
}

/* ---------- 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) {
  .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; }
}
