/* ==========================================================================
   Treasure Valley Water Solutions
   core.css :: tokens, reset, typography, layout primitives, accessibility
   Palette is restricted to blues, greens, white and a yellow accent.
   No orange, pink or purple appears anywhere in this codebase.
   ========================================================================== */

/* --------------------------------------------------------------------------
   01 :: Design tokens
   -------------------------------------------------------------------------- */

:root {
  /* Deep water blues, the structural spine of the brand.
     Sampled from the company logo and the original site rather than picked by
     eye. --navy-900 is the logo wordmark, --navy-800 is the original site's
     primary blue, --aqua-400 is the bright water in the droplet. Everything
     else is derived at that same 205 degree hue so the family stays coherent.
     The palette this replaced sat around 194 to 200 degrees, which read a
     touch too cyan next to the logo. */
  --navy-950: #071D2A;
  --navy-900: #102C40;  /* logo wordmark, exact */
  --navy-800: #003861;  /* original site primary, exact */
  --navy-700: #0A4E7A;
  --teal-600: #306889;
  --aqua-500: #4392C1;  /* logo droplet water, exact */
  --aqua-400: #6BA9CF;
  --aqua-300: #8FC7EA;  /* baby blue, the button fill */
  --aqua-200: #ACCFE3;
  --aqua-100: #D7EAF5;
  --aqua-50:  #F0F8FC;

  /* Royal blue, carried over from the original tvwatersolutions.com. It is the
     vivid, saturated blue their old header and buttons used (hue 211, sat .77),
     distinct from the softer logo aqua above (hue 202, sat .65). It supplies
     the "pop" accent: header phone and CTA, links, big numerals, button hover.
     --royal-500 clears AA for white button text (4.66:1); --royal-700 is the
     darker press state. */
  --royal-500: #2D76C5;  /* old site primary, exact */
  --royal-600: #1565C0;  /* old site deeper variant, exact */
  --royal-700: #2561A2;

  /* Greens signal "solved, clean, safe". The logo's foliage sits at 160
     degrees and these were already at 158, so the hue was right; they are
     darkened here so white button text clears AA, which the old --green-600
     missed at 4.33:1. */
  --green-800: #10533A;
  --green-700: #156A4B;
  --green-600: #1A855D;
  --green-500: #27A776;
  --green-300: #7FD3AF;
  --green-100: #DCF2E7;

  /* Yellow is an accent only, never a surface */
  --sun-600: #8D680D;
  --sun-500: #F5C33B;
  --sun-300: #FADF95;
  --sun-100: #FDF3D8;

  /* Neutrals carry the same 205 degree hue as the brand blues so the greys
     never read cyan beside the logo. --ink-3 is darker than it looks like it
     needs to be: it lands on the tinted page background as well as on white,
     and at its old value that pairing measured 3.76:1, under AA for the small
     print it is used on. */
  --ink:      #0A1D2B;
  --ink-2:    #3C596E;
  --ink-3:    #586C7B;
  --line:     #D8E5EE;
  --line-2:   #EDF3F7;
  --paper:    #FFFFFF;
  --bone:     #F6FAFC;

  /* Semantic surface roles, remapped by the high contrast mode */
  --surface:      var(--paper);
  --surface-alt:  var(--bone);
  --text:         var(--ink);
  --text-soft:    var(--ink-2);
  --text-mute:    var(--ink-3);
  --border:       var(--line);
  --accent:       var(--green-600);
  --accent-ink:   #FFFFFF;

  /* Type families. --font-body is swapped by the dyslexia friendly toggle. */
  --font-display: 'Figtree', -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
  --font-body: 'Figtree', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: ui-monospace, 'SF Mono', Menlo, monospace;

  /* Type scale multiplier, driven by the ADA text sizing control */
  --type-scale: 1;

  /* Fluid spacing */
  --s1: 0.25rem;
  --s2: 0.5rem;
  --s3: 0.75rem;
  --s4: 1rem;
  --s5: 1.5rem;
  --s6: 2rem;
  --s7: 3rem;
  --s8: 4.5rem;
  --s9: 7rem;
  --s10: 10rem;

  --gutter: clamp(1.15rem, 4vw, 3.5rem);
  --section-y: clamp(2.8rem, 5vw, 4.6rem);

  /* Radii */
  --r-xs: 6px;
  --r-sm: 10px;
  --r-md: 18px;
  --r-lg: 28px;
  --r-xl: 40px;
  --r-round: 999px;

  /* Elevation, tuned cool so shadows read as water not soot */
  --sh-1: 0 1px 2px rgba(6, 42, 60, .05), 0 2px 10px rgba(6, 42, 60, .04);
  --sh-2: 0 4px 14px rgba(6, 42, 60, .07), 0 14px 38px rgba(6, 42, 60, .06);
  --sh-3: 0 12px 30px rgba(6, 42, 60, .10), 0 34px 74px rgba(6, 42, 60, .10);
  --sh-4: 0 30px 70px rgba(4, 26, 38, .22);

  /* Motion */
  --ease-out: cubic-bezier(.19, 1, .22, 1);
  --ease-soft: cubic-bezier(.4, 0, .2, 1);
  --ease-spring: cubic-bezier(.34, 1.56, .64, 1);
  --dur-1: .18s;
  --dur-2: .38s;
  --dur-3: .7s;
  --dur-4: 1.1s;

  /* Layout. --wrap matches --wrap-wide so every section's content starts at
     the same left edge as the header bar; long-form line length is controlled
     by the narrower caps (.wrap-read, .prose, .section-head, .lede), not by
     the section container. */
  --wrap: 1560px;
  --wrap-wide: 1560px;
  --wrap-read: 74ch;
  --header-h: clamp(80px, 7.4vw, 116px);

  /* Safe areas for notched devices, used by the floating dock */
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
}

