/* Tonka Explorer v2 — css/app.css (owner: architect). Implements tonka-build/DESIGN.md verbatim.
   Feature agents: APPEND a clearly marked block at the end (or use your own css/<feature>.css) — do not edit above. */

/* ============ 5.1 tokens + 1.1 chart palette ============ */
:root{
  --navy:#0E3A57; --navy-2:#164C70; --ink:#14232C; --mute:#5A6A74; --line:#D5DEE3; --surf:#F1F6F8; --card:#FFFFFF;
  --ok:#1D6B44; --ok-bg:#E4F3EA; --warn:#8A5A07; --warn-bg:#FBF0D9; --bad:#9A2417; --bad-bg:#FBE3E0;
  --font:-apple-system,"SF Pro Text","Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --tab-h:60px; --safe-b:env(safe-area-inset-bottom,0px); --safe-t:env(safe-area-inset-top,0px);
  --shadow-1:0 1px 3px rgba(20,35,44,.18); --shadow-2:0 4px 16px rgba(20,35,44,.22); --r:12px;
  --land:#DDD4BF; --land-edge:#CFC5AD; --water:#F3F8FB; --shore:#3F5F7A; --island:#DDD4BF;
  --route:#5A2CA0; --me:#1A66BB;
  --pin:22px; --dl-size:11px; --lbl-bay:11px; --lbl-island:11px; --lbl-town:13px; --lbl-channel:10px; --lbl-park:11px;
  --rot:0deg; --unrot:0deg; --rotneg:0deg;
  color-scheme:light only;
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;height:100%}
body{margin:0;background:var(--surf);color:var(--ink);font:16px/1.4 var(--font);overscroll-behavior:none;font-variant-numeric:tabular-nums;height:100%}
h1,h2,h3{font-weight:700;letter-spacing:-.01em;line-height:1.05;margin:0}
p{margin:0}
button{font:inherit;color:inherit;background:none;border:0;padding:0;cursor:pointer;-webkit-tap-highlight-color:transparent;touch-action:manipulation}
a{color:var(--navy-2)}
input,select,textarea{font:16px var(--font);color:var(--ink)}
:focus-visible{outline:2px solid var(--navy);outline-offset:2px;box-shadow:0 0 0 4px #fff}
[hidden]{display:none!important}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* ============ shell ============ */
#app{display:flex;flex-direction:column;height:100vh;height:100dvh;min-height:100%;position:relative}
/* 2.0.13: no header. The only thing above the views is the status-bar strip — safe-area-inset-top tall (0 on a desktop), navy like
   the theme-color so the white iOS status text (black-translucent) stays readable; the map and every view start right under it. */
#app::before{content:'';display:block;flex:none;height:var(--safe-t);background:var(--navy)}
#offline{background:#FBF0D9;color:#5A3D00;font:600 12px/1.3 var(--font);padding:6px 12px;flex:none}
main{flex:1;min-height:0;position:relative}
.view{position:absolute;inset:0;display:none;overflow:auto;-webkit-overflow-scrolling:touch;padding-bottom:calc(var(--tab-h) + var(--safe-b) + 16px)}
.view.on{display:block}
#v-map{overflow:hidden;padding:0}
@media (min-width:760px){.view:not(#v-map) > .wrap{max-width:760px;margin:0 auto}}
.view > .wrap{width:100%}

/* tab bar (5.6) */
nav.tabs{position:fixed;left:0;right:0;bottom:0;height:calc(var(--tab-h) + var(--safe-b));padding-bottom:var(--safe-b);background:var(--card);border-top:1px solid var(--line);display:grid;grid-template-columns:repeat(5,1fr);z-index:1000}
nav.tabs button{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;font:600 11px var(--font);color:var(--mute);min-height:44px}
nav.tabs button svg{width:24px;height:24px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
nav.tabs button[aria-current="page"]{color:var(--navy)}
nav.tabs button[aria-current="page"]::after{content:'';width:20px;height:3px;border-radius:2px;background:var(--navy);margin-top:1px}
nav.tabs button::after{content:'';width:20px;height:3px;margin-top:1px}
/* 2.0.13: six tabs at 390 px = 65 px each; labels never wrap ("Go · Eat", "Weather" fit at 11 px) */
nav.tabs button{position:relative;min-width:0;padding:0 2px}
nav.tabs button .tl{max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.2}
nav.tabs button[aria-expanded="true"]{color:var(--navy)}
nav.tabs button .tn{position:absolute;top:5px;left:calc(50% + 6px);min-width:18px;height:18px;padding:0 5px;border-radius:9px;background:var(--navy);color:#fff;font:700 11px/18px var(--font);text-align:center}   /* Route: the stop count */
/* Go fly-up (Anchor · Eat · Dock) above the tab bar — thumb height, one-handed */
.goscrim{position:fixed;inset:0;z-index:1005;background:rgba(14,58,87,.22)}
.gomenu{position:fixed;left:10px;right:10px;bottom:calc(var(--tab-h) + var(--safe-b) + 10px);z-index:1010;background:var(--card);border:1px solid var(--line);border-radius:16px;box-shadow:var(--shadow-2);padding:6px;display:flex;flex-direction:column;gap:2px}
.gomenu::after{content:'';position:absolute;left:calc(var(--gox, 50%) - 8px);bottom:-8px;width:16px;height:16px;background:var(--card);border-right:1px solid var(--line);border-bottom:1px solid var(--line);transform:rotate(45deg);z-index:-1}   /* points at the Go tab (3rd of 6) */
@media (min-width:560px){.gomenu{left:auto;right:auto;width:420px;margin-left:calc(50% - 210px)}}
.gomenu button{display:flex;align-items:center;gap:14px;width:100%;min-height:60px;padding:6px 12px;border-radius:12px;text-align:left;color:var(--ink)}
.gomenu button:active,.gomenu button:focus-visible{background:var(--surf)}
.gomenu button svg{width:30px;height:30px;flex:none;stroke:var(--navy);fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.gomenu .gn{flex:1;min-width:0;font:700 17px/1.15 var(--font)}
.gomenu .gn small{display:block;font:500 12px/1.3 var(--font);color:var(--mute);margin-top:2px}
.gomenu button[aria-current="page"]{background:var(--surf)}
.gomenu button[aria-current="page"] .gn::after{content:' · open';font:600 11px var(--font);color:var(--ok);letter-spacing:.04em;text-transform:uppercase}
body.routing .mapbar,body.routing .mapfade{display:none!important}   /* route follow (plan.js adds body.following; app.js mirrors it as body.routing): the chart chrome goes */
#v-route .lede{padding-bottom:8px}
#v-weather #wx-body > h2{font-size:28px;padding:18px 16px 4px}

/* ============ map view ============ */
#mapwrap{position:absolute;inset:0;overflow:hidden;background:var(--land)}
#map{position:absolute;inset:0;background:var(--land);min-height:200px;transform-origin:50% 50%}
.leaflet-container{font-family:var(--font);background:var(--land);-webkit-touch-callout:none;user-select:none;-webkit-user-select:none}
.leaflet-container a{color:var(--navy-2)}
.leaflet-container .leaflet-marker-icon.hide{display:none!important}
.leaflet-marker-icon{outline-offset:-2px}
.leaflet-control-zoom{display:none}
@media (hover:hover){.leaflet-control-zoom{display:block}}
.leaflet-bottom.leaflet-right{bottom:calc(var(--tab-h) + var(--safe-b) + 68px)}
.leaflet-control-zoom a{width:36px;height:36px;line-height:36px;color:var(--navy);font-size:20px}

/* chips row (5.3) — 2.0.9 grouped filters: phone / tablet show search + a Layers button whose panel holds the Chart and Places groups;
   from 1024 px the groups sit inline in the bar (it may wrap; chart.js measureBar keeps labels and banners below its real bottom) */
.mapbar{position:absolute;top:8px;left:8px;right:8px;z-index:800;display:flex;flex-wrap:wrap;align-items:flex-start;gap:6px;padding:2px 0;pointer-events:none}   /* 2.0.13: the status-bar strip (#app::before) already clears the notch */
.mapbar > *{pointer-events:auto}
.mapfade{display:none}
.chip{position:relative;flex:none;height:40px;padding:0 12px;border-radius:20px;background:var(--card);border:1px solid var(--line);font:600 13px var(--font);color:var(--ink);display:flex;align-items:center;gap:6px;box-shadow:var(--shadow-1);white-space:nowrap}
.chip::before{content:'';position:absolute;inset:-2px}
.chip .dot{width:10px;height:10px;border-radius:50%;background:var(--k,#B8C2C9);flex:none}
.chip[aria-pressed="false"]{background:#EEF1F3;color:var(--mute);box-shadow:none}
.chip[aria-pressed="false"] .dot{background:#B8C2C9}
.chip.sep{width:1px;padding:0;border:0;background:rgba(20,35,44,.2);height:24px;align-self:center;box-shadow:none;flex:none}
.chip.depth .dot{background:linear-gradient(90deg,#F3F8FB,#4F8BC0);border:1px solid #5E8FB8}
.chip.streets .dot{background:#8C8271}.chip.shops .dot{background:#B4508A}.chip.bridges .dot{background:#1C2B36}
.chip[aria-pressed="false"].depth .dot,.chip[aria-pressed="false"].streets .dot,.chip[aria-pressed="false"].shops .dot,.chip[aria-pressed="false"].bridges .dot{background:#B8C2C9;border-color:#B8C2C9}
.chip.search{width:44px;height:44px;padding:0;justify-content:center}
.chip.search svg{width:20px;height:20px;stroke:var(--navy);fill:none;stroke-width:2.2;stroke-linecap:round}
.chip.layersbtn{height:44px;padding:0 14px;gap:8px;font-size:14px;color:var(--navy)}
.chip.layersbtn svg{width:20px;height:20px;stroke:var(--navy);fill:none;stroke-width:1.9;stroke-linejoin:round;flex:none}
.chip.layersbtn .lcount{font:700 11px/1 var(--font);color:#fff;background:var(--navy-2);border-radius:9px;padding:3px 6px}
.mapbar.open .chip.layersbtn{background:var(--navy);color:#fff;border-color:var(--navy)}
.mapbar.open .chip.layersbtn svg{stroke:#fff}
/* 2.0.13: the panel's own bottom edge stays above the tab bar (it used to run under it on a phone, so the last row of chips could never
   scroll into reach: 100vh on iPhone Safari is the tall viewport). dvh where supported; the panel scrolls with momentum. */
.lgroups{display:none;position:absolute;top:52px;left:0;width:min(440px,100%);max-height:calc(100vh - var(--tab-h) - var(--safe-b) - var(--safe-t) - 140px);max-height:calc(100dvh - var(--tab-h) - var(--safe-b) - var(--safe-t) - 84px);overflow:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;background:var(--card);border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow-2);padding:4px 12px 12px}
.mapbar.open .lgroups{display:block}
.lgh{display:block;font:700 12px var(--font);letter-spacing:.06em;text-transform:uppercase;color:var(--mute);padding:10px 2px 6px}
.lgrid{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.lgroups .chip{height:auto;min-height:44px;padding:4px 10px 4px 12px;white-space:normal;line-height:1.15;text-align:left;box-shadow:none}
.lgroups .chip .lt{flex:1;min-width:0}
.lgroups .chip::after{content:'On';font:700 11px var(--font);color:var(--ok);flex:none}
.lgroups .chip[aria-pressed="false"]::after{content:'Off';color:var(--mute)}
.lgroups .ldone{width:100%;margin-top:12px}
@media (min-width:420px){.lgrid{grid-template-columns:repeat(3,1fr)}}
@media (min-width:1024px){
  .chip.layersbtn,.lgroups .ldone{display:none}
  .lgroups,.mapbar.open .lgroups{display:flex;flex-wrap:wrap;gap:6px 8px;position:static;flex:1;min-width:0;width:auto;max-height:none;overflow:visible;background:none;border:0;border-radius:0;box-shadow:none;padding:0;pointer-events:none}
  .lgroup{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:2px 2px 2px 12px;border-radius:24px;background:rgba(255,255,255,.72);pointer-events:auto}
  .lgh{padding:0 2px 0 0;font-size:11px}
  .lgrid{display:flex;flex-wrap:wrap;gap:6px}
  .lgroups .chip{height:40px;min-height:40px;padding:0 12px;white-space:nowrap;box-shadow:var(--shadow-1)}
  .lgroups .chip::after{content:none}
}
body.tracking .mapbar,body.tracking .mapfade{display:none}

/* map search (5.4) */
#msearch{position:absolute;top:8px;left:8px;right:8px;z-index:802;display:none}
#msearch.on{display:block}
body.searching .mapbar,body.searching .mapfade{display:none}
#msearch .bar{display:flex;gap:8px;align-items:center}
#msearch .field{flex:1;display:flex;align-items:center;height:44px;background:rgba(255,255,255,.98);border:1px solid var(--line);border-radius:12px;padding:0 10px;box-shadow:var(--shadow-1)}
#msearch .field svg{width:20px;height:20px;stroke:var(--mute);fill:none;stroke-width:2.2;stroke-linecap:round;flex:none;margin-right:6px}
#msearch input{flex:1;min-width:0;height:42px;border:0;background:none;font:16px var(--font);color:var(--ink);outline:none}
#msearch .cancel{height:44px;padding:0 12px;border-radius:12px;background:var(--card);border:1px solid var(--line);font:600 15px var(--font);color:var(--navy);box-shadow:var(--shadow-1)}
#mres{margin-top:6px;background:var(--card);border:1px solid var(--line);border-radius:12px;overflow:hidden;box-shadow:var(--shadow-2)}
#mres:empty{display:none}
#mres button{display:flex;align-items:center;gap:10px;width:100%;min-height:48px;padding:6px 12px;border-top:1px solid var(--line);font:600 15px var(--font);text-align:left;color:var(--ink)}
#mres button:first-child{border-top:0}
#mres i{width:28px;height:28px;border-radius:14px;color:#fff;background:var(--k,#5A6A74);font:700 12px var(--font);display:flex;align-items:center;justify-content:center;font-style:normal;flex:none}
#mres small{display:block;color:var(--mute);font-weight:500;font-size:12px}
#mres .none{padding:14px 12px;font-size:14px;color:var(--mute);text-align:center}

/* 2.0.13: the depth legend chip / card and the sources button are gone from the map (they ate the bottom-left corner). There is NO
   depth colour key any more (2.0.15, owner: the contours are already labelled); the sources line is Info › About (#attr). */
.attrline{padding:8px 16px 14px;font-size:12px;line-height:1.5;color:var(--mute);background:var(--card)}
.attrline b{color:var(--ink);font-weight:600}

/* locate (5.5) */
.locate{position:absolute;right:12px;bottom:calc(var(--tab-h) + var(--safe-b) + 12px);z-index:800;width:48px;height:48px;border-radius:24px;background:var(--card);border:1px solid var(--line);box-shadow:var(--shadow-1);display:flex;align-items:center;justify-content:center;color:var(--navy)}
.locate svg{width:24px;height:24px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round}
.locate .slash{display:none}
.locate.live{background:var(--navy);border-color:var(--navy);color:#fff}
.locate.acquiring svg{animation:pulse 1.2s ease-in-out infinite}
.locate.error .slash{display:block}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.35}}
.trackbar{position:absolute;top:8px;left:8px;right:8px;z-index:810}
.nearstrip{position:absolute;top:76px;left:8px;right:8px;z-index:805;display:flex;gap:6px;overflow-x:auto;scrollbar-width:none}
.nearstrip::-webkit-scrollbar{display:none}
.fxzoom{position:absolute;right:12px;bottom:calc(var(--tab-h) + var(--safe-b) + 72px);z-index:810;display:none;flex-direction:column;gap:8px}
.fxzoom button{width:44px;height:44px;border-radius:12px;background:var(--card);border:1px solid var(--line);font:700 22px var(--font);color:var(--ink);box-shadow:var(--shadow-1)}
.northarrow{position:absolute;left:12px;top:84px;z-index:810;width:44px;height:44px;border-radius:22px;background:var(--card);border:1px solid var(--line);display:none;align-items:center;justify-content:center;box-shadow:var(--shadow-1)}
.northarrow svg{width:26px;height:26px;transform:rotate(var(--rotneg))}

/* toasts (5.12) */
#toast{position:fixed;left:12px;right:12px;bottom:calc(var(--tab-h) + var(--safe-b) + 12px);z-index:1200;display:flex;flex-direction:column;gap:8px;pointer-events:none}
#sheet.on ~ #toast{bottom:auto;top:calc(var(--safe-t) + 64px)}   /* never over the open sheet's action buttons */
.toast{pointer-events:auto;min-height:48px;background:var(--ink);color:#fff;border-radius:12px;padding:4px 8px 4px 14px;display:flex;align-items:center;gap:10px;font:500 14px/1.3 var(--font);box-shadow:var(--shadow-2)}
.toast span{flex:1}
.toast button{min-height:44px;min-width:44px;padding:0 12px;border-radius:8px;background:rgba(255,255,255,.14);color:#fff;font:700 13px var(--font)}   /* Undo / Reload / ×: 44 px targets like every underway control (QA markers; the toast grows to 52 px) */
.toast button.x{width:44px;padding:0;font-size:20px;font-weight:400}
.toast.err{background:#3B1F1C}
#errlog,#selftest{position:relative;z-index:0}
#selftest{margin:0;padding:8px 12px;font:12px/1.4 Menlo,Consolas,monospace;white-space:pre-wrap;background:var(--card);color:#14232C;border-top:1px solid var(--line)}

/* ============ chart classes ============ */
/* 3.2 pins */
.pinw{position:relative;width:32px;height:32px;padding:6px;box-sizing:content-box;display:flex;align-items:flex-end;justify-content:center;transform-origin:22px 38px}
.pin{width:var(--pin,26px);height:var(--pin,26px);border-radius:50% 50% 50% 0;transform:rotate(-45deg);transform-origin:50% 50%;border:2px solid #fff;box-shadow:0 1px 3px rgba(0,0,0,.4);display:flex;align-items:center;justify-content:center;background:var(--k)}
.pin span{transform:rotate(45deg);color:#fff;font:700 var(--pin-glyph,12px)/1 var(--font)}
.pin.approx{border-style:dashed}
.pinw.sel .pin{box-shadow:0 0 0 3px #fff,0 0 0 5px #0E3A57,0 2px 6px rgba(0,0,0,.4);transform:rotate(-45deg) scale(1.2)}
.leaflet-marker-icon.pinicon{cursor:pointer}
/* 3.6 bridge flags */
.brg{position:absolute;left:0;top:0;transform:translate(-50%,-100%);transform-origin:0 0;display:flex;flex-direction:column;align-items:center;cursor:pointer}
.brg span{background:#1C2B36;color:#fff;font:700 11px/1 var(--font);padding:4px 6px 4px 20px;border-radius:4px;white-space:nowrap;position:relative;transform:translateX(var(--fx,0px))}   /* --fx: leans at most (half the flag − 10 px) off a pin or another flag (chart.js): the label always stays over its own stem and dot */
.brg span::before{content:'';position:absolute;left:6px;top:5px;width:9px;height:7px;border:2px solid #fff;border-top-left-radius:6px;border-top-right-radius:6px;border-bottom:0}
.brg i{width:2px;height:calc(14px - var(--fy,0px));background:#1C2B36}   /* --fy:-28px / -56px (chart.js): the flag rises on a longer stem when the leans hit a pin or another flag */
.brg::after{content:'';width:6px;height:6px;border-radius:3px;background:#1C2B36;margin-top:-1px}
.brg.low span b{background:#B3261E;color:#fff;padding:1px 4px;border-radius:3px;margin:-1px -2px}
.brg.nonav span{background:#5C6C78}.brg.nonav i,.brg.nonav::after{background:#5C6C78}
.brg.nonav span::after{content:' · no passage'}   /* outside the <b>, so the red pill (measured under 10 ft) never swallows the suffix */
.brg.unk span b{opacity:.85}
.brg.sel span{outline:3px solid #fff;box-shadow:0 0 0 5px #0E3A57}
.brg.onroute span{outline:2px solid #5A2CA0}
.leaflet-bridges-pane.dots .brg span,.leaflet-bridges-pane.dots .brg i{display:none}
.leaflet-bridges-pane.dots .brg::after{width:6px;height:6px}
.leaflet-bridges-pane .leaflet-marker-icon{width:0!important;height:0!important;overflow:visible}
.leaflet-bridges-pane .leaflet-marker-icon.brgicon::before{content:'';position:absolute;left:-22px;top:-22px;width:44px;height:44px;border-radius:22px}
/* 3.7 stop badges */
.stopb{position:absolute;left:0;top:0;transform:translate(-50%,-50%);transform-origin:0 0;width:22px;height:22px;border-radius:11px;background:#0E3A57;color:#fff;border:2px solid #fff;font:700 12px/1 var(--font);display:flex;align-items:center;justify-content:center;box-shadow:0 1px 3px rgba(0,0,0,.35)}
.stopb.onpin{transform:translate(calc(-50% + var(--pin,26px)*.55),calc(-50% - var(--pin,26px)*1.05))}   /* on its place pin: the head's upper-right shoulder (chart.js badgeOffset), glyph and number both read */
/* 3.5 me (2.0.12: dot + thin black heading line, the chartplotter convention; no cone, no arrowhead in either mode) */
.mew{position:absolute;left:0;top:0;width:0;height:0;overflow:visible;transform-origin:0 0;pointer-events:none}
/* the boat: 22 px dark dot, 3 px white ring, faint blue halo — darker and rounder than any buoy glyph (their fills are red / green / white / blue disc) */
.me{position:absolute;left:0;top:0;transform:translate(-50%,-50%);width:22px;height:22px;border-radius:50%;background:#14232C;border:3px solid #fff;box-sizing:border-box;box-shadow:0 0 0 2px rgba(26,102,187,.6),0 0 0 7px rgba(26,102,187,.16),0 1px 4px rgba(0,0,0,.4)}
/* heading line: 1.5 px black on a faint white casing, from the boat along --hdg in map coordinates (chart.js updateMeLine sets --hdg and --mehl,
   the length in px = 60 s of travel at the current speed, 60–1000 m); the map itself rotates in course-up, so there it points straight up */
.merot{position:absolute;left:0;top:0;width:0;height:0;transform-origin:0 0;transform:rotate(var(--hdg,0deg))}
.meboat{position:absolute;left:-13px;top:-33.5px;width:26px;height:67px;overflow:visible;filter:drop-shadow(0 0 1.2px #fff) drop-shadow(0 0 1.2px #fff) drop-shadow(0 2px 3px rgba(0,0,0,.45))}
.mehl{position:absolute;left:-.75px;bottom:32px;width:1.5px;height:max(0px,calc(var(--mehl,0px) - 32px));background:#000;box-shadow:0 0 0 .75px rgba(255,255,255,.8);border-radius:1px}
.mew.nohdg .merot{display:none}.mew:not(.nohdg) .me{display:none}
.mew.nohdg .mehl{display:none}
/* 1.5 depth labels */
.dl{position:absolute;left:0;top:0;transform:translate(-50%,-50%);transform-origin:0 0;font:600 var(--dl-size,12px)/1.3 var(--font);color:#1E4A6E;background:#FFFFFF;border:1px solid var(--dl-border,#5E8FB8);border-radius:3px;padding:0 4px;white-space:nowrap;pointer-events:none;font-variant-numeric:tabular-nums}
/* 4 map labels */
.lbl{position:absolute;left:0;top:0;transform:translate(calc(-50% + var(--ox,0px)),calc(-50% + var(--oy,0px)));transform-origin:0 0;white-space:nowrap;pointer-events:none;font-family:var(--font);line-height:1.1;text-align:center;transition:opacity .15s linear,transform .15s ease-out;animation:lblin .15s linear}   /* --ox/--oy: the anchor chosen by chart.js placeLabels */
/* 2.0.14: a map label is hidden by opacity, never display:none, so it fades in and out (150 ms) and a changed anchor slides; a new icon fades in by the keyframes */
@keyframes lblin{from{opacity:0}to{opacity:1}}
.leaflet-container .leaflet-maplabels-pane .leaflet-marker-icon.lblicon.hide{display:block!important}
.lblicon.hide .lbl{opacity:0;visibility:hidden;transition:opacity .15s linear,visibility 0s linear .15s}
/* 2.0.14 chart convention: WATER names (bay, channel, reef) italic serif and letter-spaced, LAND names (town, island, point, park) upright sans. chart.js labelFont() measures with the same fonts */
.lbl.bay,.lbl.channel,.lbl.reef{font-family:Georgia,'Iowan Old Style','Times New Roman',serif;font-style:italic}
.lbl.bay{font-size:var(--lbl-bay);text-transform:uppercase;letter-spacing:.09em;font-weight:600;color:#4F6B82;text-shadow:0 1px 0 #fff,0 -1px 0 #fff,1px 0 0 #fff,-1px 0 0 #fff,0 0 6px #fff}
.lbl.bay.wrap{max-width:7em;white-space:normal}
.lbl.point{font-size:var(--lbl-park);font-weight:600;letter-spacing:.02em;color:#5A5243;text-shadow:0 1px 0 #DDD4BF,0 -1px 0 #DDD4BF,1px 0 0 #DDD4BF,-1px 0 0 #DDD4BF,0 0 5px #DDD4BF}
.lbl.reef{font-size:var(--lbl-channel);font-weight:600;letter-spacing:.04em;color:#3A5A78;text-shadow:0 1px 0 #fff,0 -1px 0 #fff,1px 0 0 #fff,-1px 0 0 #fff,0 0 5px #fff}
.lbl.island{font-size:var(--lbl-island);font-weight:500;letter-spacing:.02em;color:#5A5243;text-shadow:0 1px 0 #DDD4BF,0 -1px 0 #DDD4BF,1px 0 0 #DDD4BF,-1px 0 0 #DDD4BF,0 0 6px #DDD4BF}
.lbl.town{font-size:var(--lbl-town);font-weight:700;letter-spacing:.01em;color:#14232C;text-shadow:0 1px 0 #fff,0 -1px 0 #fff,1px 0 0 #fff,-1px 0 0 #fff,0 0 6px #fff}
.lbl.channel{font-size:var(--lbl-channel);font-style:italic;font-weight:600;letter-spacing:.04em;color:#3A5A78;text-shadow:0 1px 0 #fff,0 -1px 0 #fff,1px 0 0 #fff,-1px 0 0 #fff,0 0 5px #fff}
.lbl.park{font-size:var(--lbl-park);font-weight:600;color:#33592A;text-shadow:0 1px 0 #DDD4BF,0 -1px 0 #DDD4BF,1px 0 0 #DDD4BF,-1px 0 0 #DDD4BF,0 0 5px #DDD4BF}
.lbl.park::before{content:'';display:inline-block;width:10px;height:10px;margin-right:3px;vertical-align:-1px;background:currentColor;-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2l6 9h-3l4 6h-6v5h-2v-5H5l4-6H6z'/%3E%3C/svg%3E") center/contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2l6 9h-3l4 6h-6v5h-2v-5H5l4-6H6z'/%3E%3C/svg%3E") center/contain no-repeat}
/* 2.0.18 roads: the streets pane is hidden while the view's buckets are still being built, so the layer appears once and whole
   instead of dribbling segments in; it is revealed in the same task when the build fits one 8 ms chunk, so there is no delay then.
   (The global prefers-reduced-motion rule at the top of this file drops the fade.) */
.leaflet-streets-pane{transition:opacity .16s linear}
/* 2.3 road names */
.rn{position:absolute;left:0;top:0;transform:rotate(var(--th,0deg)) translate(-50%,-50%);transform-origin:0 0;font:600 11px var(--font);color:#4A4438;letter-spacing:.01em;white-space:nowrap;pointer-events:none;text-shadow:0 0 2px #DDD4BF,0 0 2px #DDD4BF,0 0 4px #DDD4BF}
body.z17 .rn{font-size:12px}
/* 2.5 shops */
.shop{position:absolute;left:0;top:0;transform:translate(-50%,-50%);transform-origin:0 0;width:20px;height:20px;border-radius:50%;background:var(--card);border:1.5px solid var(--k);color:var(--k);display:flex;align-items:center;justify-content:center;box-shadow:0 1px 2px rgba(20,35,44,.35);cursor:pointer}
.shop svg{width:13px;height:13px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.shop b{font:800 9px/1 var(--font);letter-spacing:-.02em}
.shop.k-parking{border-radius:5px}   /* parking = a rounded square (the road-sign shape no pin uses), never read as the Park pin */
.shop.z17{width:24px;height:24px}.shop.z17 svg{width:16px;height:16px}.shop.z17 b{font-size:11px}
.shop .nm{position:absolute;top:100%;left:50%;transform:translateX(-50%);margin-top:2px;font:600 10px/1.1 var(--font);color:#3B3428;white-space:nowrap;text-shadow:0 0 2px #DDD4BF,0 0 2px #DDD4BF,0 0 3px #DDD4BF;display:none}
.shop.z17.named .nm{display:block}
.leaflet-shops-pane .leaflet-marker-icon{width:0!important;height:0!important;overflow:visible}
.leaflet-shops-pane .leaflet-marker-icon::before{content:'';position:absolute;left:-22px;top:-22px;width:44px;height:44px;border-radius:22px}
.leaflet-maplabels-pane,.leaflet-depthlabels-pane{pointer-events:none}
.leaflet-maplabels-pane .leaflet-marker-icon,.leaflet-depthlabels-pane .leaflet-marker-icon{width:0!important;height:0!important;overflow:visible;pointer-events:none}

/* ============ lists (5.7) ============ */
.view h2{font-size:28px;padding:18px 16px 4px}
.view h2 small{display:block;font:500 12px var(--font);color:var(--mute);letter-spacing:.02em;margin-top:4px}
.lede{color:var(--mute);padding:0 16px 12px;font-size:14px;max-width:40em}
.lede a{color:var(--navy-2)}
.filters{display:flex;gap:6px;padding:0 16px 12px;overflow-x:auto;scrollbar-width:none}
.filters::-webkit-scrollbar{display:none}
.filters .chip{background:var(--card);box-shadow:none}
.filters .chip[aria-pressed="true"]{background:var(--navy);color:#fff;border-color:var(--navy)}
.search{margin:0 16px 12px;display:flex;align-items:center;background:var(--card);border:1px solid var(--line);border-radius:10px;padding:0 12px;height:44px}
.search svg{width:18px;height:18px;stroke:var(--mute);fill:none;stroke-width:2.2;stroke-linecap:round;flex:none;margin-right:8px}
.search input{flex:1;min-width:0;border:0;background:none;font:16px var(--font);outline:none;color:var(--ink);height:42px}
.list{background:var(--card)}
.row{display:grid;grid-template-columns:44px 1fr auto;gap:12px;align-items:center;padding:12px 16px;border-top:1px solid var(--line);background:var(--card);width:100%;text-align:left;min-height:64px;color:var(--ink)}
.list .row:last-child{border-bottom:1px solid var(--line)}
.row .ic{width:44px;height:44px;border-radius:10px;background:var(--k);color:#fff;font:700 16px var(--font);display:flex;align-items:center;justify-content:center;flex:none}
.row .mid{min-width:0}
.row .nm{font:600 18px/1.15 var(--font);display:block}
.row .sub{color:var(--mute);font-size:13px;margin-top:2px;display:block}
.row .rt{text-align:right;font:600 12px var(--font);color:var(--mute);white-space:nowrap;max-width:132px;overflow:hidden;text-overflow:ellipsis}
.row .rt b{display:block;font:700 18px var(--font);color:var(--ink)}
.row .rt.onroute b{color:var(--ok)}
.tags{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}
.tag{font:600 11px/1.2 var(--font);padding:3px 8px;border-radius:4px;background:var(--surf);border:1px solid var(--line);color:var(--ink);white-space:nowrap}
.tag.ok{background:var(--ok-bg);border-color:#B9DEC8;color:var(--ok)}
.tag.warn{background:var(--warn-bg);border-color:#EBD39E;color:var(--warn)}
.tag.no{background:var(--bad-bg);border-color:#F0B8B1;color:var(--bad)}
.empty{padding:28px 16px;text-align:center;color:var(--mute);font-size:14px}
.empty .btn{margin:14px auto 0;max-width:220px}
.approxmark{color:var(--mute);font-weight:600;margin-right:2px}

/* info sections */
.info-sec{border-top:8px solid var(--surf);background:var(--surf)}
.info-sec:first-child{border-top:0}
.info-sec h2{font-size:24px;padding:20px 16px 4px}
.tbl{width:100%;border-collapse:collapse;font-size:14px;background:var(--card)}
.tbl th,.tbl td{padding:9px 16px;border-top:1px solid var(--line);text-align:left;vertical-align:top}
.tbl th{font:600 12px var(--font);color:var(--mute)}
.tbl td.c{font:700 17px var(--font);text-align:right;white-space:nowrap}
.tbl td.c .lowtxt{color:var(--bad)}
.tbl tr.rowbtn{cursor:pointer}
.tbl tr.rowbtn:active{background:var(--surf)}
.tbl td .ch{color:var(--mute);font-size:12px;display:block}
.lowtxt{color:var(--bad);font-weight:700}
.rule{padding:12px 16px;border-top:1px solid var(--line);background:var(--card);display:grid;grid-template-columns:72px 1fr;gap:12px;align-items:start}
.rule b{font:700 22px/1.05 var(--font);color:var(--navy)}
.rule b small{display:block;font:600 10px/1.2 var(--font);color:var(--mute);letter-spacing:.02em;margin-top:2px}
.rule p{font-size:14px}
.note{margin:12px 16px;padding:12px 14px;border-left:4px solid #EBD39E;background:#FBF6EA;font-size:14px;border-radius:0 8px 8px 0;color:var(--ink)}
.linkrow{display:flex;flex-wrap:wrap;gap:8px;padding:8px 16px 16px}
.linkrow a,.linkrow button{display:inline-flex;align-items:center;min-height:44px;padding:0 14px;border-radius:10px;background:var(--card);border:1px solid var(--line);font:600 14px var(--font);color:var(--navy-2);text-decoration:none}
.linkrow a.pri{background:var(--navy);color:#fff;border-color:var(--navy)}
.bars{padding:0 16px 16px;background:var(--card)}
.bars .b{display:grid;grid-template-columns:120px 1fr 64px;align-items:center;gap:10px;padding:7px 0;border-top:1px solid var(--line)}
.bars .b .n{font:600 14px var(--font)}
.bars .b .n small{display:block;font:500 11px var(--font);color:var(--mute)}
.bars .bar{height:14px;background:linear-gradient(90deg,#DCEBF5,#4F8BC0);border-radius:2px}
.bars .bar.approx{background:repeating-linear-gradient(90deg,#A6CBE6 0 6px,#fff 6px 8px);border:1px solid #9DBACB}
.bars .f{font:700 17px var(--font);text-align:right}
.bars .f small{font:500 10px var(--font);color:var(--mute)}
.stat{display:grid;grid-template-columns:repeat(3,1fr);margin:0 16px 12px;border:1px solid var(--line);border-radius:12px;background:var(--card);overflow:hidden}
.stat div{padding:12px 8px;text-align:center;border-left:1px solid var(--line);font-size:12px;color:var(--mute)}
.stat div:first-child{border-left:0}
.stat b{display:block;font:700 22px var(--font);color:var(--ink)}
.sources{padding:0 16px 16px;font-size:13px;color:var(--mute);line-height:1.5;background:var(--card)}
.sources ul{margin:8px 0;padding-left:18px}
.sources li{margin:4px 0}
.sources li a{display:inline-block;padding:8px 0}.sources p a{padding:6px 0}   /* finger-sized source links (were 18 px tall) */
.sources .foot{font-size:12px;margin-top:10px}
.status-ok{color:var(--ok);font-weight:600}
.status-mute{color:var(--mute)}
.skel{height:14px;border-radius:4px;background:linear-gradient(90deg,#EEF1F3,#F7F9FA,#EEF1F3);background-size:200% 100%;margin:8px 16px}
@media (prefers-reduced-motion:no-preference){.skel{animation:skel 1.4s linear infinite}}
@keyframes skel{0%{background-position:200% 0}100%{background-position:-200% 0}}
.placeholder{padding:8px 16px 16px;font-size:14px;color:var(--mute)}

/* ============ sheet (5.8) ============ */
#scrim{position:fixed;inset:0;background:rgba(14,58,87,.25);z-index:1050;display:none}
#scrim.on{display:block}
#sheet{position:fixed;left:0;right:0;bottom:0;z-index:1100;background:var(--card);border-radius:16px 16px 0 0;box-shadow:0 -6px 24px rgba(20,35,44,.25);max-height:min(70vh,70%);transform:translateY(110%);transition:transform .25s ease,visibility 0s linear .25s;display:flex;flex-direction:column;padding-bottom:var(--safe-b);visibility:hidden}
#sheet{max-height:min(70vh,70%,100dvh - 250px)}   /* ≥ ~190 px of chart stays visible above the sheet (the body scrolls) */
#sheet.on{transform:none;visibility:visible;transition:transform .25s ease,visibility 0s}
#sheet .grip{width:40px;height:4px;border-radius:2px;background:var(--line);margin:8px auto 0;flex:none;pointer-events:none}
/* 2.0.13: × gets its own stacking context (z-index) so it hit-tests above the async-scrolling .body it overlaps on iOS — a tap used to
   land on the scroller and do nothing; ::before pads the 44 px button to 52 px */
#sheet .x{position:absolute;right:10px;top:10px;z-index:5;width:44px;height:44px;border-radius:22px;background:var(--surf);font-size:22px;color:var(--ink);display:flex;align-items:center;justify-content:center;touch-action:manipulation}
#sheet .x::before{content:'';position:absolute;inset:-4px;border-radius:26px}
#sheet .body{overflow:auto;padding:8px 16px 16px;-webkit-overflow-scrolling:touch}
#sheet h3{font-size:24px;margin:6px 44px 0 0}
#sheet .bay{color:var(--mute);font-size:14px;margin-top:2px}
#sheet .bay b{color:var(--ink)}
#sheet p.notes{margin-top:10px;font-size:15px;line-height:1.45}
#sheet .facts{display:grid;grid-template-columns:1fr 1fr;gap:8px 16px;margin-top:12px}
#sheet .facts div{border-top:1px solid var(--line);padding-top:6px;font-size:13px;color:var(--mute)}
#sheet .facts div b{display:block;font:700 20px var(--font);color:var(--ink)}
#sheet .facts div b.sm{font-size:15px;line-height:1.3}
#sheet .facts div.pos b{cursor:pointer;font-size:15px}
#sheet .facts div b .lowtxt{color:var(--bad)}
#sheet .acts{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:14px}
#sheet .acts + .acts{margin-top:8px}
#sheet .src{font-size:12px;color:var(--mute);margin-top:12px;line-height:1.45}
#sheet .src a{color:var(--navy-2)}
.btn{min-height:44px;border-radius:10px;font:600 15px var(--font);display:flex;align-items:center;justify-content:center;gap:6px;text-decoration:none;padding:0 8px;text-align:center;cursor:pointer}
.btn.pri{background:var(--navy);color:#fff}
.btn.sec{background:var(--surf);border:1px solid var(--line);color:var(--ink)}
.btn.bad{background:var(--bad-bg);color:var(--bad);border:1px solid #F0B8B1}
.btn.wide{width:100%}
.btn[disabled]{opacity:.5;cursor:default}

/* ============ plan view (5.11) ============ */
.speed{display:flex;align-items:center;gap:10px;padding:4px 16px 12px;font:600 14px var(--font);color:var(--mute)}
.speed input[type=range]{flex:1;accent-color:var(--navy);height:44px;margin:0}
.speed b{font:700 16px var(--font);color:var(--ink);min-width:58px;text-align:right}
.legs{padding:0 16px;background:var(--card)}
.leg{display:grid;grid-template-columns:28px 1fr 44px 44px;gap:8px;align-items:center;padding:8px 0;border-top:1px solid var(--line);min-height:56px;background:var(--card)}
.leg.dragging{opacity:.5}
.leg .k{width:28px;height:28px;border-radius:14px;background:var(--navy);color:#fff;font:700 14px var(--font);display:flex;align-items:center;justify-content:center}
.leg .nm{font:600 17px/1.15 var(--font)}
.leg .d{font-size:12px;color:var(--mute);margin-top:2px}
.leg .d .dash{display:inline-block;width:22px;height:0;border-top:3px dashed var(--route);vertical-align:middle;margin-right:4px}
.leg .h,.leg .rm{width:44px;height:44px;border-radius:22px;color:var(--mute);font-size:22px;display:flex;align-items:center;justify-content:center}
.leg .h{cursor:grab;touch-action:none}
.leg .h svg{width:22px;height:22px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round}
.total{margin:12px 16px;padding:14px 16px;background:var(--navy);color:#fff;border-radius:12px;display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px}
.total div{font-size:12px;color:#BFD5E4}.total b{display:block;font:700 24px var(--font);color:#fff}
.plan-acts{padding:4px 16px 16px;display:grid;grid-template-columns:1fr 1fr;gap:8px}
.plan-acts .btn.pri{grid-column:1 / -1}
.plan-note{padding:0 16px 8px;font-size:13px;color:var(--mute)}
.sharebox{margin:0 16px 12px;display:flex;gap:8px}
.sharebox input{flex:1;min-width:0;height:44px;border:1px solid var(--line);border-radius:10px;padding:0 10px;font:16px var(--font)}   /* 16 px: iOS Safari must not zoom when it is focused */

/* ============ focused (course-up) mode — 5.10 ============ */
body.focus #map{will-change:transform}
body.focus .pinw{transform:rotate(var(--unrot))}
body.focus .brg{transform:rotate(var(--unrot)) translate(-50%,-100%)}
body.focus .dl,body.focus .shop,body.focus .stopb{transform:rotate(var(--unrot)) translate(-50%,-50%)}   /* 2.0.21: .me left this list — a round dot needs no un-rotation, and rotating it about its own centre moved it off the GPS point */
body.focus .stopb.onpin{transform:rotate(var(--unrot)) translate(calc(-50% + var(--pin,26px)*.55),calc(-50% - var(--pin,26px)*1.05))}
body.focus .lbl{transform:rotate(var(--unrot)) translate(calc(-50% + var(--ox,0px)),calc(-50% + var(--oy,0px)));transition:opacity .15s linear}   /* no transform transition here: --unrot follows the heading */
/* the boat wrapper is NOT un-rotated in course-up (2.0.12): its heading line is drawn along --hdg in map coordinates and must turn with the map, so it points up the screen; the dot is round */
body.routing #msearch{display:none!important}   /* route mode (body.routing, track.js showBar): the map search hides with the layer chips; north arrow, own zoom buttons, trackbar and nearest strip stay */
body.focus .rn,body.focus .shop .nm{display:none!important}
body.focus .mapbar,body.focus .mapfade,body.focus .legend,body.focus .legend-card,body.focus .attr,body.focus .leaflet-control-zoom,body.focus #msearch{display:none!important}
body.focus .fxzoom{display:flex}
body.focus .northarrow{display:flex}
body.focus .leaflet-container{cursor:default}

/* ============ lake markers + zones, route follow (integration 2.0.5 — DESIGN §3.8, §5.10, §5.11) ============ */
.leaflet-markers-pane .leaflet-marker-icon{width:0!important;height:0!important;overflow:visible}
.leaflet-markers-pane .leaflet-marker-icon::before{content:'';position:absolute;left:-22px;top:-22px;width:44px;height:44px;border-radius:22px}   /* 44 px target */
.leaflet-markers-pane.mk-dot .leaflet-marker-icon{pointer-events:none}   /* a 5 px ghost at whole-lake zoom is not a tap target */
.leaflet-markers-pane.mk-dot .leaflet-marker-icon::before{display:none}
.mk{position:absolute;left:0;top:0;width:var(--mk,12px);height:var(--mk,12px);transform:translate(-50%,-50%);transform-origin:0 0;opacity:var(--mk-op,.7);cursor:pointer}
.mk svg.mkg{position:absolute;left:0;top:0;width:100%;height:100%;overflow:visible}
.leaflet-markers-pane.mk-dot .mk{width:5px;height:5px;border-radius:50%;background:var(--mkc,#5A6A74)}
.leaflet-markers-pane.mk-dot .mk svg,.leaflet-markers-pane.mk-dot .mk .mkr,.leaflet-markers-pane.mk-dot .mk .mkl{display:none}
.leaflet-markers-pane.mk-route .mk svg.mkg,.leaflet-markers-pane.mk-halo .mk svg.mkg{filter:drop-shadow(0 0 1px #fff) drop-shadow(0 0 1px #fff) drop-shadow(0 0 1.5px #fff)}   /* white halo: route / tracking mode, and from z15 in normal mode (green / red fills on the deep bands, QA markers) */
.mk .mkl{display:none;position:absolute;left:100%;top:50%;transform:translate(3px,-50%);font:700 12px/1.15 var(--font);color:#14232C;background:rgba(255,255,255,.95);border:1px solid rgba(20,35,44,.3);border-radius:4px;padding:1px 5px;white-space:nowrap;pointer-events:none}
.leaflet-markers-pane.mk-route.mk-lbl .mk.lblk .mkl{display:block}   /* hazard / point labels from z14 in route mode */
.mk.lleft .mkl{left:auto;right:100%;transform:translate(-3px,-50%)}   /* the label on the side clear of pins, flags and the boat (placeMarkers, QA markers) */
.mk .mkr{display:none;position:absolute;left:50%;top:50%;width:calc(var(--mk,16px) + 16px);height:calc(var(--mk,16px) + 16px);transform:translate(-50%,-50%);border-radius:50%;border:2.5px solid #5A2CA0;box-shadow:0 0 0 2px rgba(255,255,255,.9),inset 0 0 0 1.5px rgba(255,255,255,.9);box-sizing:border-box;pointer-events:none}
.leaflet-markers-pane.mk-route .mk.near .mkr{display:block}   /* within 150 m of the route line */
@media (prefers-reduced-motion:no-preference){.leaflet-markers-pane.mk-route .mk.near .mkr{animation:mkpulse 1.8s ease-out infinite}}   /* a static ring under reduced motion */
.leaflet-markers-pane .mk.fresh .mkr{display:block}   /* + Buoy: the new buoy's ring shows while its Undo toast does (it lands under the boat dot, QA markers) */
@media (prefers-reduced-motion:no-preference){.leaflet-markers-pane .mk.fresh .mkr{animation:mkpulse 1.2s ease-out infinite}}
@keyframes mkpulse{0%{transform:translate(-50%,-50%) scale(.9);opacity:1}75%{transform:translate(-50%,-50%) scale(1.3);opacity:.2}100%{transform:translate(-50%,-50%) scale(1.3);opacity:0}}
.mk.sel::after{content:'';position:absolute;left:50%;top:50%;width:calc(var(--mk,16px) + 10px);height:calc(var(--mk,16px) + 10px);transform:translate(-50%,-50%);border-radius:50%;box-shadow:0 0 0 3px #fff,0 0 0 5px #0E3A57;pointer-events:none}
body.focus .mk{transform:rotate(var(--unrot)) translate(-50%,-50%)}   /* course-up: glyphs and labels stay upright */
.stopb.next{box-shadow:0 0 0 3px #fff,0 0 0 6px #5A2CA0,0 2px 6px rgba(0,0,0,.35)}   /* route follow: the next stop */
/* ---- 2.0.9: bay sheet (search by bay), parking details, pair-editor ghosts ---- */
#sheet .bayh{font:700 12px var(--font);color:var(--mute);letter-spacing:.06em;text-transform:uppercase;margin:14px 0 0}
#sheet .tag.baymk{display:inline-flex;align-items:center;gap:4px}
#sheet .tag.baymk svg{width:14px;height:14px;flex:none}
#sheet .baylist{margin-top:8px;border-top:1px solid var(--line)}
#sheet .bayrow{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:6px 2px;border-bottom:1px solid var(--line);background:none;font:600 15px/1.2 var(--font);color:var(--ink);text-align:left}
#sheet .bayrow i{width:24px;height:24px;border-radius:12px;background:var(--k,#5A6A74);color:#fff;font:700 11px var(--font);font-style:normal;display:flex;align-items:center;justify-content:center;flex:none}
#sheet .bayrow small{display:block;font:500 12px var(--font);color:var(--mute);margin-top:2px}
#sheet .baymore{font-size:13px;color:var(--mute);padding:8px 2px}
#sheet .facts.parking{margin-top:8px}
#sheet .acts .btn.span2{grid-column:span 2}
.leaflet-markers-pane .mk.pehide{opacity:.28;pointer-events:none}
.chip.markers .dot{background:#fff;border:2.5px solid #C45F00}
.chip[aria-pressed="false"].markers .dot{background:#B8C2C9;border-color:#B8C2C9}
.legend-card .lrow svg.mkg{width:22px;height:22px;flex:none;margin:0 3px}
.legend-card .lrow .zsw{width:22px;height:14px;flex:none;border:2px dashed #9A5B00;border-radius:2px;margin:0 3px}
.legend-card .mknote{margin-top:6px}
#mres i.mkres{background:#EAF2F7;border:1px solid var(--line)}
#mres i.mkres svg{width:22px;height:22px}
#sheet h3.mkh{display:flex;align-items:center;gap:8px}
#sheet h3.mkh .mkt{flex:none;width:32px;height:32px}
#sheet h3.mkh .mkt svg{width:32px;height:32px;display:block}
#sheet .mkmean{margin-top:10px;padding:10px 12px;background:var(--surf);border:1px solid var(--line);border-radius:10px;font-size:15px;line-height:1.45}
#sheet .mkmean b{color:var(--ink)}
#sheet .src.mkhon{margin-top:6px}
.row .ic.mkic{background:#EAF2F7;border:1px solid var(--line)}
.row .ic.mkic svg{width:30px;height:30px}
body.following .northarrow{top:128px}   /* clear the next-stop line */
.plan-acts{grid-template-columns:repeat(3,1fr)}
.plan-acts .btn.wide{grid-column:1 / -1}
.leg.done{opacity:.55}
.leg.next .k{box-shadow:0 0 0 3px #fff,0 0 0 5px #5A2CA0}

/* ============ 2.0.10 — GPS list column, Info tab, route planner (appended block; owner: lists/plan/sync agent) ============ */
/* lists: the right-hand column is distance + bearing from the boat, or nothing at all */
.row .rt.gps b{color:var(--navy)}
.row .rt.gps{letter-spacing:.05em}   /* the compass point is already upper case — never transform the "0.4 mi" above it */
.row:not(:has(.rt)){grid-template-columns:44px 1fr}   /* no column at all: the name and tags take the width (progressive — harmless where :has is unsupported) */

/* Info › Right now */
.infonow{background:var(--surf);padding:0 0 4px}
.nowh{font-size:24px;padding:20px 16px 8px}
.nowgrid{display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:0 16px 12px}
@media (max-width:359px){.nowgrid{grid-template-columns:1fr}}
.nowt{display:flex;flex-direction:column;align-items:flex-start;gap:1px;min-height:76px;padding:10px 12px;background:var(--card);border:1px solid var(--line);border-radius:12px;text-align:left;width:100%;color:var(--ink)}
.nowt .k{font:700 11px/1.2 var(--font);letter-spacing:.06em;text-transform:uppercase;color:var(--mute)}
.nowt b{font:700 20px/1.15 var(--font);color:var(--ink);word-break:break-word}
.nowt .s{font:500 12px/1.3 var(--font);color:var(--mute)}
.nowt.mute b{color:var(--mute)}
.nowt.ok b{color:var(--ok)}
.nowt.warn{background:var(--warn-bg);border-color:#EBD39E}
.nowt.warn b{color:var(--warn)}
.nowgrid > :last-child:nth-child(odd):not(.up){grid-column:1 / -1;min-height:0;flex-direction:row;flex-wrap:wrap;align-items:baseline;gap:2px 8px}   /* an odd tile count ends on one full-width row instead of a gap */
.nowt.up{grid-column:1 / -1;background:var(--ok-bg);border-color:#B9DEC8;cursor:default}
.nowt.up b{color:var(--ok)}
.nowt.up .btn{margin-top:8px;width:100%}

/* Info: long reference sections collapse */
.info-sec.isec{padding-bottom:4px}
.info-sec.isec > summary{list-style:none;display:flex;align-items:center;gap:10px;padding:14px 16px;min-height:56px;cursor:pointer}
.info-sec.isec > summary::-webkit-details-marker{display:none}
.info-sec.isec > summary h2{flex:1;min-width:0;padding:0;font-size:20px}
.info-sec.isec > summary .isub{display:none}
.info-sec.isec > summary::after{content:'';width:12px;height:12px;flex:none;border-right:2.5px solid var(--mute);border-bottom:2.5px solid var(--mute);transform:rotate(45deg) translate(-2px,-2px);transition:transform .15s ease}
.info-sec.isec[open] > summary::after{transform:rotate(225deg) translate(-2px,-2px)}
.info-sec.isec[open] > summary{border-bottom:1px solid var(--line)}
.info-sec.isec > summary:focus-visible{outline:2px solid var(--navy);outline-offset:-2px}
@media (min-width:420px){.info-sec.isec > summary{flex-wrap:wrap}.info-sec.isec > summary .isub{display:block;flex-basis:100%;font:500 12px/1.3 var(--font);color:var(--mute);margin-top:-2px}}

/* route planner */
#v-plan .lede{padding-bottom:8px}
.legs{padding:0 16px 4px}
.stop{display:grid;grid-template-columns:28px 1fr 44px 44px;gap:8px;align-items:center;padding:8px 0;min-height:64px;background:var(--card)}
.stop + .stop{border-top:1px solid var(--line)}
.stop .k{width:28px;height:28px;border-radius:14px;background:var(--navy);color:#fff;font:700 14px var(--font);display:flex;align-items:center;justify-content:center;flex:none}
.stop .si{min-width:0}
.stop .nm{font:600 17px/1.2 var(--font);overflow-wrap:anywhere}
.stop .sb{font-size:12px;color:var(--mute);margin-top:2px}
.stop .sh{width:44px;display:flex;flex-direction:column;align-items:stretch;touch-action:none}
.stop .mv{position:relative;height:30px;display:flex;align-items:center;justify-content:center;color:var(--navy);border-radius:8px;background:var(--surf)}
.stop .mv + .mv{margin-top:4px}
.stop .mv::before{content:'';position:absolute;inset:-7px 0}
.stop .mv svg{width:20px;height:20px;stroke:currentColor;fill:none;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}
.stop .mv[disabled]{opacity:.3;cursor:default}
.stop .rm{width:44px;height:44px;border-radius:22px;color:var(--mute);font-size:24px;display:flex;align-items:center;justify-content:center}
.stop.dragging{opacity:.5}
.stop.dropat{box-shadow:inset 0 3px 0 var(--navy)}
.stop.done{opacity:.55}
.stop.next .k{box-shadow:0 0 0 3px #fff,0 0 0 5px #5A2CA0}
.legline{display:grid;grid-template-columns:28px 1fr;gap:8px;padding:0 0 6px;background:var(--card)}
.legline .lstem{width:28px;display:block;position:relative}
.legline .lstem::before{content:'';position:absolute;left:13px;top:-2px;bottom:-2px;width:2px;background:var(--line)}
.legline .lx{min-width:0;display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;padding-top:2px}
.legline b{font:700 13px var(--font);color:var(--navy)}
.legline .lrun{font:500 12px var(--font);color:var(--mute)}
.legline .lts{flex-basis:100%;display:flex;flex-wrap:wrap;gap:4px;margin-top:3px}
.legline .lt{font:600 11px/1.2 var(--font);padding:3px 7px;border-radius:4px;background:var(--surf);border:1px solid var(--line);color:var(--ink)}
.legline .lt.warn{background:var(--bad-bg);border-color:#F0B8B1;color:var(--bad)}
.legline .lt.quiet{background:var(--warn-bg);border-color:#EBD39E;color:var(--warn)}
.legline .lt.straight,.legline .lt.walk{background:var(--card);color:var(--mute);border-style:dashed}
.planwarn{margin:-4px 16px 12px;display:flex;flex-wrap:wrap;gap:6px}
.planwarn .pw{font:600 12px/1.2 var(--font);padding:6px 10px;border-radius:14px;background:var(--card);border:1px solid var(--line);color:var(--ink)}
.planwarn .pw.quiet{background:var(--warn-bg);border-color:#EBD39E;color:var(--warn)}
.planadd{padding:0 16px 8px;background:var(--card)}
.planadd.on{padding-bottom:12px}
.planadd .addst{width:100%;border-style:dashed}
.planadd .search{margin:8px 0}
.planadd .ahint{font-size:12px;color:var(--mute);padding:0 2px 6px}
.planadd .ares{max-height:46vh;overflow:auto;-webkit-overflow-scrolling:touch;border:1px solid var(--line);border-radius:10px}
.planadd .arow{display:grid;grid-template-columns:32px 1fr auto;gap:10px;align-items:center;width:100%;min-height:52px;padding:8px 10px;text-align:left;border-top:1px solid var(--line);color:var(--ink);background:var(--card)}
.planadd .arow:first-child{border-top:0}
.planadd .arow .ic{width:32px;height:32px;border-radius:8px;background:var(--k);color:#fff;font:700 13px var(--font);display:flex;align-items:center;justify-content:center;flex:none}
.planadd .arow .am{min-width:0}
.planadd .arow .nm{display:block;font:600 15px/1.2 var(--font);overflow-wrap:anywhere}
.planadd .arow .sb{display:block;font-size:12px;color:var(--mute);margin-top:1px}
.planadd .arow .aa{font:700 13px var(--font);color:var(--navy);white-space:nowrap}
.planadd .arow.in{background:var(--ok-bg)}
.planadd .arow.in .aa .on{color:var(--ok);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.05em}
.planadd .anone{padding:16px 12px;text-align:center;color:var(--mute);font-size:14px}
.planadd .btn.wide{margin-top:10px}
.planempty{padding:24px 16px}
.planempty > b{display:block;font-size:18px;color:var(--ink);margin-bottom:6px}
.planempty p b{color:var(--ink)}
.planempty p{max-width:34em;margin:0 auto}
.planempty .eacts{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin:16px auto 0;max-width:340px}
.planempty .sug{margin-top:14px;font-size:13px}
.planempty .link,.sync-sub .link{color:var(--navy-2);text-decoration:underline;font:inherit;min-height:44px;padding:0 2px}

/* ================= 2.0.11 — satellite view (API.md §16) =================
   body.sat is set by chart.js while the Esri imagery layer is on. The opaque water fill and the depth bands are taken off the map in
   JS; everything here is contrast: the land is no longer tan, so every halo that was tan becomes white, and the two that sat on tan
   text colours darken. Off, not one of these rules applies and the chart is byte-for-byte the old one. */
body.sat #mapwrap,body.sat #map,body.sat .leaflet-container{background:#2C3138}   /* behind the tiles while they load, never tan */
body.sat .leaflet-satellite-pane{will-change:transform}
body.sat .lbl.island{color:#14232C;text-shadow:0 1px 0 #fff,0 -1px 0 #fff,1px 0 0 #fff,-1px 0 0 #fff,0 0 7px #fff,0 0 4px #fff}
body.sat .lbl.park,body.sat .lbl.point{color:#14232C;text-shadow:0 1px 0 #fff,0 -1px 0 #fff,1px 0 0 #fff,-1px 0 0 #fff,0 0 7px #fff,0 0 4px #fff}
body.sat .lbl.bay,body.sat .lbl.town,body.sat .lbl.channel,body.sat .lbl.reef{text-shadow:0 1px 0 #fff,0 -1px 0 #fff,1px 0 0 #fff,-1px 0 0 #fff,0 0 7px #fff,0 0 4px #fff}
body.sat .rn{color:#14232C;text-shadow:0 0 2px #fff,0 0 3px #fff,0 0 5px #fff,0 0 5px #fff}
body.sat .shop .nm{color:#14232C;text-shadow:0 0 2px #fff,0 0 3px #fff,0 0 4px #fff}
body.sat .attr{color:#14232C;text-shadow:0 0 3px #fff,0 0 3px #fff,0 0 5px #fff}
.chip.satellite .dot{background:linear-gradient(135deg,#4E7031 0 50%,#2B5C85 50% 100%)}   /* aerial: green over water */
.chip.toilets .dot{background:#2B5C85}.chip.parking .dot{background:#2B5C85}

/* ================= 2.0.19 — Info › Sources & credits (ATTR agent) =================
   The owner asked for every source credit off the other tabs and collected in one place. #info-sources is that place: a nested,
   collapsed-by-default <details> inside Info › About & sources, holding one <section class="srcgrp"> per topic plus #attrline
   (the licence-required attributions). It is NOT .info-sec, so it needs its own summary chrome — deliberately lighter than a
   top-level section so the nesting reads as "inside About", not as a second tab-level heading. Colours are tokens only, so
   css/dark.css needs no counterpart. */
#info-sources{margin:4px 0 0;border-top:1px solid var(--line);background:var(--card)}
#info-sources > summary{list-style:none;display:flex;align-items:center;gap:10px;padding:12px 16px;min-height:52px;cursor:pointer;flex-wrap:wrap}
#info-sources > summary::-webkit-details-marker{display:none}
#info-sources > summary h2{flex:1;min-width:0;margin:0;padding:0;font-size:17px;font-weight:700;color:var(--ink)}
#info-sources > summary .isub{flex-basis:100%;font:500 12px/1.35 var(--font);color:var(--mute);margin-top:-2px}
#info-sources > summary::after{content:'';width:10px;height:10px;flex:none;border-right:2.5px solid var(--mute);border-bottom:2.5px solid var(--mute);transform:rotate(45deg) translate(-2px,-2px);transition:transform .15s ease}
#info-sources[open] > summary::after{transform:rotate(225deg) translate(-2px,-2px)}
#info-sources[open] > summary{border-bottom:1px solid var(--line)}
#info-sources > summary:focus-visible{outline:2px solid var(--navy);outline-offset:-2px}
.srcgroups .srclede{margin:12px 0 4px;color:var(--mute)}
.srcgrp{padding:14px 0 2px;border-top:1px solid var(--line)}
.srcgrp:first-of-type{border-top:0;padding-top:8px}
.srcgrp h3{margin:0 0 6px;font:700 15px/1.3 var(--font);color:var(--ink)}
.srcgrp p{margin:0 0 8px}
.srclinks{margin:2px 0 8px;padding-left:0;list-style:none}
.srclinks li{margin:0;padding:0}
.srclinks li a{display:block;padding:13px 0 13px 14px;position:relative;color:var(--navy-2);font-weight:600;text-decoration:none}   /* ≥ 44 px tall: these are finger targets, not footnotes */
.srclinks li a::before{content:'';position:absolute;left:2px;top:50%;width:5px;height:5px;margin-top:-3px;border-right:2px solid var(--mute);border-bottom:2px solid var(--mute);transform:rotate(-45deg)}
.srclinks li a:active{color:var(--navy)}
.srccities{margin:4px 0 8px;padding-left:0;list-style:none}
.srccities li{margin:0;padding:8px 0;border-top:1px solid var(--line)}
.srccities li:first-child{border-top:0}
.srccities li b{display:block;color:var(--ink);font-weight:700;margin-bottom:2px}
.srccities li a{display:inline-block;padding:13px 0;line-height:1.4;color:var(--navy-2)}   /* ≥ 44 px tall */
.srcfoot{color:var(--mute)}
#info-sources .attrline{padding:10px 0 12px;border-top:1px solid var(--line);background:transparent}
