
/* Can I Swim? — the whole visual system in one file.
   Tokens first, then structure, then components. Dark mode redefines only the
   tokens, so nothing below has to know which mode it is in. */

:root{
  /* paper and ink — warmed towards sand, so it reads coastal not clinical */
  --bg:#f8f6f1;
  --bg-sunk:#f0ece3;
  --card:#fff;
  --ink:#101a1c;
  --ink-soft:#3c4b4d;
  --dim:#5b6b6d;
  --line:#e5e1d7;
  --line-strong:#d5cfc1;

  /* the sea */
  --brand:#0d4650;
  --brand-bright:#11707d;
  --brand-ink:#f4fbfa;

  /* status. These are not picked by eye: each was searched for the widest
     separation still achievable under deuteranopia and protanopia while keeping
     the conventional hue and clearing AA on both white and its own tint. The
     worst pair improves from 0.172 to 0.259 against the set they replace, and
     every one got darker and richer in the process. */
  --ok:#0f5635;        --ok-bg:#def3ea;   --ok-line:#95d8bd;
  --caution:#9e5c00;   --caution-bg:#fdf2e0; --caution-line:#f8d49a;
  --avoid:#680a04;     --avoid-bg:#fae1e0; --avoid-line:#eea09a;
  --advised:#a03113;   --advised-bg:#fdece3; --advised-line:#f0b394;
  --unknown:#4c675e;   --unknown-bg:#d5e2e0; --unknown-line:#aec7c2;

  /* waterfalls are the other half of the site and get their own accent, so the
     two halves feel distinct without leaving the family */
  --fall:#1d5c8a;      --fall-bg:#e2eff8; --fall-line:#a1cdea;

  --focus:#0b5fd6;
  /* The masthead and footer are dark teal, where the blue ring above measures
     1.8:1 — WCAG asks 3:1 of a focus indicator. This one is 5.7:1 on both. */
  --focus-brand:#8cc4ff;

  /* elevation — two steps only, used consistently */
  --lift:0 1px 2px rgba(16,26,28,.05), 0 1px 1px rgba(16,26,28,.04);
  --lift-2:0 2px 4px rgba(16,26,28,.05), 0 12px 28px -12px rgba(16,26,28,.18);

  --r-s:10px; --r-m:14px; --r-l:20px;
  --wrap:1120px; --read:760px;
  --serif:"Instrument Serif", Georgia, "Times New Roman", serif;
  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
}

@media (prefers-color-scheme:dark){
  :root{
    --bg:#0c1214;
    --bg-sunk:#080d0e;
    --card:#141d1f;
    --ink:#e9eeec;
    --ink-soft:#c2cdcb;
    --dim:#93a3a3;
    --line:#222e30;
    --line-strong:#2d3b3d;

    --brand:#0e3941;
    --brand-bright:#5ec8d3;
    --brand-ink:#eafcff;

    /* Dark mode is measured too, and the measurement says something worth
       recording: on a dark ground, status colour CANNOT carry this signal. Every
       one has to be light enough to read, which compresses exactly the
       differences colour blindness removes — the best natural set scores 0.110
       against light mode's 0.259, and chasing a higher number only produces pale
       mints and washed pinks that read as decoration rather than warning. So
       these are chosen to look right, and the map leans on size, outline and
       dash instead of hue. */
    --ok:#5fe0a4;        --ok-bg:#0e3f2e;   --ok-line:#106947;
    --caution:#f0b429;   --caution-bg:#503d17; --caution-line:#90641a;
    --avoid:#ff8f85;     --avoid-bg:#4a1a17; --avoid-line:#83211a;
    --advised:#ffa877;   --advised-bg:#4a2a17; --advised-line:#8a4d26;
    --unknown:#93a8a3;   --unknown-bg:#2a3b38; --unknown-line:#456159;

    --fall:#57a0d5;      --fall-bg:#153345; --fall-line:#205b81;

    --focus:#8cc4ff;
    --focus-brand:#8cc4ff;
    --lift:0 1px 2px rgba(0,0,0,.4);
    --lift-2:0 2px 4px rgba(0,0,0,.35), 0 16px 32px -14px rgba(0,0,0,.6);
  }
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}
  *{animation-duration:.01ms !important;transition-duration:.01ms !important}}