/* --------------------------------------------------------------------------
   02 :: Reset
   -------------------------------------------------------------------------- */

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

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

body {
  margin: 0;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-body);
  font-size: calc(1.0625rem * var(--type-scale));
  line-height: 1.68;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
  text-rendering: optimizeLegibility;
}

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

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

ul, ol { margin: 0; padding: 0; }
li { list-style: none; }

a { color: inherit; text-decoration: none; }

table { border-collapse: collapse; width: 100%; }

/* --------------------------------------------------------------------------
   03 :: Typography
   Headings use clamp() with a vw term so they scale continuously and fill
   their container. The JS fitter in app.js refines the hero headline to sit
   at exactly 100% of its parent width on every viewport.
   -------------------------------------------------------------------------- */

h1, h2, h3, h4, h5, h6 {
  margin: 0;
  font-family: var(--font-display);
  /* Figtree needs 700 to carry the weight the old serif had at 600 */
  font-weight: 700;
  /* A sans has shallower descenders than the serif this replaced, so the
     headline can sit tighter without the letterforms looking clipped. */
  line-height: 1.04;
  letter-spacing: -.028em;
  color: var(--navy-900);
  text-wrap: balance;
}

h1 { font-size: calc(clamp(2.6rem, 7.4vw, 6.4rem) * var(--type-scale)); }
h2 { font-size: calc(clamp(1.9rem, 3.6vw, 3.3rem) * var(--type-scale)); }
h3 { font-size: calc(clamp(1.35rem, 2.1vw, 1.85rem) * var(--type-scale)); line-height: 1.15; }

/* Headings living inside a grid column get less room than section-level
   ones; scale them so a forced two-line break still holds at two lines. */
.grid12 h2 { font-size: calc(clamp(1.75rem, 2.6vw, 2.7rem) * var(--type-scale)); }
h4 { font-size: calc(clamp(1.08rem, 1.4vw, 1.24rem) * var(--type-scale)); line-height: 1.25; font-weight: 700; }
h5 { font-size: calc(1rem * var(--type-scale)); font-weight: 700; }

p { margin: 0 0 1.15em; }
p:last-child { margin-bottom: 0; }

strong, b { font-weight: 700; color: var(--navy-900); }
em { font-style: italic; }

