/* GENERATED by `npm run fonts` — edit fonts.mjs, not this file.
 *
 * Fraunces (c) Undercase Type and Inter (c) Rasmus Andersson, both under the SIL Open Font
 * License 1.1. The full text is in OFL-Fraunces.txt and OFL-Inter.txt beside these files, which
 * is the condition the licence attaches to redistributing them.
 */

/* Fraunces — vietnamese */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/fraunces-vietnamese.woff2') format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* Fraunces — latin-ext */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/fraunces-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Fraunces — latin */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/fraunces-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Inter — cyrillic-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/inter-cyrillic-ext.woff2') format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* Inter — cyrillic */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/inter-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* Inter — greek-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/inter-greek-ext.woff2') format('woff2');
  unicode-range: U+1F00-1FFF;
}
/* Inter — greek */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/inter-greek.woff2') format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* Inter — vietnamese */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/inter-vietnamese.woff2') format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* Inter — latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Inter — latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root{
  --ocean:#0B2A3A; --ocean-deep:#071E2B; --ocean-soft:#134058;
  --seaglass:#8FC3B2; --seaglass-deep:#5E9C88; --seaglass-dark:#3E7A66; --seaglass-pale:#DCEAE4;
  --sand:#E8DFCE; --shell:#F6F1E7; --shell-dim:#EFE8DA;
  --coral:#DE7A5A;
  --ink:#182024; --ink-soft:#5A666B; --ink-faint:#8A9497;
  --line:#E5DCC9;
}
*{margin:0;padding:0;box-sizing:border-box;-webkit-font-smoothing:antialiased}
html{scroll-behavior:smooth}
/* A short page — /licence/, /404, a country with three pools — used to leave the footer floating
   partway up with shell colour beneath it, because the footer simply follows the content and the
   content ran out. The column stretches to the viewport and main takes the slack, so the footer sits
   at the bottom of a short page and is pushed below the fold on a long one. dvh after vh: the older
   unit measures the viewport with mobile browser chrome retracted, which overshoots by the height of
   the address bar. */
body{font-family:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--shell);color:var(--ink);line-height:1.5;
  display:flex;flex-direction:column;min-height:100vh;min-height:100dvh}
main{flex:1 0 auto}
.serif{font-family:'Fraunces',Georgia,serif;font-weight:400}
a{color:inherit;text-decoration:none}
img{max-width:100%;display:block}
.wrap{max-width:1180px;margin:0 auto;padding:0 32px}
/* Deliberately loud and deliberately not styled to match. A preview page that looked like a real one
   would be a page you could screenshot, send on, or mistake for reviewed work. It sits above the nav
   on EVERY page of a preview build, not only the unreviewed country's own pages — see PREVIEW. */
.previewbar{background:#B4472F;color:#fff;font-size:12px;font-weight:700;letter-spacing:.02em;
  padding:9px 32px;text-align:center;line-height:1.4}
.skip{position:absolute;left:-9999px;top:0;background:var(--ocean);color:var(--shell);padding:10px 16px;z-index:100}
.skip:focus{left:8px;top:8px}
:focus-visible{outline:2px solid var(--seaglass-dark);outline-offset:2px}

/* nav */
.nav{background:var(--ocean-deep);border-bottom:1px solid rgba(246,241,231,.07)}
.nav .wrap{display:flex;align-items:center;justify-content:space-between;height:66px;gap:24px}

/* THE BAR OVER THE FILM, ON THE HOME PAGE AND NOWHERE ELSE.
   A solid bar above a moving shore reads as two pages stacked: the film starts 67 points down, at a
   hard horizontal line, and the first thing the reader meets is the edge rather than the water. So
   on the one page that has footage the bar becomes glass and the footage runs up behind it.

   IT IS DONE WITH A NEGATIVE MARGIN, NOT WITH position:absolute, and that is the whole of the
   trick. An absolute bar at top:0 leaves normal flow, which means it lands on top of .previewbar in
   every preview build — a red band saying this country is unreviewed, with the navigation printed
   over it. Left in flow and given a z-index, the bar stacks correctly against everything above it,
   and it is the HERO that moves: up by exactly the bar's height, so the video's box begins behind
   it, with the same distance restored inside .hero .wrap so no copy moves a pixel.

   --navh IS THEREFORE LOAD-BEARING IN TWO PLACES AT ONCE and has to match the bar's real height,
   border included. 67 is the 66 the wrap is pinned to plus the rule below it, and both are integers
   the stylesheet sets outright, so that one is exact.

   THE TWO DIRECTIONS OF ERROR ARE NOT EQUALLY BAD, which is why the narrow value is not exact.
   Overshoot and the film starts a pixel or two above the viewport: invisible, because it is
   object-fit:cover and the top row was never the subject. Undershoot and the hero begins BELOW the
   top of the bar, leaving a band with nothing behind it — and body's background is --shell, so that
   band is cream, full width, across the top of the home page. Bright, and unmistakable.

   So under 560, where the bar wraps to two rows on purpose and its height is content-derived rather
   than declared — 13 + brand + 12 + links + 13, measured at 105 across all five trees — the value
   carries three points of deliberate slack. A font that loads a little taller, or a fifth locale
   with a longer word in it, then costs three pixels off the top of a video instead of a cream
   stripe. (Measured while checking this: French needs 295.9 points for its second row against the
   296 a 360-point screen leaves. It fits, at every locale, by a tenth of a point. That margin is
   the nav's own and predates this, but it is the thing that would put the bar on a third row.)

   THERE IS NO SCRIM AND NO BLUR. Both were here, as a masked ::before — a gradient easing to
   nothing, with the backdrop-filter masked alongside it so the blur did not end in a hard line of
   its own. It was rejected on sight, and looking at it again the objection is right: a bar that is
   half-there is a bar you notice being half-there, and the footage under this one is dark wet rock
   that the type reads against unaided. So the bar is simply not painted, and the links are plain
   white rather than the 60%-opacity cream they were, which is what a transparent bar costs and all
   it costs. */
:root{--navh:67px}
@media (max-width:560px){:root{--navh:108px}}
.nav.navover{position:relative;z-index:20;background:none;border-bottom-color:transparent}
.navover + main .hero{margin-top:calc(-1 * var(--navh))}
.navover + main .hero .wrap{padding-top:calc(60px + var(--navh))}
.brand{display:flex;align-items:center;gap:10px;color:var(--shell)}
.brand span{font-size:19px}
.navlinks{display:flex;align-items:center;gap:26px;flex-wrap:wrap}
/* Plain white, on every page rather than only over the film. The bar is one component and the cream
   at 60% was dim wherever it appeared; over transparent footage it was worse than dim. Hover goes to
   seaglass because white cannot get any whiter, and seaglass is already what the current page's link
   is coloured, so the two states rhyme. */