body{
  margin:0;background:var(--bg);color:var(--ink);
  font:400 16.5px/1.6 var(--sans);
  -webkit-font-smoothing:antialiased;
  padding-bottom:env(safe-area-inset-bottom);
}
img{max-width:100%}
a{color:var(--brand-bright);text-underline-offset:2px}
a:hover{color:var(--brand)}
@media (prefers-color-scheme:dark){a:hover{color:#8fe3ec}}
:focus-visible{outline:3px solid var(--focus);outline-offset:2px;border-radius:6px}
.masthead :focus-visible,.sitefoot :focus-visible{outline-color:var(--focus-brand)}

.wrap{max-width:var(--wrap);margin:0 auto;padding:0 20px}
.read{max-width:var(--read);margin:0 auto}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
/* The first tab stop on every page. Without it a keyboard or screen reader user
   walks the whole masthead before reaching the thing they came for. */
.skip{position:absolute;left:-9999px;top:0;z-index:1200;background:var(--card);color:var(--ink);
  border:1px solid var(--line-strong);border-radius:0 0 10px 0;padding:12px 18px;font-weight:650;
  text-decoration:none;box-shadow:var(--lift-2)}
.skip:focus{left:0}
#content:focus{outline:none}

/* ---------- header ------------------------------------------------------ */
/* The header carries the brand the way the footer does, so the page sits framed
   between two blocks of sea rather than fading off at the top. */
.masthead{
  position:sticky;top:0;z-index:1000;
  /* Solid first, translucent second. A browser too old for color-mix() drops
     that declaration and keeps this one; without it the background fell back to
     transparent while backdrop-filter — supported years earlier — kept working,
     so the header text sat unreadable over whatever scrolled beneath it. */
  background:var(--brand);
  background:color-mix(in srgb, var(--brand) 94%, transparent);
  backdrop-filter:saturate(1.4) blur(12px);
  -webkit-backdrop-filter:saturate(1.4) blur(12px);
  border-bottom:1px solid rgba(255,255,255,.14);
}
.masthead .inner{
  max-width:var(--wrap);margin:0 auto;padding:0 20px;
  display:flex;align-items:center;justify-content:space-between;gap:18px;min-height:62px;
}
.brand{
  display:inline-flex;align-items:center;gap:10px;text-decoration:none;color:#fff;
  font:400 22px/1 var(--serif);letter-spacing:.01em;white-space:nowrap;
}
.brand:hover{color:#fff}
.brand .mark{
  width:26px;height:26px;border-radius:8px;flex:none;
  background:rgba(255,255,255,.16);border:1px solid rgba(255,255,255,.28);
  display:grid;place-items:center;color:#fff;font-size:14px;
}
.masthead nav{display:flex;gap:4px;align-items:center;overflow-x:auto;scrollbar-width:none}
.masthead nav::-webkit-scrollbar{display:none}
.masthead nav a{
  color:#b9d3d5;text-decoration:none;font-size:14.5px;font-weight:500;
  padding:8px 11px;border-radius:999px;white-space:nowrap;
}
.masthead nav a:hover{color:#fff;background:rgba(255,255,255,.10)}

/* Under 600px the four links need 402px beside a 130px wordmark, so they were
   living in a 187px scroller with the scrollbar hidden: three of the site's four
   sections were invisible on every phone made. Give them their own row. The
   sticky search bar below follows via --headh rather than a fixed 62px. */
@media (max-width:599px){
  /* Two rows of links plus the wordmark is about 145px, and holding that at the
     top of an 812px phone for the whole scroll costs more than it gives. The
     header goes with the page and the search bar takes over the sticky job — so
     the sections are all there when you arrive, and the screen is yours after. */
  .masthead{position:static}
  .masthead .inner{
    flex-direction:column;align-items:stretch;justify-content:center;
    gap:0;min-height:0;padding:7px 16px 5px;
  }
  .masthead nav{overflow-x:visible;flex-wrap:wrap;gap:2px;justify-content:flex-start}
  .masthead nav a{padding:9px 10px;font-size:14px}
  .brand{font-size:20px;align-self:flex-start;padding:3px 0 5px}
}
.masthead nav a[aria-current=page]{color:#fff;background:rgba(255,255,255,.17);font-weight:650}

/* Touch. Apple asks 44px, Android 48dp; the pills sat at 40 and the nav at 39.
   Scoped to coarse pointers so the desktop layout keeps its proportions. */
@media (pointer:coarse){
  .btn{min-height:44px}
  .pill{min-height:44px;padding-top:10px;padding-bottom:10px}
  .masthead nav a{min-height:44px;display:inline-flex;align-items:center}
  .brand{min-height:44px}
  /* Leaflet's own stylesheet is injected at runtime, so it lands after this one
     and wins any tie. Naming the control class takes the specificity to 0,3,1
     against its 0,2,1 — no !important needed. */
  .seenpick{min-height:44px}
  /* The footer is a list of links to the site's five sections — navigation, not
     a sentence, so the inline-link exemption does not cover it. */
  .sitefoot li a{display:inline-flex;align-items:center;min-height:44px}
  .leaflet-touch .leaflet-bar a.leaflet-control-zoom-in,
  .leaflet-touch .leaflet-bar a.leaflet-control-zoom-out{
    width:44px;height:44px;line-height:44px;font-size:20px;
  }
}

/* ---------- page furniture ---------------------------------------------- */
main{display:block}
.page{padding:26px 0 70px}
h1{font:400 clamp(30px,4.4vw,44px)/1.08 var(--serif);margin:0 0 8px;letter-spacing:-.005em}
h2{font:650 21px/1.25 var(--sans);margin:34px 0 12px;letter-spacing:-.015em}
h3{font:650 16px/1.3 var(--sans);margin:22px 0 8px}
.sub{color:var(--dim);font-size:16px;margin:0 0 4px;max-width:62ch}
.crumb{font-size:13px;color:var(--dim);margin:0 0 12px}
.crumb a{color:var(--dim);text-decoration:none}
.crumb a:hover{color:var(--brand-bright);text-decoration:underline}

.freshness{display:inline-flex;align-items:center;gap:7px;font-size:13px;color:var(--dim);
  margin-top:10px;background:var(--card);border:1px solid var(--line);
  padding:5px 11px;border-radius:999px;box-shadow:var(--lift)}
.dot{width:7px;height:7px;border-radius:50%;background:var(--ok);flex:none;
  box-shadow:0 0 0 3px color-mix(in srgb, var(--ok) 18%, transparent)}
.dot.stale{background:var(--caution);box-shadow:0 0 0 3px color-mix(in srgb, var(--caution) 18%, transparent)}
.dot.bad{background:var(--avoid);box-shadow:0 0 0 3px color-mix(in srgb, var(--avoid) 18%, transparent)}

/* ---------- controls ----------------------------------------------------- */
button{font:inherit;cursor:pointer}
.btn{
  border:1px solid var(--line-strong);background:var(--card);color:var(--ink);
  border-radius:999px;padding:11px 17px;box-shadow:var(--lift);white-space:nowrap;
  display:inline-flex;align-items:center;gap:8px;font-size:14.5px;font-weight:550;
  transition:border-color .15s, transform .15s, box-shadow .15s;
}
.btn:hover{border-color:var(--brand-bright);box-shadow:var(--lift-2)}
.btn:active{transform:translateY(1px)}
.btn[aria-pressed=true]{background:var(--brand);color:var(--brand-ink);border-color:var(--brand)}

.search{position:sticky;top:var(--headh,62px);z-index:900;background:var(--bg);padding:12px 0;
  box-shadow:0 10px 12px -12px rgba(16,26,28,.28)}
/* Must come after the rule above, not with the rest of the small-screen header:
   same specificity, so whichever is written last wins. On a phone the masthead
   scrolls away and this takes the top itself. */
@media (max-width:599px){.search{top:0}}
/* "Near me" beside the box leaves it 169px wide, and the placeholder needs 247,
   so it read "Search a beach, lake,". Stack them and the box gets the full
   width — the wording is right, so it should be the layout that gives. */
@media (max-width:479px){
  .searchrow{flex-wrap:wrap}
  .field{flex:1 1 100%}
  .searchrow .btn{flex:1 1 100%;justify-content:center}
}
.searchrow{display:flex;gap:10px}
.field{position:relative;flex:1}
.field input{
  width:100%;padding:14px 16px 14px 44px;font-size:16px;
  border:1px solid var(--line-strong);border-radius:999px;
  background:var(--card);color:var(--ink);box-shadow:var(--lift);
}
.field input:focus{border-color:var(--brand-bright)}
.field svg{position:absolute;left:16px;top:50%;transform:translateY(-50%);opacity:.5}

.summary{display:flex;gap:8px;flex-wrap:wrap;margin:4px 0 16px}
.pill{
  display:inline-flex;align-items:center;gap:8px;padding:8px 14px;border-radius:999px;
  font-size:14px;font-weight:650;background:var(--card);box-shadow:var(--lift);
  border:1px solid var(--line);
}
.pill .n{font-variant-numeric:tabular-nums;font-weight:700}
.pill.avoid{color:var(--avoid);background:var(--avoid-bg);border-color:var(--avoid-line)}
.pill.advised{color:var(--advised);background:var(--advised-bg);border-color:var(--advised-line)}
.pill.caution{color:var(--caution);background:var(--caution-bg);border-color:var(--caution-line)}
.pill.ok{color:var(--ok);background:var(--ok-bg);border-color:var(--ok-line)}
.pill.unknown{color:var(--unknown);background:var(--unknown-bg);border-color:var(--unknown-line)}
.pill[aria-pressed=true]{outline:2px solid currentColor;outline-offset:1px}
/* ...but a keyboard ring must win over the "pressed" outline, on this row as
   well as the area row below. Same specificity trap, same fix. */
.pill[aria-pressed=true]:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
/* The area row sits under the status row and is quieter: status is what you came
   for, area is how you narrow it. */
.regions{margin:-6px 0 16px}
.regions .pill{background:var(--card);color:var(--ink-soft);border-color:var(--line);font-weight:550}
.regions .pill:hover{border-color:var(--brand-bright);color:var(--ink)}
.regions .pill[aria-pressed=true]{background:var(--brand);color:var(--brand-ink);
  border-color:var(--brand);outline:none}
/* ...but not while it has keyboard focus. The rule above outranks :focus-visible,
   and the list re-render deliberately returns focus to this button, so a keyboard
   user was left standing on a control with no ring at all. */
.regions .pill[aria-pressed=true]:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
.regions .pill[aria-pressed=true] .n{color:#fff}

.banner{
  border:1px solid var(--caution-line);border-left:4px solid var(--caution);
  background:var(--caution-bg);color:var(--caution);
  border-radius:var(--r-s);padding:12px 15px;font-size:14.5px;margin:0 0 12px;
}

/* ---------- lists and cards ---------------------------------------------- */
.list{display:flex;flex-direction:column;gap:10px}
.beach{
  background:var(--card);border:1px solid var(--line);border-radius:var(--r-m);
  box-shadow:var(--lift);transition:border-color .15s, box-shadow .15s, transform .15s;
}
.beach:hover{border-color:var(--line-strong);box-shadow:var(--lift-2)}
h3.bh{margin:0;font:inherit}
.beach a.head,.beach button.head{
  width:100%;display:flex;gap:14px;align-items:flex-start;text-align:left;
  padding:16px;background:none;border:0;color:inherit;border-radius:var(--r-m);text-decoration:none;
}
.mark{
  flex:none;width:40px;height:40px;border-radius:12px;display:grid;place-items:center;
  font-weight:700;font-size:17px;border:1px solid transparent;
}
.mark.ok{background:var(--ok-bg);color:var(--ok);border-color:var(--ok-line)}
.mark.caution{background:var(--caution-bg);color:var(--caution);border-color:var(--caution-line)}
.mark.avoid{background:var(--avoid-bg);color:var(--avoid);border-color:var(--avoid-line)}
.mark.advised{background:var(--advised-bg);color:var(--advised);border-color:var(--advised-line)}
.mark.unknown{background:var(--unknown-bg);color:var(--unknown);border-color:var(--unknown-line)}
.bmain{flex:1;min-width:0}
.bname{font-weight:650;font-size:17.5px;letter-spacing:-.012em;display:block}
.bwhere{color:var(--dim);font-size:13px;margin-top:2px}
.bverdict{font-size:14.5px;margin-top:6px;font-weight:650}
.bverdict.ok{color:var(--ok)} .bverdict.caution{color:var(--caution)}
.bverdict.avoid{color:var(--avoid)} .bverdict.advised{color:var(--advised)}
.bverdict.unknown{color:var(--unknown)}
.breason{color:var(--ink-soft);font-size:14.5px;margin-top:3px}
.bgap{color:var(--caution);font-size:13px;margin-top:4px}
.bdist{flex:none;color:var(--dim);font-size:13px;font-variant-numeric:tabular-nums;padding-top:4px}

/* ---------- the verdict, on a single place -------------------------------- */
.verdictcard{
  background:var(--card);border:1px solid var(--line);border-radius:var(--r-l);
  box-shadow:var(--lift-2);padding:24px;margin:10px 0 20px;
}
.verdictcard .big{display:flex;gap:16px;align-items:center}
.verdictcard .mark{width:58px;height:58px;font-size:26px;border-radius:16px}
.verdictcard .word{font:400 clamp(24px,3.4vw,32px)/1.05 var(--serif);letter-spacing:-.01em}
.verdictcard .word.ok{color:var(--ok)} .verdictcard .word.caution{color:var(--caution)}
.verdictcard .word.avoid{color:var(--avoid)} .verdictcard .word.advised{color:var(--advised)}
.verdictcard .word.unknown{color:var(--unknown)}
.verdictcard .when{color:var(--dim);font-size:13.5px;margin-top:5px}

.why{list-style:none;margin:20px 0 0;padding:0;display:flex;flex-direction:column;gap:12px}
.why li{display:flex;gap:12px;align-items:flex-start}
.why .ic{flex:none;width:24px;height:24px;border-radius:8px;display:grid;place-items:center;
  font-size:12px;margin-top:1px;font-weight:700}
.why .txt{flex:1}
.why .src{display:block;color:var(--dim);font-size:12.5px;margin-top:2px}
.subhead{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;
  color:var(--dim);margin:22px 0 8px}
.checks{list-style:none;margin:0;padding:0;font-size:14.5px}
.checks li{display:flex;gap:10px;padding:4px 0}
.checks .t{color:var(--ok);font-weight:700;flex:none}
.checks .g{color:var(--caution);font-weight:700;flex:none}

.facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(158px,1fr));gap:10px;margin-top:16px}
.fact{background:var(--bg-sunk);border:1px solid var(--line);border-radius:var(--r-s);padding:11px 13px}
.fact dt{color:var(--dim);font-size:12.5px;margin:0 0 3px}
.fact dd{margin:0;font-weight:650;font-size:15.5px}

details.more{margin-top:16px;font-size:14.5px}
details.more summary{cursor:pointer;color:var(--brand-bright);font-weight:600}
table{width:100%;border-collapse:collapse;margin-top:10px;font-size:13.5px}
th,td{text-align:left;padding:8px 10px;border-bottom:1px solid var(--line)}
th{color:var(--dim);font-weight:600;font-size:12.5px;text-transform:uppercase;letter-spacing:.05em}
td.st{white-space:nowrap;font-weight:650}
td.st.now{color:var(--avoid)} td.st.recent{color:var(--caution)}
td.st.off{color:var(--caution)} td.st.clear{color:var(--ok)}

/* ---------- media -------------------------------------------------------- */
figure.photo{margin:16px 0 6px}
figure.photo img{width:100%;height:auto;max-height:440px;object-fit:cover;
  border-radius:var(--r-m);border:1px solid var(--line);display:block;background:var(--bg-sunk)}
figure.photo figcaption{color:var(--dim);font-size:12.5px;margin-top:8px}

.beachmap{height:360px;border-radius:var(--r-m);border:1px solid var(--line);margin:12px 0 8px;
  background:var(--bg-sunk);display:grid;place-items:center;color:var(--dim);font-size:14px;
  position:relative;z-index:0;isolation:isolate}
.beachmap.failed{display:none}
.maphint{display:none;color:var(--dim);font-size:13px;margin:0 0 8px}
#map{height:clamp(460px, 78vh, 820px);border-radius:var(--r-m);border:1px solid var(--line);
  margin-bottom:10px;background:var(--bg-sunk);position:relative;z-index:0;isolation:isolate}
.bigmap{height:clamp(520px, 82vh, 900px);border-radius:var(--r-m);border:1px solid var(--line);
  margin:14px 0 8px;background:var(--bg-sunk);display:grid;place-items:center;color:var(--dim);
  position:relative;z-index:0;isolation:isolate}
.legend{gap:14px;flex-wrap:wrap;font-size:12.5px;color:var(--dim);margin:0 0 16px;display:none}
.leaflet-container{border-radius:calc(var(--r-m) - 1px);font:inherit}
/* A map is worth most of a desktop screen and rather less of a phone's, where it
   also swallows the scroll: Leaflet takes the touch, so a finger landing inside
   pans the map instead of moving the page. Half the screen leaves room to get
   past it. */
@media (max-width:599px){
  #map{height:clamp(300px, 52vh, 520px)}
  .bigmap{height:clamp(340px, 58vh, 560px)}
  /* The outfall map on every beach and waterfall page. Leaflet claims the touch
     here too, so it gets the same treatment as the other two rather than being
     the one map left filling half a phone with no way past it. */
  .beachmap{height:clamp(220px, 34vh, 320px)}
}

/* ---------- tiles and prose ---------------------------------------------- */
.prose{max-width:66ch}
.prose p{margin:12px 0}
.prose ul{margin:12px 0;padding-left:22px}
.prose li{margin:6px 0}
.tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(224px,1fr));gap:12px;margin-top:14px}
.tile{background:var(--card);border:1px solid var(--line);border-radius:var(--r-m);
  padding:14px 15px;text-decoration:none;color:inherit;box-shadow:var(--lift);display:block;
  transition:border-color .15s, box-shadow .15s}
.tile:hover{border-color:var(--brand-bright);box-shadow:var(--lift-2)}
.tile b{display:block;font-size:15.5px;font-weight:650;letter-spacing:-.01em}
.tile span{color:var(--dim);font-size:13px}
.empty{text-align:center;color:var(--dim);padding:48px 10px}
.more-btn{margin:18px auto 0;display:block}

/* ---------- footer ------------------------------------------------------- */
.sitefoot{background:var(--brand);border-top:1px solid var(--brand);margin-top:56px;
  padding:48px 0 32px;color:#a9c6c9;font-size:14px}
.footgrid{max-width:var(--wrap);margin:0 auto;padding:0 20px;
  display:grid;grid-template-columns:1.5fr 1fr 1fr;gap:34px}
@media (max-width:720px){.footgrid{grid-template-columns:1fr;gap:26px}}
.sitefoot h2{font:650 12px/1.3 var(--sans);text-transform:uppercase;letter-spacing:.08em;
  color:#e8f4f4;margin:0 0 10px}
.sitefoot ul{list-style:none;margin:0;padding:0}
.sitefoot li{margin:6px 0}
.sitefoot a{color:#d6e7e8;text-decoration:none}
.sitefoot a:hover{color:#fff;text-decoration:underline}
.footbrand{font:400 22px/1.2 var(--serif);color:#fff;margin:0 0 8px;
  display:inline-flex;align-items:center;gap:9px}
.footnote{max-width:44ch;margin:0 0 12px}
.footbar{max-width:var(--wrap);margin:28px auto 0;padding:20px 20px 0;
  border-top:1px solid rgba(255,255,255,.16);font-size:12.5px;line-height:1.6}
.footbar strong{color:#fff}
.stat{display:flex;gap:18px;flex-wrap:wrap;margin:10px 0 0;font-size:13px}
.stat b{color:#fff;font-weight:650;font-variant-numeric:tabular-nums}