/* Headline that is fitted to exactly 100% of its container by JS */
.fit-line {
  display: block;
  white-space: nowrap;
  transform-origin: left center;
  will-change: transform;
}
.fit-wrap { width: 100%; overflow: hidden; }

/* Editorial accents */
.script {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  letter-spacing: -.01em;
}

.mark-sun {
  background-image: linear-gradient(180deg, transparent 58%, var(--sun-300) 58%, var(--sun-300) 92%, transparent 92%);
  padding-inline: .06em;
}

.mark-underline {
  position: relative;
  display: inline-block;
}
.mark-underline::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: .04em;
  height: .09em;
  border-radius: 2px;
  background: var(--green-500);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-3) var(--ease-out);
}
.is-in .mark-underline::after, .mark-underline.is-in::after { transform: scaleX(1); }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: .6em;
  font-family: var(--font-body);
  font-size: calc(.78rem * var(--type-scale));
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--green-700);
}
.eyebrow::before {
  content: "";
  width: 1.9rem;
  height: 2px;
  background: currentColor;
  opacity: .55;
}
.eyebrow.is-light { color: var(--sun-500); }

.lede {
  font-size: calc(clamp(1.075rem, 1.55vw, 1.32rem) * var(--type-scale));
  line-height: 1.6;
  color: var(--text-soft);
  max-width: 58ch;
}

.overline-num {
  font-family: var(--font-mono);
  font-size: calc(.76rem * var(--type-scale));
  letter-spacing: .16em;
  color: var(--text-mute);
}

/* --------------------------------------------------------------------------
   04 :: Layout primitives
   -------------------------------------------------------------------------- */

.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gutter); }
.wrap-wide { max-width: var(--wrap-wide); }
/* Self sufficient: these carry their own centring and gutters so that using
   them without .wrap (which is where margin-inline:auto lives) still centres
   rather than silently pinning the block to the left edge. */
.wrap-read {
  max-width: var(--wrap-read);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: var(--section-y); position: relative; }
.section-sm { padding-block: clamp(2.5rem, 5vw, 4.5rem); }

.bg-bone { background: var(--surface-alt); }
.bg-mist { background: var(--aqua-50); }
.bg-deep {
  background: var(--navy-900);
  color: var(--aqua-100);
}
.bg-deep h1, .bg-deep h2, .bg-deep h3, .bg-deep h4 { color: #fff; }
.bg-deep .lede { color: var(--aqua-200); }
/* The eyebrow's dark green is for light surfaces. On navy it measured
   2.19:1; the light green from the same family reads 8.13:1. */
.bg-deep .eyebrow, .cta-band .eyebrow { color: var(--green-300); }

/* Asymmetric editorial grid. Twelve columns, generous gutters. */
.grid12 {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(1.25rem, 2.6vw, 2.75rem);
}
.col-full { grid-column: 1 / -1; }
.col-l7 { grid-column: 1 / span 7; }
.col-l6 { grid-column: 1 / span 6; }
.col-l5 { grid-column: 1 / span 5; }
.col-r5 { grid-column: 8 / -1; }
.col-r6 { grid-column: 7 / -1; }
.col-r7 { grid-column: 6 / -1; }
.col-mid8 { grid-column: 3 / span 8; }
.col-mid6 { grid-column: 4 / span 6; }

@media (max-width: 900px) {
  .col-l7, .col-l6, .col-l5, .col-r5, .col-r6, .col-r7, .col-mid8, .col-mid6 { grid-column: 1 / -1; }
}

.stack > * + * { margin-top: var(--flow, 1.15rem); }
.stack-lg { --flow: 1.9rem; }
.stack-sm { --flow: .7rem; }

.cluster { display: flex; flex-wrap: wrap; gap: var(--s4); align-items: center; }
.cluster-tight { gap: var(--s3); }

.auto-grid {
  display: grid;
  gap: clamp(1rem, 2vw, 1.9rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--min, 260px)), 1fr));
}

.center { text-align: center; }
.center .lede { margin-inline: auto; }
.center .eyebrow::before { display: none; }

