/* =============================================================================
   WATERLOGGED - the consumer Daily River Watch.

   Ported from the owner-approved mock-ups in docs/ui_candidates/opus/. The base
   is sailing_weather_demo.html's stylesheet, which is sailing.html's with the
   licensed weather module added; index.html's and map.html's own rules follow,
   each scoped to its page class (body.p-home, body.p-map) because the three
   pages disagree about shared selectors -- the front door sets a narrower
   .wrap than the watch page, and an unscoped concatenation would hand every
   page whichever value happened to come last.

   Four class names changed on the way across, and only these four. They carried
   words the owner has banned from this product's voice, and a class name
   reaches the rendered page:
       .card   -> .stopbox      .gap (the staff's missing water) -> .void
       .strip  -> .riverrow     .rstrip / .strip-lede -> .wxgauge / .wxlede
   Everything else - every size, colour, breakpoint and comment - is the
   approved file's own.
   ============================================================================= */

/* ============================================================================
   WATERLOGGED — consumer sailing page (Opus candidate, rev 2)
   Self-contained mockup. No build step, no server, no network.
   ========================================================================== */

:root{
  --paper:#F6F3ED;
  --card:#FFFFFF;
  --navy:#1F3864;          /* brand */
  --ink:#16233D;
  --ink-2:#4A5568;
  --rule:#DBD4C6;
  --rule-2:#EDE7DA;
  --amber:#C8641B;         /* logo marker orange, used as a plain accent */

  /* ---- the signal ladder ------------------------------------------------ */
  --red:#A4232B;          --red-bg:#FCF1F0;        /* severely low          */
  --orange:#A9530D;       --orange-bg:#FDF3E8;     /* concerning            */
  --green:#1B6B45;        --green-bg:#F0F6F1;      /* clear                 */
  --grey:#5E6B7E;         --grey-bg:#F1EFEA;       /* no official data                       */
  /* lock-controlled reaches. The hue is --water-b, which the map pin for a lock-held stop
     already uses, so the tile, the chip and the pin agree without a new colour being coined. */
  --lock:#2F6193;         --lock-bg:#EDF3F9;       /* lock-controlled                       */
  /* days the ship does not sail. An earth tone, chosen so it reads as "not the river" rather
     than as another rung of the water ladder: every other status colour on this page is a
     verdict about water, and this one has to say there is none. */
  --land:#8A6F4E;         --land-bg:#F7F4EF;       /* not sailing (land or hotel day)       */
  /* days we hold no river transit for. Off the water ladder as well, and a different family
     from the earth tone above it, because the two must not read as shades of one status: one
     says the ship is ashore, the other says only that no stretch of river is being read. */
  --port:#6B5F8C;         --port-bg:#F4F2F8;       /* in port, no transit on record         */
  /* a real stretch of river that we watch no gauge on. It stays ON the water ladder's side of
     the palette -- a cool slate-blue, deliberately a neighbour of --grey rather than of --lock
     -- because this day IS on the river and its answer is an absence of OUR reading, not an
     absence of water. It must not read as a shade of the lock blue: that is the claim it exists
     to withdraw. */
  --nog:#4A5A66;          --nog-bg:#EEF1F3;        /* no gauge of ours on this stretch      */

  --slate:#5E6B7E;
  --water-a:#6E9EC6;
  --water-b:#2F6193;
  --focus:#0B63CE;

  --serif:Georgia,"Iowan Old Style","Palatino Linotype","Times New Roman",serif;
  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;

  --shadow:0 1px 2px rgba(22,35,61,.06),0 6px 18px rgba(22,35,61,.06);
  --pad:clamp(14px,3.2vw,26px);
}

/* Larger-text control: one class on <html>, everything is in rem. */
html{font-size:17px;-webkit-text-size-adjust:100%}
html.bigtext{font-size:20px}

*,*::before,*::after{box-sizing:border-box}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--sans);font-size:1rem;line-height:1.55;
  -webkit-font-smoothing:antialiased;
}
h1,h2,h3,h4{font-family:var(--serif);font-weight:700;line-height:1.18;margin:0;color:var(--navy)}
p{margin:0 0 .6em}
a{color:var(--navy)}
a:focus-visible,button:focus-visible,select:focus-visible{
  outline:3px solid var(--focus);outline-offset:2px;border-radius:3px}