.navlinks a{font-size:13px;font-weight:500;color:#fff}
.navlinks a:hover{color:var(--seaglass)}
.navlinks a.on{color:var(--seaglass);font-weight:600;border-bottom:2px solid var(--seaglass);padding-bottom:3px}
/* Scoped under .navlinks on purpose, and it is not decoration. The button lives inside that div, so
   the .navlinks a colour above matches it too — and at (0,1,1) that out-specifies a bare .navcta at
   (0,1,0), whatever the source order. The dark ink below was being thrown away and the button
   rendered 60%-opacity cream on pale seaglass: 1.42:1, against the 8.48:1 this sets. It read as a
   disabled control in every language and had done since the nav was written. */
.navlinks a.navcta{font-size:13px;font-weight:600;color:#0A2029;background:var(--seaglass);padding:9px 18px;border-radius:18px}
.navlinks a.navcta:hover{color:#0A2029;background:#a5d0c1}
/* TWO ROWS, BECAUSE ONE ROW IS NOT BIG ENOUGH — in any language.
   .navlinks already carried flex-wrap:wrap, so the links DID wrap; they wrapped inside a parent
   pinned to height:66px, so the second row had nowhere to go. On a 390-point screen the result was
   83px of content in a 66px bar: "Tide Pool Directory" clipped off the top edge and the Download
   pill hanging down into the hero. Every current iPhone, every language, and invisible to anyone
   testing on a desktop at a narrow window — it is clean from 480px up.

   Measured at 13px, the one row needs brand 117 + gap 24 + link + gap 26 + button:

       en 385    pt 408    es 419    fr 449

   against the 326 a 390-point screen leaves after the 32px gutters. French does not fit until a
   513-point viewport. Tightening the gaps and the type buys about fifty points, so no amount of
   shrinking gets there, and the alternatives all delete something: drop the wordmark and the brand
   is a bare glyph; drop the link and the directory — the entire site — leaves the navigation on the
   devices most likely to be used one-handed.

   So it wraps on purpose. Brand on its own row, then the directory link and the download button
   spread across the second. 560 rather than 513 because the breakpoint is shared by all four
   locales and has to clear the worst of them with room; the nav is static, not sticky, so the extra
   44px is paid once at the top of the page and never again. */
@media (max-width:560px){
  .nav .wrap{height:auto;flex-direction:column;align-items:stretch;gap:0;padding-top:13px;padding-bottom:13px}
  .navlinks{justify-content:space-between;gap:14px;margin-top:12px}
}

/* hero */
.hero{background:linear-gradient(168deg,#0E3042 0%,#0A2434 52%,#071E2B 100%);color:var(--shell);position:relative;overflow:hidden}
/* THE HERO IS A COLUMN UNTIL IT CAN AFFORD NOT TO BE, AND EVERY QUERY THAT CHANGES THAT IS A
   min-width. That second half is not a style preference, it is the one bug this file keeps finding.

   A viewport is not an integer. On a 1.25x display an "1179-point" window is 1179.2 points wide, and
   it satisfies neither (max-width:1179px) nor (min-width:1180px) — so a rule pair written as those
   two complements leaves a sliver of widths with NO layout at all. This was written that way once,
   measured at exactly 1179 on a 1.25x screen, and produced a hero that was stacked either side of a
   band where it was suddenly side by side with a 353-point copy column. Overlapping min-widths
   cannot do that: something always matches, and the widest declaration wins.

   So the stacked arrangement is the DEFAULT — no query, therefore no gap — and 1180 opts into the
   side-by-side one. 1180 is where .wrap stops growing, which is where the hero stops being short of
   room; see the note above the fan's ladder.

   The copy keeps the slack there, and the demo fills it. This was briefly capped at 620 and centred
   as a pair, to close a 351-point hole between the end of the headline and a single phone pushed
   against the right edge. It closed the hole and bought a 150-point indent from the brand above it,
   which was the wrong trade — the answer was never to move the copy, it was that one phone is not
   enough object to hold that side of a 1116-point hero. Three are. See .phonefan. */
.hero .wrap{display:flex;flex-direction:column;align-items:stretch;gap:38px;
  padding-top:60px;padding-bottom:66px;position:relative}
.hero-copy{flex:1;min-width:0}
.eyebrow{font-size:10.5px;letter-spacing:.24em;font-weight:700;color:var(--seaglass)}
.hero h1{margin-top:18px;font-size:clamp(34px,5vw,56px);line-height:1.06;color:var(--shell)}
.hero h1 em{font-style:normal;color:var(--seaglass)}
.hero p.lede{margin-top:20px;font-size:15.5px;line-height:1.65;color:rgba(246,241,231,.74);max-width:470px}
.rings{position:absolute;inset:0;pointer-events:none;overflow:hidden;transition:opacity .8s ease}
.rings i{position:absolute;border-radius:50%;border:1px solid rgba(143,195,178,.09)}
.rings i:nth-child(1){width:560px;height:560px;right:40px;top:-180px}
.rings i:nth-child(2){width:560px;height:560px;right:-40px;top:-100px;border-color:rgba(143,195,178,.06)}
.rings i:nth-child(3){width:420px;height:420px;right:60px;top:40px;border:0;background:radial-gradient(circle,rgba(143,195,178,.14),transparent 65%)}

/* THE HERO FILM, AND THE GRADIENT IT DOES NOT REPLACE.
   .hero keeps its own gradient background, unconditionally. That is not a fallback bolted on
   afterwards — it is the hero as designed, and it stays the thing that paints when the film has not
   arrived, will not arrive, or was never asked for. There is no state in which this section renders
   as a black box waiting for eleven megabytes.

   Which is why the element carries no src in the markup and no autoplay attribute. Both belong to
   hero.js, which decides whether this reader should be spending the bytes at all — see the
   conditions there. opacity:0 here, and .on from script once the first frame has actually decoded,
   so the crossfade starts from the gradient rather than from a flash of nothing. */
.herovid{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity 1.1s ease;pointer-events:none;-webkit-user-select:none;user-select:none}
.herovid.on{opacity:1}
/* The veil: horizontal first, then a seat at top and bottom. Both were tuned against a frame of the
   actual footage rather than guessed, and the first guess was wrong in the direction these always
   go — .86 falling to .56 turned a tide pool into a grey wash. If the shore is not legible there is
   no reason to have paid for the file.

   THE VEIL TURNS WITH THE LAYOUT, so it is declared twice and the default is the stacked one. A
   column puts the copy across the full width at the TOP with the demo below it, so the weight goes
   vertical: heaviest behind the headline and the lede, easing through the badges, and lighter over
   the demo, which brings its own dark body and needs no help. The side-by-side version at 1180 is
   weighted LEFT instead, because there the copy is on the left and the phones are on the right.

   The number either has to hold is the lede, cream at 74% — the smallest, faintest text over the
   widest range of frames. The seaglass headline is the other one to watch: #8FC3B2 over sunlit water
   is where this first fell down.

   In the 1180 version the 180deg layer does not darken the middle at all. It seats the two edges —
   the navigation above, which is near-black and would otherwise sit on a bright frame with nothing
   under it, and the cut to the cream section below. */
.heroveil{position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(6,22,32,.88) 0%,rgba(6,22,32,.8) 34%,rgba(7,26,37,.6) 58%,rgba(7,30,43,.5) 100%)}
@media (min-width:1180px){
  .heroveil{background:linear-gradient(180deg,rgba(7,26,37,.34) 0%,rgba(7,26,37,0) 26%,rgba(7,26,37,0) 68%,rgba(7,26,37,.4) 100%),
             linear-gradient(102deg,rgba(6,22,32,.8) 0%,rgba(7,26,37,.6) 46%,rgba(7,30,43,.46) 100%)}
}
/* The rings are drawn at 6–14% alpha against a flat gradient. Over moving water they stop being a
   suggestion of ripples and become dirt on the lens, so they leave when the film arrives. */
.hero.filmed .rings{opacity:0}

/* the phone in the hero */
/* The phone is a picture of the app, not text anyone should be able to take out of it — it is already
   aria-hidden for the same reason. Dragging a selection across the hero used to highlight "LOW 5:02
   PM" and the species names, which are illustrations of a screen rather than content of this page.
   -webkit- prefix included: Safari still needs it for user-select. */
/* IT GROWS BY TRANSFORM, NEVER BY WIDTH, and the difference is the whole reason it can grow at all.
   The chrome inside the screen is hand-tuned pixels for a 250x512 phone — .ptitle top 44, .pframe
   inset 96/26/130, .pfoot bottom 38, .pcard bottom 44, .sdots bottom 20 — while the scan markers are
   positioned in percentages. Change width and height and those two disagree: the labels keep tracking
   the photograph, the frame around them does not, and they drift a few points apart at a time. A
   transform scales the rendered result, so every one of those numbers scales with it and nothing can
   drift. This was written off as un-resizable once; it is resizable, just not that way.

   One variable drives both the reserved box and the transform, because a transform does not reflow —
   the wrap has to be told the size or a bigger phone silently overlaps the copy beside it. Setting
   them from the same --ps means they cannot fall out of step. */
.phonewrap{--ps:1;flex:none;align-self:center;display:flex;justify-content:center;align-items:center;
  width:calc(250px * var(--ps));height:calc(512px * var(--ps));
  -webkit-user-select:none;user-select:none}
/* THE FAN. Three handsets, the middle one in front, the outer two smaller and set back — the shore,
   the scan, and what the app keeps afterwards, all readable at once instead of one at a time.

   ONLY WHERE THREE FIT, which is 768 and up — but not in the same arrangement all the way.

   The fan is about 500 points wide and the sentences beside it want roughly another 550 before the
   store badges wrap, so a hero with both side by side needs about 1100. Below that the arithmetic is
   merciless: at 1024, copy plus fan leaves the copy 366 against a 50px headline; at 768 it leaves
   150, which is not a column. Shrinking the fan to fit does not rescue it either, because 686 points
   shared with a 436-point copy puts the middle handset at 134 points wide, and a 134-point phone
   showing a scan is a picture of a phone rather than a picture of the app.

   So the fan does not compete with the copy for the same line. FROM 768 TO 1179 THE HERO STACKS: the
   sentences take the full column and the fan sits under them with the whole width to itself — 627
   points at an iPad Mini, 712 on a 1024 iPad Pro, against the 501 it gets on a 1440 desktop. A
   tablet reader sees MORE of the app than a desktop one, which is the right way round for the device
   that could actually install it.

   1180 is where side by side becomes affordable, and it is not a round number picked for looking
   like one: .wrap stops growing there, so it is the width at which the hero stops being short of
   room. Below 768 — phones — the fan collapses to the middle handset alone; see the note there.

   The wrap is told the fan's width rather than the middle phone's, so flex takes that space off the
   copy honestly. The side phones are still absolute: they overlap the middle one by design, and in
   flow they would claim their full width twice over.

   Every rule here is written .phonefan .pf-* rather than .pf-* alone, and that is not decoration:
   .phone sets position:relative and width:250px at the same (0,1,0) specificity, and it is
   declared BELOW this block, so a bare .pf-side lost to it on source order — the side phones stayed
   in flow and flex-shrank three handsets into one 250-point box, 83 points each. Two classes beats
   one whatever the order.

   The side phones are inert scenery: no scanline, no cycling, no dots. */
.phonefan{position:relative;display:flex;align-items:center;justify-content:center;width:100%;height:100%}
.phonefan .pf-main{position:relative;flex:none;z-index:3}
.phonefan .pf-side{display:none;position:absolute;top:50%;flex:none;z-index:1;opacity:.9;
  transform-origin:center}
/* The two offsets are declared once, outside any query, and driven entirely by --ps. A transform on
   a display:none element costs nothing, so the breakpoints below only have to decide whether the
   side phones exist and how big --ps is — they never restate the geometry. That is the whole reason
   the fan could move from one breakpoint to three without the ratio drifting. */
.phonefan .pf-left{left:50%;transform:translate(calc(-50% - 185px * var(--ps)),-50%) scale(calc(var(--ps) / 1.25))}
.phonefan .pf-right{left:50%;transform:translate(calc(-50% + 185px * var(--ps)),-50%) scale(calc(var(--ps) / 1.25))}
/* THE FAN'S GEOMETRY IS DERIVED, NOT DIALLED IN. Two requirements fix everything else: the middle
   phone is 1.25x the side phones, and 80% of each side phone stays visible. Writing them out with
   C as the middle phone's width:

       side width    = C / 1.25            = 0.8C
       hidden 20%    = 0.2 x 0.8C          = 0.16C
       offset o      = 0.5C + 0.4C - 0.16C = 0.74C
       fan width     = 2(o + 0.4C)         = 2.28C

   C is 250 x --ps, so those become 185px x --ps for the offset and 570px x --ps for the width, and
   one number sets all three. Change --ps and the ratio and the overlap both hold.

   WHAT SETS --ps: not the phones. The store badges are 546 points side by side and .badges wraps, so
   the copy cannot go below 546 without the App Store and Google Play buttons landing on separate
   lines. The hero has 1116 to divide and the gap is 50, which leaves the fan at most 520. .88 puts
   it at 502 and the copy at 564 — eighteen points of margin, and the headline's widest line is 516,
   so that clears too. If this is ever widened, 546 is the number that breaks first, and it will
   break as a wrapped badge rather than as anything obviously wrong.

   THAT CONSTRAINT DOES NOT EXIST WHERE THE HERO STACKS, which is why --ps is BIGGER on a tablet than
   on a desktop. Nothing is beside the fan from 768 to 1179, so the only limit is the column itself,
   and at 768 that is 720 points. 1.1 puts the fan at 627, leaving 93 points of air.

   ONE SIZE ACROSS THE WHOLE STACKED BAND. There was briefly a second step at 1000 taking --ps to
   1.25, on the reasoning that a 1024 column has 976 points and could hold more fan. It could, and
   the fan should not take it: growing the demo through the band and then shrinking it again at 1180
   means a reader widening a window watches the phones swell and then snap back, and the same
   argument was already made and rejected once for the lone phone. The band is one size and the
   change of arrangement at 1180 is the only event in it.

   No rotation. It was -5/+5 degrees and it made two flat screens read as a photograph of some
   phones rather than as the app.

   ORDER MATTERS BELOW AND THE CASCADE IS THE ONLY THING ENFORCING IT. The 1000px rule and the 1180px
   rule both set --ps on .phonewrap at identical specificity, so the later one wins wherever both
   apply — which is everywhere the fan exists. It was declared after the fan and silently held --ps
   at 1.35 there, giving a 337-point middle phone in a box sized for 220. Both are min-width and they
   are written widest-last on purpose; a max-width on the first would reintroduce the fractional seam
   this comment exists to warn about. */
/* The ladder. All min-width, written narrowest-first so the widest declaration wins where several
   apply — see the cascade warning above; a max-width anywhere in here would reintroduce the
   fractional seam it exists to warn about.

   The wrap is told the FAN's width from 768 up rather than the middle phone's, so a stacked hero
   centres the three handsets instead of the one in front of them, and a side-by-side hero takes the
   right amount of space off the copy. */
@media (min-width:768px){
  .hero .wrap{gap:44px;padding-left:24px;padding-right:24px}
  .phonewrap{--ps:1.1;width:calc(570px * var(--ps))}
  .phonefan .pf-side{display:block}
  /* THE COPY COLUMN IS THE FAN'S WIDTH. Left to itself it shrink-to-fits — 470 points at both 768
     and 1024 — and a 470 text block centred over a 713 fan has two different left edges and two
     different right ones, which reads as two things that were laid out separately. Matched, the
     eyebrow, the headline and the store badges all start exactly where the left-hand handset starts.
     The number is the fan's own arithmetic and nothing else: 570 x 1.1 = 627. If --ps moves this
     moves with it, and the failure is a visible misalignment rather than anything subtle.
     width:100% is load-bearing — an auto margin in the cross axis makes a flex item shrink-to-fit,
     so without it the cap never binds and the column is 470 again. */
  .hero-copy{width:100%;max-width:627px;margin-left:auto;margin-right:auto}
}
/* SIDE BY SIDE, and everything the column set has to be put back — a min-width ladder buys its
   missing seam at the price of explicit resets, which is the right way round: a reset that is
   forgotten is visible immediately, a viewport that matches no rule is visible only on one machine
   at one zoom level. */
@media (min-width:1180px){
  .hero .wrap{flex-direction:row;align-items:center;gap:50px;padding-left:32px;padding-right:32px}
  .hero-copy{width:auto;max-width:none;margin-left:0;margin-right:0}
  /* The lede needs no reset at any width: .hero p.lede caps it at 470 unconditionally, which is a
     measure rather than a layout, and 470 characters-per-line reads the same in a column as beside
     one. It is why the copy block shrink-to-fits to 470 when nothing else is holding it open. */
  .phonewrap{--ps:.88}
}
.phone{position:relative;width:250px;height:512px;border-radius:40px;background:#05131b;padding:9px;
  transform:scale(var(--ps));
  box-shadow:0 30px 70px -24px rgba(0,0,0,.65),0 0 0 1px rgba(246,241,231,.13)}
/* THE BAND WHERE THE HERO IS SHORT OF ROOM, and nowhere else.
   .wrap is max-width:1180 with 32px gutters and border-box sizing, so at 1180 and above the hero
   always has exactly 1116 points to lay out in — 1280, 1440, a 5K display, all identical. Below
   1180 it gets whatever the viewport gives it, and at 1024 that came to copy plus gap plus phone
   equalling the space available to the point, which is what read as cramped.

   So the demo grows only across that squeeze, and the top of the band is not a round number picked
   for looking like one: 1180 IS the width at which the container stops growing, so it is the width
   at which the problem stops existing.

   This did apply from 1000 upward, which made the desktop hero 817 points tall and the phone 338 at
   1440. That was reported as too big, and it was — at 1180+ the copy has 816 points and the layout
   is not short of anything, so enlarging the demo there solves nothing and costs the hero its
   proportions. A demo that grows and then returns to its drawn size as a window widens is the odd
   part of this rule, and it is odd on purpose: the thing being corrected is a squeeze, and the
   squeeze ends. */
.pscreen{position:relative;width:100%;height:100%;border-radius:32px;overflow:hidden;background:#0A2434}
.scene{position:absolute;inset:0;opacity:0;transform:scale(.99);transition:opacity .55s ease,transform .55s ease}
.scene.on{opacity:1;transform:none;z-index:2}
.scene img{width:100%;height:100%;object-fit:cover}
.pshade{position:absolute;inset:0;background:linear-gradient(180deg,rgba(6,17,24,.66),rgba(6,17,24,.06) 34%,rgba(6,17,24,.08) 58%,rgba(6,17,24,.8))}
.ptitle{position:absolute;top:44px;left:0;right:0;text-align:center}
.ptitle b{display:block;font-family:'Fraunces',Georgia,serif;font-weight:400;font-size:19px;color:var(--shell);text-shadow:0 2px 12px rgba(6,17,24,.7)}
.ptitle span{display:block;font-size:10.5px;color:rgba(246,241,231,.8);margin-top:4px}
.pchip{position:absolute;top:22px;left:50%;transform:translateX(-50%);white-space:nowrap;
  font-size:9px;font-weight:600;color:#0A2029;background:var(--seaglass);padding:5px 10px;border-radius:11px;z-index:3}
.pframe{position:absolute;inset:96px 26px 130px}
.pframe > i{position:absolute;width:15px;height:15px;border-color:rgba(246,241,231,.9);border-style:solid;border-width:0}
.pframe > i:nth-child(1){left:0;top:0;border-left-width:2px;border-top-width:2px;border-radius:5px 0 0 0}
.pframe > i:nth-child(2){right:0;top:0;border-right-width:2px;border-top-width:2px;border-radius:0 5px 0 0}
.pframe > i:nth-child(3){left:0;bottom:0;border-left-width:2px;border-bottom-width:2px;border-radius:0 0 0 5px}
.pframe > i:nth-child(4){right:0;bottom:0;border-right-width:2px;border-bottom-width:2px;border-radius:0 0 5px 0}
@keyframes scansweep{0%,100%{top:6%}50%{top:92%}}
.scanline{position:absolute;left:4%;right:4%;height:2px;background:linear-gradient(90deg,transparent,#8FC3B2 30%,#F6F1E7 50%,#8FC3B2 70%,transparent);box-shadow:0 0 12px rgba(143,195,178,.9);animation:scansweep 4.2s ease-in-out infinite}
@keyframes ringpop{0%,100%{transform:translate(-50%,-50%) scale(1)}50%{transform:translate(-50%,-50%) scale(1.18)}}
.ring{position:absolute;width:18px;height:18px;border-radius:50%;background:rgba(8,22,30,.45);border:1.5px solid rgba(246,241,231,.92);transform:translate(-50%,-50%);animation:ringpop 2.4s ease-in-out infinite}
.pfoot{position:absolute;bottom:38px;left:0;right:0;display:flex;justify-content:center}
.pfoot .pill{font-size:9.5px;font-weight:600;color:rgba(246,241,231,.88);background:rgba(8,18,24,.55);border:1px solid rgba(246,241,231,.2);padding:5px 11px;border-radius:12px}
@keyframes markerin{from{opacity:0;transform:translate(-50%,-50%) scale(.85)}to{opacity:1;transform:translate(-50%,-50%) scale(1)}}
.spot{position:absolute;display:flex;align-items:center;gap:5px;transform:translate(-50%,-50%);opacity:0;z-index:3}
.scene.on .spot{animation:markerin .45s both}
.scene.on .spot:nth-of-type(2){animation-delay:.16s}
.scene.on .spot:nth-of-type(3){animation-delay:.32s}
.scene.on .spot:nth-of-type(4){animation-delay:.48s}
.spot i{width:8px;height:8px;border-radius:50%;background:var(--seaglass);box-shadow:0 0 0 3px rgba(143,195,178,.3);flex:none}
.spot b{font-size:8.5px;font-weight:600;color:var(--shell);background:rgba(8,20,28,.74);border:1px solid rgba(246,241,231,.16);padding:2px 6px;border-radius:7px;white-space:nowrap}
.pcard{position:absolute;left:14px;right:14px;bottom:44px;display:flex;align-items:center;gap:9px;z-index:3;
  background:rgba(9,24,32,.84);border:1px solid rgba(246,241,231,.14);border-radius:15px;padding:9px 10px}
.pcard img{width:32px;height:32px;border-radius:9px;object-fit:cover;flex:none}
.pcard div{flex:1;min-width:0}
.pcard b{display:block;font-size:11px;font-weight:600;color:var(--shell)}
.pcard span{display:block;font-size:9px;color:rgba(246,241,231,.66);margin-top:1px}
.pcard em{font-style:normal;font-size:9px;font-weight:600;color:var(--seaglass);border:1px solid rgba(143,195,178,.45);padding:4px 8px;border-radius:9px}
.ppage{position:absolute;inset:0;background:var(--shell);padding:26px 13px 0;display:flex;flex-direction:column;gap:9px;overflow:hidden}
/* Each block arrives in turn, so the screen assembles rather than appearing. The delays start after
   the scene's own cross-fade has finished, or the first block fades in twice. */
@keyframes pfadein{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.ppage > *{opacity:0}
.scene.on .ppage > *{animation:pfadein .42s ease-out both}
.scene.on .ppage > *:nth-child(1){animation-delay:.5s}
.scene.on .ppage > *:nth-child(2){animation-delay:.72s}
.scene.on .ppage > *:nth-child(3){animation-delay:.94s}
.scene.on .ppage > *:nth-child(4){animation-delay:1.16s}
.scene.on .ppage > *:nth-child(5){animation-delay:1.38s}
.pmap{position:relative;height:148px;border-radius:12px;overflow:hidden;border:1px solid var(--line)}
.pmap svg{display:block;width:100%;height:100%}
.ppin{position:absolute;left:50%;top:49%;width:11px;height:11px;margin:-5.5px 0 0 -5.5px;border-radius:50%;
  background:var(--coral);border:2px solid #fff;box-shadow:0 2px 6px rgba(4,12,17,.4)}
.pphead{display:flex;align-items:center;gap:7px}
.pphead b{display:block;font-size:14px;font-weight:500;color:var(--ink);line-height:1.15}
.pphead span{display:block;font-size:8.5px;color:var(--ink-soft);margin-top:2px}
.ptide{background:#fff;border:1px solid var(--line);border-radius:14px;padding:9px 10px 6px}
.ptidehead{display:flex;align-items:baseline;justify-content:space-between}
.plabel{font-size:7px;font-weight:700;letter-spacing:.09em;color:var(--ink-faint)}
.pnow{font-size:8px;font-weight:600;color:var(--seaglass-dark)}
.ptide svg{display:block;width:100%;margin-top:5px}
.ptide line{stroke:#EFE9D9;stroke-width:1}
.pbest{font-size:8px;font-weight:700;fill:#3E7A66;text-anchor:middle}
.plowtxt{font-size:8.5px;font-weight:600;fill:#5A666B;text-anchor:middle}
.ptick{font-size:8px;fill:#8A9497}
.pfound b{display:block;font-size:12px;color:var(--ink)}
.pgrid{display:flex;gap:6px;margin-top:6px}
.pgrid div{flex:1;min-width:0}
.pgrid img{width:100%;height:42px;object-fit:cover;border-radius:8px;display:block}
.pgrid span{display:block;font-size:7.5px;font-weight:600;color:var(--ink);margin-top:3px;text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pnote{display:flex;gap:6px;align-items:center;background:#FBF3E4;border:1px solid #EBDDBE;border-radius:10px;padding:7px 9px}
.pnote svg{flex:none}
.pnote span{font-size:8.5px;color:#7A6430;line-height:1.4}
/* the journal screen — the right-hand phone in the fan */
.pjournal{padding:16px 14px}
.pjhead b{display:block;font-size:15px;color:var(--ink);line-height:1.2}
.pjhead span{display:block;font-size:9px;color:#6C7A80;margin-top:3px}
.pjlabel{font-size:7.5px;letter-spacing:.18em;font-weight:700;color:#8A9497;margin:14px 0 7px}
.pjlist{display:flex;flex-direction:column;gap:7px}
.pjrow{display:flex;align-items:center;gap:8px;background:#fff;border-radius:9px;padding:6px 8px;
  box-shadow:0 1px 2px rgba(11,42,58,.07)}
.pjrow img{width:30px;height:30px;border-radius:7px;object-fit:cover;flex:none}
.pjrow b{flex:1;min-width:0;font-size:10px;font-weight:600;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pjrow em{font-style:normal;font-size:9.5px;font-weight:600;color:#5E9C88}
.sdots{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);display:flex;gap:5px;z-index:9;
  background:rgba(8,18,24,.5);padding:5px 9px;border-radius:11px}
.sdots span{width:5px;height:5px;border-radius:3px;background:rgba(246,241,231,.35);transition:all .3s}
.sdots span.on{width:14px;background:var(--seaglass)}
/* Three dots for the three-page flow, and the third goes once the fan appears — because the phone on
   the left is already showing that page and the middle one stops cycling to it. A dot for a screen
   this handset will not reach is a promise it does not keep. The count has to agree with the slice
   in hero.js; both are the same 768, which is also where the side phones turn on. Three numbers, one
   fact: below it there is one handset and it carries the whole flow. */
@media (min-width:768px){.sdots span:nth-child(3){display:none}}
/* WHERE THE HERO'S NUMBERS LIVE NOW, because they used to be gathered here and are not any more.
   The arrangement, the veil, the fan's --ps and the copy's width are all declared with the fan's
   ladder above, as overlapping min-widths — see the note over .hero .wrap for why they must be.
   There is nothing left to say at a max-width, so there is no rule here.

   The demo never disappears. It was a flat display:none at 900 once, and the arrangement was
   backwards: the desktop reader, who cannot install anything, got the film AND the animated app
   mock, while the reader holding a phone — one tap from the App Store, the likeliest install on the
   site — got a gradient with some text on it and no picture of the product anywhere on the page.
   Below 768 the column order is already right in the markup — copy, store badges, then the phone —
   so the buttons stay above the fold and the proof sits directly under them.

   THE FILM'S BREAKPOINT IS 767 AND IT NO LONGER MATCHES ANY LAYOUT RULE, on purpose. hero.js carries
   the string (max-width: 767px) character for character to choose between the wide film and the
   portrait crop, and that used to be the same number the hero stacked at. It is not: the hero now
   stacks all the way to 1179, and the crop is a question about the SHAPE of the hole the film fills
   rather than about the arrangement inside it. At 900 points the hero is stacked and still a wide
   rectangle, and a 608-wide portrait crop crushed across it would be the wrong file. Aspect, not
   layout — and since nothing in this stylesheet keys off 767 any more, that string in hero.js is now
   answerable to the video's dimensions alone. */
/* ------------------------------------------------------------------ the drain

   --sc-p IS THE ONLY INPUT AND IT DEFAULTS TO 1. Every rule below is a calc() against it, and 1
   means "the tide has fully gone out": no water, all four organisms named, the chart's marker at
   low. That is the state a reader gets with JavaScript off or blocked, and it is a finished section
   rather than a degraded one. reef.js lowers it to 0 on arrival and drives it from there, so the
   only thing script adds is the movement.

   THE ONE THING THAT MUST NOT REGRESS: .reefframe is an aspect-ratio box, never object-fit:cover.
   The markers are percentages of the PHOTOGRAPH. Crop the photograph and every label points at
   different rock, at a different offset on every screen shape, with nothing on screen to say so. */
.reef{--sc-p:1;--reef-l:106;position:relative;
  background:linear-gradient(178deg,#071E2B 0%,#0A2434 38%,#061A26 100%);color:var(--shell)}
/* WITHOUT SCRIPT THIS IS AN ORDINARY SECTION and it is finished: a heading, the photograph, and
   four organisms named on it at once. A labelled specimen plate, which is a reasonable thing for a
   page to contain and exactly what a crawler indexes.
   .live is added by reef.js and is what turns it into the drain. So the tall scroll budget and
   the sticky stage are BOTH inside .live — a 2.2-viewport run with nothing moving in it would be
   two flicks of dead scroll for anyone with JavaScript off, and it is also, for free, the right
   answer under reduced motion, because reef.js declines to attach there and the class never
   arrives. */
/* THE HEADING IS INSIDE THE PIN, AND IT WAS OUTSIDE IT, and the reason for the reversal is what
   the section looked like on ARRIVAL rather than what it looked like once it was running.

   Above the pin, the heading is in flow and the sticky stage begins beneath it. So for the first
   240 points of scroll the stage is not at the top of the screen — it is 240 points down, still a
   full viewport tall, hanging off the bottom. The frame is centred in THAT, which puts it 240
   points low and cuts about a fifth of the photograph off the bottom edge. Then the heading
   scrolls away, the stage snaps to the top, and the frame jumps up to the middle of the screen.
   Nothing is broken and the whole section reflows under the reader on the way in.

   No frame size fixes it, because the fault is the stage's CENTRE, not the frame's height. Inside
   the pin, the stage is at the top of the screen from the first pixel of the section, holds the
   heading and the photograph together, and never moves again.

   IT COSTS THE PICTURE ABOUT 240 POINTS OF HEIGHT, which is the objection that moved it out in the
   first place and is still true: on a short wide window the frame goes from 1184 to about 810. The
   trade was made deliberately the other way this time. A composition that is right on arrival and
   smaller beats one that is bigger and assembles itself while you watch. */
.reefstage{display:flex;flex-direction:column;align-items:center;justify-content:center;}
.reefhead{width:100%;flex:none;text-align:center;padding-top:clamp(20px,3vh,34px);padding-bottom:clamp(20px,3vh,34px)}
/* THE FOOT OF THE SECTION, on the section rather than on the run. It used to be scoped to the
   un-pinned state, because pinned the stage was a full viewport and the bottom half of it was the
   gap. The captions are outside the run now and are the last thing in the section at narrow widths,
   so the space has to come after THEM, and it is wanted in both states. Matched to .reefhead's top
   padding so the section sits the same distance from its neighbours at both ends. */
.reef{padding-bottom:clamp(34px,5vh,58px)}
/* The run is the scroll budget; the stage is what the reader sees, stuck to the top of it.
   THIS NUMBER IS THE SPEED, and it is the only thing that sets it. --sc-p runs 0 to 1 across the
   run whatever the run is, so every cue in this stylesheet is a fraction of it and none of them
   moves when this does: halve the budget and the same tide goes out over half the scroll, with the
   four finds still landing at 0.27, 0.51, 0.63 and 0.68 of the way through.
   2.2 viewport-heights, down from 4.4, on the note that the reveal wanted to be twice as quick.
   dvh after vh for the same reason body does it — the older unit measures with mobile browser
   chrome retracted. */
.reef.live .reefrun{height:220vh;height:220dvh}
/* THE PINNED STAGE IS THE HEIGHT OF WHAT IS IN IT, NOT THE HEIGHT OF THE SCREEN, and that is the
   whole of what keeps the two states identical.

   It was height:100dvh with justify-content:center, which is the obvious way to pin something and
   is why the section had two different spacings. A full-viewport box centres its content by
   splitting the leftover: at 1440x813 the heading and the frame come to 743, so 70 points were
   shared out as 35 above the heading and 35 below the picture. Un-pinned the stage is exactly its
   content, that leftover does not exist, and the 35 above the heading is not there. Scroll in and
   the section sits one way; scroll back after it has played and it sits another, 35 points higher.
   Nothing declared either number and neither could be found by reading the spacing rules.

   Auto height removes the leftover rather than balancing it. The stage is the same box pinned and
   un-pinned, so the before and the after are the same picture BY CONSTRUCTION — not by two values
   that have to be kept equal. The space above the heading is .reefhead's own padding in both, which
   is the one place it is written down.

   This is safe only because the frame is already sized to leave room for the heading: --reef-head
   guarantees head + frame is at most a viewport less sixty points, so the stage can never be taller
   than the screen it is stuck to. overflow:hidden went with the fixed height — there is nothing to
   clip now, and keeping it cropped the frame's own shadow. */
.reef.live .reefstage{position:sticky;top:0}
.reefhead h2{margin-top:14px;font-size:clamp(26px,3.6vw,42px);line-height:1.08;color:var(--shell)}
.reefhead h2 em{font-style:normal;color:var(--seaglass)}
.reeflede{margin:14px auto 0;max-width:52ch;font-size:14.5px;line-height:1.62;color:rgba(246,241,231,.72)}

/* THE HEIGHT CAP IS EXPRESSED AS A WIDTH, and that is not a flourish. max-height beside
   aspect-ratio does not preserve the ratio — it wins, and the box goes to 1180x638 on a 862-tall
   viewport, which is 1.85:1 against a 16:9 file. The frame then either distorts the rock or crops
   it, and every marker is a percentage of that rock. So the tallest the frame may be is folded back
   into the widest it may be, the ratio is left to do its job unopposed, and the box is 16:9 at every
   viewport by construction rather than by luck.

   --reef-head IS WHAT THE HEADING TAKES OFF THE TOP, and it is one number for both shapes because
   the heading is about the same height at all of them: measured 210 at 760 points wide, 229 at
   1000, 242 at 1440, and 239 in French at 500, where the lede wraps to four lines. 300 is the worst
   of those plus the stage's own gap plus about thirty points of slack, so a longer lede in a
   language nobody here reads costs the picture a little width rather than clipping the heading. */
/* THE FRAME'S WIDTH, RESTATED WITHOUT A PERCENTAGE, so that something other than the frame can be
   measured against it. A label is capped at a fraction of the picture it sits on, and it used to be
   capped at a fraction of the VIEWPORT instead — which agreed with the picture only while the
   picture was as wide as the viewport. It is not any more: --reef-head means a short window gets a
   frame far narrower than the screen, and at 1100x756 that put "Sea star" 38 points off the right
   edge and cut the first letter off "Turban snail" on the left. Both clipped by the frame's own
   overflow, silently.
   100vw - 56 rather than 100% - 40 because a custom property is substituted textually: a percentage
   in here would resolve against whatever element used it, and .reeflabel's containing block is a
   zero-width point. The extra 16 covers a classic scrollbar, so the cap errs narrow. */
.reef{--reef-head:300px;
  --reef-fw:min(1400px,100vw - 56px,(100dvh - var(--reef-head)) * 16 / 9)}
.reefframe{position:relative;flex:none;aspect-ratio:16/9;
  width:min(1400px,100% - 40px,(100vh - var(--reef-head)) * 16 / 9,(100dvh - var(--reef-head)) * 16 / 9);
  border-radius:20px;overflow:hidden;
  box-shadow:0 30px 90px rgba(3,12,18,.55),0 0 0 1px rgba(246,241,231,.09)}
/* THE PLATE IS THE PHOTOGRAPH; THE FRAME IS THE WINDOW ONTO IT. On a desktop the two are the same
   box and this layer does nothing. It exists for the phone, where it is wider than the window and
   sits off to one side — see the note in the narrow query. Everything that is positioned as a
   percentage of the picture lives in here: both images, the water, the rim and all four markers.
   The tide chart deliberately does not, because it is anchored to the window's corner and must not
   travel with the crop. */
.reefplate{position:absolute;inset:0}
.reefplate img{position:absolute;inset:0;width:100%;height:100%;object-fit:fill}
/* object-fit:fill, deliberately. The box is already 16/9 and so is the file, so fill and cover
   agree — but if the two ever disagree, fill distorts visibly and cover crops silently, and a
   visible fault on a section whose markers depend on the framing is the better failure. */

/* THE WATER. The same photograph again, graded as if seen through it, masked to an ellipse that
   retreats toward the pool's deepest point. Two <img> of one file is one download.

   RADIAL, NOT A FALLING HORIZONTAL LINE, because that is what a pool does: it empties from the rim
   inward and the deepest point goes last. The composition then comes free — the deepest point is
   the middle of the frame, the middle of the frame is the anemone, so the anemone is uncovered
   last without anybody having arranged for it.

   A mask rather than clip-path, for the feathered edge. The soft stop is a fraction of the radius
   rather than a fixed distance, so the rim tightens as the puddle shrinks, which is also what
   happens. 3.2 on the x radius flattens the ellipse hard, and the number came out of arithmetic rather than
   taste: it is the flattening that separates the sea star from the snail in time, and 106 is the
   smallest starting radius that still leaves the frame's TOP CORNERS fully covered at p = 0 — at
   67.3 they came up dry before the reader had scrolled at all, so the section opened on a pool that
   was already half empty. See reef.js, which holds the matching constants. */
/* A LEVEL THAT FALLS, NOT A SHAPE THAT SHRINKS.
   --reef-l is the waterline, in per cent of the frame's height: above it is dry rock, below it is
   water. It starts above the top edge and finishes below the bottom one.

   It was a radial mask retreating toward the pool's deepest point, which is truer to how a pool
   actually empties and was wrong on the screen. At any radius small enough to be interesting, a
   flattened ellipse in the middle of a photograph does not read as water — it reads as a smudge on
   the lens, or as a vignette somebody left switched on. A level reads as water at every position it
   can hold, needs no explaining, and is the same event the chart in the corner is drawing.

   The cost was the reveal order, which is now simply top to bottom, and the composition was changed
   to suit rather than the mechanism bent to preserve it: the snail moved to the other shell in the
   frame so that the anemone is still the deepest of the four and still the last one named.

   IT LEAVES BEFORE IT REACHES THE BOTTOM. The last of the travel is across rock nothing is marked
   on, so rather than watch a band crawl off the edge, the whole layer fades between 74% and 92%.
   Both defaults — the opacity at --reef-l: 106 and the mask stop past the bottom edge — resolve to
   nothing, which is what the section renders with no script running. */
.reefwater,.reefrim{opacity:clamp(0,calc((92 - var(--reef-l)) / 18),1)}
.reefwater{position:absolute;inset:0;
  -webkit-mask-image:linear-gradient(to bottom,transparent calc(var(--reef-l) * 1%),#000 calc((var(--reef-l) + 7) * 1%));
  mask-image:linear-gradient(to bottom,transparent calc(var(--reef-l) * 1%),#000 calc((var(--reef-l) + 7) * 1%))}
/* Subtler than it was. The grade only has to say "this is under water", and the earlier setting
   said it by taking most of the light out — which on a photograph of dark wet rock left a rectangle
   the reader could see nothing in at all. */
.reefwater img{filter:saturate(.74) brightness(.86) contrast(.97) blur(.6px)}
.reefwater::after{content:'';position:absolute;inset:0;
  background:linear-gradient(to bottom,rgba(9,32,46,.16),rgba(6,24,36,.36))}
/* The meniscus: one bright line where air meets water, drawn at the level rather than masked to a
   ring. Two per cent of the frame, which is a few points — anything thicker stops being a surface
   and starts being a stripe. */
.reefrim{position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(to bottom,
    transparent calc((var(--reef-l) - 0.5) * 1%),
    rgba(226,238,234,.30) calc((var(--reef-l) + 0.7) * 1%),
    rgba(226,238,234,.10) calc((var(--reef-l) + 1.8) * 1%),
    transparent calc((var(--reef-l) + 4) * 1%))}

/* THE FINDS. --at is when this one is uncovered, --on is how far in it is. Both are plain numbers
   substituted into calc(), so the whole cue is stylesheet arithmetic and script never touches an
   element. The ramp is deliberately short: an organism is either named or it is not, and a label
   drifting up over half a viewport reads as a page still loading. */
/* A MARK IS A POINT, NOT A BOX, and that is the whole reason this is written the way it is.
   It was a flex row holding the dot and the label, offset by translate(-50%, -50%) to centre it on
   its coordinates. That centres the ROW — dot plus a three-hundred-point label — so the dot landed
   half a label away from the rock it names: the sea star's marker was declared at 65.4% and sat at
   77.8%, on bare barnacle crust, and the anemone's at 49.5% sat at 37.1%. Every one was wrong,
   every one by a different amount, because each label is a different width. The vertical was
   correct throughout, which is what made it survive a look: the markers sit at believable heights on
   believable rock, and nothing about the screen says they are pointing at nothing.
   So the mark is now zero by zero — it IS the coordinate — and the dot and the label are both
   placed against it. Nothing that depends on the label's width can move the dot again. */
.reefmarks{position:absolute;inset:0}
/* --on is how far in a mark is, and it is 1 unless there is a scroll to bring it in with. IN ONLY:
   an identification, once made, stays on the picture, so there is no closing half to this cue and
   the section ends on all four at once. The default of 1 is what the static plate renders. */
.reefmark{--ramp:.06;--on:1;position:absolute;width:0;height:0;opacity:var(--on)}
.reef.live .reefmark{--on:clamp(0,calc((var(--sc-p) - var(--at)) / var(--ramp)),1)}
.reefdot{position:absolute;left:0;top:0;width:11px;height:11px;border-radius:50%;
  background:var(--seaglass);
  box-shadow:0 0 0 calc(3px + 7px * (1 - var(--on))) rgba(143,195,178,calc(.42 * var(--on))),0 0 16px rgba(143,195,178,.6);
  transform:translate(-50%,-50%) scale(calc(.55 + .45 * var(--on)))}
.reeflabel{display:block;position:absolute;left:16px;width:max-content;max-width:min(30ch,calc(var(--reef-fw) * 0.3));
  padding:8px 12px;border-radius:12px;
  background:rgba(7,20,28,.82);border:1px solid rgba(246,241,231,.16);
  backdrop-filter:blur(7px);-webkit-backdrop-filter:blur(7px);
  transform:translateY(calc(-50% + 7px * (1 - var(--on))))}
/* Past about two thirds across, the label would run off the right edge of the frame and be clipped
   by its overflow, so it goes on the other side of the dot instead. right against a zero-width
   containing block measures from the coordinate itself. */
.reefflip .reeflabel{left:auto;right:16px}
/* Under the dot and centred on it, which is the one placement that does not cover the animal it
   names. The anemone is the only find that needs it, and it is the only find the section is
   actually building towards. */
.reefbelow .reeflabel{left:50%;right:auto;top:26px;
  transform:translate(-50%,calc(7px * (1 - var(--on))))}
.reeflabel b{display:block;font-size:12.5px;font-weight:600;color:var(--shell);letter-spacing:.01em}
.reeflabel span{display:block;margin-top:3px;font-size:11px;line-height:1.5;color:rgba(246,241,231,.72)}
/* The last one is the one the section exists for, so it is bigger. Selected by position rather than
   by an extra class: the anemone is last in REEF.finds because it is deepest, and if that order
   ever changes the emphasis should follow it. */
.reefmark:last-child .reeflabel{padding:11px 15px}
.reefmark:last-child .reeflabel b{font-family:'Fraunces',Georgia,serif;font-weight:400;font-size:17px}
.reefmark:last-child .reeflabel span{font-size:11.5px}
.reefmark:last-child .reefdot{width:14px;height:14px}

/* The chart. Not tideCard — see TIDE_CURVE. No times on it, because its marker is the reader's
   scroll position and a dot somebody is dragging cannot sit under the word "Now". */
.reefchart{position:absolute;left:18px;bottom:18px;width:min(226px,30%);
  background:rgba(7,20,28,.76);border:1px solid rgba(246,241,231,.14);border-radius:13px;
  padding:9px 11px 7px;backdrop-filter:blur(7px);-webkit-backdrop-filter:blur(7px)}
.reefchartlabel{display:block;font-size:8.5px;letter-spacing:.16em;font-weight:700;color:var(--seaglass)}
/* Uniform scaling, so no preserveAspectRatio="none" and no fixed height. The marker is a circle
   placed in user units by reef.js; stretch the box and the dot becomes an ellipse and the curve's
   stroke thins on one axis. */
.reefchart svg{display:block;width:100%;height:auto;margin-top:5px;overflow:visible}
.reefchart line{stroke:rgba(246,241,231,.12);stroke-width:1}

/* The panel is the narrow-screen answer to a label that would be four words wide beside its dot.
   Hidden above 760, where the labels sit on the rock instead. */
/* WHERE THE WORDS LIVE, AND WHY THE BREAKPOINT IS 1000 RATHER THAN THE USUAL 760.

   All four identifications stay up, so all four labels have to fit on the picture at once, and
   whether they fit is a question about the frame's HEIGHT. Two pairs are tight: the sea star and the
   snail are 14.7% of the frame apart vertically, the snail and the anemone 5.2%, and every pair
   overlaps horizontally. A label is about 70 points tall whatever the width, so the gaps close as
   the frame shrinks and the star lands on the snail somewhere around a 900-point viewport.

   Below that the words move under the photograph and the dots stay on it — the dot is the "where"
   and is legible at any size, the label is a 30-character box that at 390 points is a smear. The
   panel lists all four, in order, exactly as the labels do. Neither arrangement is the fallback for
   the other; they are the same content at two widths.

   This is also the static plate, unchanged: .live no longer switches any of it, because the end
   state of the drain and the state of a section that never ran are now the same picture. */
/* OUT OF THE PIN AND UNDER IT. Inside the stage the captions were competing with the photograph
   for one screen, and the arithmetic that settled the argument was the bug above. Here they are
   ordinary flow after the run: the reader scrolls the drain, the picture names everything on
   itself as it empties, and then the sentences arrive. Nothing is squeezed, and there is no height
   at which the two have to be traded off. */
.reefpanel{position:relative;width:100%;max-width:760px;margin:0 auto;padding:clamp(22px,3.4vh,34px) 22px 0}
/* Tighter than it was, because it is no longer carrying the identification on its own. The name is
   on the rock; this is the sentence about it, and it repeats the name only so the sentence has
   something to belong to. */
.reefpanelitem + .reefpanelitem{margin-top:11px}
.reefpanelitem b{display:block;font-family:'Fraunces',Georgia,serif;font-weight:400;font-size:16px;color:var(--shell)}
.reefpanelitem span{display:block;margin-top:3px;font-size:12.5px;line-height:1.5;color:rgba(246,241,231,.74)}

/* THE PILL: THE SAME LABELS, WITH THE SENTENCE TAKEN OUT.
   The note above is right about why a full label cannot live on a small frame, and wrong about the
   conclusion it drew. What does not fit is the SENTENCE — a 30-character box is about 70 points
   tall, the star and the snail are 14.7% of the frame apart and the snail and the anemone 5.2%, so
   below roughly 900 points the boxes close on each other. The NAME is a single line. A pill is
   twenty-two points tall, the same four gaps are then several times what they need to be, and the
   arrangement that was impossible at 390 is comfortable.

   So nothing moves under the picture any more. The dots keep their names on the rock at every
   width, which is the section's whole claim — everything in it has a name — and the panel below
   stops being the place the names live and becomes the place the sentences do.

   Sizes are set here rather than scaled with a factor, because the last find is deliberately larger
   than the other three and a uniform shrink would have kept a serif display face at a size it is
   not drawn for. */
@media (max-width:999px),(max-height:639px){
  .reeflabel{left:12px;max-width:min(22ch,calc(var(--reef-fw) * 0.3));padding:5px 9px;border-radius:9px}
  .reeflabel span{display:none}
  .reeflabel b{font-size:10.5px}
  .reefflip .reeflabel{left:auto;right:12px}
  .reefbelow .reeflabel{left:50%;right:auto;top:18px}
  .reefmark:last-child .reeflabel{padding:5px 10px}
  .reefmark:last-child .reeflabel b{font-size:11.5px}
  .reefmark:last-child .reeflabel span{display:none}
}
/* A SHORT WINDOW CANNOT AFFORD THE WHOLE HEADING. --reef-head is a flat 300, which is fine against
   a 900-point screen and is most of a 477-point one: it left the frame 315 wide, with the pills
   piled on the tide chart and the anemone's off the bottom. The same shape of fault as the flat 380
   this replaced, one level up.

   So the lede goes and the budget drops with it. The h2 is the claim — low tide does not empty the
   shore — and the lede restates it in longer words; losing the second one on a window this size is
   the cheapest thing on the section to lose, and it buys the photograph back about 180 points of
   width. Not scoped to .live, because a lede that reappears when the drain collapses is a reflow
   under the reader for no reason. */
@media (max-height:639px){
  .reef{--reef-head:200px}
  .reeflede{display:none}
  /* AND THE CHART CROSSES THE FRAME. Bottom left is the snail's corner too, and on a frame this
     short the pill's underside and the card's top edge came within two points of each other —
     close enough that a sub-pixel difference decided it, which is not a layout, it is a coin toss.
     Bottom right is empty here: the sea star's label is the only thing on that side and it sits in
     the upper half. The narrow query moves it to the same corner for its own reasons. */
  .reefchart{left:auto;right:18px;width:min(180px,26%)}
}

/* AND THE SENTENCE NEEDS HEIGHT AS WELL AS WIDTH. The last find's label hangs BELOW its dot, at
   66.2% down the frame, so it needs the bottom third of the picture to land in: .662H + 26 + 88
   has to stay inside H, which wants a frame at least 337 points tall and therefore a window of
   about 640. Under that the anemone's caption simply falls off the bottom edge. */
@media (min-width:1000px) and (min-height:640px){
  .reefpanel{display:none}
}

@media (max-width:759px){
  /* Halved with the desktop budget, and kept slightly shorter than it for the same reason it always
     was: a phone flick covers more of a short viewport than a trackpad does of a tall one. */
  .reef.live .reefrun{height:200vh;height:200dvh}
  /* A 16:9 FRAME ON A PHONE IS A LETTERBOX, so here the window is portrait and the photograph is
     bigger than it. Full width at 16:9 on a 390-point screen is 219 points tall — a quarter of the
     viewport, with the pool too small to read an animal in and 240 points of empty ground above and
     below it. So the window becomes 39:44 and the plate is scaled to fill its HEIGHT, which makes
     the picture 2.005 times the window's width and pushes 50% of it out of view.

     WHICH 50% IS THE WHOLE QUESTION, and it is answered by the markers rather than by composition:
     the visible band has to contain all four organisms or the section loses one on phones only.
     They span 37.0% to 65.4% across the picture, so the window is centred on the middle of it,
     showing roughly 25% to 75% — every find inside, with real margin at each end.

     The two numbers are derived, not chosen: width is (16/9) / (39/44), and left is 50% minus half
     that width. Change the window's aspect and both have to be recomputed.

     THE HEIGHT IS CAPPED BY THE HEADING ABOVE IT, and by nothing else. It used to be capped by the
     captions too, which is what made this the worst line in the file: 100dvh minus a flat 380 has a
     floor of nothing, and at a viewport 477 points tall it resolved to a frame 86 points wide — the
     photograph as a postage stamp with four labels and a tide chart piled on it. The captions are
     out of the pin now and cannot squeeze it, so the only thing sharing the screen is the heading,
     and --reef-head is a bound on ONE element rather than on a stack of them. */
  .reef{--reef-fw:min(100vw,(100dvh - var(--reef-head)) * 39 / 44)}
  .reefframe{width:min(100%,(100vh - var(--reef-head)) * 39 / 44,(100dvh - var(--reef-head)) * 39 / 44);
    aspect-ratio:39/44;border-radius:0;box-shadow:0 20px 60px rgba(3,12,18,.5)}
  .reefplate{left:-50.3%;width:200.6%}
  .reefhead{padding-left:22px;padding-right:22px}
  .reefhead h2{font-size:clamp(24px,7vw,32px)}
  .reeflede{font-size:13.5px}
  .reefdot{width:13px;height:13px}
  /* THE ONE CORNER THAT IS CLEAR OF ALL FOUR. Bottom left sat on the anemone, which is two thirds
     of the way down and just left of centre in this crop; top left then sat on the coralline, which
     is a fifth of the way down and a little left of centre. Bottom right is empty: the lowest
     marker is the anemone at 66% and the chart starts below 75%. */
  .reefchart{right:12px;bottom:12px;left:auto;top:auto;width:46%;padding:7px 9px 5px}
  /* EVERY PILL GOES LEFT HERE, WHICHEVER SIDE OF THE PICTURE ITS ANIMAL IS ON.
     Above this width the sides are derived from the animal's column and that is the right rule.
     Below it the plate is cropped to the middle half, so a find at 65.4% ACROSS THE PICTURE is at
     80.8% across the WINDOW — and the room left to its right is a fifth of a phone. "Sea star" fits
     in it; "Étoile de mer" does not, and would be cut off by the frame's own overflow with nothing
     on screen to say a word was missing. Left of the dot there is always most of a screen. */
  .reefmark:not(.reefbelow) .reeflabel{left:auto;right:12px}
  /* ...except the two on the left half, which have a whole screen to their right and none to their
     left. reefMark decides which; see the note over it. */
  .reefmark.reefnear:not(.reefbelow) .reeflabel{left:12px;right:auto}
  /* AND THE LAST ONE STOPS BEING CENTRED ON ITS DOT, because the tide chart is in that corner.
     The anemone sits at 48.9% across the cropped window and 66.2% down it, so anything directly
     under it lands in the bottom band the chart occupies — measured as a 70x11 overlap, the caption
     the section is built towards sitting on the drawing that explains it. Anchoring the label's
     RIGHT edge just left of the dot puts it in the one corner nothing else wants, and it holds by
     construction rather than by arithmetic: the label is left-anchored and capped at 40% of the
     frame, the chart is right-anchored at 46%, and the two cannot meet at any width. */
  .reefbelow .reeflabel{left:auto;right:calc(50% + 8px);
    transform:translateY(calc(7px * (1 - var(--on))))}
}

/* The panel arrives find by find and then stays, exactly as the labels do on a wider screen. In
   flow rather than stacked in one box, so the four reserve their space from the start and the frame
   above them does not move as they come in. */
.reef.live .reefpanelitem{opacity:clamp(0,calc((var(--sc-p) - var(--at)) / 0.06),1)}

/* Sections arriving in turn, and the one property that decides whether this is safe.
   The fill mode is doing the work. animation-fill-mode:backwards makes the keyframe's start state
   apply ONLY during the delay; the element's own declared opacity stays 1, so anything that stops
   the animation running — reduced motion, an old engine, a stylesheet that half-loaded — leaves the
   content visible. Compare the phone in the hero, which sets opacity:0 in a rule and therefore needs
   that rule undone under reduced motion or the content disappears along with the movement.

   So there is no opacity:0 here, and there must never be one: it would turn a decoration into a
   requirement, on a site whose whole job is to be read.

   Scoped to the sections inside main — the hero is .hero, and the nav and footer are outside main.
   Opacity and transform only, both composited: no layout is touched, so nothing shifts and CLS is
   unaffected. The first child has NO delay, because on a page with no hero it is the largest thing
   painted and delaying it would push LCP back for a decoration. */
@keyframes sectionin{from{opacity:0;transform:translateY(10px)}}
main > .section > .wrap > *{animation:sectionin .5s ease-out backwards}
main > .section > .wrap > :nth-child(2){animation-delay:.07s}
main > .section > .wrap > :nth-child(3){animation-delay:.14s}
main > .section > .wrap > :nth-child(4){animation-delay:.21s}
main > .section > .wrap > :nth-child(5){animation-delay:.28s}
main > .section > .wrap > :nth-child(n+6){animation-delay:.35s}

@media (prefers-reduced-motion:reduce){
  .scanline,.ring,.scene.on .spot,.scene.on .ppage > *{animation:none}
  /* The drain needs nothing undone here, which is the point of building it the other way up:
     reef.js declines to attach under this setting, so .live never arrives and the section is
     already the plain labelled plate. Nothing in it animates on its own any more. */
  /* No opacity to restore for these — see the note above @keyframes sectionin. That is the whole
     point of the fill mode: turning the animation off returns them to their normal state. */
  main > .section > .wrap > *{animation:none}
  /* Anything hidden ONLY so an animation could reveal it has to be put back, or reducing motion
     removes the content rather than the movement. Scene three is entirely ppage children. */
  .spot,.ppage > *{opacity:1}
}

/* store badges */
.badges{display:flex;gap:12px;margin-top:30px;flex-wrap:wrap}
@media (max-width:560px){.badges{justify-content:center}}
/* The band centres its children, but the badges carry a top margin for their use in the hero, which
   pushed them below the centre line. Inside the band the flexbox does the aligning. */
.ctaband .badges{margin-top:0}
.badge{display:flex;align-items:center;gap:10px;background:#000;border:1px solid rgba(246,241,231,.3);border-radius:11px;padding:9px 16px;opacity:.55;cursor:default}
.badge small{font-size:8.5px;color:rgba(246,241,231,.65);display:block;line-height:1.15}
.badge b{font-size:14.5px;font-weight:600;color:#fff;display:block;line-height:1.15}

/* sections */
.section{padding:44px 0 52px}
.sechead{display:flex;align-items:flex-end;justify-content:space-between;gap:32px;flex-wrap:wrap}
.sechead h2{margin-top:12px;font-size:clamp(26px,3.4vw,36px);color:var(--ink)}
.sechead p{max-width:360px;font-size:13px;line-height:1.65;color:var(--ink-soft)}
/* The link that replaced the paragraph in the section head. It keeps p's baseline alignment — the
   head is align-items:flex-end, so this sits on the same line as the bottom of the heading — but
   drops the reading measure, which was there to hold a sentence to 360 points and would now just
   be an arbitrary box round eight words. */
.sechead-link{max-width:none;font-size:14px;line-height:1.4}
/* SEAGLASS, WHICH IS WHAT A LINK IS ON THIS SITE — see .crumb a, a.pill.more, .poollist a:hover.
   This one was var(--ocean), inherited from the inline styles it carried when it sat under the
   cards, and it had been the only navy link on the page for as long as it existed. Nobody saw it
   because at the foot of a section, in isolation, dark navy on cream just reads as emphasis. Put on
   the same baseline as a heading it reads as a heading, which is what made it obvious. */
.sechead-link a{font-weight:600;color:var(--seaglass-dark);border-bottom:1.5px solid rgba(62,122,102,.32);padding-bottom:2px}
.sechead-link a:hover{border-bottom-color:var(--seaglass-dark)}
/* Wrapped, .sechead becomes a column and the link lands hard under a 36px heading with no space
   between them, reading as a caption on it rather than as an action. */
@media (max-width:640px){.sechead-link{margin-top:10px}}
.eyebrow.dark{color:var(--seaglass-dark)}

/* pool cards */
/* Three across, as the mock draws them, so the six featured cards land as two full rows rather than
   as whatever auto-fill happens to give at this viewport — the same even-grid reasoning as the
   species and country lists. Two, then one, on the way down. */
.grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;margin-top:24px}
@media (max-width:900px){.grid{grid-template-columns:repeat(2,1fr)}}
@media (max-width:560px){.grid{grid-template-columns:1fr;gap:14px}}
.card{background:#fff;border:1px solid var(--line);border-radius:18px;overflow:hidden;display:block;transition:transform .15s ease,box-shadow .15s ease}
.card:hover{transform:translateY(-2px);box-shadow:0 12px 28px -12px rgba(11,42,58,.28)}
.card .shot{width:100%;height:132px;object-fit:cover;background:var(--seaglass-pale)}
/* The drawn coastline that replaces the card photograph.
   One ground and one line, with no land-versus-water colouring. The fill could only be worked out
   where a coastline way crossed the whole card, so some cards had a shore and others a bare line —
   and a directory of 190 places wants 190 cards that read the same way. It is also the honest amount
   of certainty available about a coast drawn at this scale, from a coordinate rounded to a kilometre. */
.coast{position:relative;display:block;overflow:hidden;background:var(--seaglass-pale)}
.coast svg{display:block;width:100%;height:100%}
.coast .edge{fill:none;stroke:var(--seaglass-dark);stroke-linecap:round;stroke-linejoin:round;
  opacity:.72}
/* stroke-width is an attribute on the group, not a rule here: it is in view units, and the view is
   four times the card so a fixed number in CSS would draw a hairline. See STROKE in
   data/places/coastGeometry.mjs. */
.coastpin{position:absolute;left:50%;top:50%;width:10px;height:10px;margin:-5px 0 0 -5px;
  border-radius:50%;background:var(--coral);border:2px solid #fff;box-shadow:0 1px 4px rgba(4,12,17,.45)}
.card .body{padding:12px 14px 13px}
.card h3{font-size:16.5px;color:var(--ink);font-weight:400}
.card .where{display:flex;align-items:center;gap:5px;font-size:11px;color:var(--ink-soft);margin-top:3px}
.card .meta{display:flex;align-items:center;gap:6px;margin-top:9px;flex-wrap:wrap}
/* Name left, tide right, both on the same baseline — align-items:baseline rather than center, which
   is the whole difference between the time sitting beside the place name and floating near it. The
   name may run to two lines and the tide must stay on the first, so it takes no slack and the
   heading takes all of it. */
.cardhead{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
.cardhead h3{min-width:0}
/* Empty until assets/cards.js fills it, so it must not reserve a gap when it stays empty — a card
   with no timezone or no chart renders nothing here at all. */
.low{flex:none;font-size:10.5px;font-weight:600;color:var(--seaglass-dark);white-space:nowrap}
.low:empty{display:none}

.count{font-size:10px;color:var(--ink-faint)}
.spacer{flex:1}

/* The directory and country listings. Same .card as the home page; four across, and never fewer
   than two, because a one-per-row list of photographs is a very long page and reads as a feed. */
.rows{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-top:22px}
@media (max-width:1040px){.rows{grid-template-columns:repeat(3,1fr)}}
@media (max-width:760px){.rows{grid-template-columns:repeat(2,1fr);gap:12px}}
/* .card sets display:block, and an author declaration beats the UA rule for [hidden] — so without
   this the search box would filter nothing at all. The list version had the same guard. */
.card[hidden]{display:none}
.card .dist{font-size:11px;color:var(--ink-faint);margin-top:5px}
/* Every card ships in the markup because searching happens over this DOM rather than over a fetched
   index — see poolCard for why that is a licence decision and not a preference. So the browser is
   told it may skip layout and paint for the ones off screen, and given the height to reserve so the
   scrollbar does not jump as it catches up. Costs nothing where unsupported. */
.rows > .card{content-visibility:auto;contain-intrinsic-size:auto 232px}

/* controls */
.controls{display:flex;gap:10px;margin-top:26px;align-items:center;flex-wrap:wrap}
.search{flex:1;min-width:240px;max-width:400px;display:flex;align-items:center;gap:10px;background:#fff;border:1px solid var(--line);border-radius:23px;padding:0 16px;height:44px}
.search input{flex:1;border:0;outline:0;font:inherit;font-size:13px;color:var(--ink);background:transparent}
/* The look. Kept unscoped because the phone mock in the hero borrows it for its SCANNING label — and
   kept to LOOK only for the same reason: sizing this rule broke that label, which is 9.5px inside a
   240px phone and cannot be 32px tall. Anything about size belongs in the .controls rule below. */
.pill{font-size:11.5px;font-weight:500;color:var(--ink-soft);border:1px solid var(--line);
  padding:9px 14px;border-radius:16px;background:#fff;cursor:pointer;font-family:inherit}
.pill.on{color:#0A2029;background:var(--seaglass);border-color:var(--seaglass);font-weight:600}

/* The region row on a country page. Reuses .pill so a state reads as the same kind of shortcut a
   country does in the home page chips, and wraps rather than scrolls: England has 33 pools and
   California 35, but Scotland, Wales and the rest are the point of the row and a horizontal scroller
   hides everything past the third. The count is inside the pill because a region with two pools and
   one with thirty-five are not the same offer. */
.regionstrip{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:18px 0 4px}
.regionstrip .pill span{color:var(--ink-soft);opacity:.7;margin-left:3px}

/* Chips are 32px against the 44px of the search field and the nearest button, and the gap is the
   point: height is how a control row says what leads. The search field is where most people start and
   the button is the primary action; the chips are shortcuts past them. Matching all three would make
   five countries look as important as the two things that actually do something.
   They were 37px, which is the worst of both — close enough to 44 to read as a failed attempt at
   alignment rather than as a smaller thing. An ambiguous difference looks like a bug; a clear one
   looks like a decision. */
.controls .pill{display:inline-flex;align-items:center;height:32px;padding:0 13px}

/* Sort by nearest is the front door — most people want the shore they can reach this afternoon, not a
   country to browse — so it is a filled button at the head of the row rather than the last chip in it. */
.nearbtn{display:inline-flex;align-items:center;gap:8px;height:44px;padding:0 20px;border:0;
  border-radius:23px;background:var(--ocean);color:var(--shell);font:inherit;font-size:13.5px;
  font-weight:600;cursor:pointer;flex:none;transition:background .15s ease}
.nearbtn:hover{background:var(--ocean-deep)}
.nearbtn:disabled{opacity:.65;cursor:default}
.nearbtn.on{background:var(--seaglass);color:#0A2029}

/* The country index. Two columns of name-and-count, which is a list rather than a set of cards
   because there is nothing to look at — the country's own page is where the photographs are. */
.countrygrid{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;margin-top:22px}
@media (max-width:700px){.countrygrid{grid-template-columns:1fr}}
.countryrow{display:flex;align-items:baseline;justify-content:space-between;gap:14px;background:#fff;
  border:1px solid var(--line);border-radius:13px;padding:13px 16px}
.countryrow:hover{border-color:var(--seaglass-dark)}
.countryrow b{font-family:'Fraunces',Georgia,serif;font-size:16px;font-weight:400;color:var(--ink)}
.countryrow span{font-size:11.5px;color:var(--ink-soft);flex:none}

.note{font-size:11.5px;color:var(--ink-faint)}

/* pool page */
/* The country chips are links now, so they get the affordance of one. */
a.pill{text-decoration:none}
a.pill:hover{border-color:var(--seaglass-dark);color:var(--seaglass-dark)}

/* Not a chip. It leaves the list rather than narrowing it, so it has no border and reads as the link
   it is — the dashed outline it had looked like an unfinished element.
   Both selectors carry the element and both name .more, because the a.pill:hover rule above is MORE
   specific than a plain .pill.more — which is why the border came back the moment you hovered it. A
   transparent border rather than none, so the text does not shift by a pixel against its neighbours. */
a.pill.more{color:var(--seaglass-dark);font-weight:600;background:transparent;
  border-color:transparent;padding-left:4px}
a.pill.more:hover{color:var(--ocean);border-color:transparent;text-decoration:underline}
.crumb{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--ink-faint);flex-wrap:wrap}
.crumb a{color:var(--seaglass-dark);font-weight:600}
.poolhead{display:flex;align-items:flex-end;justify-content:space-between;gap:24px;margin-top:16px;flex-wrap:wrap}
.poolhead h1{font-size:clamp(28px,4vw,38px);color:var(--ink)}
.poolhead .sub{font-size:13px;color:var(--ink-soft);margin-top:6px}
.tags{display:flex;gap:7px;flex-wrap:wrap}
.tag{font-size:10px;font-weight:600;color:var(--ocean);background:#fff;border:1px solid var(--line);padding:6px 11px;border-radius:9px}
.split{display:grid;grid-template-columns:1.18fr .82fr;gap:20px;margin-top:22px}
@media (max-width:900px){.split{grid-template-columns:1fr}}
.panel{background:#fff;border:1px solid var(--line);border-radius:18px;padding:14px 16px}
.panel h3{font-size:9px;font-weight:700;letter-spacing:.09em;color:var(--ink-faint);text-transform:uppercase}
.dark-panel{background:linear-gradient(160deg,#0E3042,#0A2434);border-radius:18px;padding:16px 18px;color:var(--shell)}
.dark-panel h3{font-size:9px;font-weight:700;letter-spacing:.09em;color:var(--seaglass);text-transform:uppercase}
/* The icon centres on the FIRST LINE of the text, which is not what align-items can do: a tip that
   wraps to two lines has a flex line 36px tall, so centring would drop the icon into the gap between
   them. So it is top-aligned and pushed down by half the difference between the line box and the
   icon — and computed rather than typed, because the 3px that was there was measured against a font
   size this has since changed and was a pixel low ever after.
   The type is on .tip rather than on .tip span so 1em means the same thing to both children. */
.tip{display:flex;gap:9px;margin-top:10px;align-items:flex-start;font-size:12px;line-height:1.5}
.tip svg{flex:none;margin-top:calc((1.5em - 14px) / 2)}
.tip span{color:var(--ink-soft)}
.warnbox{background:#FBF3E4;border:1px solid #EBDDBE;border-radius:12px;padding:9px 13px;display:flex;gap:8px;align-items:center;margin-top:14px}
.warnbox span{font-size:11.5px;color:#7A6430;line-height:1.45}

/* map */
.mapbox{background:#fff;border:1px solid var(--line);border-radius:18px;overflow:hidden;position:relative;min-height:340px;display:flex;align-items:center;justify-content:center}
.mapframe{width:100%;height:100%;min-height:340px;border:0;display:block}
.mapoff{text-align:center;padding:28px;max-width:340px;font-size:12px;color:var(--ink-soft)}
.mapbox iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
/* The click-to-load face of the map. It fills the box rather than sitting in the middle of it, so
   the whole panel is the target and the layout does not move when the iframe replaces it. */
.mapask{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:6px;background:var(--shell-dim);color:var(--ink-soft);
  text-align:center;padding:24px;cursor:pointer}
.mapask:hover{background:var(--sand);color:var(--ink)}
.mapask b{font-size:14px;font-weight:600;color:var(--ink)}
.mapask span{font-size:11.5px;max-width:34ch}
/* Above the placeholder in the stacking order, so it stays pressable — .mapask covers the whole box
   and would otherwise sit over it. */
.mapwhy{position:absolute;bottom:12px;right:14px;z-index:1;font-size:11px;
  color:var(--ink-faint);text-decoration:underline}
.mapwhy:hover{color:var(--ink)}
.nearbylink{color:var(--seaglass);text-decoration:underline;text-underline-offset:2px}
/* The withdrawal control, over the loaded map. Deliberately quiet — it is an obligation to offer,
   not a thing to advertise — but a real button with a real hit area. */
.mapforget{position:absolute;bottom:12px;right:12px;z-index:1;font-family:inherit;font-size:11px;
  color:var(--ink-soft);background:rgba(246,241,231,.92);border:1px solid var(--line);
  border-radius:9px;padding:5px 10px;cursor:pointer}
.mapforget:hover{color:var(--ink);background:#fff}


/* The species list on a pool page. Cards are a mark and two lines of text — no photograph, because
   four species in five have none we are licensed to show. Compact enough that four fit across, and
   the row that would be ragged is hidden at that width rather than the data being cut. */
.slist{display:grid;grid-template-columns:repeat(1,1fr);gap:8px;margin-top:16px}
.scard{display:flex;align-items:center;gap:11px;background:#fff;border:1px solid var(--line);
  border-radius:13px;padding:10px 13px;min-width:0}
.scard > div{min-width:0}
.scard b{display:block;font-size:13.5px;font-weight:600;color:var(--ink);line-height:1.25;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.scard i{display:block;font-size:11px;font-style:italic;color:var(--ink-soft);margin-top:1px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* No cursor change on hover. The help cursor put a question mark over every icon on the page, which
   reads as "something is wrong here" rather than as "there is a label under this". The native title
   tooltip is the affordance; it does not need a second one. */
.mark{flex:none;width:34px;height:34px;border-radius:10px;display:flex;align-items:center;
  justify-content:center;background:var(--seaglass-pale);color:var(--seaglass-dark)}
.mark svg{width:21px;height:21px}
@media (min-width:520px){.list-1{grid-template-columns:repeat(2,1fr)}.list-1 > *{display:flex}.list-1 > *:nth-child(n+1){display:none}}
@media (min-width:760px){.list-1{grid-template-columns:repeat(3,1fr)}.list-1 > *{display:flex}.list-1 > *:nth-child(n+1){display:none}}
@media (min-width:1000px){.list-1{grid-template-columns:repeat(4,1fr)}.list-1 > *{display:flex}.list-1 > *:nth-child(n+1){display:none}}
@media (min-width:520px){.list-2{grid-template-columns:repeat(2,1fr)}.list-2 > *{display:flex}}
@media (min-width:760px){.list-2{grid-template-columns:repeat(3,1fr)}.list-2 > *{display:flex}.list-2 > *:nth-child(n+1){display:none}}
@media (min-width:1000px){.list-2{grid-template-columns:repeat(4,1fr)}.list-2 > *{display:flex}.list-2 > *:nth-child(n+1){display:none}}
@media (min-width:520px){.list-3{grid-template-columns:repeat(2,1fr)}.list-3 > *{display:flex}.list-3 > *:nth-child(n+3){display:none}}
@media (min-width:760px){.list-3{grid-template-columns:repeat(3,1fr)}.list-3 > *{display:flex}}
@media (min-width:1000px){.list-3{grid-template-columns:repeat(4,1fr)}.list-3 > *{display:flex}.list-3 > *:nth-child(n+1){display:none}}
@media (min-width:520px){.list-4{grid-template-columns:repeat(2,1fr)}.list-4 > *{display:flex}}
@media (min-width:760px){.list-4{grid-template-columns:repeat(3,1fr)}.list-4 > *{display:flex}.list-4 > *:nth-child(n+4){display:none}}
@media (min-width:1000px){.list-4{grid-template-columns:repeat(4,1fr)}.list-4 > *{display:flex}}
@media (min-width:520px){.list-5{grid-template-columns:repeat(2,1fr)}.list-5 > *{display:flex}.list-5 > *:nth-child(n+5){display:none}}
@media (min-width:760px){.list-5{grid-template-columns:repeat(3,1fr)}.list-5 > *{display:flex}.list-5 > *:nth-child(n+4){display:none}}
@media (min-width:1000px){.list-5{grid-template-columns:repeat(4,1fr)}.list-5 > *{display:flex}.list-5 > *:nth-child(n+5){display:none}}
@media (min-width:520px){.list-6{grid-template-columns:repeat(2,1fr)}.list-6 > *{display:flex}}
@media (min-width:760px){.list-6{grid-template-columns:repeat(3,1fr)}.list-6 > *{display:flex}}
@media (min-width:1000px){.list-6{grid-template-columns:repeat(4,1fr)}.list-6 > *{display:flex}.list-6 > *:nth-child(n+5){display:none}}
@media (min-width:520px){.list-7{grid-template-columns:repeat(2,1fr)}.list-7 > *{display:flex}.list-7 > *:nth-child(n+7){display:none}}
@media (min-width:760px){.list-7{grid-template-columns:repeat(3,1fr)}.list-7 > *{display:flex}.list-7 > *:nth-child(n+7){display:none}}
@media (min-width:1000px){.list-7{grid-template-columns:repeat(4,1fr)}.list-7 > *{display:flex}.list-7 > *:nth-child(n+5){display:none}}
@media (min-width:520px){.list-8{grid-template-columns:repeat(2,1fr)}.list-8 > *{display:flex}}
@media (min-width:760px){.list-8{grid-template-columns:repeat(3,1fr)}.list-8 > *{display:flex}.list-8 > *:nth-child(n+7){display:none}}
@media (min-width:1000px){.list-8{grid-template-columns:repeat(4,1fr)}.list-8 > *{display:flex}}
@media (min-width:520px){.list-9{grid-template-columns:repeat(2,1fr)}.list-9 > *{display:flex}.list-9 > *:nth-child(n+9){display:none}}
@media (min-width:760px){.list-9{grid-template-columns:repeat(3,1fr)}.list-9 > *{display:flex}}
@media (min-width:1000px){.list-9{grid-template-columns:repeat(4,1fr)}.list-9 > *{display:flex}.list-9 > *:nth-child(n+9){display:none}}
@media (min-width:520px){.list-10{grid-template-columns:repeat(2,1fr)}.list-10 > *{display:flex}}
@media (min-width:760px){.list-10{grid-template-columns:repeat(3,1fr)}.list-10 > *{display:flex}.list-10 > *:nth-child(n+10){display:none}}
@media (min-width:1000px){.list-10{grid-template-columns:repeat(4,1fr)}.list-10 > *{display:flex}.list-10 > *:nth-child(n+9){display:none}}
@media (min-width:520px){.list-11{grid-template-columns:repeat(2,1fr)}.list-11 > *{display:flex}.list-11 > *:nth-child(n+11){display:none}}
@media (min-width:760px){.list-11{grid-template-columns:repeat(3,1fr)}.list-11 > *{display:flex}.list-11 > *:nth-child(n+10){display:none}}
@media (min-width:1000px){.list-11{grid-template-columns:repeat(4,1fr)}.list-11 > *{display:flex}.list-11 > *:nth-child(n+9){display:none}}
@media (min-width:520px){.list-12{grid-template-columns:repeat(2,1fr)}.list-12 > *{display:flex}}
@media (min-width:760px){.list-12{grid-template-columns:repeat(3,1fr)}.list-12 > *{display:flex}}
@media (min-width:1000px){.list-12{grid-template-columns:repeat(4,1fr)}.list-12 > *{display:flex}}
@media (min-width:520px){.list-13{grid-template-columns:repeat(2,1fr)}.list-13 > *{display:flex}.list-13 > *:nth-child(n+13){display:none}}
@media (min-width:760px){.list-13{grid-template-columns:repeat(3,1fr)}.list-13 > *{display:flex}.list-13 > *:nth-child(n+13){display:none}}
@media (min-width:1000px){.list-13{grid-template-columns:repeat(4,1fr)}.list-13 > *{display:flex}.list-13 > *:nth-child(n+13){display:none}}
@media (min-width:520px){.list-14{grid-template-columns:repeat(2,1fr)}.list-14 > *{display:flex}}
@media (min-width:760px){.list-14{grid-template-columns:repeat(3,1fr)}.list-14 > *{display:flex}.list-14 > *:nth-child(n+13){display:none}}
@media (min-width:1000px){.list-14{grid-template-columns:repeat(4,1fr)}.list-14 > *{display:flex}.list-14 > *:nth-child(n+13){display:none}}
@media (min-width:520px){.list-15{grid-template-columns:repeat(2,1fr)}.list-15 > *{display:flex}.list-15 > *:nth-child(n+15){display:none}}
@media (min-width:760px){.list-15{grid-template-columns:repeat(3,1fr)}.list-15 > *{display:flex}}
@media (min-width:1000px){.list-15{grid-template-columns:repeat(4,1fr)}.list-15 > *{display:flex}.list-15 > *:nth-child(n+13){display:none}}
@media (min-width:520px){.list-16{grid-template-columns:repeat(2,1fr)}.list-16 > *{display:flex}}
@media (min-width:760px){.list-16{grid-template-columns:repeat(3,1fr)}.list-16 > *{display:flex}.list-16 > *:nth-child(n+16){display:none}}
@media (min-width:1000px){.list-16{grid-template-columns:repeat(4,1fr)}.list-16 > *{display:flex}}
@media (min-width:520px){.list-17{grid-template-columns:repeat(2,1fr)}.list-17 > *{display:flex}.list-17 > *:nth-child(n+17){display:none}}
@media (min-width:760px){.list-17{grid-template-columns:repeat(3,1fr)}.list-17 > *{display:flex}.list-17 > *:nth-child(n+16){display:none}}
@media (min-width:1000px){.list-17{grid-template-columns:repeat(4,1fr)}.list-17 > *{display:flex}.list-17 > *:nth-child(n+17){display:none}}
@media (min-width:520px){.list-18{grid-template-columns:repeat(2,1fr)}.list-18 > *{display:flex}}
@media (min-width:760px){.list-18{grid-template-columns:repeat(3,1fr)}.list-18 > *{display:flex}}
@media (min-width:1000px){.list-18{grid-template-columns:repeat(4,1fr)}.list-18 > *{display:flex}.list-18 > *:nth-child(n+17){display:none}}
@media (min-width:520px){.list-19{grid-template-columns:repeat(2,1fr)}.list-19 > *{display:flex}.list-19 > *:nth-child(n+19){display:none}}
@media (min-width:760px){.list-19{grid-template-columns:repeat(3,1fr)}.list-19 > *{display:flex}.list-19 > *:nth-child(n+19){display:none}}
@media (min-width:1000px){.list-19{grid-template-columns:repeat(4,1fr)}.list-19 > *{display:flex}.list-19 > *:nth-child(n+17){display:none}}
@media (min-width:520px){.list-20{grid-template-columns:repeat(2,1fr)}.list-20 > *{display:flex}}
@media (min-width:760px){.list-20{grid-template-columns:repeat(3,1fr)}.list-20 > *{display:flex}.list-20 > *:nth-child(n+19){display:none}}
@media (min-width:1000px){.list-20{grid-template-columns:repeat(4,1fr)}.list-20 > *{display:flex}}
@media (min-width:520px){.list-21{grid-template-columns:repeat(2,1fr)}.list-21 > *{display:flex}.list-21 > *:nth-child(n+21){display:none}}
@media (min-width:760px){.list-21{grid-template-columns:repeat(3,1fr)}.list-21 > *{display:flex}}
@media (min-width:1000px){.list-21{grid-template-columns:repeat(4,1fr)}.list-21 > *{display:flex}.list-21 > *:nth-child(n+21){display:none}}
@media (min-width:520px){.list-22{grid-template-columns:repeat(2,1fr)}.list-22 > *{display:flex}}
@media (min-width:760px){.list-22{grid-template-columns:repeat(3,1fr)}.list-22 > *{display:flex}.list-22 > *:nth-child(n+22){display:none}}
@media (min-width:1000px){.list-22{grid-template-columns:repeat(4,1fr)}.list-22 > *{display:flex}.list-22 > *:nth-child(n+21){display:none}}
@media (min-width:520px){.list-23{grid-template-columns:repeat(2,1fr)}.list-23 > *{display:flex}.list-23 > *:nth-child(n+23){display:none}}
@media (min-width:760px){.list-23{grid-template-columns:repeat(3,1fr)}.list-23 > *{display:flex}.list-23 > *:nth-child(n+22){display:none}}
@media (min-width:1000px){.list-23{grid-template-columns:repeat(4,1fr)}.list-23 > *{display:flex}.list-23 > *:nth-child(n+21){display:none}}
@media (min-width:520px){.list-24{grid-template-columns:repeat(2,1fr)}.list-24 > *{display:flex}}
@media (min-width:760px){.list-24{grid-template-columns:repeat(3,1fr)}.list-24 > *{display:flex}}
@media (min-width:1000px){.list-24{grid-template-columns:repeat(4,1fr)}.list-24 > *{display:flex}}
@media (min-width:520px){.list-25{grid-template-columns:repeat(2,1fr)}.list-25 > *{display:flex}.list-25 > *:nth-child(n+25){display:none}}
@media (min-width:760px){.list-25{grid-template-columns:repeat(3,1fr)}.list-25 > *{display:flex}.list-25 > *:nth-child(n+25){display:none}}
@media (min-width:1000px){.list-25{grid-template-columns:repeat(4,1fr)}.list-25 > *{display:flex}.list-25 > *:nth-child(n+25){display:none}}
@media (min-width:520px){.list-26{grid-template-columns:repeat(2,1fr)}.list-26 > *{display:flex}}
@media (min-width:760px){.list-26{grid-template-columns:repeat(3,1fr)}.list-26 > *{display:flex}.list-26 > *:nth-child(n+25){display:none}}
@media (min-width:1000px){.list-26{grid-template-columns:repeat(4,1fr)}.list-26 > *{display:flex}.list-26 > *:nth-child(n+25){display:none}}
@media (min-width:520px){.list-27{grid-template-columns:repeat(2,1fr)}.list-27 > *{display:flex}.list-27 > *:nth-child(n+27){display:none}}
@media (min-width:760px){.list-27{grid-template-columns:repeat(3,1fr)}.list-27 > *{display:flex}}
@media (min-width:1000px){.list-27{grid-template-columns:repeat(4,1fr)}.list-27 > *{display:flex}.list-27 > *:nth-child(n+25){display:none}}
@media (min-width:520px){.list-28{grid-template-columns:repeat(2,1fr)}.list-28 > *{display:flex}}
@media (min-width:760px){.list-28{grid-template-columns:repeat(3,1fr)}.list-28 > *{display:flex}.list-28 > *:nth-child(n+28){display:none}}
@media (min-width:1000px){.list-28{grid-template-columns:repeat(4,1fr)}.list-28 > *{display:flex}}
@media (min-width:520px){.list-29{grid-template-columns:repeat(2,1fr)}.list-29 > *{display:flex}.list-29 > *:nth-child(n+29){display:none}}
@media (min-width:760px){.list-29{grid-template-columns:repeat(3,1fr)}.list-29 > *{display:flex}.list-29 > *:nth-child(n+28){display:none}}
@media (min-width:1000px){.list-29{grid-template-columns:repeat(4,1fr)}.list-29 > *{display:flex}.list-29 > *:nth-child(n+29){display:none}}
@media (min-width:520px){.list-30{grid-template-columns:repeat(2,1fr)}.list-30 > *{display:flex}}
@media (min-width:760px){.list-30{grid-template-columns:repeat(3,1fr)}.list-30 > *{display:flex}}
@media (min-width:1000px){.list-30{grid-template-columns:repeat(4,1fr)}.list-30 > *{display:flex}.list-30 > *:nth-child(n+29){display:none}}
@media (min-width:520px){.list-31{grid-template-columns:repeat(2,1fr)}.list-31 > *{display:flex}.list-31 > *:nth-child(n+31){display:none}}
@media (min-width:760px){.list-31{grid-template-columns:repeat(3,1fr)}.list-31 > *{display:flex}.list-31 > *:nth-child(n+31){display:none}}
@media (min-width:1000px){.list-31{grid-template-columns:repeat(4,1fr)}.list-31 > *{display:flex}.list-31 > *:nth-child(n+29){display:none}}
@media (min-width:520px){.list-32{grid-template-columns:repeat(2,1fr)}.list-32 > *{display:flex}}
@media (min-width:760px){.list-32{grid-template-columns:repeat(3,1fr)}.list-32 > *{display:flex}.list-32 > *:nth-child(n+31){display:none}}
@media (min-width:1000px){.list-32{grid-template-columns:repeat(4,1fr)}.list-32 > *{display:flex}}
@media (min-width:520px){.list-33{grid-template-columns:repeat(2,1fr)}.list-33 > *{display:flex}.list-33 > *:nth-child(n+33){display:none}}
@media (min-width:760px){.list-33{grid-template-columns:repeat(3,1fr)}.list-33 > *{display:flex}}
@media (min-width:1000px){.list-33{grid-template-columns:repeat(4,1fr)}.list-33 > *{display:flex}.list-33 > *:nth-child(n+33){display:none}}
@media (min-width:520px){.list-34{grid-template-columns:repeat(2,1fr)}.list-34 > *{display:flex}}
@media (min-width:760px){.list-34{grid-template-columns:repeat(3,1fr)}.list-34 > *{display:flex}.list-34 > *:nth-child(n+34){display:none}}
@media (min-width:1000px){.list-34{grid-template-columns:repeat(4,1fr)}.list-34 > *{display:flex}.list-34 > *:nth-child(n+33){display:none}}
@media (min-width:520px){.list-35{grid-template-columns:repeat(2,1fr)}.list-35 > *{display:flex}.list-35 > *:nth-child(n+35){display:none}}
@media (min-width:760px){.list-35{grid-template-columns:repeat(3,1fr)}.list-35 > *{display:flex}.list-35 > *:nth-child(n+34){display:none}}
@media (min-width:1000px){.list-35{grid-template-columns:repeat(4,1fr)}.list-35 > *{display:flex}.list-35 > *:nth-child(n+33){display:none}}
@media (min-width:520px){.list-36{grid-template-columns:repeat(2,1fr)}.list-36 > *{display:flex}}
@media (min-width:760px){.list-36{grid-template-columns:repeat(3,1fr)}.list-36 > *{display:flex}}
@media (min-width:1000px){.list-36{grid-template-columns:repeat(4,1fr)}.list-36 > *{display:flex}}
@media (min-width:520px){.list-37{grid-template-columns:repeat(2,1fr)}.list-37 > *{display:flex}.list-37 > *:nth-child(n+37){display:none}}
@media (min-width:760px){.list-37{grid-template-columns:repeat(3,1fr)}.list-37 > *{display:flex}.list-37 > *:nth-child(n+37){display:none}}
@media (min-width:1000px){.list-37{grid-template-columns:repeat(4,1fr)}.list-37 > *{display:flex}.list-37 > *:nth-child(n+37){display:none}}
@media (min-width:520px){.list-38{grid-template-columns:repeat(2,1fr)}.list-38 > *{display:flex}}
@media (min-width:760px){.list-38{grid-template-columns:repeat(3,1fr)}.list-38 > *{display:flex}.list-38 > *:nth-child(n+37){display:none}}
@media (min-width:1000px){.list-38{grid-template-columns:repeat(4,1fr)}.list-38 > *{display:flex}.list-38 > *:nth-child(n+37){display:none}}
@media (min-width:520px){.list-39{grid-template-columns:repeat(2,1fr)}.list-39 > *{display:flex}.list-39 > *:nth-child(n+39){display:none}}
@media (min-width:760px){.list-39{grid-template-columns:repeat(3,1fr)}.list-39 > *{display:flex}}
@media (min-width:1000px){.list-39{grid-template-columns:repeat(4,1fr)}.list-39 > *{display:flex}.list-39 > *:nth-child(n+37){display:none}}
@media (min-width:520px){.list-40{grid-template-columns:repeat(2,1fr)}.list-40 > *{display:flex}}
@media (min-width:760px){.list-40{grid-template-columns:repeat(3,1fr)}.list-40 > *{display:flex}.list-40 > *:nth-child(n+40){display:none}}
@media (min-width:1000px){.list-40{grid-template-columns:repeat(4,1fr)}.list-40 > *{display:flex}}

/* species */
/* No grid-template-columns here: an even- class supplies it, chosen from the divisors of the number of
   items so the last row is never short. Base is two columns, which is also what a browser with no
   media-query support would land on. */
.species{display:grid;grid-template-columns:repeat(2,1fr);gap:12px;margin-top:16px}
/* Where else a species turns up. Name and region, no photograph — the page already has the species
   pictured at the top, and forty more images would bury it. Columns come from an even- class, same as
   the grids above, so this list has no short last row either. */
.poollist{display:grid;gap:8px;margin-top:16px}
.poollist a{display:block;background:#fff;border:1px solid var(--line);border-radius:13px;padding:11px 14px}
.poollist a:hover{border-color:var(--seaglass-dark)}
.poollist b{display:block;font-family:'Fraunces',Georgia,serif;font-size:15px;font-weight:400;color:var(--ink);line-height:1.25}
.poollist small{display:block;font-size:11px;color:var(--ink-soft);margin-top:3px}
.even-1{grid-template-columns:repeat(1,1fr)}
.even-2{grid-template-columns:repeat(2,1fr)}
.even-3{grid-template-columns:repeat(3,1fr)}
.even-4-2{grid-template-columns:repeat(2,1fr)}
@media (min-width:760px){.even-4-2{grid-template-columns:repeat(4,1fr)}}
.even-6-3-2{grid-template-columns:repeat(2,1fr)}
@media (min-width:580px){.even-6-3-2{grid-template-columns:repeat(3,1fr)}}
@media (min-width:1100px){.even-6-3-2{grid-template-columns:repeat(6,1fr)}}
.even-5-2{grid-template-columns:repeat(2,1fr)}
@media (min-width:940px){.even-5-2{grid-template-columns:repeat(5,1fr)}}
.even-6-4-3-2{grid-template-columns:repeat(2,1fr)}
@media (min-width:580px){.even-6-4-3-2{grid-template-columns:repeat(3,1fr)}}
@media (min-width:760px){.even-6-4-3-2{grid-template-columns:repeat(4,1fr)}}
@media (min-width:1100px){.even-6-4-3-2{grid-template-columns:repeat(6,1fr)}}
.even-5-4-2{grid-template-columns:repeat(2,1fr)}
@media (min-width:760px){.even-5-4-2{grid-template-columns:repeat(4,1fr)}}
@media (min-width:940px){.even-5-4-2{grid-template-columns:repeat(5,1fr)}}
.even-6-5-3-2{grid-template-columns:repeat(2,1fr)}
@media (min-width:580px){.even-6-5-3-2{grid-template-columns:repeat(3,1fr)}}
@media (min-width:940px){.even-6-5-3-2{grid-template-columns:repeat(5,1fr)}}
@media (min-width:1100px){.even-6-5-3-2{grid-template-columns:repeat(6,1fr)}}
.even-6-5-4-3-2{grid-template-columns:repeat(2,1fr)}
@media (min-width:580px){.even-6-5-4-3-2{grid-template-columns:repeat(3,1fr)}}
@media (min-width:760px){.even-6-5-4-3-2{grid-template-columns:repeat(4,1fr)}}
@media (min-width:940px){.even-6-5-4-3-2{grid-template-columns:repeat(5,1fr)}}
@media (min-width:1100px){.even-6-5-4-3-2{grid-template-columns:repeat(6,1fr)}}
.sp{background:#fff;border:1px solid var(--line);border-radius:14px;overflow:hidden}
.sp img{width:100%;height:88px;object-fit:cover;background:var(--seaglass-pale)}
/* Stands in for a photograph we are not licensed to show. Same height as one, so a grid of mixed
   cards stays on its rows. Tinted rather than grey, and carrying a mark, so it reads as "no
   photograph of this" rather than as an image that failed to load. */
.notile{height:88px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  background:linear-gradient(160deg,var(--seaglass-pale),#EAF1EE);color:var(--seaglass-dark)}
.notile svg{width:30px;height:30px;opacity:.62}
.notile span{font-size:9px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;opacity:.72}
.sp .body{padding:8px 10px 9px}
.sp b{font-size:11.5px;font-weight:600;color:var(--ink);display:block}
.sp i{font-style:italic;font-size:10px;color:var(--ink-faint);display:block;margin-top:1px}
.sp small{font-size:9.5px;color:var(--seaglass-dark);font-weight:600;display:block;margin-top:2px}
.credit{font-size:8.5px;color:var(--ink-faint);padding:0 10px 8px;line-height:1.35}
.credit a{text-decoration:underline}
.sectioncredit{font-size:10.5px;color:var(--ink-faint);text-align:right;margin-top:12px}
/* On the heading line instead, sharing its baseline. Baseline rather than flex-end because the two
   sit at very different sizes — 26px against 10.5px — and aligning their BOXES would leave the small
   one looking dropped. */
.sechead.credited{align-items:baseline}
.sechead.credited .sectioncredit{margin-top:0}
.sectioncredit a{text-decoration:underline}

/* season */
.season{display:flex;align-items:flex-end;gap:3px;height:44px;margin-top:10px}
.season i{flex:1;background:var(--seaglass-pale);border-radius:2px 2px 0 0;min-height:2px;display:block}
.season i.peak{background:var(--seaglass-deep)}
.seasonx{display:flex;gap:3px;margin-top:4px}
.seasonx span{flex:1;font-size:8px;color:var(--ink-faint);text-align:center}
.seasonnote{margin-top:10px;font-size:11.5px;line-height:1.5;color:var(--ink-soft)}

/* tide */
/* No margin. The column this sits in is a flex stack with gap:14px, so a margin here was added ON TOP
   of that gap and made one seam in the stack twice the size of the others. */
.tidecard{background:#fff;border:1px solid var(--line);border-radius:18px;padding:14px 16px 10px}
.tidehead{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
.tidehead b{font-size:9px;font-weight:700;letter-spacing:.09em;color:var(--ink-faint);text-transform:uppercase}
.tidesource{font-size:10.5px;color:var(--ink-faint);margin-top:6px}
.tidesource a{text-decoration:underline}
.tidenote a{color:var(--seaglass-dark);text-decoration:underline;text-underline-offset:2px}
.tidenote{font-size:11.5px;color:var(--ink-soft);line-height:1.5;margin-top:8px}
/* The triangle opening the after-dark sentence. NO COLOUR AND NO WEIGHT OF ITS OWN: the sentence
   inherits .tidenote entirely, which is the point — it was amber and bold on its own line, and a
   warning badge over a quiet note is furniture on a card this small. No [hidden] override is
   needed anywhere in this note: a span has no display of its own to beat. */
.tidenote svg{vertical-align:-2px;margin-right:4px}
/* The week, folded under the chart. A real <details>, so it opens without script; the summary is
   styled as the link it reads as, with a chevron that turns, and the default triangle is removed in
   both engines that draw one. */
.tideweek{margin-top:10px;border-top:1px solid var(--shell-dim);padding-top:8px}
.tideweek summary{list-style:none;cursor:pointer;font-size:12px;font-weight:600;color:var(--seaglass-dark);display:flex;align-items:center;gap:6px;padding:2px 0}
.tideweek summary::-webkit-details-marker{display:none}
.tideweek summary::after{content:'';width:6px;height:6px;border-right:1.6px solid currentColor;border-bottom:1.6px solid currentColor;transform:rotate(45deg);margin:-3px 0 0 2px;transition:transform .15s}
.tideweek[open] summary::after{transform:rotate(-135deg);margin-top:3px}
.weeklist{list-style:none;margin:8px 0 0;padding:0}
.weeklist li{display:grid;grid-template-columns:auto 1fr;column-gap:12px;align-items:baseline;padding:7px 0;border-bottom:1px solid var(--shell-dim);font-size:12px;color:var(--ink)}
.weeklist li[hidden],.wklow[hidden]{display:none}
.wkdate{font-weight:600}
.wklows{display:grid;row-gap:3px}
.wklow{display:grid;grid-template-columns:1fr auto 3.6em;column-gap:10px;align-items:baseline}
.wklow.dark{color:var(--ink-faint)}
.wktime{grid-column:2;font-variant-numeric:tabular-nums;text-align:right}
.wkheight{grid-column:3;font-variant-numeric:tabular-nums;text-align:right;color:var(--ink-soft)}
.wklow.dark .wkheight{color:inherit}
.wkdark{grid-column:1;font-size:10.5px;text-align:right}
.wkdark[hidden]{display:none}
.weeknote{font-size:10.5px;color:var(--ink-faint);margin-top:8px}
.weekapp{margin:12px -16px -10px;padding:14px 16px 16px;background:linear-gradient(160deg,#0E3042,#0A2434);border-radius:0 0 17px 17px}
.weekapp b{font-family:'Fraunces',Georgia,serif;font-size:17px;font-weight:400;color:var(--shell);display:block}
.weekapp ul{margin:8px 0 0;padding:0 0 0 16px;font-size:11.5px;line-height:1.6;color:rgba(246,241,231,.78)}
.weekapp .badges{margin-top:12px;gap:8px;justify-content:flex-start}
.weekapp .badge{padding:7px 12px}
/* The way out of a card that has nothing to draw, and it is a SENTENCE. It carries .tidenote as
   well, so the size, colour and leading are the note's above it and only the shore's name is a link.

   THE ONE OVERRIDE IS THE LINK'S COLOUR. .nearbylink is var(--seaglass) — #8FC3B2, chosen for the
   species card, which is navy. This card is cream, where that green is a highlighter. The dark
   seaglass is the same one every other link on a light surface uses. */
.tideelsewhere{margin-top:6px}
.tideelsewhere .nearbylink{color:var(--seaglass-dark)}
.tidechart{width:100%;height:auto;display:block;margin-top:6px}

/* cta */
.ctaband{margin-top:30px;background:linear-gradient(160deg,#0E3042,#0A2434);border-radius:20px;padding:24px 28px;display:flex;align-items:center;justify-content:space-between;gap:24px;flex-wrap:wrap}
.ctaband b{font-family:'Fraunces',Georgia,serif;font-size:21px;font-weight:400;color:var(--shell);display:block}
.ctaband p{font-size:12px;color:rgba(246,241,231,.65);margin-top:4px}

/* prose */
.prose{max-width:680px}
.prose h2{font-family:'Fraunces',Georgia,serif;font-size:22px;font-weight:400;margin-top:28px;color:var(--ink)}
.prose p{font-size:14.5px;line-height:1.7;color:var(--ink-soft);margin-top:10px}
.prose li{font-size:14.5px;line-height:1.7;color:var(--ink-soft);margin-top:8px;margin-left:18px}

/* how it works
   Four columns wide, one numbered list narrow, and the SAME ordered list either way. The numerals
   are typeset rather than generated by a counter because they are part of the design and because a
   counter cannot be styled as a different typeface from the item it labels. */
.steps{display:grid;grid-template-columns:repeat(4,1fr);gap:26px;margin-top:26px;list-style:none}
.step{border-top:2px solid var(--seaglass-pale);padding-top:14px}
.stepn{display:block;font-size:20px;color:var(--seaglass-deep);letter-spacing:.02em}
.step h3{margin-top:8px;font-size:15px;font-weight:600;color:var(--ink);line-height:1.35}
.step p{margin-top:7px;font-size:13.5px;line-height:1.65;color:var(--ink-soft)}
@media (max-width:900px){.steps{grid-template-columns:repeat(2,1fr);gap:22px}}
@media (max-width:560px){
  .steps{grid-template-columns:1fr;gap:0}
  /* A list on a phone, which is what a four-column row of steps is when it has one column. The rule
     moves to the left of each item so the numerals read as a sequence down the page rather than as
     four unrelated cards stacked. */
  .step{border-top:0;border-left:2px solid var(--seaglass-pale);padding:2px 0 18px 16px}
  .step:last-child{padding-bottom:0}
  .stepn{font-size:16px}
}

/* faq
   A details element with no script. The open state is the browser's, the marker is ours, and the
   answer is in the document whether or not anybody expands it. */
.faq{margin-top:22px;border-top:1px solid var(--line);max-width:820px}
.qa{border-bottom:1px solid var(--line)}
.qa summary{list-style:none;cursor:pointer;padding:15px 34px 15px 0;position:relative;
  font-size:15px;font-weight:600;color:var(--ink);line-height:1.45}
.qa summary::-webkit-details-marker{display:none}
.qa summary::after{content:'';position:absolute;right:8px;top:50%;width:9px;height:9px;
  border-right:2px solid var(--seaglass-deep);border-bottom:2px solid var(--seaglass-deep);
  transform:translateY(-70%) rotate(45deg);transition:transform .18s ease}
.qa[open] summary::after{transform:translateY(-30%) rotate(-135deg)}
.qa summary:hover{color:var(--seaglass-dark)}
.qa summary:focus-visible{outline:2px solid var(--seaglass-dark);outline-offset:2px}
.qa p{padding:0 34px 17px 0;font-size:14px;line-height:1.7;color:var(--ink-soft);max-width:660px}
@media (prefers-reduced-motion:reduce){.qa summary::after{transition:none}}

/* guides */
.pagelede{max-width:620px;margin-top:16px;font-size:15px;line-height:1.7;color:var(--ink-soft)}
/* Cards stretch to their row, which is the grid's own default and what this had to stop doing for a
   while. When only two of the nine carried a picture, stretching gave the other card in their row a
   hundred and fifty pixels of blank inside a bordered white box, which reads as an image that failed
   to load rather than as spacing. Every card carries one now, so the bottom edges line up and the
   difference between a long blurb and a short one is trailing white where it belongs. */
.guidegrid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;margin-top:26px}
@media (max-width:900px){.guidegrid{grid-template-columns:repeat(2,1fr)}}
@media (max-width:560px){.guidegrid{grid-template-columns:1fr;gap:14px}}
.guidecard{display:block;background:#fff;border:1px solid var(--line);border-radius:18px;
  overflow:hidden;transition:transform .15s ease,box-shadow .15s ease}
.guidecardtext{padding:22px 22px 24px}
/* The two articles that have a hero show it here. A fixed height rather than the file's own ratio,
   because three cards across a row have to agree about where their headings start — one card
   setting its own height would push the row and leave the other two with a strip of white. */
.guidecardimg{display:block;width:100%;height:150px;object-fit:cover}
.guidecard:hover{transform:translateY(-2px);box-shadow:0 12px 28px -12px rgba(11,42,58,.28)}
.guidecard h3{font-size:19px;font-weight:400;color:var(--ink);line-height:1.3}
.guidecard p{margin-top:9px;font-size:13.5px;line-height:1.65;color:var(--ink-soft)}
/* guide photographs
   The hero sits between the lede and the first heading and is cropped to a letterbox, because these
   are square-ish species photographs and a 3:2 crop is what stops one filling the screen before a
   word of the article is visible. Section figures keep their own shape. */
.guidehero{margin-top:22px}
.guidehero img{display:block;width:100%;height:clamp(220px,34vw,340px);object-fit:cover;
  border-radius:18px}
/* EVERY PHOTOGRAPH HERE IS LANDSCAPE, which is what lets this be three lines.
   It was not always: two came back portrait, and a portrait photograph at the full width of a 680 px
   column is over a thousand pixels tall and swallows the article. That was handled by capping the
   height and centring the image on a pale ground, which showed a strip of that ground down each side
   and read as a mistake. The files are cropped to a band now (see guidePhotos.mjs), so there is
   nothing to letterbox and no ground to show. */
.guidefig{margin-top:18px}
/* height:auto is load-bearing. The width and height ATTRIBUTES are presentational hints, so
   height="683" is a CSS height of 683px unless an author rule says otherwise, and every other image
   on this site sets an explicit height in CSS — which is why the attributes never bit before. */
.guidefig img{display:block;width:100%;height:auto;border-radius:14px}
/* The credit, under its own photograph and against the right edge, which is where a caption of this
   kind sits and is out of the way of the prose returning underneath it. */
.figcredit{margin-top:7px;font-size:10.5px;color:var(--ink-faint);text-align:right;line-height:1.6}
.figcredit a{text-decoration:underline}
/* The tide window card, borrowed from the phone mock on the home page and shown at four times the
   size it was drawn for. Only the two labels above the chart need resetting: everything inside the
   SVG is in user units and scales with the viewBox, which is why this is six lines and not thirty.
   The pale ground is what stops a white card on a cream page reading as a hole. */
.guidescene{background:var(--seaglass-pale);border-radius:18px;padding:clamp(18px,4vw,34px);
  display:flex;justify-content:center}
.guidescene .ptide{width:100%;max-width:520px;padding:16px 18px 12px;border-radius:16px}
.guidescene .plabel{font-size:10px}
.guidescene .pnow{font-size:11px}
.guidescene .ptide svg{margin-top:9px}
/* Inside a card the chart is back at roughly its phone size, so the mock's own type sizes are right
   and only the box needs setting. Height matches .guidecardimg so a row of cards agrees.

   THE MAX-WIDTH IS WHAT KEEPS IT INSIDE THAT HEIGHT. The chart is a fixed 340:118 viewBox scaled to
   whatever width it is given, so its height is a function of the card's width — and a card is at its
   WIDEST in the one-column layout, where a full-bleed chart came out taller than the 150px box and
   was clipped by the card's own overflow. Capping the width caps the height; the chart then centres
   in the ground instead of overflowing it, which is what it already did on a three-column row.

   The arithmetic, so the next person can redo it rather than guess: the chart is 15px of vertical
   padding plus the head and its margin plus the SVG, which is (max-width - 20) x 118/340. At a cap of
   340 that lands at 145 in a 150 box, measured. The slack is deliberate — 352 also fits, at exactly
   149, and a cap that depends on a label's line-height not changing is not a cap. */
.guidecardscene{background:var(--seaglass-pale);height:150px;padding:0 16px;
  display:flex;align-items:center;justify-content:center}
.guidecardscene .ptide{width:100%;max-width:340px}
.crumb{font-size:13px;margin-bottom:14px}
.crumb a{color:var(--seaglass-dark);font-weight:600}
.prose p.lead{margin-top:14px;font-size:16.5px;line-height:1.65;color:var(--ink)}
.morelink{margin-top:14px;font-size:14px}
.morelink a{color:var(--seaglass-dark);font-weight:600;border-bottom:1.5px solid rgba(62,122,102,.32);padding-bottom:2px}
.morelink a:hover{border-bottom-color:var(--seaglass-dark)}
/* The shore cards inside an article sit in a 680px column, so three across would be 210px wide.
   Two, and the prose column widens to hold them. */
.prose .tightgrid{grid-template-columns:repeat(2,1fr);margin-top:18px}
@media (max-width:560px){.prose .tightgrid{grid-template-columns:1fr}}
/* The guide links a pool page carries — under its tide card and at the foot of its advice panel. */
/* A guide link sitting inside a sentence rather than in a row of its own. This replaced
   the old .guidelinks rule, a paragraph of links under the whole panel — deleted with the function
   that drew it, rather than kept warm for a layout nothing asks for any more.
   UNDERLINED, which the row of links was not, because .tidenote a is the site's existing idiom for
   a link inside a sentence and that is what these now are. Standing alone under a panel, colour and
   weight were enough to read as a link; trailing a line of body copy they are not.
   white-space:nowrap keeps a two-word title from breaking across the line it is trailing.
   In the warning box the green would be a third colour in an amber panel, so it borrows that
   panel's ink a shade darker: still plainly a link against #7A6430 body text, still in key. */
.inlineguide{color:var(--seaglass-dark);font-weight:600;text-decoration:underline;
  text-underline-offset:2px;white-space:nowrap}
.warnbox .inlineguide{color:#6B5520}
.guidelist{list-style:none;margin-top:6px}
.guidelist li{margin-left:0}
.guidelist a{color:var(--seaglass-dark);font-weight:600}
.inlinelink{color:var(--seaglass-dark);font-weight:600;text-decoration:underline;text-underline-offset:2px}
.printhead{display:none}
.printbtn{margin-top:14px;font:inherit;font-size:13px;font-weight:600;color:var(--seaglass-dark);background:none;
  border:1.5px solid var(--seaglass-dark);border-radius:999px;padding:7px 16px;cursor:pointer}
.printbtn[hidden]{display:none}
/* Printing the checklist alone: print.js sets .print-one on <html> for the length of the dialog.
   Everything that neither is, holds nor sits inside .printable is taken out of the layout, so the
   sheet is one page rather than the article's length in blank paper. White and black, for ink. */
@media print{
  html.print-one body *:not(.printable):not(:has(.printable)):not(.printable *){display:none}
  html.print-one body,html.print-one main,html.print-one .section,html.print-one .wrap{background:#fff;padding:0;margin:0;max-width:none}
  html.print-one .printable{color:#000}
  html.print-one .printable>p:not(.printhead),html.print-one .printbtn{display:none}
  html.print-one .printhead{display:block;font-size:11px;color:#555;margin-bottom:8px}
  html.print-one .guidechecklist li{font-size:14px;margin-bottom:12px;color:#000}
  html.print-one .guidechecklist li::before{border-color:#000}
}
.guidechecklist{list-style:none;margin-top:12px}
.guidechecklist li{position:relative;margin-left:0;padding-left:30px}
.guidechecklist li::before{content:'';position:absolute;left:0;top:4px;width:15px;height:15px;
  border:1.5px solid var(--seaglass-dark);border-radius:4px}

/* footer */
.foot{background:var(--ocean-deep);padding:34px 0;margin-top:20px}
.foot .wrap{display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap}
.foot .brand span{font-size:15px}
.foot p,.foot a{font-size:11.5px;color:rgba(246,241,231,.5)}
.foot a{text-decoration:underline}
.attrib{font-size:11px;color:rgba(246,241,231,.42);line-height:1.6;margin-top:14px}
.attrib a{color:rgba(246,241,231,.62)}