.section-head {
  /* No width cap here: it strangled two-line headlines. The lede carries its
     own 58ch line-length limit, which is the thing the cap was really for. */
  max-width: none;
  /* Breathing room before whatever the section head introduces. Without this,
     any follower that carries no top margin of its own (the reviews summary
     bar, plain grids) sits jammed against the heading. */
  margin-bottom: clamp(1.8rem, 3.5vw, 3rem);
}
.section-head.center { margin-inline: auto; }
.section-head > * + * { margin-top: var(--s4); }

/* --------------------------------------------------------------------------
   05 :: Accessibility scaffolding
   -------------------------------------------------------------------------- */

.skip-link {
  position: fixed;
  top: -100%;
  left: var(--s4);
  z-index: 9999;
  background: var(--navy-900);
  color: #fff;
  padding: .9rem 1.4rem;
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  font-weight: 700;
  transition: top var(--dur-1) var(--ease-soft);
}
.skip-link:focus { top: 0; }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

:focus-visible {
  outline: 3px solid var(--aqua-500);
  outline-offset: 3px;
  border-radius: 4px;
}
.bg-deep :focus-visible { outline-color: var(--sun-500); }

/* --------------------------------------------------------------------------
   06 :: Accessibility modes, toggled by the ADA widget on <html>
   -------------------------------------------------------------------------- */