.num{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
.sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.wrap{max-width:940px;margin:0 auto;padding:0 var(--pad)}

/* DEMONSTRATION STATE ONLY. This file is a mock-up of the licensed-weather
   future; the ribbon is the first thing on the page, on screen and on paper,
   so no screenshot of it can circulate without the caveat attached. */

/* ---------------------------------------------------------------- header */
/* CHANGE 1 — the owner's own artwork, not a recreation: logo-lockup.png,
   cropped to content with the light-blue smudge below the ship painted out.
   78 px tall (56 on a phone) so the full "Waterlogged River Cruise Watch"
   reads and the header still sits on one line. */
.topbar{background:var(--card);border-bottom:1px solid var(--rule)}
/* vertical padding only — the shorthand used to reset .wrap's gutter to 0,
   which left the header flush to the screen edge (invisible on outline pills,
   obvious once the map button became a filled block of colour) */
.topbar-in{display:flex;align-items:center;gap:16px;flex-wrap:wrap;padding-top:15px;padding-bottom:15px}
.brand{display:flex;align-items:center;gap:13px;text-decoration:none;flex:0 0 auto}
/* The <picture> that offers the WebP is a wrapper, not a box: display:contents removes it from
   layout entirely so the <img> stays the direct flex child of .brand (and of .lockup .brandmark on the
   home page), and adding the WebP source changed no geometry anywhere. */
.brand-pic{display:contents}
.brand-mark{display:block;height:58px;width:auto}
/* THE WORDMARK IS TEXT, and it has to be, because the box it used to live in could not grow.
   It was an <svg viewBox="0 0 246 64"> with two <text> lines set at font-size:27 USER UNITS in
   the stack below. 246 is not a design decision, it is a measurement of ONE font: "RIVER CRUISE
   WATCH" in Arial Narrow Bold at 27px is 245.9px wide, so the artwork fitted its box with a
   tenth of a pixel to spare -- and an outermost <svg> clips at its viewBox (the UA stylesheet
   puts overflow:hidden on svg:root). Every other font in the fallback chain sets that line
   wider, so on every device that has no Arial Narrow the name was cut off mid-word. Measured
   from the real font files at the same 27px: Arial Narrow 245.9, Segoe UI 282.6, Arial 300.0,
   Tahoma 308.7, Verdana 341.4 -- and Arial Narrow ships on Windows and macOS but NOT on iOS or
   Android, which is most of the readership. The second cause is the same arithmetic from the
   other side: a reader who has turned up the system text size scales the 27 user units too, so
   even a machine WITH Arial Narrow overflowed 246 once the scale factor passed 1.0. Neither
   cause is a width or a media query, which is why it truncated at every window size.

   Real text has the property the old box did not: it is as wide as the words in whatever font
   actually arrives, and when there is no room for it, it wraps instead of being cut. The two
   lines set at the same size, family and colour as the drawn ones, so on a machine with Arial
   Narrow this is the same masthead to the pixel -- 24.47px = 27 x 58/64 is the size the drawn
   wordmark rendered at, and 1.1852 = 32/27 is the gap its two baselines were set with. The
   copy is in ordinary case and dressed uppercase, so a screen reader says the name rather than
   spelling it and the markup carries the brand in its canonical spelling. */
.brand-words{display:block;min-width:0;
  font-family:"Arial Narrow","Helvetica Neue",Helvetica,Arial,sans-serif;
  font-weight:700;font-size:24.47px;line-height:1.1852;color:var(--navy);
  text-transform:uppercase;letter-spacing:0}
.brand-words span{display:block}
@media(max-width:700px){.brand-mark{height:46px}.brand-words{font-size:19.41px}}

/* ---------------------------------------------------------------- the strapline */
/* The owner's tagline, beside the wordmark. It is the third thing this header says, after the
   mark and the name, and it is dressed to stay third: the serif face against the wordmark's
   bold sans, a step down in size, and --slate rather than --navy. Quiet, not competing.

   The layout rule is that the strapline yields and the tools row never does. .brandline makes
   the lockup and the strapline ONE flex item of .topbar-in, so the strapline is not a third
   sibling bidding against .topbar-tools for the line -- but that on its own is not enough, and
   the map page proved it: a flex line is broken on each item's HYPOTHETICAL size, before any
   shrinking is worked out, so a .brandline whose natural width included the strapline pushed
   the tools onto a second row at 900px, where they had always fitted. Measured, not reasoned
   about: the header went 89px -> 149px.

   `flex-basis:min-content` is the fix. It makes the size .topbar-in breaks the line on the
   width of the lockup ALONE -- the strapline is allowed to wrap, so it contributes nothing to
   the minimum -- which is the same number the old markup contributed, so the tools wrap at
   exactly the width they wrapped at before this line existed, at every text size and on both
   sides of the 700px lockup breakpoint. `flex-grow:1` then hands .brandline the free space the
   tools are not using, which is where the strapline is set. The 294px basis in front of it is
   the same measurement for browsers too old to take an intrinsic keyword there; they fall back
   to a fixed number rather than to a broken header.

   So: room for it beside the wordmark and it sits beside the wordmark, in space that was empty,
   costing the header no height at all. No room and it drops under the wordmark, and the tools
   row above it does not move.

   22ch is the measure, and it is measured rather than chosen: the tightest of the two headers
   is the map's, whose "Back to my day-by-day" button leaves 227px beside the wordmark at a
   1280px window, and this sets the line in two inside that with about 20px to spare. The spare
   is the point. At 24ch it fitted by two pixels here and did not fit in a second browser, whose
   buttons set a few pixels wider -- the header was correct in both, but it was deciding between
   two different shapes on a rounding error, and a masthead should not do that. Two lines are
   40px against the lockup's 58px, so the strapline sits inside the header's existing height and
   the header stays exactly 89px tall -- the number it was before any of this.

   Two gaps, not one: 13px beside the wordmark, which is the lockup's own spacing, and 6px above
   the strapline when it has dropped under it. The row gap is only ever spent in the narrow case,
   and in the narrow case every pixel of header is a pixel of map. */
.brandline{display:flex;align-items:center;gap:6px 13px;flex-wrap:wrap;min-width:0;
  flex:1 1 294px;flex-basis:min-content}
.brand-tag{margin:0;font-family:var(--serif);line-height:1.32;color:var(--slate)}
.brandline .brand-tag{font-size:.9rem;max-width:22ch;flex:0 1 auto}
/* The two-line measure is what the INLINE case needs. Under 1000px neither header has room
   beside the wordmark any more, so the strapline is going underneath it whatever happens, and
   underneath it there is a whole row: it sets as one line at its natural width instead of a
   two-line column, which is 20px of header handed back -- and on the map page 20px of header
   is 20px of map. The tools row is unaffected either way, because .brandline is measured for
   line-breaking on the lockup alone. */
@media(max-width:999px){.brandline .brand-tag{max-width:none}}

.topbar-tools{margin-left:auto;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.tool{font:inherit;font-size:.90rem;font-weight:600;background:var(--paper);border:1.5px solid var(--rule);
  color:var(--navy);padding:8px 15px;border-radius:999px;cursor:pointer;text-decoration:none;
  display:inline-flex;align-items:center;gap:7px;min-height:44px}
.tool:hover{border-color:var(--navy)}
.tool[aria-pressed="true"]{background:var(--navy);color:#fff;border-color:var(--navy)}
/* The row's primary action. Same amber family as the front page's
   "Show my sailing", so one colour means one thing across the product;
   the other two stay quiet pills. */
.tool.cta{background:var(--amber);border-color:var(--amber);color:#fff;font-weight:800;
  box-shadow:0 2px 0 #9E4E12}
.tool.cta:hover{background:#B45815;border-color:#B45815;color:#fff}
.tool.cta svg{display:block;flex:0 0 auto}

/* ---------------------------------------------------------------- your sailing */
.sailing{background:var(--navy);color:#fff;padding:22px 0 24px}
.sailing h1{color:#fff;font-size:clamp(1.4rem,4vw,1.9rem);margin:2px 0 6px}
.kicker{font-size:.70rem;letter-spacing:.19em;text-transform:uppercase;font-weight:700;color:#A9C0E0;margin:0 0 4px}
.sailing-meta{font-size:1rem;color:#DEE7F3;margin:0}
.sailing-meta strong{color:#fff}
.sailing-row{display:flex;gap:18px;align-items:flex-end;flex-wrap:wrap}
.sailing-row>div:first-child{flex:1 1 340px}
.btn-change{font:inherit;font-size:.92rem;font-weight:700;background:transparent;color:#fff;border:2px solid #7E9DC6;
  padding:10px 16px;border-radius:8px;cursor:pointer;white-space:nowrap}
.btn-change:hover{border-color:#fff;background:rgba(255,255,255,.10)}
.picker{display:none;margin-top:16px;background:#FFFFFF;color:var(--ink);border-radius:10px;padding:16px}
.picker.open{display:block}
.picker label{display:block;font-size:.76rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--slate);margin-bottom:5px}
.picker select{width:100%;font:inherit;font-size:1rem;padding:11px 10px;border:2px solid var(--rule);border-radius:7px;background:#fff;color:var(--ink)}
.picker .btn-go{font:inherit;font-weight:700;background:var(--amber);color:#fff;border:0;padding:12px 18px;border-radius:7px;cursor:pointer;font-size:1rem}
/* The unconfirmed-vessel sentence. It sits INSIDE the dark masthead, above the as-of line and
   below the ship name it is about, because the claim it qualifies is the title. Amber rule on
   the leading edge so it reads as a caveat rather than as more of the meta line; wraps and
   never scrolls, so it survives a 390 px screen. */
.unconfirmed{font-size:.92rem;line-height:1.5;color:#E7EEF7;margin:14px 0 0;max-width:74ch;
  border-left:3px solid var(--amber);padding:2px 0 2px 12px;overflow-wrap:anywhere}
.unconfirmed strong{color:#fff}
.asof{font-size:.92rem;color:#B9CBE4;margin:14px 0 0}

/* ---------------------------------------------------------------- answer strip */
.answer{margin:22px 0 6px}
/* the daily masthead: the date is rendered from the same TODAY_ISO the as-of
   line and the horizon arithmetic use, so the three can never disagree. */
.watch-head{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;
  padding:0 0 9px;margin:0 0 13px;border-bottom:2px solid var(--navy)}
.watch-title{font-family:var(--serif);font-weight:700;color:var(--navy);margin:0;
  font-size:clamp(1.45rem,4.2vw,1.95rem);letter-spacing:-.012em;line-height:1.1}
.watch-date{margin:0;font-size:.95rem;font-weight:700;letter-spacing:.05em;color:var(--slate)}
@media(max-width:560px){.watch-head{gap:3px}.watch-date{flex:1 1 100%}}
.answer h3{font-size:clamp(1.1rem,2.9vw,1.3rem);margin-bottom:10px}
.answer h3 .clarifier{font-weight:400;color:var(--slate);font-size:.93em}
.counts{display:grid;gap:11px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));list-style:none;padding:0;margin:0}
.count{background:var(--card);border:2px solid var(--rule);border-left-width:11px;border-radius:10px;padding:13px 14px;box-shadow:var(--shadow)}
.count b{display:block;font-family:var(--serif);font-size:2.3rem;line-height:1;letter-spacing:-.02em}
.count span{display:block;font-size:.92rem;font-weight:600;margin-top:5px;color:var(--ink)}
.count.sev{border-left-color:var(--red)}    .count.sev b{color:var(--red)}
.count.con{border-left-color:var(--orange)} .count.con b{color:var(--orange)}
.count.clr{border-left-color:var(--green)}  .count.clr b{color:var(--green)}
/* lock-controlled reaches: their own tile, in the blue the map pin already uses for them.
   They used to be added to the green "clear" total, which reported two unlike things as one. */
.count.lock{border-left-color:var(--lock)}  .count.lock b{color:var(--lock)}
.count.non{border-left-color:var(--grey)}   .count.non b{color:var(--grey)}
/* not sailing: drawn only where the itinerary has such a day, so this rule is absent from
   most pages rather than printing a zero nobody asked about. */
.count.land{border-left-color:var(--land)}  .count.land b{color:var(--land)}
/* in port, no transit on record: its own tile, because until tonight these days were added to
   the lock-controlled total on the left and are usually the larger part of it. */
.count.port{border-left-color:var(--port)}  .count.port b{color:var(--port)}
/* a real stretch of river with no gauge of ours on it: its own tile, because until tonight these
   days were added to the lock-controlled total as well, and on a lower-Danube sailing they were
   all of it. */
.count.nog{border-left-color:var(--nog)}    .count.nog b{color:var(--nog)}

/* ---------------------------------------------------------------- key */
/* CHANGE 3 — the description of each signal sits UNDER its badge, smaller. */
/* OWNER CHANGE (item 27): every description now sits DIRECTLY UNDER its own
   count chip. The key list runs on exactly the same grid geometry as .counts
   — four equal columns, the same 11 px gap, the same outer width — so the two
   rows line up to the pixel. Both "Clear" entries stack inside the clear
   column. The card chrome comes off the key so its columns are not inset from
   the counts above; a rule keeps the separation the card used to give. The
   badges and the text are set smaller so a column holds them without ragged
   wrapping. */
.key{margin:15px 0 4px;background:transparent;border:0;border-top:1px solid var(--rule);
  border-radius:0;padding:13px 0 0}
.key h3{font-size:.98rem;margin-bottom:10px}
/* the SAME track template and gap as .counts, on a block of the same width:
   the columns therefore land on the same x-positions at every screen size */
.key ul{list-style:none;margin:0;padding:0;display:grid;gap:11px;
  grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}
.key li{display:block;min-width:0}
/* the "no line published" and "no reading yet" entries stack in the same column: they share
   one count tile, because neither can be measured against a line today */
.key .ke+.ke{margin-top:12px}
.key-foot{margin:11px 0 0;font-size:.79rem;line-height:1.45;color:var(--slate)}
.key-foot strong{color:var(--ink)}
.key .chip{margin-bottom:5px;font-size:.79rem;letter-spacing:.035em;padding:6px 9px;gap:6px}
.key em{font-style:normal;color:var(--slate);font-size:.79rem;line-height:1.4;display:block}
.key em strong{color:var(--ink)}
/* mobile: one column, and each count chip is followed by its own description.
   The two lists share one flex context so the pairs can interleave. */
@media(max-width:560px){
  .answer{display:flex;flex-direction:column;gap:11px}
  .answer .counts,.answer .key,.answer .key ul{display:contents}
  .answer .watch-head{order:1}
  .answer>h3{order:2}
  /* the rain-check one-liner shares the heading's order slot, so DOM order
     alone decides the tie and no existing order number has to move */
  .answer>.rain-check{order:2}
  .key h3{order:3;margin:4px 0 0;padding-top:12px;border-top:1px solid var(--rule)}
  .count.sev{order:4}  .k-sev{order:5}
  .count.con{order:6}  .k-con{order:7}
  .count.clr{order:8}  .k-clr{order:9}
  .count.lock{order:10} .k-lock{order:11}
  .count.non{order:12} .k-non{order:13}
  /* the ninth state pairs after the two no-reading entries and before the two no-river ones,
     which is where watch.view.CATEGORY_ORDER puts it; the two below it shift by two slots. */
  .count.nog{order:14} .k-nog{order:15}
  .count.port{order:16} .k-port{order:17}
  .count.land{order:18} .k-land{order:19}
}

/* ---------------------------------------------------------------- signal chip */
.chip{display:inline-flex;align-items:center;gap:7px;font-weight:800;font-size:.88rem;letter-spacing:.05em;
  text-transform:uppercase;padding:7px 12px;border-radius:6px;border:2px solid;white-space:nowrap}
.chip .g{font-size:1.08em;line-height:1}
.chip.sev{background:var(--red);border-color:var(--red);color:#fff}
.chip.con{background:var(--orange-bg);border-color:var(--orange);color:var(--orange)}
.chip.clr{background:var(--green-bg);border-color:var(--green);color:var(--green)}
.chip.lock{background:var(--lock-bg);border-color:var(--lock);color:var(--lock)}
.chip.non{background:var(--grey-bg);border-color:var(--grey);color:var(--grey)}
.chip.land{background:var(--land-bg);border-color:var(--land);color:var(--land)}
.chip.port{background:var(--port-bg);border-color:var(--port);color:var(--port)}
.chip.nog{background:var(--nog-bg);border-color:var(--nog);color:var(--nog)}

/* ------------------------------------------------------- forward outlook */
.outlook{margin:22px 0 0;background:var(--card);border:1px solid var(--rule);border-top:6px solid var(--amber);
  border-radius:10px;padding:15px var(--pad);box-shadow:var(--shadow)}
.outlook h2{font-size:clamp(1.08rem,2.9vw,1.28rem);margin-bottom:5px}
.outlook-lede{font-size:.92rem;color:var(--ink-2);max-width:66ch;margin:0 0 13px}
/* one tight line of per-gauge reports; wraps on a phone, and the
   "(PDF, German)" qualifier is stated once for the row rather than per link */

/* ---------------------------------------------------------------- timeline */
.voyage{margin:26px 0 10px}
.voyage>h2{font-size:clamp(1.2rem,3.2vw,1.45rem)}
.voyage>.lede{color:var(--ink-2);font-size:.94rem;max-width:62ch;margin:.4em 0 18px}

.stop{display:grid;grid-template-columns:104px 1fr;align-items:stretch}
@media(max-width:640px){.stop{grid-template-columns:74px 1fr}}

.rail{position:relative;padding:0 14px 0 0}
.rail::before{content:"";position:absolute;top:0;bottom:-1px;left:50%;width:4px;margin-left:-2px;background:#CFD8E6;border-radius:2px}
.stop:first-of-type .rail::before{top:34px}
.stop:last-of-type .rail::before{bottom:auto;height:34px}
.daytag{position:relative;z-index:1;margin:14px auto 0;width:100%;max-width:86px;text-align:center;
  background:var(--navy);color:#fff;border-radius:7px;padding:7px 4px;box-shadow:var(--shadow)}
.daytag .d{display:block;font-size:.64rem;letter-spacing:.17em;text-transform:uppercase;color:#A9C0E0;font-weight:700}
.daytag .n{display:block;font-family:var(--serif);font-size:1.3rem;line-height:1.1;font-weight:700}
@media(max-width:640px){.daytag{max-width:60px}.daytag .n{font-size:1.12rem}}

/* CHANGE 4 — day boxes keep every field; the type is a step smaller throughout. */
.stopbox{background:var(--card);border:1px solid var(--rule);border-left:9px solid var(--grey);
  border-radius:10px;padding:15px var(--pad);margin:13px 0;box-shadow:var(--shadow)}
.stopbox.sev{border-left-color:var(--red);background:linear-gradient(90deg,var(--red-bg),var(--card) 42%)}
.stopbox.con{border-left-color:var(--orange)}
.stopbox.clr{border-left-color:var(--green)}
.stopbox.lock{border-left-color:var(--lock)}
.stopbox.non{border-left-color:var(--grey)}
.stopbox.land{border-left-color:var(--land)}
.stopbox.port{border-left-color:var(--port)}
.stopbox.nog{border-left-color:var(--nog)}

.stopbox-head{display:flex;gap:14px;align-items:flex-start;flex-wrap:wrap;margin-bottom:12px}
.ttl{flex:1 1 220px;min-width:0}
.city{font-size:clamp(1.25rem,3.4vw,1.6rem);letter-spacing:-.005em}
.when{font-size:.9rem;color:var(--ink-2);margin:2px 0 0;font-weight:600}
.when .cty{color:var(--slate);font-weight:400}
.sig{flex:0 1 250px;margin-left:auto;min-width:175px}
.sig-note{font-size:.81rem;color:var(--slate);line-height:1.42;margin:5px 0 0}
.sig-note strong{color:var(--ink)}
@media(max-width:560px){.sig{margin-left:0;flex:1 1 100%}}

/* -------- the reading: staff + figures ---------------------------------- */
.reading{display:flex;gap:clamp(13px,2.8vw,22px);align-items:flex-start;flex-wrap:wrap}
.staff-col{flex:0 0 auto;text-align:center}
.staff{position:relative;width:70px;height:194px;border:2px solid var(--navy);border-radius:5px;background:#fff}
.staff-in{position:absolute;inset:0;overflow:hidden;border-radius:3px}
.ticks{position:absolute;inset:0;
  background-image:repeating-linear-gradient(to top,transparent 0 18px,rgba(31,56,100,.16) 18px 19px)}
.water{position:absolute;left:0;right:0;bottom:0;background:linear-gradient(180deg,var(--water-a),var(--water-b));
  border-top:3px solid #1D4E7C}
/* the missing water, drawn as an absence */
.void{position:absolute;left:0;right:0;
  background-image:repeating-linear-gradient(45deg,rgba(164,35,43,.30) 0 5px,rgba(164,35,43,.07) 5px 11px)}
.void.con{background-image:repeating-linear-gradient(45deg,rgba(169,83,13,.32) 0 5px,rgba(169,83,13,.08) 5px 11px)}
.mark{position:absolute;left:-9px;right:-9px;height:0;z-index:2}
/* CHANGE 3 — the line the ship needs is a dotted black rule, the same
   language the graph now uses. */
.mark-req{border-top:4px dotted #111}
.mark-typ{border-top:3px dotted #6A7686;right:46%}
.mark-ctx{border-top:2px solid #98A3B3;right:22%}
/* OWNER CHANGE — the board carries its own figures, printed against the lines
   they mark: the level measured now at the water surface, the line this ship
   needs, the normal-for-the-date line, and any published reference marks. Each
   value is the same field the table beside the board prints; nothing here is
   derived. Ten-pixel type, the smallest the page sets, and never below nine.
   A white halo — the board's own background — keeps a figure readable where it
   sits over the hatching. Figures sit at the right edge, which the normal and
   reference rules stop short of. A figure whose neighbour is too close moves to
   the left edge and drops under its own rule, so neither is ever left floating
   away from the line it names. */
.slbls{position:absolute;inset:0;z-index:3;pointer-events:none}
.slbl{position:absolute;right:4px;font-size:10px;line-height:11px;font-weight:800;
  font-variant-numeric:tabular-nums;white-space:nowrap;
  text-shadow:0 0 3px #fff,0 0 2px #fff,1px 0 0 #fff,-1px 0 0 #fff,0 1px 0 #fff,0 -1px 0 #fff}
.slbl.sl-l{left:4px;right:auto}
.slbl .u{font-style:normal;font-weight:inherit}
.sl-now{color:var(--water-b)}
.sl-req{color:#111}
.sl-typ,.sl-ctx{color:var(--slate)}
@media(max-width:600px){.slbl .u{display:none}}
@media(max-width:430px){.slbl{font-size:9px;right:3px}.slbl.sl-l{left:3px}}
.staff-cap{font-size:.74rem;letter-spacing:.09em;text-transform:uppercase;color:var(--slate);font-weight:700;margin-top:8px}

.figs{flex:1 1 300px;min-width:250px}
.verdict{font-family:var(--serif);font-size:clamp(1.5rem,4.6vw,2.05rem);line-height:1.06;margin:0 0 3px;letter-spacing:-.015em}
.verdict.sev{color:var(--red)} .verdict.con{color:var(--orange)}
.verdict.clr{color:var(--green)} .verdict.non{color:var(--grey)} .verdict.lock{color:var(--lock)}
.verdict-sub{font-size:.94rem;color:var(--ink);margin:0 0 12px;font-weight:600}

table.rows{width:100%;border-collapse:collapse;margin:0 0 11px}
table.rows th,table.rows td{text-align:left;padding:7px 0;border-bottom:1px solid var(--rule-2);vertical-align:baseline}
table.rows th{font-weight:600;font-size:.92rem;color:var(--ink);padding-right:12px;overflow-wrap:anywhere}
table.rows td{text-align:right;font-weight:800;font-size:1.06rem;white-space:nowrap}
table.rows tr:last-child th,table.rows tr:last-child td{border-bottom:0}
.sw{display:inline-block;width:24px;height:0;vertical-align:middle;margin-right:8px}
.sw-now{border-top:8px solid var(--water-b);border-radius:1px}
.sw-req{border-top:4px dotted #111}
.sw-typ{border-top:3px dotted #6A7686}

/* CHANGE 6 — the arrow dominates; the caveat shrinks under it. */
.trend{display:flex;align-items:flex-start;gap:11px;margin:0 0 12px}
.trend .arrow{font-size:2.4rem;line-height:.86;font-weight:900;color:var(--red);flex:0 0 auto;
  text-shadow:0 1px 0 rgba(164,35,43,.25)}
.trend.flat .arrow{color:var(--slate);text-shadow:none;font-size:2rem}
.trend.flat .val b{color:var(--slate)}
.trend.up .arrow{color:var(--green);text-shadow:0 1px 0 rgba(27,107,69,.25)}
.trend .val{display:block;font-size:1.04rem;font-weight:800;color:var(--ink);line-height:1.28}
.trend .val b{color:var(--red);font-weight:800}
.trend.up .val b{color:var(--green)}
.trend .why{display:block;font-size:.76rem;color:var(--slate);font-weight:400;line-height:1.38;margin-top:2px}

/* CHANGE 5 — the seasonal mini-graph: measured to today, then the historical
   same-date average carried on to 31 October, with the cruise window shaded */
/* OWNER CHANGE (item 25): the graph runs the FULL width of the card and is
   drawn bigger (about half as tall again on a wide screen). Its written
   description moved out of the column beside it and into the pop-out bubble
   opened by the small button underneath. */
.spark{margin:13px 0 0;padding-top:12px;border-top:1px solid var(--rule-2);display:block}
.spark-fig{width:100%}
.spark svg{display:block;width:100%;max-width:none;height:auto}
.spark-more{margin:10px 0 0}
.spark-more .wlterm-btn{display:inline-flex;align-items:center;gap:8px;font-size:.85rem;font-weight:700;
  color:var(--navy);background:#fff;border:1.5px solid var(--rule);border-radius:999px;
  padding:8px 14px;min-height:38px;text-decoration:none;cursor:pointer}
.spark-more .wlterm-btn:hover{border-color:var(--navy);background:var(--paper)}
.spark-more .wlterm-btn .ic{font-size:1.05em;line-height:1;color:var(--amber)}
.spark-key{list-style:none;display:flex;flex-wrap:wrap;gap:5px 15px;margin:9px 0 0;padding:0;
  font-size:.78rem;color:var(--ink-2);line-height:1.3}
.spark-key li{display:flex;align-items:center;gap:7px}
/* The stamped caption under a map-page graph that drew BfG's layer. The watch page's own copy is
   an <li> inside .spark-key and needs none of this; the map page has no key list to sit in. */
/* .wlsn-cap shares the look but NOT the class: bfg-fc-cap is an excision marker the BfG
   isolation proof strips, and the WLSN key is our own line, not BfG content. */
p.bfg-fc-cap,p.eur-fc-cap,p.wlsn-cap{display:flex;align-items:center;gap:7px;margin:8px 0 0;
  font-size:.78rem;color:var(--ink-2);line-height:1.3}
.k{width:26px;flex:0 0 auto;display:inline-block;height:0}
.k-now{border-top:3px solid #2F6193}
.k-hist{border-top:3px dashed #7A8494}
/* BfG's forecast layers in the seasonal graph: their green, as their own panel draws it. The
   14-day swatch is a line because that product draws as a line; the 6-week swatch is a block
   because that product draws as whole-week blocks, and the legend should look like the layer.
   DASHED, because the line it names is. BfG's green and the measured blue were measured against
   each other rather than eyeballed: #1B6B45 has a relative luminance of 0.112 and #2F6193 has
   0.113, which is a contrast ratio of 1.01:1 -- the same grey. A reader with no colour vision, or
   anybody printing this page in black and white, had two solid strokes of nearly equal weight
   (2.2 and 2.6) and nothing else to tell a forecast from a measurement. So the graph now keeps
   one rule a reader can learn: solid is measured, broken is not. This swatch follows its line. */
.k-bfg{border-top:3px dashed #1B6B45}
.k-bfg-wk{height:11px;border-radius:2px;background:rgba(27,107,69,.14);
  border:1px solid rgba(27,107,69,.42)}
/* EuRIS's prediction layer: the page's amber accent, drawn solid exactly as the line is drawn.
   Solid rather than dashed because these predictions run three to five days on a 125-day frame,
   and a dashed line that short reads as debris rather than as a line; the colour is what tells it
   apart from BfG's green and the measured blue. That last clause was checked rather than assumed
   when BfG's layers were dashed above, and it holds: #C8641B against the measured #2F6193 is a
   luminance ratio of 1.63:1, and under both red-blind and green-blind simulation the two sit
   about 120 to 160 apart in sRGB, where BfG's green sat under 80. Amber and blue survive the loss
   of colour on lightness alone; green and blue did not. EuRIS and BfG never draw on one graph. */
.k-eur{border-top:3px solid #C8641B}
/* Bolded with the rule it stands for: the WLSN line on the graph is 2.6 units heavy, and a
   legend swatch lighter than its line would name the wrong drawing. */
.k-req{border-top:4px dotted #111}
.k-short{height:13px;border-radius:2px;border:1px solid rgba(164,35,43,.38);
  background:repeating-linear-gradient(45deg,rgba(164,35,43,.32) 0 4px,rgba(164,35,43,.08) 4px 9px)}

/* OWNER CHANGE — the writing inside the graph, on a phone. The graph is drawn
   on a 520-unit canvas and stretched to whatever width the card gives it; on a
   375-pixel screen that is about 258 pixels, so the 10-unit type inside it was
   landing at under 5 real pixels. These sizes are in the same canvas units, so
   at that half-size they come out near 10 real pixels. The y-axis numbers stop
   at 18: the gutter they hang in is 33 units wide and a larger size would push
   "300" off the left edge of the canvas, where it would be cut off. Nothing
   here applies above 560 pixels, so the desktop graph is unchanged.
   The two nudges buy the room the larger type needs, in canvas units:
   TODAY and YOUR CRUISE sit on a baseline 18 units down, which at this size
   left the tops of the capitals above the edge of the canvas and cut off, so
   they drop 4 units into the empty band above the plot; the y-axis numbers
   rise 4 so the zero clears the "1 Jul" beneath it, which lands them on their
   own gridlines. */
/* Scoped off the mobile VARIANT on purpose. Everything above is a correction applied
   after the fact to a drawing solved for a 520-unit canvas; the phone variant is solved
   for its own canvas on the server (watch.graph.MOBILE_*), and applying both would be
   correcting a drawing that was already right. */
@media(max-width:560px){
  body:not(.mob) .spark svg text.gx-xax{font-size:20px}
  body:not(.mob) .spark svg text.gx-today,body:not(.mob) .spark svg text.gx-cruise{font-size:19px;transform:translateY(4px)}
  body:not(.mob) .spark svg text.gx-need{font-size:18px}
  body:not(.mob) .spark svg text.gx-yax{font-size:18px;transform:translateY(-4px)}
}

.record{background:#FFF8E8;border:1px solid #E8D6A8;border-radius:7px;padding:9px 11px;font-size:.87rem;margin:0 0 10px}
.record b{color:#7A4A08}
.stretch{font-size:.87rem;color:var(--ink-2);margin:0 0 10px}

.prov{font-size:.83rem;color:var(--slate);margin:0;line-height:1.5;overflow-wrap:anywhere}
.tag{display:inline-block;background:#EFEDE7;border:1px solid var(--rule);border-radius:4px;
  padding:2px 7px;font-size:.79rem;font-weight:700;color:var(--ink-2);letter-spacing:.02em}

/* CHANGE 7 — the official-forecast guidance is a pop-out bubble, shut by default */
.btn-guide{display:flex;align-items:center;gap:11px;width:100%;justify-content:flex-start;
  background:#FDFBF6;border:1.5px solid var(--rule);border-left:6px solid var(--amber);
  border-radius:9px;padding:11px 13px;font:inherit;font-weight:700;font-size:.92rem;
  color:var(--navy);cursor:pointer;margin-top:13px;text-align:left}
.btn-guide:hover{background:#FAF4E9;border-color:var(--amber)}
.btn-guide .ic{font-size:1.15rem;line-height:1;flex:0 0 auto}
.btn-guide .pop{margin-left:auto;color:var(--amber);font-size:1.1rem;flex:0 0 auto}
.btn-guide .who{font-weight:600;color:var(--slate)}

dialog.guide{border:0;padding:0;border-radius:16px;max-width:min(640px,94vw);width:100%;
  box-shadow:0 20px 64px rgba(22,35,61,.38);color:var(--ink);background:var(--card)}
dialog.guide::backdrop{background:rgba(22,35,61,.58)}
.guide-head{background:var(--navy);color:#fff;padding:16px 20px;display:flex;gap:14px;align-items:flex-start;
  border-radius:16px 16px 0 0}
.guide-head h3{color:#fff;font-size:1.16rem;margin:0}
.guide-head .where{display:block;font-family:var(--sans);font-size:.8rem;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:#A9C0E0;margin-bottom:5px}
.guide-close{margin-left:auto;flex:0 0 auto;background:transparent;border:2px solid #7E9DC6;color:#fff;
  width:40px;height:40px;border-radius:999px;font-size:1.15rem;line-height:1;cursor:pointer;font-family:var(--sans)}
.guide-close:hover{background:rgba(255,255,255,.14);border-color:#fff}
.guide-body{padding:18px 20px 22px;max-height:min(64vh,560px);overflow:auto}
.guide-body .pub{font-size:.86rem;color:var(--slate);margin:0 0 12px}
.guide-body .pub-sub{display:inline-block;margin-top:4px;font-weight:700;color:var(--ink-2)}
.guide-body p{font-size:.97rem;margin:0 0 .7em}
.guide-body mark{background:#FBE9C9;padding:0 3px;border-radius:2px;font-weight:700;color:var(--ink)}
.btn-out{display:inline-flex;align-items:center;gap:9px;background:var(--navy);color:#fff;text-decoration:none;
  font-weight:700;font-size:.98rem;padding:12px 17px;border-radius:8px;margin-top:8px}
.btn-out:hover{background:#16294A}
.guide-body .second{display:inline-block;margin-top:10px;font-size:.92rem;font-weight:600}
.horizon{display:inline-block;font-size:.74rem;font-weight:800;letter-spacing:.1em;text-transform:uppercase;
  background:#FDF6EC;color:#8A4A0D;border:1.5px solid #D9A46A;border-radius:5px;padding:4px 9px;margin:0 0 12px}
.guide-links{display:flex;flex-wrap:wrap;gap:9px;margin-top:10px}
.btn-out.alt{background:#fff;color:var(--navy);border:2px solid var(--rule)}
.btn-out.alt:hover{border-color:var(--navy);background:var(--paper)}
.howto{margin:16px 0 0;padding:14px 15px;background:var(--paper);border:1px solid var(--rule);border-radius:9px}
.howto h4{font-family:var(--sans);font-size:.72rem;letter-spacing:.15em;text-transform:uppercase;color:var(--slate);margin:0 0 6px}
.howto-lead{font-size:.9rem;color:var(--ink-2);margin:0 0 10px}
.eng{margin-top:11px;border:1.5px solid var(--rule);border-radius:8px;background:var(--card)}
.eng>summary{cursor:pointer;list-style:none;padding:11px 13px;font-weight:800;font-size:.95rem;color:var(--navy);display:flex;align-items:center;gap:9px}
.eng>summary::-webkit-details-marker{display:none}
.eng>summary::after{content:"\25be";margin-left:auto;color:var(--amber);font-size:1.05rem}
.eng[open]>summary::after{content:"\25b4"}
.eng>summary:hover{background:var(--paper)}
.eng>p{padding:0 13px;font-size:.94rem}
.eng>p:last-child{padding-bottom:12px}
.eng-sub{font-size:.8rem;color:var(--slate);font-style:italic}
.howto .tr{margin:11px 0 0;font-size:.9rem}
.guide-links.secondary{margin-top:12px}
.guide-body .checked{font-size:.8rem;color:var(--slate);margin:12px 0 0}

/* -------- lock-held panel ------------------------------------------------ */
.held{display:flex;gap:15px;align-items:center;flex-wrap:wrap}
.held svg{flex:0 0 auto}
.held-text{flex:1 1 250px}
.held-text p{margin:0 0 .4em;font-size:.94rem}
.held-text .big{font-family:var(--serif);font-size:clamp(1.2rem,3.2vw,1.42rem);color:var(--green);margin-bottom:.2em}
/* The land-day panel reuses the held panel's layout and overrides its one green claim: that
   sentence is the lock finding, and this day has no finding about water to state. */
.held.land .big{color:var(--land)}
/* and the in-port panel the same way: its own sentence is not a finding about water either. */
.held.port .big{color:var(--port)}
/* and the not-gauged panel the same way: its sentence is a statement about our instruments,
   not a finding about the water, so it must not wear the green the lock finding wears. */
.held.nog .big{color:var(--nog)}
.held-text .fine{color:var(--slate);font-size:.85rem;margin-top:.5em}
/* Everything under that green sentence, one native disclosure down: what holds the level, the
   table, the fine print and the authority's guidance. Same arrow idiom as .eng and .bfg-more --
   the browser's own marker dropped and a caret drawn in its place -- but sized as a modest line
   rather than a full-width bar, because it sits inside the panel's own column. */
.held-more{margin:.2em 0 0}
.held-more>summary{cursor:pointer;list-style:none;display:inline-flex;align-items:center;gap:8px;
  font-weight:700;font-size:.9rem;color:var(--navy);padding:4px 0}
.held-more>summary::-webkit-details-marker{display:none}
.held-more>summary::after{content:"\25be";color:var(--amber);font-size:1.05rem}
.held-more[open]>summary::after{content:"\25b4"}
.held-more[open]>summary{margin-bottom:.35em}

/* -------- the day's sailing information ---------------------------------- */

/* -------- lock-stop status table ------------------------------------------ */
table.held-rows{margin:10px 0 4px;max-width:420px}
table.held-rows th{font-size:.88rem;font-weight:600}
table.held-rows td{font-size:.95rem}
table.held-rows td.ok{color:var(--green);font-weight:800}
table.held-rows td.txt{font-weight:600;color:var(--ink-2);white-space:normal;text-align:right}

/* -------- cruising spacer ------------------------------------------------ */
.cruise{color:var(--slate);font-size:.89rem;padding:13px 0 13px var(--pad);font-style:italic}

/* ------------------------------------------------------------- rain & the river */
/* Sol's rain component, adapted to this page's furniture. Everything is scoped
   under .rain-module so none of it leaks: her .chip and .foot would otherwise
   collide with the signal chips and the page footer. */
.rain-module{background:var(--card);border:1px solid var(--rule);border-top:7px solid var(--navy);
  border-radius:10px;margin:26px 0 0;box-shadow:var(--shadow);overflow:hidden}
.rain-module .rain-head{padding:var(--pad);display:flex;gap:18px;align-items:flex-start;
  flex-wrap:wrap;border-bottom:1px solid var(--rule-2)}
.rain-module .rain-title{flex:1 1 440px}
.rain-module .rain-title h2{font-size:clamp(1.2rem,3.2vw,1.45rem);margin-bottom:6px}
.rain-module .rain-title p{color:var(--ink-2);font-size:.94rem;max-width:66ch;margin:0}
.rain-module .rain-chip{display:inline-flex;align-items:center;gap:7px;font-weight:800;font-size:.86rem;
  letter-spacing:.05em;text-transform:uppercase;padding:7px 12px;border-radius:6px;
  border:2px solid var(--water-b);background:#EDF4FA;color:var(--navy);white-space:nowrap}
.rain-module .rain-chip .drop{font-size:1.05em;color:var(--water-b)}
.rain-module .rain-body{padding:var(--pad)}

.rain-module .forecast-box{border:1px solid #E6D3A3;border-left:7px solid var(--amber);
  border-radius:9px;background:#FFF9EC;padding:15px 16px}
.rain-module .forecast-row{display:flex;align-items:center;gap:18px;flex-wrap:wrap}
.rain-module .forecast-copy{flex:1 1 400px}
.rain-module .forecast-copy h3{font-size:1.1rem;margin-bottom:5px}
.rain-module .forecast-copy p{font-size:.92rem;color:var(--ink-2);margin:0;max-width:62ch}
/* the amber family the header CTA and the front page's "Show my sailing" use */
.rain-module .rain-cta{display:inline-flex;align-items:center;justify-content:center;gap:9px;
  font:inherit;font-weight:800;font-size:1rem;background:var(--amber);color:#fff;
  border:2px solid var(--amber);padding:12px 18px;border-radius:9px;min-height:44px;
  text-decoration:none;line-height:1.3;box-shadow:0 2px 0 #9E4E12}
.rain-module .rain-cta:hover{background:#B45815;border-color:#B45815;color:#fff}
.rain-module .city-links{list-style:none;padding:0;margin:14px 0 0;display:flex;gap:8px;flex-wrap:wrap}
.rain-module .city-links a{display:inline-flex;align-items:center;gap:6px;min-height:44px;
  padding:8px 12px;border:1.5px solid var(--rule);border-radius:7px;background:#fff;
  color:var(--navy);text-decoration:none;font-weight:700;font-size:.88rem}
.rain-module .city-links a:hover{border-color:var(--navy);background:var(--grey-bg)}
.rain-module .city-links .arr{color:var(--amber)}
.rain-module .licence-note{font-size:.8rem;color:var(--slate);margin:11px 0 0}
.rain-module .licence-note strong{color:var(--ink)}

.rain-module .rain-sec{padding-top:22px;margin-top:22px;border-top:1px solid var(--rule-2)}
.rain-module .rain-sec h3{font-size:clamp(1.08rem,2.9vw,1.28rem);margin-bottom:6px}
.rain-module .rain-sec>.rain-lede{color:var(--ink-2);font-size:.93rem;max-width:66ch}

.rain-module .river-path{display:grid;grid-template-columns:repeat(5,1fr);gap:0;list-style:none;
  padding:0;margin:16px 0 0;border:1px solid var(--rule);border-radius:9px;overflow:hidden;background:#FDFCF9}
.rain-module .river-path li{position:relative;padding:13px 12px 14px;border-right:1px solid var(--rule);min-height:104px}
.rain-module .river-path li:last-child{border-right:0}
.rain-module .river-path li:not(:last-child)::after{content:"\2192";position:absolute;right:-12px;top:34px;
  z-index:1;width:23px;height:23px;border-radius:50%;background:var(--navy);color:#fff;
  text-align:center;line-height:21px;font-weight:800}
.rain-module .river-path b{display:block;font-family:var(--serif);color:var(--navy);font-size:.98rem;margin-bottom:4px}
.rain-module .river-path span{display:block;font-size:.81rem;line-height:1.4;color:var(--slate)}

.rain-module .plain-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:13px;margin-top:16px}
.rain-module .plain-stopbox{border:1px solid var(--rule);border-radius:8px;padding:13px 14px;background:#FDFCF9}
.rain-module .plain-stopbox h4{font-size:1rem;margin-bottom:6px}
.rain-module .plain-stopbox p{font-size:.9rem;margin:0;color:var(--ink-2)}
.rain-module .plain-stopbox strong{color:var(--ink)}

.rain-module .half-life-wrap{margin-top:17px;overflow-x:auto;border:1px solid var(--rule);border-radius:9px}
.rain-module .half-life{width:100%;border-collapse:collapse;min-width:600px;background:#fff}
.rain-module .half-life caption{text-align:left;padding:12px 14px;background:var(--navy);color:#fff;
  font-family:var(--serif);font-weight:700;font-size:1rem}
.rain-module .half-life th,.rain-module .half-life td{padding:11px 13px;text-align:left;
  vertical-align:top;border-bottom:1px solid var(--rule-2)}
.rain-module .half-life thead th{font-size:.76rem;letter-spacing:.08em;text-transform:uppercase;
  color:var(--slate);background:#F7F5F0}
.rain-module .half-life tbody th{font-family:var(--serif);color:var(--navy);font-size:.98rem;width:22%}
.rain-module .half-life tbody tr:last-child th,.rain-module .half-life tbody tr:last-child td{border-bottom:0}
.rain-module .fit{display:block;font-family:var(--serif);font-size:1.2rem;font-weight:700;color:var(--ink)}
.rain-module .src{display:block;margin-top:4px;color:var(--slate);font-size:.68rem;line-height:1.34;overflow-wrap:anywhere}
.rain-module .table-note{font-size:.8rem;color:var(--slate);margin:9px 2px 0}
.rain-module .table-note strong{color:var(--ink)}

.rain-module .rules{counter-reset:rule;list-style:none;padding:0;margin:15px 0 0;display:grid;gap:11px}
.rain-module .rules li{counter-increment:rule;display:grid;grid-template-columns:42px 1fr;column-gap:12px;
  padding:13px 14px;border:1px solid var(--rule);border-radius:9px;background:#FDFCF9}
.rain-module .rules li::before{content:counter(rule);grid-row:1 / span 2;display:flex;align-items:center;
  justify-content:center;width:38px;height:38px;border-radius:7px;background:var(--navy);color:#fff;
  font-family:var(--serif);font-size:1.2rem;font-weight:700}
.rain-module .rule-sentence{font-weight:700;margin:0;color:var(--ink);line-height:1.48;font-size:.95rem}
.rain-module .rule-source{font-size:.71rem;color:var(--slate);margin:5px 0 0;line-height:1.38;overflow-wrap:anywhere}

.rain-module .caution{margin-top:17px;padding:14px 16px;border:1px solid #E5C9C9;
  border-left:7px solid var(--red);border-radius:9px;background:var(--red-bg)}
.rain-module .caution h4{font-size:1.04rem;color:var(--red);margin-bottom:6px}
.rain-module .caution p{font-size:.93rem;margin-bottom:.5em}
.rain-module .closing{margin:22px 0 0;padding:14px 16px;border-left:8px solid var(--amber);
  border-radius:8px;background:var(--paper);font-family:var(--serif);
  font-size:clamp(1.02rem,2.6vw,1.18rem);font-weight:700;color:var(--navy)}
.rain-module .rain-foot{border-top:1px solid var(--rule);padding:17px var(--pad) 20px;
  font-size:.82rem;color:var(--slate);background:#FBFAF7}
.rain-module .rain-foot p{margin:0;max-width:76ch}

@media(max-width:760px){
  .rain-module .river-path{grid-template-columns:1fr}
  .rain-module .river-path li{min-height:0;border-right:0;border-bottom:1px solid var(--rule);padding-left:16px}
  .rain-module .river-path li:last-child{border-bottom:0}
  .rain-module .river-path li:not(:last-child)::after{content:"\2193";right:auto;left:50%;top:auto;bottom:-12px;margin-left:-11px}
}
@media(max-width:600px){
  .rain-module .plain-grid{grid-template-columns:1fr}
  .rain-module .rules li{grid-template-columns:36px 1fr;padding:12px 11px;column-gap:10px}
  .rain-module .rules li::before{width:34px;height:34px}
  .rain-module .rain-cta{width:100%}
}

/* ------------------------------------------------ LICENSED STATE: rain strips */
/* One row per gauge that matters to this sailing. The bars are the licensed
   forecast's rain; the sentence under them is OUR reading of what rain that
   size has historically done to THIS gauge. The two are kept visibly apart —
   different type, different weight — because only the first is anybody's
   forecast and the second is a statement about the past. */
.rain-module .rain-stamp{margin:0 0 2px;font-size:.86rem;color:var(--ink-2)}
.rain-module .rain-stamp .clock{font-weight:700;color:var(--ink)}
.rain-module .rain-chip{white-space:normal;text-align:left;line-height:1.3;max-width:22rem}

.rain-module .wxlede{display:flex;gap:12px;align-items:baseline;flex-wrap:wrap;
  margin:0 0 14px;padding-bottom:11px;border-bottom:1px solid var(--rule-2)}
.rain-module .wxlede h3{font-size:clamp(1.08rem,2.9vw,1.28rem);margin:0}
.rain-module .wxlede .scale-note{font-size:.8rem;color:var(--slate);margin:0}

.rain-module .wxgauge{border:1px solid var(--rule);border-radius:9px;background:#FDFCF9;
  padding:13px 14px 12px;margin:0 0 11px}
.rain-module .wxgauge:last-of-type{margin-bottom:0}
.rain-module .rs-head{display:flex;gap:10px;align-items:baseline;flex-wrap:wrap;margin-bottom:10px}
.rain-module .rs-head h4{font-size:1.04rem;margin:0;color:var(--navy)}
.rain-module .rs-where{font-family:var(--sans);font-size:.8rem;font-weight:400;color:var(--slate)}
.rain-module .rs-head .chip{margin-left:auto;font-size:.72rem;padding:4px 8px;letter-spacing:.04em}

/* the bar strip and its total sit side by side; the total is the one number a
   reader takes away, so it gets its own box rather than a caption */
.rain-module .rs-body{display:flex;gap:16px;align-items:stretch;flex-wrap:wrap}
.rain-module .rs-chart{flex:1 1 320px;min-width:0}
.rain-module .rs-bars{position:relative;display:flex;align-items:flex-end;gap:3px;height:62px;
  padding:0;margin:0;border-bottom:2px solid #C6BDAC}
.rain-module .rs-bars .b{flex:1 1 0;min-width:0;border-radius:2px 2px 0 0;background:var(--water-a)}
.rain-module .rs-bars .b.wet{background:var(--water-b)}
.rain-module .rs-bars .b.dry{background:#E2DCCE;height:3px}
/* the shared 10 mm reference, so six strips at one scale can be read against
   each other without counting pixels */
.rain-module .rs-ref{position:absolute;left:0;right:0;bottom:83.3%;height:0;
  border-top:1px dashed #B4AA98;pointer-events:none}
.rain-module .rs-ref span{position:absolute;right:0;top:-15px;font-size:.66rem;color:var(--slate);
  background:#FDFCF9;padding:0 3px;letter-spacing:.02em}
.rain-module .rs-axis{display:flex;justify-content:space-between;margin:5px 0 0;
  font-size:.68rem;color:var(--slate);letter-spacing:.03em}
.rain-module .rs-cap{margin:3px 0 0;font-size:.68rem;color:var(--slate);font-style:italic;letter-spacing:.02em}
.rain-module .rs-total{flex:0 0 auto;min-width:132px;display:flex;flex-direction:column;
  justify-content:center;text-align:right;border-left:1px solid var(--rule);padding-left:15px}
@media(max-width:560px){
  .rain-module .rs-total{border-left:0;border-top:1px solid var(--rule);
    padding-left:0;padding-top:9px;text-align:left;min-width:0;flex:1 1 100%}
}
.rain-module .rs-total b{display:block;font-family:var(--serif);font-size:1.5rem;line-height:1.05;color:var(--navy)}
.rain-module .rs-total small{display:block;font-size:.72rem;color:var(--slate);line-height:1.35;margin-top:4px}

/* the interpretation: this is the product. It is set larger than the numbers
   above it because it is the sentence a passenger actually uses. */
.rain-module .rs-read{margin:12px 0 0;padding:11px 13px;background:#fff;border:1px solid var(--rule-2);
  border-left:5px solid var(--water-b);border-radius:0 7px 7px 0;
  font-size:.95rem;line-height:1.55;color:var(--ink)}
.rain-module .rs-read b{color:var(--navy)}
.rain-module .rs-tag{margin:7px 0 0;font-size:.72rem;color:var(--slate);line-height:1.4}
/* the data-status line: provider, the moment we fetched the forecast, and the days it
   covers. It sits with the figures it describes rather than in the footer, because a
   reader deciding what a total means is looking at the total, not at the small print. */
.rain-module .rs-status{margin:7px 0 0;font-size:.72rem;color:var(--slate);line-height:1.4}
.rain-module .rs-foot{margin:14px 0 0;font-size:.84rem;color:var(--ink-2);line-height:1.55;max-width:76ch}
.rain-module .rs-foot strong{color:var(--ink)}

/* ------------------------------------------- LICENSED STATE: sky + daily high */
/* Two more rows a day, sitting directly above that gauge's rain bars. The grid
   geometry is deliberately identical to the bars below it — fourteen equal
   columns, 3 px gutter — so day 4's cloud sits over day 4's bar with no
   arithmetic. The sky symbol is derived in JS from the same millimetre the bar
   is drawn from, so the two can never disagree. */
.rain-module .rs-wxcap{margin:0 0 3px;font-size:.68rem;color:var(--slate);
  font-style:italic;letter-spacing:.02em}
.rain-module .rs-wx{display:grid;grid-template-columns:repeat(14,minmax(0,1fr));
  gap:3px;margin:0 0 8px}
/* WAS overflow:hidden. That was a guard on the daily high, which is the only thing in here that
   can outgrow its column, and it is kept as a guard on the daily high below -- same cap, same
   clipping, same result on the page. It comes off the column itself because the month tag has
   to be allowed out: "Aug" does not fit a 13.9 px column at 320 px and it is not going to. */
.rain-module .rs-wx .d{min-width:0;display:flex;flex-direction:column;
  align-items:center;gap:1px;overflow:visible}
.rain-module .wxi{display:block;flex:0 0 auto;
  width:clamp(11px,1.02vw,14px);height:clamp(11px,1.02vw,14px)}
.rain-module .wxi-sun,.rain-module .wxi-part{color:var(--amber)}
.rain-module .wxi-cloud{color:var(--water-b)}
.rain-module .rs-wx .t{font-size:clamp(.55rem,1.45vw,.68rem);line-height:1.15;
  color:var(--ink-2);font-variant-numeric:tabular-nums;letter-spacing:-.02em;
  white-space:nowrap;max-width:100%;overflow:hidden;text-align:center}

/* ---------------------------------------------- the date at the head of every column */
/* The owner's order was that the fourteen days say which days they are. Two lines, above the
   sky symbol, so a column reads down like a calendar entry: weekday, date, sky, daily high.

   THE WIDTH IS THE WHOLE PROBLEM. At 320 px with "Make text larger" on, a column is 13.9 px and
   the day number at .55rem is about 10 px of it. Two letters of weekday at .5rem is about 11 px.
   Both fit. Three letters of month do not fit and never will, so the month is NOT in the flow:
   it is printed under the number, out of flow, only on the days that need it, where it is free
   to be wider than its own column because the line it sits on is empty in every other column.
   That is why `.d` gives up overflow:hidden above.

   The 3 px gutter is untouched, and no padding or border is added to `.d`, so a day's symbol
   still sits exactly over that day's bar -- the constraint the phone rules below are written to. */
.rain-module .rs-wx .dl{position:relative;width:100%;display:flex;flex-direction:column;
  align-items:center;line-height:1.12;padding-bottom:clamp(.52rem,1.35vw,.64rem)}
/* -.03em is not decoration. "Mo" is the widest of the seven and at 320 px with larger text on it
   comes out 0.9 px wider than its own column; the tracking takes that back, so no weekday letter
   reaches into the 3 px gutter its neighbour is drawn from. */
.rain-module .rs-wx .dw{font-size:clamp(.5rem,1.3vw,.62rem);color:var(--slate);
  letter-spacing:-.03em;white-space:nowrap}
.rain-module .rs-wx .dn{font-size:clamp(.55rem,1.45vw,.68rem);font-weight:700;color:var(--navy);
  font-variant-numeric:tabular-nums;letter-spacing:-.02em;white-space:nowrap}
/* The month, on the day the month changes and on the first day drawn. Centred on its own column
   and allowed to spill into the empty line either side of it; pinned inside the row at the two
   ends, where spilling would put type outside the drawing. */
.rain-module .rs-wx .dm{position:absolute;bottom:0;left:50%;transform:translateX(-50%);
  white-space:nowrap;font-size:clamp(.5rem,1.3vw,.62rem);font-weight:700;color:var(--navy);
  letter-spacing:.01em;line-height:1}
.rain-module .rs-wx .d:first-child .dm{left:0;transform:none}
.rain-module .rs-wx .d:last-child .dm{left:auto;right:0;transform:none}
/* And the change of month drawn as well as written, so the eye sees the break before it reads
   the word. Out of flow, in the gutter, costing the columns nothing. */
.rain-module .rs-wx .mstart:not(:first-child) .dl::before{content:"";position:absolute;
  left:-2px;top:0;bottom:0;border-left:1px solid #B4AA98}
/* The reader's own sailing days, where any of them fall inside the fortnight. Navy at the same
   weight the seasonal graph shades its cruise band with, so the two drawings on one page mean
   the same thing by the same colour -- and deliberately not any of the status colours, because
   nothing in this module is a status. */
.rain-module .rs-wx .sail .dl{background:rgba(31,56,100,.11);border-radius:3px}
.rain-module .sail-note{margin:0;font-size:.8rem;color:var(--ink-2);line-height:1.45}
.rain-module .sail-note b{color:var(--navy)}

/* the ports with no river signal: same fourteen days, weather only, set lighter
   than a gauge row because there is no river reading underneath it */
.rain-module .wx-only{margin:15px 0 0;padding:13px 15px 12px;
  border:1px dashed var(--rule);border-radius:9px;background:#FBFAF7}
.rain-module .wx-only h4{font-size:1rem;margin:0 0 5px}
.rain-module .wx-lede{font-size:.84rem;color:var(--ink-2);line-height:1.55;
  margin:0 0 11px;max-width:76ch}
.rain-module .wx-lede strong{color:var(--ink)}
.rain-module .wxrow{display:flex;gap:14px;align-items:center;
  padding:7px 0;border-top:1px solid var(--rule-2)}
.rain-module .wxrow:first-of-type{border-top:0;padding-top:1px}
.rain-module .wxrow-name{flex:0 0 152px;min-width:0;font-family:var(--serif);
  color:var(--navy);font-size:.95rem;line-height:1.25}
.rain-module .wxrow-name .w{display:block;font-family:var(--sans);font-size:.71rem;
  font-weight:400;color:var(--slate);line-height:1.35;margin-top:1px}
.rain-module .wxrow .rs-wx{flex:1 1 250px;margin:0}
.rain-module .wx-foot{margin:9px 0 0;font-size:.7rem;color:var(--slate);
  font-style:italic;letter-spacing:.02em}
/* On a phone the port name goes above its own fourteen days. The 3 px gutter is
   NOT tightened here: it has to stay identical to the bars' gutter or a day's
   sky would sit fractionally off its own bar. At 375 px this leaves a ~17.8 px
   column holding a ~13 px "31°" at 9.35 px type — legible, and all fourteen
   days keep both their symbol and their number.

   Re-measured after the dates went in, in Chrome, "Make text larger" on and
   every fold open. 390 px: an 18.85 px column, "We" 13.98, "12" 12.22, "32°"
   15.36. 320 px: a 13.88 px column, "We" 13.98 — hence the -.03em on .dw above
   — "12" 12.22, and "32°" still capped at the column as it always was. The
   month tag is the one thing wider than a column, and it is out of flow. */
@media(max-width:560px){
  .rain-module .wxrow{display:block;padding:8px 0}
  .rain-module .wxrow-name{margin-bottom:5px}
}

/* the demoted teaching block: everything Sol taught, one fold down */
.rain-module .teach{margin:20px 0 0;border:1.5px solid var(--rule);border-radius:9px;background:#FDFCF9}
.rain-module .teach>summary{cursor:pointer;list-style:none;padding:13px 15px;font-family:var(--serif);
  font-weight:700;font-size:1.02rem;color:var(--navy);display:flex;align-items:center;gap:10px}
.rain-module .teach>summary::-webkit-details-marker{display:none}
.rain-module .teach>summary::after{content:"\25be";margin-left:auto;color:var(--amber);font-size:1.1rem}
.rain-module .teach[open]>summary::after{content:"\25b4"}
.rain-module .teach>summary:hover{background:var(--paper)}
.rain-module .teach>summary .sub{font-family:var(--sans);font-weight:400;font-size:.82rem;color:var(--slate)}
.rain-module .teach-in{padding:0 15px 16px}
.rain-module .teach-in .rain-sec:first-child{padding-top:6px;margin-top:0;border-top:0}

/* the quiet one-liner under the morning counts */
.rain-check{margin:13px 0 0;font-size:.9rem;color:var(--ink-2);line-height:1.5;
  padding-left:13px;border-left:3px solid var(--water-a);max-width:78ch}
.rain-check b{color:var(--ink);font-weight:700}

/* ---------------------------------------------------------------- policy */
.policy{background:var(--card);border:1px solid var(--rule);border-top:7px solid var(--navy);
  border-radius:10px;padding:var(--pad);margin:34px 0 8px;box-shadow:var(--shadow)}
.policy h2{font-size:clamp(1.2rem,3.2vw,1.45rem);margin-bottom:6px}
.policy .lede{color:var(--ink-2);max-width:64ch;font-size:.94rem}
.ask{margin:16px 0 0;padding:14px 16px;background:var(--paper);border-radius:8px}
.ask h3{font-size:.98rem;margin-bottom:8px}
.ask ol{margin:0;padding-left:1.25em}
.ask li{margin-bottom:6px;font-size:.93rem}

/* ---------------------------------------------------------------- footer */
.notes{margin:28px 0 0;font-size:.88rem;color:var(--slate);line-height:1.6}
.notes h3{font-size:.78rem;letter-spacing:.14em;text-transform:uppercase;color:var(--slate);font-family:var(--sans);margin-bottom:7px}
.notes ul{margin:0 0 14px;padding-left:1.15em}
.notes li{margin-bottom:5px}
.foot{border-top:1px solid var(--rule);margin-top:22px;padding:20px 0 44px;font-size:.88rem;color:var(--slate)}
.foot p{max-width:74ch}

/* ---------------------------------------------------------------- narrow */
@media(max-width:600px){
  .reading{gap:12px}
  .staff{width:58px;height:176px}
  .figs{flex:1 1 170px;min-width:170px}
}
@media(max-width:430px){
  .stop{grid-template-columns:54px 1fr}
  .daytag{max-width:52px;padding:6px 2px}
  .daytag .n{font-size:1rem}
  .rail{padding-right:8px}
  .staff{width:50px;height:164px}
  .figs{flex:1 1 120px;min-width:120px}
  .chip{white-space:normal;font-size:.82rem;padding:6px 9px}
  .stopbox,.policy{padding-left:13px;padding-right:13px}
  .trend .arrow{font-size:2rem}
  .sig{min-width:0}
}
.key em{overflow-wrap:anywhere}

/* ------------------------------------------------- floating term bubbles */
/* ONE component, shared by both pages. A dotted-underline term opens a small
   floating explanation on hover, tap and keyboard focus; Escape or moving the
   focus away closes it. It is position:fixed so no card's overflow can clip
   it, and it prints as plain text in brackets after the term. */
.wlterm{position:relative;display:inline}
.wlterm-btn{font:inherit;color:inherit;background:none;border:0;padding:0;margin:0;
  cursor:help;text-align:inherit;line-height:inherit;
  text-decoration:underline;text-decoration-style:dotted;text-decoration-thickness:1.5px;
  text-underline-offset:3px}
.wlterm-btn:hover{text-decoration-style:solid}
/* the explanation must read the same wherever the term sits, so its own
   typography wins over whatever the surrounding block sets (e.g. the
   .river-path span rule, which would otherwise shrink it to 13.8 px) */
/* the display rules carry !important because a surrounding block can otherwise
   out-specify them and pin a closed bubble open: .rain-module .river-path span
   (0,2,1) beat the plain .wlterm-pop (0,1,0) and left three explanations stuck
   in the top-left corner of the viewport */
.wlterm-pop{display:none!important;position:fixed;z-index:9999;left:0;top:0;
  width:max-content;max-width:min(320px,88vw);
  background:#16233D;color:#FFFFFF;
  font-family:var(--sans)!important;font-size:1rem!important;font-weight:400!important;
  font-style:normal!important;line-height:1.45!important;letter-spacing:normal!important;
  text-transform:none!important;text-align:left!important;
  padding:11px 13px;border-radius:9px;box-shadow:0 10px 30px rgba(22,35,61,.35)}
.wlterm.on>.wlterm-pop{display:block!important}
/* OWNER CHANGE (items 22 and 25): the long bubbles — "How we calculate ship
   need" on every ship-needs label, and the per-graph description — get a wider
   box, a heading and their own scroll, using the same component. */
.wlterm-pop.wide{max-width:min(460px,92vw);max-height:min(62vh,540px);overflow:auto;
  font-size:.95rem!important;line-height:1.5!important}
.wlterm-ttl{display:block;font-family:var(--serif)!important;font-size:1.04rem;font-weight:700;
  color:#FFFFFF;margin:0 0 7px}
@media print{
  .wlterm-btn{text-decoration:none}
  .wlterm-pop{display:inline!important;position:static!important;width:auto;max-width:none;
    background:transparent!important;color:#444!important;box-shadow:none;padding:0;
    border-radius:0;font-size:.9em!important;font-style:italic!important}
  .wlterm-pop::before{content:" ("}
  .wlterm-pop::after{content:")"}
}

/* ---------------------------------------------------------------- print */
@media print{
  html{font-size:11.5pt}
  body{background:#fff}
  /* Nobody prints a share button, and nobody fills in a form on paper. One rule, and it reaches
     all three pages that hold the row, because all three load this stylesheet. The "do not see
     your sailing?" sentence is NOT in this list: it is prose with an address in it, and it is
     exactly the sort of thing somebody who prints a page wants to still be able to read. */
  .topbar-tools,.btn-change,.picker,.btn-guide,.sharerow,.watchask-form{display:none!important}
  /* The strapline is part of the masthead, so it goes on the paper with it: a printed page of
     this product should still say whose logbook it is. Only the buttons above are dropped --
     they are controls, and paper has none. Darkened for ink. */
  .brand-tag{display:block!important;color:#3B4657!important}
  /* belt and braces: if the tools row is ever un-hidden for print, the amber
     call-to-action must not come out as a solid dark block of ink */
  .tool.cta{background:transparent!important;color:var(--navy)!important;
    border:1.5px solid var(--rule)!important;box-shadow:none!important}
  .stopbox,.policy,.count,.key{box-shadow:none;break-inside:avoid}
  .stop{break-inside:avoid}
  /* the guidance cannot pop out on paper, so it prints in full under each stop */
  .print-guide{display:block!important}
  .rain-module{box-shadow:none;break-inside:auto}
  .rain-module .forecast-box,.rain-module .plain-stopbox,.rain-module .rules li,
  .rain-module .caution,.rain-module .closing,.rain-module .river-path{break-inside:avoid;background:#fff}
  .rain-module .half-life-wrap{overflow:visible;break-inside:avoid}
  .rain-module .half-life{min-width:0}
  .rain-module .half-life caption{background:#fff;color:var(--navy);border-bottom:2px solid var(--navy)}
  .rain-module .rain-cta{background:transparent!important;color:var(--navy)!important;
    border:1.5px solid var(--rule)!important;box-shadow:none!important}
  /* the demonstration caveat must survive the printer: a page that comes out
     of a tray without it could be mistaken for the live product */

  .rain-module .wxgauge,.rain-module .rs-read,.rain-module .teach{break-inside:avoid;background:#fff}
  .rain-module .wx-only{break-inside:avoid;background:#fff}
  .rain-module .wxrow{break-inside:avoid}
  .rain-module .wxi{width:11px;height:11px}
  .rain-module .rs-bars .b{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  /* the folded teaching block prints open — paper has no disclosure triangle */
  .rain-module .teach>summary::after{content:""}
  .rain-module .teach-in{display:block!important}
  .rain-check{break-inside:avoid}
  .sailing{background:#fff;color:var(--ink);border-bottom:3px solid var(--navy)}
  .sailing h1,.sailing-meta strong{color:var(--navy)}
  .sailing-meta,.asof{color:var(--ink-2)}
  .unconfirmed{color:var(--ink-2)}
  .unconfirmed strong{color:var(--navy)}
  .kicker{color:var(--slate)}
  a[href^="http"]::after{content:" (" attr(href) ")";font-size:.8em;color:#555;word-break:break-all}
}
.print-guide{display:none}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* ================= from index.html: the front door ================= */
body.p-home a:focus-visible,body.p-home button:focus-visible,body.p-home select:focus-visible{outline:3px solid var(--focus);outline-offset:3px;border-radius:4px}
/* -------- utility row ---------------------------------------------------- */
body.p-home .util{display:flex;justify-content:flex-end;padding:12px 0 0}
body.p-home .tool{font:inherit;font-size:.90rem;font-weight:600;background:var(--card);border:1.5px solid var(--rule);
  color:var(--navy);padding:8px 14px;border-radius:999px;cursor:pointer}
/* -------- the mark ------------------------------------------------------- */
body.p-home .lockup{padding:26px 0 4px}
/* Hero lockup: the whole thing scales up, and the two text lines keep the
   SAME font-size as each other. OWNER CHANGE: no textLength justification —
   the words set at their natural letterspacing and stack left-aligned, so the
   two lines end where the letters end rather than being stretched to match. */
/* The mark and the name sit on one line, vertically centred on each other, and the strapline
   runs under both. Keyed on .brandmark, not h1: the home page's <h1> moved to the visible
   promise line (a heading made of a logo and a drawn wordmark carries no readable text), and
   this rule silently stopped matching -- which stacked the name under the mark. */
/* `flex-wrap:wrap` is the safety valve the nowrap version did not have. The hero lockup is the
   widest thing on the front door, and at 320px the mark and the name together want 353px inside
   a 292px content box -- true before this change as well, because neither an <img> nor an <svg>
   sized off a viewBox will shrink below its transferred width, so the old lockup simply ran off
   the side of a 320px screen. Allowed to wrap, the name drops UNDER the mark instead, which is
   the same thing the topbar's strapline already does when the row runs out of room. Nothing
   moves at 390px and up, where the two still fit side by side. */
body.p-home .lockup .brandmark{margin:0;display:flex;align-items:center;justify-content:center;
  gap:clamp(12px,3vw,20px);flex-wrap:wrap}
body.p-home .lockup .brand-mark{display:block;height:clamp(74px,17vw,116px);width:auto}
/* The same size the drawn wordmark rendered at, expressed as type rather than as a box:
   27 x clamp(74px,17vw,116px)/64. The three numbers are that multiplication done. */
body.p-home .lockup .brand-words{font-size:clamp(31.22px,7.17vw,48.94px)}
/* -------- the strapline -------------------------------------------------- */
/* The front door has no topbar, and its lockup is centred with nothing beside it, so the
   tagline goes under the mark instead of next to it -- still inside .lockup, so it reads as
   part of the brand rather than as the promise, which is the serif line below it and is
   deliberately larger. 1rem here (17px, and 20 under the larger-text control) because this is
   the one page where a first-time reader meets the sentence. */
body.p-home .brand-tag{text-align:center;max-width:34ch;margin:11px auto 0;font-size:1rem}

/* -------- the promise ---------------------------------------------------- */
body.p-home .vp{text-align:center;font-family:var(--serif);font-size:clamp(1.12rem,3.4vw,1.42rem);color:var(--ink);
  line-height:1.42;max-width:32ch;margin:24px auto 0}
/* THE FIRST SCREEN OF A PHONE, the owner's ruling of 2026-08-16: "Find your sailing" must land
   on it. The header above the entry card is brand and promise — worth reading once, not worth
   a whole screen — so on a phone every piece keeps its words and gives up its air: the mark
   drops to topbar scale, the name keeps the mark's 27/64 ratio, the strapline and promise
   tighten their margins, and the entry card follows sooner. Measured at 375x812: the section
   heading, both sub lines and the first menu sit inside the first viewport. Nothing here hides
   a sentence — compression, not deletion. */
@media(max-width:640px){
  body.p-home .util{padding:6px 0 0}
  body.p-home .tool{font-size:.82rem;padding:5px 11px}
  body.p-home .lockup{padding:8px 0 0}
  body.p-home .lockup .brand-mark{height:clamp(44px,12vw,74px)}
  body.p-home .lockup .brand-words{font-size:clamp(18.56px,5.06vw,31.22px)}
  /* The tagline and the sub lines keep the site's 16px prose floor (test_header_tagline
     guards the tagline explicitly) — the compression here is all margin, not type size. */
  body.p-home .brand-tag{margin:5px auto 0;font-size:.95rem}
  body.p-home .vp{margin:10px auto 0;font-size:1.02rem;line-height:1.35}
  body.p-home .entry{margin:12px 0 0;padding:14px 16px 18px}
  body.p-home .entry h2{margin-bottom:2px}
  body.p-home .entry .sub{margin:0 0 10px}
}
/* -------- the entry flow ------------------------------------------------- */
body.p-home .entry{background:var(--card);border:1px solid var(--rule);border-top:8px solid var(--navy);
  border-radius:14px;padding:clamp(18px,4vw,28px);margin:26px 0 0;box-shadow:var(--shadow)}
body.p-home .entry h2{font-size:clamp(1.08rem,3vw,1.25rem);margin-bottom:3px}
body.p-home .entry .sub{font-size:.93rem;color:var(--slate);margin:0 0 18px}
/* "Do not see your sailing?" -- the way off this page, moved out of the fineprint at the foot of
   the form and up under the header at the owner's direction. Sized as body copy rather than as a
   note, and set on the page's own water-blue with a rule down its left edge so the eye finds it
   while the menus are being read. Deliberately NOT amber and deliberately not a button: amber is
   reserved for the page's one ask, and this is the sentence for the reader that ask has failed. */
body.p-home .entry .ask-add{font-size:.97rem;line-height:1.5;color:var(--ink);max-width:62ch;
  margin:0 0 20px;padding:11px 14px;background:#E4EEF7;border-left:4px solid var(--navy);
  border-radius:0 8px 8px 0}
body.p-home .entry .ask-add a{font-weight:700;color:var(--navy)}
/* The no-script repair's one sentence (routes.RELINE_NOTE), printed only on the render that
   POST /check sends back. Amber-edged rather than blue, because unlike the sentence above it this
   one is about something that has just happened to the reader's own press; body copy and no
   colour behind it, because it is news and not an error the reader made. */
body.p-home .entry .picker-note{font-size:.97rem;line-height:1.5;color:var(--ink);max-width:62ch;
  margin:0 0 18px;padding:11px 14px;border-left:4px solid var(--amber);background:#FDF6E7;
  border-radius:0 8px 8px 0}
body.p-home .steps{display:grid;gap:16px;grid-template-columns:1fr}
@media(min-width:720px){body.p-home .steps{grid-template-columns:repeat(3,1fr)}}
body.p-home .step label{display:flex;align-items:center;gap:9px;font-size:.79rem;font-weight:800;letter-spacing:.13em;
  text-transform:uppercase;color:var(--slate);margin-bottom:7px}
body.p-home .step .n{display:inline-flex;align-items:center;justify-content:center;width:23px;height:23px;flex:0 0 auto;
  border-radius:999px;background:var(--navy);color:#fff;font-family:var(--serif);font-size:.86rem;letter-spacing:0}
body.p-home .step select{width:100%;font:inherit;font-size:1.04rem;font-weight:600;color:var(--ink);
  padding:14px 12px;border:2px solid var(--rule);border-radius:9px;background:var(--card);min-height:52px}
body.p-home .step select:hover{border-color:var(--navy)}
body.p-home .go{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-top:20px}
body.p-home .btn-go{font:inherit;font-weight:800;font-size:1.12rem;background:var(--amber);color:#fff;border:0;
  padding:16px 30px;border-radius:10px;cursor:pointer;text-decoration:none;display:inline-block;
  box-shadow:0 2px 0 #9E4E12}
body.p-home .btn-go:hover{background:#B45815}
@media(max-width:520px){body.p-home .btn-go{width:100%;text-align:center}}
/* FIND MY SHIP. THE SAME CONTROL, IN THE OTHER BRAND COLOUR. Its first cut was an outlined
   button, which the owner read as not visible enough — an outline reads as a secondary action,
   and this is not one: the readers who need it are the ones who know only their vessel's name
   and cannot use the cruise-line menu above at all.

   Every measurement is copied from .btn-go rather than re-chosen, so the two boxes are identical
   in size: same font-size, same weight, same padding, same radius, same border:0, same 2px solid
   drop. Only the fill differs — navy against the picker's amber, both brand colours, so it is
   plainly a second door rather than a second submit. */
body.p-home .go-ship{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin:12px 0 0}
body.p-home .btn-ship{font:inherit;font-weight:800;font-size:1.12rem;background:var(--navy);color:#fff;border:0;
  padding:16px 30px;border-radius:10px;cursor:pointer;text-decoration:none;display:inline-block;
  box-shadow:0 2px 0 #14264A}
body.p-home .btn-ship:hover{background:#16294F}
@media(max-width:520px){body.p-home .btn-ship{width:100%;text-align:center;box-sizing:border-box}}
body.p-home .go .free{font-size:.88rem;color:var(--slate);margin:0}
body.p-home .date-key{font-size:.8rem;color:var(--slate);margin:10px 0 0;max-width:62ch;line-height:1.5}
/* The sentence a reader's email asked for on 13 August 2026: somebody who found only two dates in
   the menu read the absence as a cancellation. Set slightly larger and darker than the date key
   above it, because it is not a key to a marker -- it is the answer to a fear, and a reader who
   is worried is not the reader who reads 0.8rem grey. */
body.p-home .date-missing{font-size:.9rem;color:var(--ink);margin:8px 0 0;max-width:62ch;line-height:1.55}
body.p-home .date-missing a{font-weight:700;color:var(--navy)}
/* JUST ADDED — the evidence under the ask, and IT DOES NOT MOVE.

   The owner asked for a scrolling line. There is no animation, no transition and no transform in
   this component, and that is deliberate: the list is eight entries, which is one row on a laptop
   and three on a phone, so there is nothing to scroll THROUGH -- and this site is read by people
   in their fifties, sixties and seventies over ship wifi, for whom tracking a moving line to find
   their own cruise line is strictly worse than reading a short one that has stopped. The full
   argument sits beside the markup in watch_home.html.

   The consequence worth naming: a reader under prefers-reduced-motion is served exactly the same
   page as everybody else, because there is nothing here to reduce, and every sailing is clickable
   the moment the page paints rather than when it comes round. tests/test_just_added.py holds all
   of that by reading this file -- a stylesheet is not in the response body, so a suite that only
   renders cannot see an animation being added later.

   Set apart from the form above it by a rule and a tint rather than by a box, because it is a
   footnote to the ask and not a fourth step in it. */
body.p-home .justadded{border-top:1px solid var(--rule-2);margin:18px 0 0;padding:14px 0 0}
body.p-home .justadded h3{font-size:1rem;margin:0 0 6px;color:var(--navy-deep)}
body.p-home .ja-list{margin:0;max-width:70ch;line-height:1.9;font-size:.97rem}
/* Padded so each entry is a target a thumb can hit without the line becoming a list. */
body.p-home .ja-list a{display:inline-block;padding:2px 0;font-weight:700;color:var(--navy)}
body.p-home .ja-list span{color:var(--slate);padding:0 2px}
body.p-home .ja-note{font-size:.85rem;color:var(--slate);margin:8px 0 0;max-width:62ch;line-height:1.55}
body.p-home .step select:disabled{opacity:.6}
/* -------- the live strip ------------------------------------------------- */
/* The three doors under the finder: whole-tile links to the most visited pages. A grid that
   stacks on a phone; the tap target is the box, not the words. Light water-blue at the owner's
   direction, so they read as buttons at a glance -- in the graphs' own blue family, and
   deliberately not amber, which stays reserved for the page's one ask. */
body.p-home .home-doors{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin:26px 0 0}
body.p-home .home-doors .door{display:block;padding:14px 40px 14px 16px;background:#E4EEF7;
  border:2px solid #9DBCD8;border-radius:10px;text-decoration:none;color:inherit;position:relative}
body.p-home .home-doors .door::after{content:"\2192";position:absolute;right:14px;top:50%;
  transform:translateY(-50%);color:var(--navy);font-size:1.15rem;font-weight:700}
body.p-home .home-doors .door:hover,body.p-home .home-doors .door:focus-visible{background:#D6E5F3;
  border-color:var(--navy)}
body.p-home .home-doors .door strong{display:block;color:var(--navy);font-size:1.02rem;margin-bottom:4px}
body.p-home .home-doors .door span{display:block;font-size:.88rem;color:#3E4C63;line-height:1.4}
@media (max-width:720px){body.p-home .home-doors{grid-template-columns:1fr}}

/* -------- right now, and three real sailings -------------------------------- */
/* The two blocks a visitor arriving from somebody else's share meets first. Both are dressed
   DOWN, not up: this page already has one filled block of colour and one amber button, and a
   front door with three things shouting on it has nothing leading. The summary borrows the
   doors' pale blue and the examples borrow the entry panel's card, so neither introduces a
   colour or a shape the page did not already have. */
body.p-home .rightnow{margin:26px 0 0;padding:15px 17px;background:#E4EEF7;
  border:1px solid #C7DBEC;border-radius:11px}
body.p-home .rightnow h2{font-size:.79rem;font-weight:800;letter-spacing:.13em;
  text-transform:uppercase;font-family:var(--sans);color:var(--water-b);margin:0 0 6px}
body.p-home .rn-say{margin:0;font-family:var(--serif);font-size:1.06rem;line-height:1.45;
  color:var(--ink)}
body.p-home .rn-gloss{margin:7px 0 0;font-size:.85rem;line-height:1.5;color:#3E4C63}

body.p-home .home-examples{margin:26px 0 0}
body.p-home .home-examples h2{font-size:clamp(1.05rem,2.9vw,1.2rem);margin-bottom:2px}
body.p-home .ex-sub{font-size:.86rem;color:var(--slate);margin:0 0 12px}
body.p-home .exlist{list-style:none;margin:0;padding:0;display:grid;gap:11px;
  grid-template-columns:1fr}
@media(min-width:680px){body.p-home .exlist{grid-template-columns:repeat(3,1fr)}}
/* Whole-tile links with a 44px target, like .door -- the front page is read with a thumb. */
body.p-home .exlist a{display:block;height:100%;padding:13px 15px;background:var(--card);
  border:1px solid var(--rule);border-left:9px solid var(--water-a);border-radius:11px;
  text-decoration:none;box-shadow:var(--shadow)}
body.p-home .exlist a:hover,body.p-home .exlist a:focus-visible{border-left-color:var(--water-b)}
body.p-home .exlist strong{display:block;font-family:var(--serif);font-size:1.1rem;
  color:var(--navy);margin-bottom:3px}
body.p-home .exlist .ex-line{display:block;font-size:.88rem;color:#3E4C63;line-height:1.4}
body.p-home .exlist .ex-when{display:block;font-size:.83rem;color:var(--slate);margin-top:4px}

body.p-home .live{margin:34px 0 0}
body.p-home .live h2{font-size:clamp(1.05rem,2.9vw,1.2rem);margin-bottom:2px}
body.p-home .live .stamp{font-size:.86rem;color:var(--slate);margin:0 0 14px}
body.p-home .riverrow{list-style:none;margin:0;padding:0;display:grid;gap:11px;grid-template-columns:1fr}
@media(min-width:680px){body.p-home .riverrow{grid-template-columns:repeat(3,1fr)}}
body.p-home .item{background:var(--card);border:1px solid var(--rule);border-left:9px solid var(--grey);
  border-radius:10px;padding:14px 15px;box-shadow:var(--shadow)}
body.p-home .item.sev{border-left-color:var(--red)}
body.p-home .item.con{border-left-color:var(--orange)}
body.p-home .item.clr{border-left-color:var(--green)}
body.p-home .item .place{font-family:var(--serif);font-size:1.14rem;font-weight:700;color:var(--navy);margin:10px 0 1px}
body.p-home .item .now{font-size:1.7rem;font-family:var(--serif);line-height:1.1;margin:4px 0 1px;letter-spacing:-.01em}
body.p-home .item.sev .now{color:var(--red)}
body.p-home .item.con .now{color:var(--orange)}
body.p-home .item.clr .now{color:var(--green)}
body.p-home .item .short{font-size:.9rem;color:var(--ink-2);font-weight:600;margin:0}
/* the shared signal chip */
body.p-home .chip{display:inline-flex;align-items:center;gap:7px;font-weight:800;font-size:.85rem;letter-spacing:.05em;
  text-transform:uppercase;padding:6px 11px;border-radius:6px;border:2px solid;white-space:nowrap}
@media(max-width:400px){body.p-home .chip{white-space:normal;font-size:.8rem}}
/* OWNER CHANGE: the line under the strip runs to the SAME right edge as the
   third card above it (the Concerning one), so the two align. No max-width. */
body.p-home .live .after{font-size:.94rem;color:var(--ink-2);margin:14px 0 0;max-width:none}
body.p-home .live .after strong{color:var(--ink)}
/* -------- footer --------------------------------------------------------- */
body.p-home .foot{border-top:1px solid var(--rule);margin-top:36px;padding:20px 0 46px;font-size:.87rem;color:var(--slate)}
body.p-home .foot p{max-width:74ch;margin:0 0 .5em}
@media print{body.p-home .util,body.p-home .btn-go{display:none}
body.p-home .entry,body.p-home .item{box-shadow:none}}

/* ================= from map.html: the route map ================= */
body.p-map a:focus-visible,body.p-map button:focus-visible,body.p-map [tabindex]:focus-visible{outline:3px solid var(--focus);outline-offset:3px;border-radius:4px}
/* header — CHANGE 1, the logo is materially bigger */
body.p-map .topbar{background:var(--card);border-bottom:1px solid var(--rule)}
/* vertical padding only, so .wrap keeps its gutter (matches sailing.html) */
body.p-map .topbar-in{display:flex;align-items:center;gap:16px;flex-wrap:wrap;padding-top:15px;padding-bottom:15px}
body.p-map .tool{font:inherit;font-size:.90rem;font-weight:600;background:var(--paper);border:1.5px solid var(--rule);color:var(--navy);padding:8px 13px;border-radius:999px;cursor:pointer;text-decoration:none;display:inline-block}
body.p-map .tool.primary{background:var(--navy);color:#fff;border-color:var(--navy)}
body.p-map .sailing{background:var(--navy);color:#fff;padding:20px 0 22px}
body.p-map .sailing h1{color:#fff;font-size:clamp(1.35rem,3.8vw,1.8rem);margin:2px 0 6px}
body.p-map .asof{font-size:.92rem;color:#B9CBE4;margin:12px 0 0}
/* map frame */
body.p-map .mapwrap{position:relative;background:var(--card);border:1px solid var(--rule);border-radius:12px;padding:10px;margin:22px 0 0;box-shadow:var(--shadow)}
body.p-map .mapwrap svg#routemap{display:block;width:100%;height:auto;border-radius:8px;background:#FBF9F4;touch-action:manipulation}
body.p-map .hint{font-size:.95rem;color:var(--slate);margin:10px 4px 2px;text-align:center}
/* pins */
body.p-map .pin{cursor:pointer}
body.p-map .pin .halo{opacity:0;transition:opacity .12s}
body.p-map .pin:hover .halo,body.p-map .pin:focus .halo,body.p-map .pin.sel .halo{opacity:1}
body.p-map .pin.sel .disc{stroke:#16233D;stroke-width:var(--rm-pinstroke,4.5)}
/* A CALL THAT SHARES A DOT HAS NO DISC AND NO HALO OF ITS OWN -- one dot is the whole point of
   merging it -- so hover, keyboard focus and selection are shown on the one thing that IS its
   own: its line of the label block. Without this, tabbing onto the second call of a shared pin
   lit nothing anywhere on the page. The rect carries fill:#FFFFFF and fill-opacity:0 as
   presentation attributes so that it stays invisible if this file never arrives; a stylesheet
   beats a presentation attribute, which is the whole of what these two lines rely on. */
body.p-map .pin .pintap{fill:#1F3864;fill-opacity:0;transition:fill-opacity .12s}
body.p-map .pin:hover .pintap,body.p-map .pin:focus .pintap,body.p-map .pin.sel .pintap{fill-opacity:.09}
/* THE TYPE SIZE IS THE MAP'S, NOT THIS FILE'S. A stylesheet beats an SVG presentation attribute,
   so the 21px and 16px that used to stand here were the sizes every route map was really drawn
   at -- whatever routemap.py had computed -- and they are sizes in the FRAME's units, which means
   they were 19px of type on a Rhine frame and 87px on a Douro one. routemap.chrome_for sizes them
   per frame and watch_map.html passes them in as --rm-*. The fallbacks are the retired corridor
   artwork's own numbers, which is the only drawing left that carries no chrome of its own. */
body.p-map .plabel{font-family:var(--sans);font-weight:800;font-size:var(--rm-label,21px);fill:var(--ink);paint-order:stroke;stroke:#FBF9F4;stroke-width:var(--rm-halo,6px);stroke-linejoin:round;pointer-events:none}
body.p-map .plabel .day{font-weight:700;font-size:var(--rm-day,16px);fill:var(--slate)}
body.p-map .plabel .day.sev{fill:#A4232B}
body.p-map .plabel .day.con{fill:#A9530D}
body.p-map .plabel .day.lock{fill:#2F6193}
body.p-map .plabel .day.clr{fill:#1B6B45}
body.p-map .plabel .day.land{fill:#8A6F4E}
body.p-map .plabel .day.port{fill:#6B5F8C}
body.p-map .plabel .day.nog{fill:#4A5A66}
body.p-map .cty{font-family:var(--sans);font-size:19px;font-weight:700;letter-spacing:.34em;fill:#B6AE9C;pointer-events:none;text-transform:uppercase}
body.p-map .grat{stroke:#DED6C6;stroke-width:1;stroke-dasharray:3 6}
body.p-map .gratlab{font-family:var(--sans);font-size:12px;fill:#BDB4A2;pointer-events:none}
/* ---------------------------------------------------------------------------
   CHANGE 8 — a real map popup, sized to be read. Anchored over the pin.
   --------------------------------------------------------------------------- */
body.p-map .bubble{position:absolute;z-index:5;width:min(330px,84vw);background:var(--card);
  border:2px solid var(--navy);border-radius:14px;box-shadow:0 14px 40px rgba(22,35,61,.30);
  padding:14px 16px 13px;display:none}
body.p-map .bubble.on{display:block}
body.p-map .bubble::after{content:"";position:absolute;left:var(--tip,50%);width:16px;height:16px;
  background:var(--card);border-right:2px solid var(--navy);border-bottom:2px solid var(--navy);
  transform:translateX(-50%) rotate(45deg)}
body.p-map .bubble.above::after{bottom:-10px}
body.p-map .bubble.below::after{top:-10px;border:0;border-left:2px solid var(--navy);border-top:2px solid var(--navy)}
body.p-map .bubble.sev{border-color:var(--red)}
body.p-map .bubble.sev::after{border-color:var(--red)}
body.p-map .bubble.con{border-color:var(--orange)}
body.p-map .bubble.con::after{border-color:var(--orange)}
body.p-map .bubble.lock{border-color:var(--lock)}
body.p-map .bubble.lock::after{border-color:var(--lock)}
body.p-map .bubble.clr{border-color:var(--green)}
body.p-map .bubble.clr::after{border-color:var(--green)}
body.p-map .bubble.non{border-color:var(--grey)}
body.p-map .bubble.non::after{border-color:var(--grey)}
body.p-map .bubble.land{border-color:var(--land)}
body.p-map .bubble.land::after{border-color:var(--land)}
body.p-map .bubble.port{border-color:var(--port)}
body.p-map .bubble.port::after{border-color:var(--port)}
body.p-map .bubble.nog{border-color:var(--nog)}
body.p-map .bubble.nog::after{border-color:var(--nog)}
body.p-map .bubble h3{font-size:1.42rem;line-height:1.1;margin:0 0 2px;padding-right:30px}
body.p-map .bubble .bwhen{font-size:.86rem;color:var(--slate);font-weight:600;margin:0 0 9px}
body.p-map .bubble .bnum{font-family:var(--serif);font-size:1.9rem;line-height:1.05;margin:8px 0 2px}
body.p-map .bubble .bnum.sev{color:var(--red)}
body.p-map .bubble .bnum.con{color:var(--orange)}
body.p-map .bubble .bnum.clr{color:var(--green)}
body.p-map .bubble .bnum.non{color:var(--grey)}
body.p-map .bclose{position:absolute;top:8px;right:9px;width:30px;height:30px;border-radius:999px;border:1.5px solid var(--rule);
  background:var(--paper);color:var(--ink-2);font-size:.95rem;line-height:1;cursor:pointer;font-family:inherit}
body.p-map .bclose:hover{border-color:var(--navy);color:var(--navy)}
/* ---------------------------------------------------------------------------
   CHANGE 8 — the per-gauge write-up: bigger, with the big falling arrow and
   the same seasonal graph as the day boxes.
   --------------------------------------------------------------------------- */
body.p-map .detail{margin:18px 0 0;background:var(--card);border:1px solid var(--rule);border-left:11px solid var(--grey);
  border-radius:10px;padding:20px var(--pad);box-shadow:var(--shadow);min-height:180px}
body.p-map .detail.con{border-left-color:var(--orange)}
body.p-map .detail.sev{border-left-color:var(--red);background:linear-gradient(90deg,var(--red-bg),var(--card) 40%)}
body.p-map .detail.clr{border-left-color:var(--green)}
body.p-map .detail.non{border-left-color:var(--grey)}
body.p-map .detail.land{border-left-color:var(--land)}
body.p-map .detail.port{border-left-color:var(--port)}
body.p-map .detail.nog{border-left-color:var(--nog)}
body.p-map .detail-head{display:flex;gap:14px;align-items:flex-start;flex-wrap:wrap;margin-bottom:2px}
body.p-map .detail h2{font-size:clamp(1.5rem,4.2vw,2rem)}
body.p-map .detail .sig{flex:0 1 250px;margin-left:auto;min-width:175px}
body.p-map .detail .sig-note{font-size:.82rem;color:var(--slate);line-height:1.42;margin:5px 0 0}
body.p-map .detail .sig-note strong{color:var(--ink)}
@media(max-width:560px){body.p-map .detail .sig{margin-left:0;flex:1 1 100%}}
body.p-map .detail .when{font-size:.96rem;color:var(--ink-2);font-weight:600;margin:2px 0 16px}
body.p-map .detail-body{display:flex;gap:26px;flex-wrap:wrap;align-items:flex-start}
body.p-map .detail-figs{flex:1 1 320px;min-width:280px}
body.p-map .detail-side{flex:1 1 300px;min-width:280px}
body.p-map .bignum{font-family:var(--serif);font-size:clamp(1.9rem,5.4vw,2.5rem);line-height:1.05;margin:0 0 3px}
body.p-map .bignum.sev{color:var(--red)}
body.p-map .bignum.con{color:var(--orange)}
body.p-map .bignum.clr{color:var(--green)}
body.p-map .bignum.non{color:var(--grey)}
body.p-map .bignum.land{color:var(--land)}
body.p-map .bignum.port{color:var(--port)}
body.p-map .bignum.nog{color:var(--nog)}
body.p-map .subline{font-size:1.02rem;font-weight:600;margin:0 0 14px}
body.p-map table.rows{width:100%;border-collapse:collapse;margin:0 0 12px;max-width:430px}
body.p-map table.rows th,body.p-map table.rows td{text-align:left;padding:8px 0;border-bottom:1px solid var(--rule-2)}
body.p-map table.rows th{font-weight:600;font-size:.96rem;padding-right:12px}
body.p-map table.rows td{text-align:right;font-weight:800;font-size:1.12rem;white-space:nowrap;font-variant-numeric:tabular-nums}
body.p-map .detail .prov{font-size:.86rem;color:var(--slate);margin:0;overflow-wrap:anywhere}
body.p-map .detail .out{display:inline-flex;align-items:center;gap:9px;background:var(--navy);color:#fff;text-decoration:none;
  font-weight:700;font-size:1rem;padding:12px 17px;border-radius:8px;margin-top:10px}
body.p-map .detail .out:hover{background:#16294A}
body.p-map .detail .out.alt{background:#fff;color:var(--navy);border:2px solid var(--rule)}
body.p-map .detail .out.alt:hover{background:var(--paper);border-color:var(--navy)}
body.p-map .eng-sub{font-size:.8rem;color:var(--slate);font-style:italic;margin:8px 0 0}
body.p-map .horizon-note{display:inline-block;font-size:.78rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase;
  background:#FDF6EC;color:#8A4A0D;border:1.5px solid #D9A46A;border-radius:5px;padding:5px 10px;margin:0 0 10px}
body.p-map .detail .look{font-size:.97rem;margin:0 0 6px}
/* the big falling arrow, shared with sailing.html */
body.p-map .trend{display:flex;align-items:flex-start;gap:12px;margin:0 0 14px}
body.p-map .trend .arrow{font-size:2.6rem;line-height:.86;font-weight:900;color:var(--red);flex:0 0 auto;text-shadow:0 1px 0 rgba(164,35,43,.25)}
body.p-map .trend.up .arrow{color:var(--green)}
body.p-map .trend .val{display:block;font-size:1.08rem;font-weight:800;color:var(--ink);line-height:1.28}
body.p-map .trend .val b{color:var(--red)}
body.p-map .trend .why{display:block;font-size:.78rem;color:var(--slate);font-weight:400;line-height:1.38;margin-top:2px}
/* the seasonal graph, shared with sailing.html */
body.p-map .spark{margin:16px 0 0;padding-top:14px;border-top:1px solid var(--rule-2);display:block}
@media(max-width:560px){body.p-map:not(.mob) .spark svg text.gx-xax{font-size:23px}
body.p-map:not(.mob) .spark svg text.gx-today,body.p-map:not(.mob) .spark svg text.gx-cruise{font-size:21px;transform:translateY(6px)}
body.p-map:not(.mob) .spark svg text.gx-need{font-size:20px}
body.p-map:not(.mob) .spark svg text.gx-yax{font-size:18px;transform:translateY(-5px)}}
body.p-map .chip{display:inline-flex;align-items:center;gap:7px;font-weight:800;font-size:.88rem;letter-spacing:.05em;
  text-transform:uppercase;padding:7px 12px;border-radius:6px;border:2px solid;white-space:nowrap}
@media(max-width:430px){body.p-map .chip{white-space:normal;font-size:.82rem;padding:6px 9px}}
/* legend — descriptions under the badges */
body.p-map .legend{margin:20px 0 0;background:var(--card);border:1px solid var(--rule);border-radius:10px;padding:15px var(--pad)}
body.p-map .legend h3{font-size:.98rem;margin-bottom:11px}
body.p-map .legend-grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));margin:0;padding:0;list-style:none}
body.p-map .legend li{display:block}
body.p-map .legend .chip{margin-bottom:5px}
body.p-map .legend em{font-style:normal;color:var(--slate);font-size:.83rem;line-height:1.42;display:block;overflow-wrap:anywhere}
body.p-map .legend em strong{color:var(--ink)}
body.p-map .legend .foot-note{font-size:.86rem;color:var(--slate);margin:14px 0 0}
/* stops list */
body.p-map .stops{margin:22px 0 0}
body.p-map .stops h2{font-size:clamp(1.15rem,3vw,1.4rem);margin-bottom:4px}
body.p-map .stops .lede{color:var(--ink-2);font-size:.93rem;margin-bottom:12px}
body.p-map .stoplist{list-style:none;margin:0;padding:0;display:grid;gap:9px}
body.p-map .stoprow{display:flex;gap:12px;align-items:center;background:var(--card);border:1px solid var(--rule);
  border-left:8px solid var(--grey);border-radius:8px;padding:11px 14px;cursor:pointer;text-align:left;width:100%;font:inherit}
body.p-map .stoprow:hover{border-color:var(--navy)}
body.p-map .stoprow.sev{border-left-color:var(--red)}
body.p-map .stoprow.con{border-left-color:var(--orange)}
body.p-map .stoprow.clr{border-left-color:var(--green)}
body.p-map .stoprow.land{border-left-color:var(--land)}
body.p-map .stoprow.port{border-left-color:var(--port)}
body.p-map .stoprow.nog{border-left-color:var(--nog)}
body.p-map .stoprow .d{flex:0 0 82px;font-size:.80rem;letter-spacing:.12em;text-transform:uppercase;color:var(--slate);font-weight:800}
body.p-map .stoprow .c{flex:1 1 auto;font-family:var(--serif);font-size:1.12rem;font-weight:700;color:var(--navy)}
body.p-map .stoprow .v{flex:0 0 auto;font-weight:800;font-variant-numeric:tabular-nums;font-size:.98rem}
body.p-map .stoprow .v.sev{color:var(--red)}
body.p-map .stoprow .v.con{color:var(--orange)}
body.p-map .stoprow .v.clr{color:var(--green)}
body.p-map .stoprow .v.non{color:var(--slate)}
@media(max-width:560px){body.p-map .stoprow{flex-wrap:wrap}
body.p-map .stoprow .d{flex:0 0 100%}}
body.p-map .foot{border-top:1px solid var(--rule);margin-top:26px;padding:20px 0 44px;font-size:.88rem;color:var(--slate)}
body.p-map .foot p{max-width:76ch}
body.p-map .projnote{font-size:.86rem;color:var(--slate);margin:12px 4px 0;text-align:center}
/* the explanation must read the same wherever the term sits, so its own
   typography wins over whatever the surrounding block sets (e.g. the
   .river-path span rule, which would otherwise shrink it to 13.8 px) */
body.p-map .wlterm-pop{display:none!important;position:fixed;z-index:9999;left:0;top:0;
  width:max-content;max-width:min(320px,88vw);
  background:#16233D;color:#FFFFFF;
  font-family:var(--sans)!important;font-size:1rem!important;font-weight:400!important;
  font-style:normal!important;line-height:1.45!important;letter-spacing:normal!important;
  text-transform:none!important;text-align:left!important;
  padding:11px 13px;border-radius:9px;box-shadow:0 10px 30px rgba(22,35,61,.35)}
/* OWNER CHANGE (item 22, mirrored from sailing.html): the long "How we
   calculate ship need" bubble gets a wider box, a heading and its own scroll. */
body.p-map .wlterm-pop.wide{max-width:min(460px,92vw);max-height:min(62vh,540px);overflow:auto;
  font-size:.95rem!important;line-height:1.5!important}
@media print{body.p-map .topbar-tools,body.p-map .hint,body.p-map .bubble{display:none!important}
body.p-map .mapwrap,body.p-map .detail,body.p-map .legend{box-shadow:none;break-inside:avoid}
body.p-map .sailing{background:#fff;color:var(--ink);border-bottom:3px solid var(--navy)}
body.p-map .sailing h1{color:var(--navy)}
body.p-map .sailing-meta,body.p-map .asof{color:var(--ink-2)}
body.p-map .kicker{color:var(--slate)}}

/* ================= production additions =================
   Rules the mock-ups did not need, because a mock-up never has a feed that is
   late, an archive it may not republish, or a keyboard user arriving on a page
   with fourteen stop cards between them and the content. */

/* The front door sets a narrower measure than the watch page. In the mock-ups
   that lived in each file's own .wrap; here the two share a stylesheet, so the
   narrower one is scoped to the page that wants it. */
body.p-home .wrap{max-width:820px}

.skip-link{position:absolute;left:-9999px;top:0;background:var(--navy);color:#fff;
  padding:10px 16px;border-radius:0 0 8px 0;z-index:10000;font-weight:700}
.skip-link:focus{left:0}

/* A feed that is late, said out loud rather than papered over with yesterday's
   numbers. Deliberately plain: this is an absence, not a status. */
.wx-out{margin:15px 0 0;padding:13px 15px;border:1px dashed var(--rule);border-radius:9px;
  background:#FBFAF7;font-size:.92rem;color:var(--ink-2);line-height:1.55;max-width:76ch}

/* Where a gauge has a live reading but an archive we are not free to republish,
   the graph's slot carries the reason instead of an empty frame. */
.spark-absent{margin:13px 0 0;padding-top:12px;border-top:1px solid var(--rule-2);
  font-size:.83rem;color:var(--slate);line-height:1.5;max-width:60ch}

/* The weather module's own attribution line. */
.rain-module .wx-source{margin:9px 0 0;font-size:.75rem;color:var(--slate);line-height:1.4}

/* The mock-ups coloured these table cells with inline style attributes, which a
   server-rendered template turns into classes instead. Same colours. */
table.rows td.below{color:var(--red)}
table.rows td.below.con{color:var(--orange)}
table.rows td.need{color:#111}
table.rows td.typ{color:#4A5568}
table.rows th em.qual{font-weight:400;color:var(--slate);font-size:.86em;font-style:italic}

/* The print-only copy of each stop's official guidance. */
.print-guide h4{font-size:1rem;margin:14px 0 4px}
.print-guide .pub{font-size:.86rem;color:var(--slate);margin:0 0 8px}

/* The quiet link row at the foot of the consumer pages. */
.footer-meta{font-size:.85rem;color:var(--slate);margin-top:10px}
.footer-meta a{color:var(--navy)}

/* ------------------------------------------------------- ask us to watch this sailing */
/* The capture form at the foot of the day-by-day, dressed as CLOSING MATTER exactly as the share
   row below it is: the same --rule-2 hairline, the same 26px above it, the same serif heading at
   the same size and colour. It introduces no button language and no colour of its own -- the
   submit control is the header's `.tool` pill, unmodified, which is the same control the share
   row uses. Amber is deliberately NOT used: the page's one amber call is "See the map", and a
   second one would make two things look like the page's ask.

   The field is 1rem, which on this stylesheet's 17px root is 17px. That is not a taste decision:
   under 16px iOS zooms the whole page the moment the field takes focus, and this form's readers
   are on phones. */
.watchask{border-top:1px solid var(--rule-2);margin-top:26px;padding-top:16px}
.watchask h2{margin:0 0 8px;font-family:var(--serif);font-size:1.02rem;font-weight:600;
  color:var(--ink-2);letter-spacing:.01em}
.watchask-lede{margin:0 0 8px;font-size:.95rem;line-height:1.55;color:var(--slate);max-width:62ch}
.watchask-said{margin:0 0 12px;font-size:.95rem;line-height:1.55;color:var(--navy);
  font-weight:600;max-width:62ch}
.watchask-label{display:block;font-size:.95rem;font-weight:700;color:var(--ink-2);margin:0 0 6px}
.watchask-row{display:flex;flex-wrap:wrap;gap:10px;align-items:center}
/* `min-width:0` is what stops a flex item refusing to shrink below its intrinsic width, which is
   how an input in a row overflows a 390px screen sideways. */
.watchask-email{flex:1 1 16rem;min-width:0;font:inherit;font-size:1rem;color:var(--ink);
  padding:11px 12px;border:1.5px solid var(--rule);border-radius:9px;background:var(--card);
  min-height:44px}
.watchask-email:hover{border-color:var(--navy)}
.watchask-go{flex:0 0 auto;justify-content:center}
.watchask-fine{margin:10px 0 0;font-size:.86rem;line-height:1.55;color:var(--slate);max-width:62ch}

/* -------------------------------------------------- "do not see your sailing?" on these pages */
/* The front door prints this same sentence (_ask_add.html) as an inset note inside its entry
   block, because there it interrupts a reader who is part-way through three menus. Here the
   reader has already had the answer they came for, so it is closing matter like the two blocks
   around it -- same hairline, same measure, one step quieter than body copy. */
body.p-watch .ask-add,body.p-map .ask-add{border-top:1px solid var(--rule-2);margin:26px 0 0;
  padding-top:16px;font-size:.95rem;line-height:1.55;color:var(--ink-2);max-width:62ch}
body.p-watch .ask-add a,body.p-map .ask-add a{font-weight:700;color:var(--navy)}

/* ---------------------------------------------------------------- the share row */
/* One quiet row at the foot of the watch page, the river pages and the FAQ, so a reader who has
   just read their sailing's status can send it to somebody without selecting the address bar by
   hand. It is dressed as CLOSING MATTER, not as an offer.

   Nothing here is a new look. The hairline and the heading are the front door's river index --
   `body.p-home .rivers`, the other quiet block that sits on a footer -- and the controls are the
   header's own `.tool` pills, unmodified: same paper fill, same 1.5px rule border, same 999px
   radius, same navy, same 44px minimum. The row therefore introduces no button language, no
   colour and no type size that this product did not already own. --rule-2 is the lightest rule
   token, which is what keeps it a hairline above the footer's own heavier line rather than a
   second box.

   It is a <section> with a real heading rather than a bare row of controls: a reader meeting
   "Facebook" from the keyboard or a screen reader is told once what these are for. */
.sharerow{border-top:1px solid var(--rule-2);margin-top:26px;padding-top:16px}
.sharerow-title{margin:0 0 10px;font-family:var(--serif);font-size:1.02rem;font-weight:600;
  color:var(--ink-2);letter-spacing:.01em}
.sharerow-acts{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
/* `[hidden]` loses to `.tool`'s display:inline-flex on specificity alone, so the controls that
   need scripting would have sat there visible and dead until watch.js ran. Two classes beats
   one, and this is the rule that makes `hidden` mean hidden on them. Both the foot row's buttons
   and the masthead control are named, because both ship hidden for the same reason. */
.sharebtn[hidden],.sharetool[hidden]{display:none}
/* "Make text larger" has the same fault and needed a different answer. It is also a control that
   can do nothing at all without scripting -- it toggles one class from watch.js and that is the
   whole of it -- and it had been sitting in every masthead and on the front door, focusable and
   44px and dead, for a reader with scripting off.
   But `hidden` was the wrong tool HERE, and measuring said so: on a 390px phone the watch page's
   tools row wraps, and this pill is what makes it wrap. Ship it display:none and the masthead is
   211px until the deferred script runs and 263px after -- a 52px jolt down the page, on load, for
   the ninety-nine readers in a hundred who DO have scripting, to spare the hundredth a dead
   button. `visibility` keeps the box and drops the button: the row is laid out once, at the size
   it will keep, and a hidden-by-visibility control is out of the tab order and out of the
   accessibility tree just as thoroughly as `hidden` would put it. watch.js takes the attribute
   off. Measured after: 263px before the script and 263px after it. */
.tool[data-needs-script]{visibility:hidden}
/* The confirmation. Its line is reserved whether or not there is anything in it -- min-height,
   not an element that appears from nowhere -- so pressing "Copy link" moves nothing on the page.
   Deliberately NOT --green: green is a signal-ladder colour on these pages and means the river
   is clear, and a confirmation that borrowed it would be a second meaning for one colour.

   `line-height` and `min-height` here are ONE number and must stay that way: the first sets how
   tall a filled line is, the second reserves exactly that much while it is empty. They were 1.35em
   against an inherited 1.55 to begin with, and the row grew 3.06px under the reader's thumb at the
   moment of pressing -- measured in a browser at 1280, which is the only place a gap that size is
   ever found. test_pressing_copy_moves_nothing_on_the_page now checks them against each other. */
.sharerow-said{margin:9px 0 0;line-height:1.55;min-height:1.55em;font-size:.9rem;
  color:var(--navy);font-weight:600}

/* ---------------------------------------------------------------- the masthead share control */
/* It is a `.tool` and this adds NOTHING to that pill -- no colour, no border, no size, no radius,
   not even the 44px minimum, which it inherits. Restating any of them here is what would let the
   masthead's two buttons drift apart, and they must stay the same button.
   The print rule needs no entry either: this sits inside `.topbar-tools`, which that block
   already hides.

   All this file contributes is the three states, stacked in ONE grid cell so that the widest of
   them -- "Link copied", at eleven characters -- sets the width of the button and the other two
   are measured against it. Swapping which one is visible therefore cannot resize the button, so
   pressing it cannot reflow the masthead. It is the foot row's "reserve the space" answer with no
   hard-coded width to keep in step with the strings: change the wording and the reservation
   changes with it.

   `visibility:hidden` rather than `display:none` on the inactive two, because that is what keeps
   them occupying the cell -- and it also keeps them out of the accessibility tree, so the button's
   name is the one word showing and not all three at once. */
.sharetool-states{display:grid;align-items:center;justify-items:center}
.sharetool-states>span{grid-area:1/1;visibility:hidden}
.sharetool[data-state="idle"] .s-share,
.sharetool[data-state="done"] .s-done,
.sharetool[data-state="fail"] .s-fail{visibility:visible}

/* The front door's "Change sailing" control is a link on the live pages, not a
   disclosure button: the picker lives on the front page now. */
a.btn-change{display:inline-block;text-decoration:none}

/* The river index on the front door. Quiet -- it is the second way in, not the first: a reader
   who knows their sailing uses the picker above and never needs this. Same measure and rhythm as
   the footer it sits on, so it reads as part of the closing matter rather than a new offer. */
body.p-home .rivers{max-width:var(--measure,68ch);margin:34px auto 0;padding:18px 0 0;
  border-top:1px solid var(--rule-2);text-align:center}
body.p-home .rivers h2{margin:0 0 8px;font-family:var(--serif);font-size:1.02rem;font-weight:600;
  color:var(--ink-2);letter-spacing:.01em}
body.p-home .rivers p{margin:0;font-size:.95rem;line-height:2;color:var(--slate)}
body.p-home .rivers a{color:var(--navy);text-decoration:none;border-bottom:1px solid var(--rule);
  padding:6px 2px;display:inline-block;min-height:22px}
body.p-home .rivers a:hover{border-bottom-color:var(--navy)}

/* ------------------------------------------------------------------ the official BfG forecast
   BfG granted written permission to show these values, on the condition that a shown forecast
   names its own issue stamp. So `.bfg-stamp` is styled to be read, not to be fine print: it sits
   at body weight beside the credit, and no rule anywhere may hide either of them.

   The panel is deliberately quieter than the measured reading above it -- a hairline edge and a
   pale ground rather than a status colour -- because it is somebody else's product sitting beside
   ours, and it must never read as one of this page's own verdicts.

   Widths are set for a 390px phone with nothing to spare: the table is four columns of short
   text, the first column takes what it needs and the three figure columns share the rest, so the
   panel never pushes the page sideways. `overflow-x:auto` on the table is the belt to that
   braces -- a longer month name scrolls the table, never the document. */
.bfg{margin:18px 0 0;padding:12px 13px;border:1px solid #E3DED2;border-radius:8px;background:#FCFBF8}
.bfg-h{margin:0 0 8px;font-size:1rem;line-height:1.3}
.bfg-block{margin:0 0 14px}
.bfg-block:last-of-type{margin-bottom:8px}
/* The figures one native disclosure down: the closed row names the product and its issue stamp;
   open, the full credit line, drawing and table unfold in place. Same disclosure idiom as .eng
   and the weather module's .teach. */
.bfg-more{border:1px solid #E3DED2;border-radius:9px;background:#fff}
.bfg-more>summary{cursor:pointer;list-style:none;padding:9px 12px;font-weight:700;font-size:.9rem;
  color:var(--navy);display:flex;align-items:center;gap:8px}
.bfg-more>summary::-webkit-details-marker{display:none}
.bfg-more>summary::after{content:"\25be";margin-left:auto;color:var(--amber);font-size:1.05rem}
.bfg-more[open]>summary::after{content:"\25b4"}
.bfg-more>summary:hover{background:var(--paper)}
.bfg-more>summary .who{display:block;font-weight:400;font-size:.8rem;color:#5E6B7E}
.bfg-more>*:not(summary){margin-left:12px;margin-right:12px}
.bfg-more>*:last-child{margin-bottom:12px}
.bfg-more[open]>summary{border-bottom:1px solid #EFEAE0;margin-bottom:10px}
.bfg-name{margin:0 0 4px;font-size:.95rem;line-height:1.35}
.bfg-cred{margin:0 0 8px;font-size:.9rem;line-height:1.45}
.bfg-stamp{white-space:nowrap}
.bfg-old{margin:0 0 8px;font-size:.9rem;line-height:1.45;color:#6B4A16}
.bfg-none{margin:0 0 8px;font-size:.9rem;line-height:1.45}
/* The width cap lives on the container, not on the <svg>. `body.mob img, body.mob svg,
   body.mob table{max-width:100%}` is one class and two type selectors, so it outranks
   `.bfg-fig svg` and quietly won on the phone -- the figure was drawn at its designed scale
   on a laptop and stretched on a phone, which is the opposite of the intent. A max-width on
   the block that holds it cannot be reached by a rule about svg elements at all. */
.bfg-fig{margin:0 0 8px;max-width:340px}
.bfg-fig svg{display:block;width:100%;height:auto}
.bfg-table{width:100%;max-width:100%;border-collapse:collapse;margin:0 0 8px;font-size:.88rem;
  display:block;overflow-x:auto}
.bfg-table thead th{text-align:right;font-weight:700;padding:3px 6px;border-bottom:1px solid #E3DED2;
  white-space:nowrap}
.bfg-table thead th:first-child{text-align:left}
.bfg-table tbody th{text-align:left;font-weight:400;padding:3px 6px;white-space:nowrap}
.bfg-table tbody td{text-align:right;padding:3px 6px;font-variant-numeric:tabular-nums;
  white-space:nowrap}
.bfg-table tbody tr:nth-child(even){background:#F6F3EC}
.bfg-note{margin:0 0 6px;font-size:.85rem;line-height:1.5;color:#4A4636}
.bfg-src{margin:0;font-size:.85rem;line-height:1.5}
.bfg-sep{margin:10px 0 6px;font-size:.88rem;line-height:1.5;font-weight:700}
.bfg-cap{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* -------------------------------------------------------------- the official EuRIS prediction
   Its own classes rather than a second name on the BfG rules: `.eur-*` marks EuRIS content, and
   the isolation proof in tests/test_euris_display.py removes exactly that content. Sharing a
   selector list with `.bfg-*` would make one authority's markup indistinguishable from another's
   in the very place where telling them apart is the point.

   The look is deliberately the BfG panel's: both are somebody else's product sitting beside ours,
   and neither may read as one of this page's own verdicts. Two columns here rather than four,
   because EuRIS publishes one figure per time, and `overflow-x:auto` again keeps a long row
   inside the table rather than pushing a 390px page sideways. */
.eur{margin:18px 0 0;padding:12px 13px;border:1px solid #E3DED2;border-radius:8px;background:#FCFBF8}
.eur-h{margin:0 0 8px;font-size:1rem;line-height:1.3}
.eur-block{margin:0 0 8px}
.eur-more{border:1px solid #E3DED2;border-radius:9px;background:#fff}
.eur-more>summary{cursor:pointer;list-style:none;padding:9px 12px;font-weight:700;font-size:.9rem;
  color:var(--navy);display:flex;align-items:center;gap:8px}
.eur-more>summary::-webkit-details-marker{display:none}
.eur-more>summary::after{content:"\25be";margin-left:auto;color:var(--amber);font-size:1.05rem}
.eur-more[open]>summary::after{content:"\25b4"}
.eur-more>summary:hover{background:var(--paper)}
.eur-more>summary .who{display:block;font-weight:400;font-size:.8rem;color:#5E6B7E}
.eur-more>*:not(summary){margin-left:12px;margin-right:12px}
.eur-more>*:last-child{margin-bottom:12px}
.eur-more[open]>summary{border-bottom:1px solid #EFEAE0;margin-bottom:10px}
.eur-name{margin:0 0 4px;font-size:.95rem;line-height:1.35}
.eur-cred{margin:0 0 8px;font-size:.9rem;line-height:1.45}
.eur-stamp{white-space:nowrap}
.eur-old{margin:0 0 8px;font-size:.9rem;line-height:1.45;color:#6B4A16}
.eur-none{margin:0 0 8px;font-size:.9rem;line-height:1.45}
.eur-table{width:100%;max-width:100%;border-collapse:collapse;margin:0 0 8px;font-size:.88rem;
  display:block;overflow-x:auto}
.eur-table thead th{text-align:right;font-weight:700;padding:3px 6px;border-bottom:1px solid #E3DED2;
  white-space:nowrap}
.eur-table thead th:first-child{text-align:left}
.eur-table tbody th{text-align:left;font-weight:400;padding:3px 6px;white-space:nowrap}
.eur-table tbody td{text-align:right;padding:3px 6px;font-variant-numeric:tabular-nums;
  white-space:nowrap}
.eur-table tbody tr:nth-child(even){background:#F6F3EC}
.eur-note{margin:0 0 6px;font-size:.85rem;line-height:1.5;color:#4A4636}
.eur-fine{margin:0 0 6px;font-size:.78rem;line-height:1.5;color:#5E6B7E;word-break:break-word}
.eur-src{margin:0 0 4px;font-size:.85rem;line-height:1.5}
.eur-sep{margin:10px 0 6px;font-size:.88rem;line-height:1.5;font-weight:700}
.eur-cap{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ==========================================================================================
   THE MOBILE VARIANT

   Everything below applies only where the server decided this visitor gets the phone-shaped
   page and put `mob` on the body (waterlogged/watch/device.py). It is deliberately NOT a
   media query: a narrow window on a laptop still gets the desktop page, which is a whole page
   of content laid out narrow, and folding THAT into disclosures would take something away
   from a reader who can see all of it.

   The audience is people in their fifties and up, on a phone, often on ship wifi. Three rules
   run through all of it: nothing a thumb has to hit is under 44 px, nothing a reader has to
   read is under 16 px (which is also what stops iOS zooming the page when a select takes
   focus), and nothing scrolls sideways except the two things that are meant to.
   ========================================================================================== */
body.mob{font-size:17px;overflow-x:hidden}
body.mob .wrap{padding-left:14px;padding-right:14px}
body.mob p,body.mob li,body.mob td,body.mob th{font-size:1rem}
body.mob a,body.mob button,body.mob summary{touch-action:manipulation}
body.mob img,body.mob svg,body.mob table{max-width:100%}

/* the chrome */
body.mob .topbar-in{gap:10px}
/* The strapline gets its own line under the wordmark on a phone, and the whole width of it.
   Beside the wordmark there is about 110px left on a 375px screen, which would set this
   sentence as a four-line column against a two-line mark: crowding the one thing in the header
   that has to be read at a glance. Under it, at the full width, it is one line.
   It is NOT hidden here. The old consumer header dropped it under 560px; the owner asked for
   the tagline in the header, and a phone is where most of these readers are.
   .95rem is 16.15px, which clears the 16px floor this variant holds prose to -- a tagline is a
   sentence a reader reads, not a label on a drawing, so it is raised with the prose and is not
   one of the named exceptions at the foot of this file. */
body.mob .brandline{flex-basis:100%}
body.mob .brandline .brand-tag{flex-basis:100%;max-width:none;font-size:.95rem}
body.mob .topbar-tools{display:flex;flex-wrap:wrap;gap:8px;width:100%}
body.mob .topbar-tools .tool{min-height:44px;display:inline-flex;align-items:center;
  justify-content:center;font-size:1rem;flex:1 1 auto}
body.mob .btn-change{min-height:44px;display:inline-flex;align-items:center;font-size:1rem}

/* the morning counts and the status key stack rather than wrap into orphans */
body.mob .counts{display:grid;grid-template-columns:1fr 1fr;gap:9px}
body.mob .counts .count{width:auto;margin:0}
body.mob .key ul{display:block}
body.mob .key li{margin-bottom:12px}
body.mob .chip{white-space:normal;font-size:.9rem;padding:7px 10px}

/* ---------------------------------------------------------------- the day-by-day fold */
/* One column, one entry at a time: the day tag and the port on top, that entry's own headline
   figure under it, and everything else behind a native disclosure. The disclosure IS the
   mechanism -- it works with no script, it is focusable and operable from a keyboard without
   anybody writing that, and its content is server-rendered, so nothing is fetched when it
   opens and nothing is missing if scripting never runs. */
body.mob .stop{display:block;margin-bottom:16px}
body.mob .rail{padding:0 0 6px;display:flex}
body.mob .daytag{max-width:none;display:inline-flex;align-items:baseline;gap:7px;padding:5px 11px}
body.mob .daytag .n{font-size:1.05rem}
body.mob .stopbox-head{display:block}
body.mob .stopbox-head .sig{margin-left:0;margin-top:9px}
body.mob .brief{margin:11px 0 0}
body.mob .brief .verdict{font-size:1.3rem;line-height:1.22;margin:0}
body.mob .brief .verdict-sub{font-size:.95rem;margin:6px 0 0}
body.mob .brief .big{font-size:1.15rem;font-weight:800;color:var(--navy);margin:0}

body.mob .deep{margin:12px 0 0;border-top:1px solid var(--rule-2)}
body.mob .deep>summary{list-style:none;cursor:pointer;min-height:44px;display:flex;align-items:center;
  gap:9px;font-weight:700;font-size:1rem;color:var(--navy);padding:11px 2px}
body.mob .deep>summary::-webkit-details-marker{display:none}
body.mob .deep>summary::after{content:"\25be";margin-left:auto;color:var(--amber);font-size:1.3rem;line-height:1}
body.mob .deep[open]>summary::after{content:"\25b4"}
body.mob .deep>summary .deep-shut{display:none}
body.mob .deep[open]>summary .deep-open{display:none}
body.mob .deep[open]>summary .deep-shut{display:inline}
body.mob .deep-in{padding-bottom:6px}

/* the reading, in one column */
body.mob .reading{display:block}
/* The gauge board gets a row to itself here, so it can be bigger than it is when it has to sit
   beside the figures -- and its own printed figures come back up off the 9 px the narrow-screen
   rule drops them to, which was chosen for a board squeezed into a corner and is under half the
   size the rest of this page is set at. The board grows faster than the labels do, so the
   placement solver has MORE room per label than it was tuned for, not less. */
body.mob .staff-col{margin:0 auto 12px}
body.mob .staff{width:74px;height:210px}
body.mob .slbl{font-size:12px}
body.mob .slbl .u{display:inline}
body.mob .figs{min-width:0;width:100%;flex:1 1 auto}
body.mob .rows th,body.mob .rows td{font-size:.98rem;padding-top:7px;padding-bottom:7px}
body.mob .held{display:block}
body.mob .held svg{display:block;margin:0 auto 10px}
/* the fold under the green sentence: a thumb-sized target, at the body size */
body.mob .held-more>summary{min-height:44px;font-size:1rem}

/* the graph. It is already solved for this width on the server, so all that is left here is
   to let it fill the column and keep the key readable. */
body.mob .spark svg{width:100%;height:auto}
body.mob .spark-key{font-size:.86rem;gap:6px 14px}
body.mob .spark-more .wlterm-btn{min-height:44px;font-size:.95rem}

/* ------------------------------------------------- the authority panels, on a phone */
/* BfG's and EuRIS's own figures. The comment beside `.bfg-table` says the widths were "set for a
   390px phone with nothing to spare" and that `overflow-x:auto` is only the belt to that braces.
   Measured in a browser at 390px they were not: BfG's 6-week table wanted 334px in the 296px the
   phone gives it and EuRIS's wanted 300px, so the last column stood outside the frame and only
   about a third of "Upper" was on screen -- with no scrollbar on a phone to say a column was
   missing. Two things had pushed the drawing past its own budget. The panel sits two boxes deeper
   here than the gauge page it was measured on (`.stopbox` and `.bfg` each add their padding, and
   `.bfg-more` its 12px side margins), and `body.mob td,body.mob th` sets the cells at 17px where
   `.bfg-table` had designed them at 14.96px -- it wins on source order at equal specificity, and
   it should, because a table of figures is something a reader reads.
   So the type stays at 17px and the two things that cost nothing give way instead: the row label
   may wrap, and the cells lose 2px of side padding each. Measured after: every authority table on
   the page fits its frame exactly at 390px, nothing is hidden and nothing wraps, because a table
   that fits has no reason to break a line. Below 390 -- and with "Make text larger" on -- the
   frame still scrolls, which is what it has always been there for. */
body.mob .bfg-table tbody th,body.mob .eur-table tbody th{white-space:normal}
body.mob .bfg-table th,body.mob .bfg-table td,
body.mob .eur-table th,body.mob .eur-table td{padding-left:4px;padding-right:4px}
/* The link to the authority's own file was 22px tall on a phone -- the smallest target on the
   watch page, and the one control in the panel a reader actually reaches for. Padding rather than
   a height, the same answer `.footer-meta a` and `.detail-more a` already give, so it still reads
   as a sentence and not as a button. */
body.mob .bfg-src a,body.mob .eur-src a{display:inline-block;padding:11px 2px}

/* the official guidance: a native fold, not a modal opened by script */
body.mob .official{margin:12px 0 0;border:1.5px solid var(--rule);border-left:6px solid var(--amber);
  border-radius:9px;background:#FDFBF6}
body.mob .official>summary{list-style:none;cursor:pointer;min-height:48px;display:flex;align-items:center;
  gap:10px;padding:11px 13px;font-weight:700;font-size:.98rem;color:var(--navy)}
body.mob .official>summary::-webkit-details-marker{display:none}
body.mob .official>summary::after{content:"\25be";margin-left:auto;color:var(--amber);font-size:1.3rem;line-height:1}
body.mob .official[open]>summary::after{content:"\25b4"}
body.mob .official .who{display:block;font-weight:400;font-size:.86rem;color:var(--slate)}
body.mob .official .guide-body{padding:0 13px 14px;font-size:.98rem}
body.mob .official .guide-body p{margin:0 0 9px}
body.mob .official .guide-links{margin:11px 0}
body.mob .official .btn-out{display:flex;align-items:center;justify-content:center;min-height:48px;
  width:100%;box-sizing:border-box;text-align:center}
body.mob .official .eng>summary{min-height:44px;display:flex;align-items:center}

/* Term bubbles are placed by script at position:fixed and clamped inside the viewport, so
   they cannot overflow it; what they can do on a phone is come out too narrow to read. */
body.mob .wlterm-pop{max-width:calc(100vw - 20px);font-size:.95rem}
body.mob .wlterm-btn{min-height:44px}

/* The footer's own row of links is the last place on the page where a target is a line of text
   rather than a control. Padding rather than a height, so the row still reads as a sentence of
   links separated by middots, and every one of them is 44 px to a thumb. */
body.mob .footer-meta a{display:inline-block;padding:12px 3px}

/* ---------------------------------------------------------------- the weather module */
/* The fourteen columns stay fourteen columns. Comparing days across a fortnight is what the
   module is for, and the existing narrow treatment already fits all fourteen at 375 px with
   both the symbol and the number. What changes here is only that the half-life table may
   scroll inside its own frame -- one of the two deliberate exceptions to the no-sideways rule.

   Fourteen columns now carry a weekday and a date as well, and they did not cost a breakpoint:
   nothing in this block moved for them, because the type that had to fit was sized against the
   column rather than the column against the type. See the .dl/.dw/.dn/.dm rules above. The page
   measures 320 = 320 and 390 = 390 with larger text on and every fold open. */
body.mob .rain-module .rs-body{display:block}
body.mob .rain-module .rs-chart{flex:1 1 100%}
body.mob .rain-module .rs-total{border-left:0;border-top:1px solid var(--rule);padding:9px 0 0;
  margin-top:10px;text-align:left}
body.mob .rain-module .rs-read{font-size:1rem}
body.mob .rain-module .rain-chip{max-width:none}
body.mob .rain-module .teach>summary{min-height:48px;font-size:1rem}
body.mob .rain-module .half-life-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}

/* ---------------------------------------------------------------- the front page */
body.mob.p-home .steps{grid-template-columns:1fr;gap:14px}
body.mob.p-home .step label{font-size:1rem}
/* 16 px on a select is the number that stops iOS zooming the whole page when it takes focus. */
body.mob.p-home select{width:100%;min-height:48px;font-size:16px;padding:11px 12px;box-sizing:border-box}
body.mob.p-home .btn-go{width:100%;min-height:52px;font-size:1.05rem}
body.mob.p-home .riverrow{grid-template-columns:1fr;gap:12px}
body.mob.p-home .util{display:flex;justify-content:flex-end}
body.mob.p-home .util .tool{min-height:44px;display:inline-flex;align-items:center;font-size:1rem}
/* "Do not see your sailing? Email ..." -- the address is a link inside a sentence, and it is the
   only way off this page for a reader whose sailing we do not carry. Padded like the footer's
   row rather than made a button, for the same reason: it is a sentence, and it should still read
   as one. Both selectors, because the sentence moved up to .ask-add while the date key keeps its
   own thumb-sized targets for any address it comes to hold. */
body.mob.p-home .date-key a,body.mob.p-home .ask-add a{display:inline-block;padding:12px 2px}

/* ---------------------------------------------------------------- the map page */
/* The map is a drawing of half a continent. On a phone it is held at a width it stays legible
   at and allowed to scroll sideways INSIDE ITS OWN FRAME -- the other deliberate exception --
   while the page itself never scrolls sideways. The port list is rendered above it, so a
   reader who does not want to pan a map never has to touch one. */
body.mob.p-map .mapwrap{overflow-x:auto;-webkit-overflow-scrolling:touch;padding-bottom:4px}
/* 866, not 640, since 16 August 2026, and it is the same number as routemap.REFERENCE_WIDTH.
   The route map's type is sized in the pixels it will be READ at, and that arithmetic is done
   against the width the drawing is given: at 640 the same drawing came out at 10.4 px on the day
   line, under the site's own floor for small type. Held at the width it is designed for, a phone
   pans a little further and reads the same 14 px the laptop does. */
body.mob.p-map #routemap{min-width:866px}
body.mob.p-map .hint{font-size:.92rem}
body.mob.p-map .stops{margin-bottom:20px}
body.mob.p-map .stoprow{min-height:52px;flex-wrap:wrap;font-size:1rem;text-align:left}
body.mob.p-map .detail{display:block}
body.mob.p-map .detail-body{display:block}
body.mob.p-map .detail-side{margin-top:14px}
body.mob.p-map .out{display:flex;align-items:center;justify-content:center;min-height:48px;
  width:100%;box-sizing:border-box}
body.mob.p-map .bubble{max-width:calc(100vw - 28px)}
/* The two controls on this page that a laptop sizes for a cursor. The close disc is 30 px --
   fine for a pointer, and the smallest thing on the page for a thumb, sitting in the corner of
   a bubble that covers what the reader was looking at. The "read the full guide" link is an
   inline line of text at 22 px. Both are the thing a reader reaches for once they have found
   their port, so both get the 44 px the rest of this variant keeps to; the link takes it as
   padding so it still reads as a sentence rather than turning into a button. */
body.mob.p-map .bclose{width:44px;height:44px;top:6px;right:6px;font-size:1.05rem}
body.mob.p-map .detail-more a{display:inline-block;padding:11px 2px}

/* ------------------------------------------------------- the 16 px floor under the prose */
/* `body.mob p` at the top of this section sets the body size, but it loses on specificity to
   every two-class rule in this stylesheet -- `.guide-body .checked`, `.rain-module .rs-tag`,
   `.key em` -- which were written in fractions of a rem for a laptop. Measured in the phone
   variant they arrive between 11.6 px and 15.8 px, and among them are the licence line, the
   publisher line, the status key's explanations and the graph's own start-date note: the
   sentences this product is judged on, at a size the readers it was built for cannot read.
   So each is named and raised. Named rather than blanketed, because the exceptions below are
   real and a blanket rule would take them too.

   `1rem` is 17 px here (html is set to 17), `.95rem` is 16.15 px; both clear 16. The split is
   between a sentence and a caption, not between important and unimportant. */
body.mob .voyage>.lede,
body.mob .key em,
body.mob .rain-module .rain-title p,
body.mob .rain-module .rain-sec>.rain-lede,
body.mob .rain-module .plain-stopbox p,
body.mob .rain-module .caution p,
body.mob.p-map .stops .lede{font-size:1rem}

body.mob .guide-body .pub,
body.mob .guide-body .checked,
body.mob .held-text .fine,
body.mob .howto .tr,
body.mob .howto .tr a,
body.mob .rain-module .wx-lede,
body.mob .rain-module .table-note,
body.mob .rain-module .wxlede .scale-note,
body.mob .rain-module .rs-tag,
body.mob .rain-module .wx-source{font-size:.95rem}

/* The exceptions, named so that "no prose under 16 px" stays a checkable claim rather than a
   slogan. These are labels ON a drawing and provenance strings, not sentences a reader reads:
   the rain chart's axis caption and footnote, the `.rs-total small` that captions the total
   ("expected upstream over 14 days"), and the two file-path citations that say which line of
   which file a number came from. Raising
   them is what would break the fourteen columns the module needs to stay comparable across a
   fortnight, and none of them carries a claim -- every claim they sit under is raised above.

   They are listed and not written: .rs-cap, .wx-foot, .src, .rule-source and the unclassed
   `small` in .rs-total each already win on specificity against the `body.mob p` rule above, so
   leaving them out of this section IS the decision to leave them alone. A rule here setting
   them to `inherit` would raise them, which is the one thing this paragraph says not to do. */

/* Printing a phone-shaped page: a shut fold would print as a heading with nothing under it,
   so every fold is opened for the printer. Nothing on this variant is withheld from print. */
@media print{
  body.mob details>*:not(summary){display:block!important}
  body.mob .deep>summary,body.mob .official>summary{page-break-after:avoid}
}

/* The river index, thumb-sized: bigger type off the prose floor and a 44px target per link. */
body.mob.p-home .rivers p{font-size:1rem;line-height:2.2}
body.mob.p-home .rivers a{padding:11px 4px;min-height:44px;display:inline-flex;align-items:center}

/* The share row, thumb-sized. The 44px minimum is already `.tool`'s and is not restated here --
   restating it would let the two drift. What this adds is the phone's reading size on the pills
   and on the confirmation, and an even split of the row: `flex:1 1 auto` is what the header's
   own tools row does on a phone, so two controls come out as two halves rather than as a pair of
   small pills with a ragged tail beside them. The heading needs no rule at all: 1.02rem is
   17.3px, already above this variant's 16px floor. */
body.mob .sharerow-acts{gap:9px}
body.mob .sharerow .sharebtn{font-size:1rem;flex:1 1 auto;justify-content:center}
body.mob .sharerow-said{font-size:1rem}

/* The capture form and the "do not see your sailing?" sentence, thumb-sized. The field and the
   button each take the whole width rather than sharing a row: at 390px, minus this variant's
   14px gutters, a side-by-side pair leaves an address field about eleven characters wide, which
   is where somebody typing on a phone loses sight of what they have typed. The consent line is
   the only thing here written below the prose floor for a laptop, so it is raised -- it is the
   sentence that says what happens to the address, which is not fine print on a phone. The link
   in the sentence gets the same thumb-sized target the front door's already has. */
body.mob .watchask-row{flex-direction:column;align-items:stretch}
body.mob .watchask-email{flex:1 1 auto;min-height:48px}
body.mob .watchask-go{width:100%;justify-content:center;font-size:1rem}
body.mob .watchask-fine{font-size:.95rem}
body.mob.p-watch .ask-add a,body.mob.p-map .ask-add a{display:inline-block;padding:12px 2px}

/* The masthead control, on a phone. It keeps `.tool`'s 44px and this variant's 1rem, both
   inherited; the one thing it opts OUT of is the row's `flex:1 1 auto`.
   Measured at 375, which is why this rule exists at all. The three tools on a watch page --
   "Make text larger" 158px, "See the map" 156px, this 120px -- come to 451px of content in a
   347px row, so a third control cannot share the line whatever it is called: even stripped to
   the word "Share" alone it is still 415px. The row therefore wraps, and the only question left
   is what the wrapped item looks like. Left to stretch it became a full-width outlined banner
   under the amber call to action -- a third equal-weight action, which is the widget bar this
   feature keeps being written not to be. At its natural width and pushed to the end of the line
   it is a quiet pill sitting under "See the map", which is what a secondary control should look
   like, and it is the same alignment `.topbar-tools` already uses on a laptop.
   The river pages and the FAQ carry two tools, not three, so there the row does not wrap at all
   and this simply holds the button at its own width against the right-hand edge. */
body.mob .topbar-tools .sharetool{flex:0 0 auto;margin-left:auto}