/* High contrast: flatten decorative colour, force strong separation */
html[data-contrast="high"] {
  --surface: #FFFFFF;
  --surface-alt: #FFFFFF;
  --text: #000000;
  --text-soft: #14202A;
  --text-mute: #24333D;
  --border: #000000;
  --accent: #0A4D33;
  --line: #000000;
  --line-2: #000000;
  --navy-900: #000000;
  --navy-800: #002233;
  --sh-1: none; --sh-2: none; --sh-3: none; --sh-4: none;
}
html[data-contrast="high"] .card,
html[data-contrast="high"] .panel,
html[data-contrast="high"] .acc-panel,
html[data-contrast="high"] .stat-card { border: 2px solid #000 !important; }
html[data-contrast="high"] .bg-deep { background: #001622; }
html[data-contrast="high"] img:not(.brand-img) { filter: contrast(1.15) saturate(.85); }
html[data-contrast="high"] .media-tint::after { display: none; }

/* Dyslexia friendly typeface */
html[data-dyslexic="on"] {
  --font-body: 'Atkinson Hyperlegible', Verdana, sans-serif;
  --font-display: 'Atkinson Hyperlegible', Verdana, sans-serif;
  letter-spacing: .012em;
  word-spacing: .09em;
}
html[data-dyslexic="on"] h1, html[data-dyslexic="on"] h2,
html[data-dyslexic="on"] h3, html[data-dyslexic="on"] h4 {
  font-variation-settings: normal;
  letter-spacing: 0;
  line-height: 1.2;
}

/* Underline every link, for users who cannot rely on colour alone */
html[data-links="underline"] a:not(.btn):not(.brand):not(.dock-item) {
  text-decoration: underline;
  text-underline-offset: .18em;
}

/* Reading guide bar follows the cursor */
html[data-guide="on"] .reading-guide { display: block; }
.reading-guide {
  display: none;
  position: fixed;
  left: 0; right: 0;
  height: 2.6rem;
  z-index: 9000;
  pointer-events: none;
  background: rgba(27, 156, 196, .14);
  border-top: 2px solid var(--aqua-500);
  border-bottom: 2px solid var(--aqua-500);
}

/* Motion reduction, either by user preference or the widget toggle */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
html[data-motion="off"] { scroll-behavior: auto; }
html[data-motion="off"] *,
html[data-motion="off"] *::before,
html[data-motion="off"] *::after {
  animation-duration: .001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: .001ms !important;
}
html[data-motion="off"] .reveal,
html[data-motion="off"] .reveal-child > * { opacity: 1 !important; transform: none !important; }
html[data-motion="off"] .parallax { transform: none !important; }

/* --------------------------------------------------------------------------
   07 :: Buttons
   -------------------------------------------------------------------------- */

/* Baby blue is far too light to carry white type: white on it measures
   1.8:1. The label is navy instead, which reads 7.9:1. The border is not
   decoration either. A baby blue fill sits only 1.8:1 against the white page,
   under the 3:1 a control needs to be discernible as a control, so the deeper
   blue edge is what actually defines the button's shape. */
.btn {
  --btn-bg: var(--aqua-300);
  --btn-ink: var(--navy-900);
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .6em;
  padding: 1.06em 1.9em;
  font-family: var(--font-body);
  font-size: calc(1rem * var(--type-scale));
  font-weight: 700;
  line-height: 1;
  letter-spacing: -.005em;
  color: var(--btn-ink);
  background: var(--btn-bg);
  border: 2px solid var(--aqua-500);
  border-radius: var(--r-round);
  overflow: hidden;
  isolation: isolate;
  transition: transform var(--dur-2) var(--ease-spring),
              box-shadow var(--dur-2) var(--ease-soft),
              background-color var(--dur-1) var(--ease-soft),
              color var(--dur-1) var(--ease-soft);
  box-shadow: var(--sh-2);
}
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  /* Royal, so a baby blue button floods to the old site's blue on hover and
     the two blues read as one family. */
  background: var(--royal-600);
  transform: translateY(101%);
  transition: transform var(--dur-2) var(--ease-out);
}
/* The hover fill floods royal blue, so the navy label has to flip to white */
.btn:hover {
  transform: translateY(-3px);
  box-shadow: var(--sh-3);
  --btn-ink: #fff;
  border-color: var(--royal-600);
}
.btn:hover::before { transform: translateY(0); }
.btn:active { transform: translateY(-1px); }

.btn svg { width: 1.15em; height: 1.15em; flex: none; transition: transform var(--dur-2) var(--ease-out); }
.btn:hover svg { transform: translateX(3px); }

.btn-ghost {
  --btn-bg: transparent;
  --btn-ink: var(--navy-900);
  border-color: var(--border);
  box-shadow: none;
}
.btn-ghost::before { background: var(--navy-900); }
.btn-ghost:hover { --btn-ink: #fff; border-color: var(--navy-900); }

/* Sits on the dark CTA band, where it supplies its own contrast and wants no
   blue edge around it. */
.btn-light {
  --btn-bg: #fff;
  --btn-ink: var(--navy-900);
  border-color: transparent;
}
.btn-light::before { background: var(--sun-500); }
.btn-light:hover { --btn-ink: var(--navy-950); border-color: transparent; }

.btn-outline-light {
  --btn-bg: transparent;
  --btn-ink: #fff;
  border-color: rgba(255,255,255,.42);
  box-shadow: none;
}
.btn-outline-light::before { background: #fff; }
.btn-outline-light:hover { --btn-ink: var(--navy-900); border-color: #fff; }

.btn-lg { padding: 1.22em 2.3em; font-size: calc(1.06rem * var(--type-scale)); }
.btn-sm { padding: .82em 1.35em; font-size: calc(.92rem * var(--type-scale)); }
.btn-block { width: 100%; }

/* Text link with an animated rule */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: .5em;
  font-weight: 700;
  color: var(--teal-600);
  padding-bottom: .18em;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 2px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size var(--dur-2) var(--ease-out), color var(--dur-1) var(--ease-soft);
}
.link-arrow:hover { background-size: 100% 2px; color: var(--green-700); }
.link-arrow svg { width: 1em; height: 1em; transition: transform var(--dur-2) var(--ease-out); }
.link-arrow:hover svg { transform: translateX(4px); }
.bg-deep .link-arrow { color: var(--sun-500); }

/* --------------------------------------------------------------------------
   08 :: Motion utilities, progressively enhanced by app.js
   -------------------------------------------------------------------------- */

.reveal {
  opacity: 0;
  transform: translate3d(0, 26px, 0);
  transition: opacity var(--dur-3) var(--ease-out), transform var(--dur-3) var(--ease-out);
}
.reveal.is-in { opacity: 1; transform: none; }

.reveal-child > * {
  opacity: 0;
  transform: translate3d(0, 22px, 0);
  transition: opacity var(--dur-3) var(--ease-out), transform var(--dur-3) var(--ease-out);
}
.reveal-child.is-in > * { opacity: 1; transform: none; }
.reveal-child.is-in > *:nth-child(1) { transition-delay: .04s; }
.reveal-child.is-in > *:nth-child(2) { transition-delay: .12s; }
.reveal-child.is-in > *:nth-child(3) { transition-delay: .2s; }
.reveal-child.is-in > *:nth-child(4) { transition-delay: .28s; }
.reveal-child.is-in > *:nth-child(5) { transition-delay: .36s; }
.reveal-child.is-in > *:nth-child(6) { transition-delay: .44s; }
.reveal-child.is-in > *:nth-child(7) { transition-delay: .52s; }
.reveal-child.is-in > *:nth-child(8) { transition-delay: .6s; }

/* Word by word headline entrance. The line clips during the rise, so it
   needs bottom padding (with a compensating negative margin) or descenders
   on letters like y and g get sliced off permanently. Words start at 130%
   so they clear that padding zone while hidden. */
.split-line {
  display: block;
  overflow: hidden;
  padding-bottom: .16em;
  margin-bottom: -.16em;
}
.split-word {
  display: inline-block;
  transform: translate3d(0, 130%, 0);
  transition: transform var(--dur-4) var(--ease-out);
}
.is-in .split-word { transform: none; }
.is-in .split-word:nth-child(2) { transition-delay: .05s; }
.is-in .split-word:nth-child(3) { transition-delay: .1s; }
.is-in .split-word:nth-child(4) { transition-delay: .15s; }
.is-in .split-word:nth-child(5) { transition-delay: .2s; }
.is-in .split-word:nth-child(6) { transition-delay: .25s; }
.is-in .split-word:nth-child(7) { transition-delay: .3s; }
.is-in .split-word:nth-child(8) { transition-delay: .35s; }
.is-in .split-word:nth-child(9) { transition-delay: .4s; }
.is-in .split-word:nth-child(10) { transition-delay: .45s; }

.parallax { will-change: transform; }

/* Scroll progress rail */
.scroll-rail {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 3px;
  z-index: 400;
  background: transparent;
  pointer-events: none;
}
.scroll-rail span {
  display: block;
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, var(--aqua-500), var(--green-500), var(--sun-500));
  transition: width .08s linear;
}

/* Soft floating loop for decorative art */
@keyframes drift {
  0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg); }
  50%      { transform: translate3d(0, -14px, 0) rotate(1.4deg); }
}
.drift { animation: drift 9s var(--ease-soft) infinite; }
.drift-slow { animation: drift 14s var(--ease-soft) infinite; }

@keyframes ripple-out {
  0%   { transform: scale(.6); opacity: .55; }
  100% { transform: scale(2.4); opacity: 0; }
}

@keyframes marquee-x {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* --------------------------------------------------------------------------
   09 :: Media treatments
   -------------------------------------------------------------------------- */

.media {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-lg);
  background: var(--aqua-50);
}
.media img { width: 100%; height: 100%; object-fit: cover; }
.media-tall { aspect-ratio: 3 / 4; }
.media-wide { aspect-ratio: 16 / 10; }
.media-square { aspect-ratio: 1; }

.media-tint::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(200deg, rgba(6,42,60,.06), rgba(6,42,60,.5));
  pointer-events: none;
}

.media-zoom img {
  transition: transform 1.2s var(--ease-out);
}
.media-zoom:hover img { transform: scale(1.06); }

.media-caption {
  position: absolute;
  left: var(--s4); right: var(--s4); bottom: var(--s4);
  color: #fff;
  font-size: calc(.86rem * var(--type-scale));
  font-weight: 600;
  text-shadow: 0 2px 12px rgba(4,26,38,.6);
  z-index: 2;
}
/* A text shadow alone cannot carry white type over an arbitrary photograph.
   Measured against the actual image pixels, the lightest of these photos left
   the caption at 1.48:1, effectively invisible. This scrim gives the caption
   its own backdrop: on that same worst case it measures 6.06:1, and it costs
   nothing on the dark photos where the caption was already fine. Painted
   behind the text because the caption's own z-index makes a stacking context. */
.media-caption::before {
  content: "";
  position: absolute;
  left: calc(-1 * var(--s4)); right: calc(-1 * var(--s4));
  bottom: calc(-1 * var(--s4));
  top: -1.7em;
  background: linear-gradient(to top, rgba(4,26,38,.78), rgba(4,26,38,0));
  pointer-events: none;
  z-index: -1;
}

/* Photo credit, small and unobtrusive */
.credit {
  font-size: calc(.7rem * var(--type-scale));
  color: var(--text-mute);
  letter-spacing: .02em;
}

/* --------------------------------------------------------------------------
   10 :: Cards and surfaces
   -------------------------------------------------------------------------- */

.card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: clamp(1.4rem, 2.4vw, 2.1rem);
  box-shadow: var(--sh-1);
  transition: transform var(--dur-2) var(--ease-out),
              box-shadow var(--dur-2) var(--ease-soft),
              border-color var(--dur-2) var(--ease-soft);
  overflow: hidden;
}
.card:hover { transform: translateY(-5px); box-shadow: var(--sh-3); border-color: var(--aqua-200); }

.card-flush { padding: 0; }
.card-body { padding: clamp(1.4rem, 2.4vw, 2.1rem); }

.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: clamp(1.5rem, 3vw, 2.8rem);
  box-shadow: var(--sh-2);
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: .45em;
  padding: .45em 1em;
  border-radius: var(--r-round);
  font-size: calc(.78rem * var(--type-scale));
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  background: var(--green-100);
  color: var(--green-800);
}
.badge-sun { background: var(--sun-100); color: var(--sun-600); }
.badge-aqua { background: var(--aqua-100); color: var(--navy-800); }
.badge svg { width: 1em; height: 1em; }

.icon-tile {
  width: 3.1rem;
  height: 3.1rem;
  display: grid;
  place-items: center;
  border-radius: var(--r-sm);
  background: var(--aqua-100);
  color: var(--navy-800);
  flex: none;
}
.icon-tile svg { width: 1.55rem; height: 1.55rem; }
.icon-tile.is-green { background: var(--green-100); color: var(--green-800); }
.icon-tile.is-sun { background: var(--sun-100); color: var(--sun-600); }

/* Rule used to break long content, satisfies the 300 word disruption rule */
.rule {
  height: 1px;
  background: var(--border);
  border: 0;
  margin-block: var(--s6);
}

/* --------------------------------------------------------------------------
   11 :: Prose for long form and legal pages
   -------------------------------------------------------------------------- */

.prose { max-width: var(--wrap-read); }
.prose > * + * { margin-top: 1.15em; }
.prose h2 { margin-top: 2.1em; }
.prose h3 { margin-top: 1.7em; }
.prose h2 + p, .prose h3 + p { margin-top: .75em; }
.prose p, .prose li { color: var(--text-soft); }
.prose ul, .prose ol { padding-left: 1.35em; }
.prose ul li { list-style: disc; margin-bottom: .5em; }
.prose ol li { list-style: decimal; margin-bottom: .5em; }
.prose a { color: var(--royal-600); text-decoration: underline; text-underline-offset: .16em; }
.prose a:hover { color: var(--royal-700); }
.prose strong { color: var(--navy-900); }

.prose-wide { max-width: 88ch; }

/* --------------------------------------------------------------------------
   12 :: Print
   -------------------------------------------------------------------------- */

@media print {
  .site-header, .mobile-dock, .ada-launcher, .ada-panel, .scroll-rail,
  .cta-band, .btn, .translate-shell { display: none !important; }
  body { font-size: 11pt; color: #000; }
  .section { padding-block: 1rem; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .8em; color: #555; }
}

/* Forced two-line headline breaks. On narrow viewports the halves would wrap
   again anyway, so the break steps aside and natural wrapping takes over. */
@media (max-width: 700px) {
  br.h2b { display: none; }
}
