
@font-face{
  font-family:'Archivo';
  src:url('/fonts/archivo.woff2') format('woff2-variations');
  font-weight:400 800;font-stretch:100% 125%;font-style:normal;font-display:swap;
}
@font-face{
  font-family:'Newsreader';
  src:url('/fonts/newsreader.woff2') format('woff2-variations');
  font-weight:400 600;font-style:normal;font-display:swap;
}
:root{
  --bg:oklch(0.962 0.013 82);
  --surface:oklch(0.930 0.020 82);
  --foam:oklch(0.972 0.011 82);
  --ink:oklch(0.265 0.018 220);
  --muted:oklch(0.470 0.022 218);
  --sea:oklch(0.395 0.058 216);
  --sea-deep:oklch(0.310 0.052 218);
  --tile:oklch(0.600 0.132 38);
  --tile-ink:oklch(0.500 0.126 38);
  --tile-lite:oklch(0.810 0.096 52);
  --rule:oklch(0.820 0.022 82);
  --hair:oklch(0.900 0.016 82);
  --sans:'Archivo',system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --serif:'Newsreader',Georgia,'Times New Roman',serif;
  --r:14px;
  --paper:0 18px 44px -22px oklch(0.265 0.018 220/.35),0 2px 8px -2px oklch(0.265 0.018 220/.12);
  --ease:cubic-bezier(.16,1,.3,1);
  /* The masthead, and the section menu at full size: what a full-height band
     has to leave room for so band plus menu is exactly one screen. */
  --hdr:61px;
  --menu:126px;
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--ink);
  font:400 17px/1.55 var(--sans);-webkit-font-smoothing:antialiased}
@media(min-width:900px){body{font-size:18px}}
.wrap{max-width:1060px;margin:0 auto;padding:0 20px}
/* Two timetables side by side with a ticket button on every sailing want more
   than the reading measure a page of prose does. */
.main--wide{max-width:1240px}
a{color:var(--sea);text-decoration-thickness:1px;text-underline-offset:3px}
a:hover{color:var(--tile-ink)}
:focus-visible{outline:2px solid var(--tile);outline-offset:3px;border-radius:2px}
/* --tile is only 2.91:1 on the sea grounds, so the ring changes with the ground. */

.visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
/* The skip link is the first thing in the tab order and the only thing that
   un-hides itself when focused. Without it every page makes a keyboard user
   tab past the wordmark and four language links before reaching the content. */
.skip:focus{position:fixed;top:8px;left:8px;z-index:99;width:auto;height:auto;
  margin:0;clip:auto;overflow:visible;padding:12px 16px;border-radius:8px;
  background:var(--foam);color:var(--sea-deep);font:600 15px/1 var(--sans);
  text-decoration:none;box-shadow:var(--paper)}

/* the masthead is paper; the sea starts below it, under the photograph */
.masthead{background:var(--bg);color:var(--ink);border-bottom:1px solid var(--hair)}
.masthead .wrap{display:flex;align-items:center;justify-content:space-between;
  gap:16px;height:60px}
/* At 320 the wordmark plus four language codes plus the default gutter came to
   338px, so every page scrolled sideways (WCAG 1.4.10). Tighten both, and let
   the wordmark shrink rather than push. */
@media(max-width:389px){
  .masthead .wrap{gap:8px;padding:0 14px}
  .brand{font-size:17px;min-width:0}
  .langs{gap:2px}
  .langs a{padding:6px 5px}
}
.brand{font:600 23px/1 var(--serif);letter-spacing:-.01em;min-width:0;
  color:var(--sea-deep);text-decoration:none}
.brand span{font-weight:400;font-style:italic;color:var(--tile-ink)}
/* At 200% zoom the four codes ran off the right edge: the row could not wrap
   and the wordmark would not give ground. Both now do. */
.langs{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:4px;
  font:600 13px/1 var(--sans);min-width:0}
.langs a{color:var(--ink);opacity:.74;text-decoration:none;padding:6px 8px;
  border-radius:999px;transition:opacity .15s var(--ease),background .15s var(--ease)}
.langs a:hover{opacity:1;background:var(--surface);color:var(--ink)}
/* Keep the 44px vertical hit zone but stop it spilling sideways onto the
   neighbouring language, which made the seam pick the wrong one. */
.langs a.tap::after{width:100%;left:0;transform:translateY(-50%)}
.langs a[aria-current]{opacity:1;background:var(--sea-deep);color:var(--foam)}

/* The homepage chooser. The masthead codes are for someone who already knows
   the site; this is for a first arrival who does not read the language they
   landed in, so the names are big, tappable and each in its own tongue. */
.langpick{display:flex;flex-wrap:wrap;gap:8px;margin:22px 0 0}
.langpick a{color:var(--foam);text-decoration:none;padding:11px 17px;
  display:inline-flex;align-items:center;gap:9px;
  font:600 16px/1 var(--sans);border-radius:999px;
  border:1px solid rgba(255,255,255,.42);background:rgba(255,255,255,.10);
  transition:background .15s var(--ease),color .15s var(--ease)}
.langpick a:hover{background:var(--foam);color:var(--sea-deep);
  border-color:var(--foam)}
.langpick a[aria-current]{background:var(--foam);color:var(--sea-deep);
  border-color:var(--foam)}
/* A 1px hairline, not a border: on the pale Italian and Croatian whites the
   flag otherwise dissolves into the button behind it. */
.langpick .flag{flex:none;border-radius:2px;display:block;
  box-shadow:0 0 0 1px rgba(0,0,0,.28)}
@media(max-width:389px){
  .langpick{gap:6px}
  .langpick a{padding:10px 13px;font-size:15px;gap:7px}
}

.head{position:relative;isolation:isolate;overflow:hidden;background:var(--sea-deep);
  color:var(--foam);padding:clamp(36px,7vw,84px) 0 clamp(28px,4vw,44px)}
/* A band that stopped at 85% of the phone screen was neither an opening nor a
   header: the list under it showed as a two-line sliver. `head--full` makes it
   the whole first screen, and whatever comes next - the section menu, or the
   cue - is the bottom edge of that screen rather than a leftover strip. */
.head--full{min-height:calc(100svh - var(--hdr));
  display:flex;flex-direction:column;justify-content:center}
/* On a phone the opening has to hold the title and the whole question at once.
   At the shared display size the two of them ran past the fold and the button
   that answers the question was the part that fell off. */
@media(max-width:600px){
  .head--full{padding-top:18px;padding-bottom:18px}
  .head--full .head__title{padding:16px 15px 18px}
  .head--full h1{font-size:2.05rem;line-height:1.03}
  .head--full .kicker{font-size:.72rem;letter-spacing:.07em}
  .head--full .wrap{gap:16px}
}
/* Not centred. Centring treats the panel as the content and the photograph as
   wallpaper behind it, which is how the band ended up with 319px of empty sky
   above the panel and 374px of empty water below it at 834x1112 - measured.
   Anchored low, the harbour gets the top of the frame and the type sits on it. */
/* When the control strip follows, band plus strip is the screen, not band
   alone - so the opening is the photograph and the controls, with nothing cut
   short and no leftover sliver of water above a stack of bars. --menu is the
   strip's measured height, set by the script; the value here is the fallback
   for the first paint. */
/* The band keeps the whole screen and the menu sits on it. Cut short to make
   room, the opening was a half photograph over a strip of buttons over a strip
   of dates - three bands and no picture. The padding is what the chips stand
   in, so the panel above never runs under them; --menu is the strip's measured
   height, set by the script, and the value in :root is the first paint. */
.head--full:has(+ .jumpmark){padding-bottom:calc(var(--menu) + 8px)}
/* A page whose whole job is a timetable opens on the timetable. No picture, no
   scrim, no full screen of water before the first departure - just the name of
   the crossing, quietly, with the tables under it. */
.head--slim{background:var(--surface);color:var(--ink);
  padding:14px 0 13px;min-height:0;border-bottom:1px solid var(--rule)}
.head--slim::before{display:none}
.head--slim h1{font-size:clamp(1.5rem,4.2vw,2.1rem);text-shadow:none}
.head--slim .wrap{gap:10px}
/* No paper panel on the slim band. The panel exists to hold type off a
   photograph; with no photograph it is an empty card with a shadow, which is
   what made this page read as a blank rectangle above the timetable. */
.head--slim .head__title{background:none;box-shadow:none;padding:0;
  border-radius:0;backdrop-filter:none}
.head--slim h1{margin:2px 0 0}
/* Both ends of the crossing, as places rather than as prose. */
/* The rule the boat will not tell you: nine of these islands do not let a
   private car ashore, whatever is carrying it. */
.nocars{margin:8px 0 0;font:500 .92rem/1.45 var(--sans);color:oklch(0.34 0.11 38)}
.head .nocars{color:oklch(0.355 0.115 38)}
.veh:has(:disabled){opacity:.5}
.veh:has(:disabled) .veh__b{cursor:not-allowed}

/* Two links, not two buttons. They go to the island pages; a pill implies a
   control and there is nothing here to switch. */
.head__places{display:flex;flex-wrap:wrap;gap:0 18px;margin:8px 0 0;
  font:500 1rem/1.4 var(--sans)}
/* The other half of the brand. A reader who came here for a timetable and
   turns out to be arriving on their own keel is not lost - they are on the
   wrong one of two products. Set apart from the site's own links, because it
   leaves the site. */
.sister{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;
  margin:0 0 18px;padding:0 0 16px;border-bottom:1px solid var(--hair);
  font:500 1rem/1.45 var(--sans);color:var(--muted)}
.sister a{display:inline-flex;align-items:center;gap:7px;
  font-weight:650;color:var(--sea);text-decoration:none}
.sister a:hover{color:var(--tile-ink);text-decoration:underline}
.sister a svg{transition:transform .2s var(--ease)}
.sister a:hover svg{transform:translateX(3px)}
@media(prefers-reduced-motion:reduce){.sister a svg{transition:none}}

/* The site's own index, once, at the bottom of every page. It used to be a row
   of links halfway down the front page and nowhere else. */
footer .footnav{margin:14px 0 0}
footer .footnav a{margin-right:0}
footer .footnav a,.byline a{white-space:nowrap}
.head__img{position:absolute;inset:0;z-index:-2;width:100%;height:100%;
  object-fit:cover;object-position:50% 62%}
/* The scrim is what makes white type honest on a hazy photograph: near-opaque
   sea at the bottom where the title sits, thinning toward the sky. */
.head::before{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(180deg,oklch(0.31 0.052 218/.10) 0%,
    oklch(0.31 0.052 218/.12) 55%,oklch(0.27 0.05 218/.55) 100%)}
/* The photograph stays bright. Contrast comes from a paper panel under the
   type, dark ink on it, not from dimming the harbour to make white text work:
   the sea is the point of the picture.

   Measured, and it is why the panel is nearly opaque: at 44% the panel took
   its contrast from whatever the photo happened to be doing underneath, and
   over the dark hull at the bottom of the hero the kicker measured 1.48:1 and
   the lede 1.58:1. A panel with no floor is not a contrast strategy. */
.head__title,.head__lead{background:oklch(0.972 0.011 82/.62);color:var(--ink);
  -webkit-backdrop-filter:blur(26px) saturate(1.35);backdrop-filter:blur(26px) saturate(1.35);
  border-radius:var(--r);padding:clamp(20px,3vw,30px) clamp(20px,3vw,32px);
  box-shadow:var(--paper),inset 0 1px 0 oklch(1 0 0/.6)}
@media(prefers-reduced-transparency:reduce){
  .head__title,.head__lead{background:var(--foam);backdrop-filter:none;-webkit-backdrop-filter:none}}
/* Above the cue: the type-ahead panel hangs out of the band and the cue is a
   later sibling, so without this it paints over the answers. */
.head .wrap{display:grid;gap:26px;position:relative;z-index:1}
/* The one deliberate break in the stack: on a wide screen the band carries the
   title and the answer side by side instead of being a title bar. */
@media(min-width:820px){
  .head .wrap:has(.head__lead:not([hidden])){
    grid-template-columns:1.05fr .95fr;gap:12px 48px;align-items:end}
  .head__lead{justify-self:end;text-align:right}
}
.head__lead .leg__time{color:var(--sea-deep)}
/* A line is two questions - the boat out and the boat back - so the card is
   two cards, side by side where there is room. One of them alone answered
   whichever direction happened to sail sooner and hid the other. */
.head__lead--two{display:grid;gap:10px}
.head__lead--two .head__leadlabel{grid-column:1/-1}
@media(min-width:560px){.head__lead--two{grid-template-columns:1fr 1fr;gap:14px}}
.head__lead--two .leg{padding:0}
.head__lead--two .leg__time{font-size:clamp(2rem,5.5vw,2.9rem)}
/* Two columns of their own, left-aligned inside the panel: right-aligned they
   ragged against each other and "Zadar (Gazenica)" broke over two lines. */
.head__lead--two .leg,.head__lead--two .leg *{text-align:left}
@media(min-width:820px){.head__lead--two .head__leadlabel{text-align:right}}
/* The notice sits on the photograph with the other two, under both of them,
   in the glass they are made of - as a page-width slab below the band it was
   the first thing past the fold and read as small print. */
.head__note{grid-column:1/-1;justify-self:stretch;
  background:oklch(0.972 0.011 82/.62);color:var(--ink);
  -webkit-backdrop-filter:blur(26px) saturate(1.35);backdrop-filter:blur(26px) saturate(1.35);
  border-radius:var(--r);border-left:4px solid var(--tile-ink);
  padding:clamp(14px,2vw,18px) clamp(16px,2.4vw,24px);margin:0;
  box-shadow:var(--paper),inset 0 1px 0 oklch(1 0 0/.6)}
.head__note .notice__text{max-width:78ch}
@media(prefers-reduced-transparency:reduce){
  .head__note{background:var(--foam);backdrop-filter:none;-webkit-backdrop-filter:none}}

/* Not one filled blob among four words. Every section of the page is a
   destination, so every one of them looks like a control, and the one you are
   in is the filled one. */
.jump a{border:1px solid var(--rule);background:var(--foam)}
.jump--stuck a{border-color:transparent;background:transparent}
.jump--stuck a[aria-current]{background:var(--sea-deep)}
.head h1{color:var(--sea-deep);margin:0;text-shadow:0 1px 0 oklch(1 0 0/.35)}
.head .kicker{font:600 .82rem/1 var(--sans);letter-spacing:.09em;
  text-transform:uppercase;color:var(--tile-ink);margin:0 0 12px}
.head .lede{color:var(--muted);margin:12px 0 0;max-width:52ch}
/* The panel lets the harbour through now, and the two lightest colours on it
   stopped being readable over the photograph: measured at 0.68 alpha the
   terracotta caps came to 3.81:1 and the muted lede to 3.02:1. On the band
   only, both go darker until they clear 4.5. */
/* A thinner panel lets more of the harbour through, and the rust has to hold
   4.5:1 on whatever comes through it. Measured over the photograph, composited
   with the panel: 4.3:1 at the old weight on a phone, 5.4:1 at this one. */
.head .kicker,.head .op+.kind{color:oklch(0.385 0.130 38)}
.head .head__leadlabel{color:oklch(0.325 0.024 218)}
.head .lede,.head .goes__l,.head .leg__via,
.head details.towns .answer{color:oklch(0.355 0.026 218)}
.head a{color:var(--sea)}
/* What is under the fold, said out loud. A full-height band has to admit the
   page continues, and the chevron is the one piece of unprompted motion on the
   site: it is the whole message. */
.head__cue{margin:16px 0 0;text-align:center}
.head__cue a{display:inline-flex;flex-direction:column;align-items:center;gap:4px;
  padding:11px 16px 9px;border-radius:999px;text-decoration:none;
  color:oklch(0.985 0.004 90);font:600 .95rem/1 var(--sans);min-height:44px;
  text-shadow:0 1px 12px oklch(0.20 0.03 218/.75)}
.head__cue a:hover{text-decoration:underline;text-underline-offset:4px}
.head__cue svg{opacity:.55}
@media(prefers-reduced-motion:no-preference){
  .head__cue svg{animation:bob 2.4s var(--ease) infinite}
  @keyframes bob{0%,72%,100%{transform:translateY(0)}84%{transform:translateY(3px)}}}

/* The index of the page's own sections. A Split port page runs to eight phone
   screens with the camera on the sixth, and screen one says nothing about what
   is down there. Sticky rather than a block under the hero, because the person
   who needs it is the one already five screens deep and about to give up.
   The chips are the .langs pattern, unchanged - a second visual vocabulary for
   the same job (a row of small links, one of them current) would be noise. */
/* Both directions of a crossing. Side by side where there is room to compare
   them at a glance, stacked where there is not - the out and the back are the
   two halves of one question and belong on one screen. */
.both{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:8px;align-items:start}
@media(min-width:820px){.both{gap:22px}}
/* What the boards are for, said once, above them. */
/* One way out, and no second board unless a return was asked for. */
.both--one{grid-template-columns:minmax(0,1fr)}
.both--one .way{max-width:34rem}
.both__add{margin:12px 0 0}
.both__addb{width:100%;max-width:34rem;min-height:48px;border-radius:12px;
  border:1px dashed var(--rule);background:transparent;color:var(--tile-ink);
  cursor:pointer;font:600 .95rem/1.2 var(--sans)}
.both__addb:hover{border-style:solid;background:var(--surface)}
.both__hd{display:flex;align-items:center;justify-content:space-between;
  gap:12px;flex-wrap:wrap;margin:0 0 14px}
.both__lede{margin:0;max-width:52ch;color:var(--muted);
  font:400 .95rem/1.45 var(--sans)}
@media(min-width:820px){.both__lede{font-size:1.02rem}}
.both__n{border:1px solid var(--rule);border-radius:999px;background:transparent;
  color:var(--tile-ink);cursor:pointer;font:600 .84rem/1 var(--sans);
  min-height:38px;padding:0 14px}
.both__n:hover{background:var(--surface)}

/* The enamel timetable board.

   Every Jadrolinija terminal has one bolted to the wall: a deep blue plate,
   pale type, the times in a column you can read from the far side of the
   waiting room. That is what this page is, twice - one plate per direction -
   and it is the one bold thing here, so the band above it and the page around
   it stay quiet. Cream cards with a hairline and a soft shadow were the same
   rectangle as everything else on the page, which is what "no Adriatic vibe"
   meant. */
.way{--plate:oklch(0.288 0.048 218);
  --plate-lift:oklch(0.330 0.050 218);
  --plate-sink:oklch(0.252 0.044 218);
  --plate-ink:oklch(0.968 0.012 82);
  --plate-mute:oklch(0.775 0.020 212);
  --plate-line:oklch(0.968 0.012 82/.13);
  background:var(--plate);color:var(--plate-ink);
  border-radius:12px;overflow:hidden;
  box-shadow:0 18px 40px -26px oklch(0.265 0.018 220/.55)}
/* The crossing written down the card: which half of the trip this is, then
   where you get on, an arrow pointing down, where you get off. Across a
   heading it did not fit in half a phone, and "to Susak" on its own left the
   reader to work out that the other card was the way home. */
.way__h{margin:0;padding:13px 14px 14px;background:var(--plate-sink);
  display:grid;gap:7px;color:var(--plate-ink)}
.way__k{font:700 .68rem/1 var(--sans);letter-spacing:.11em;
  text-transform:uppercase;color:var(--tile-lite)}
.way__pair{display:grid;grid-template-columns:auto minmax(0,1fr);
  grid-template-rows:auto auto;align-items:center;gap:4px 10px}
.way__p{grid-column:2;font:700 1.06rem/1.15 var(--sans);letter-spacing:-.01em;
  overflow-wrap:anywhere}
.way__a{grid-column:1;grid-row:1/3;justify-self:center;color:var(--tile-lite)}
.way__h a{color:inherit;text-decoration-color:var(--plate-line)}
.way__h a:hover{color:var(--plate-ink);text-decoration-color:currentColor}
.way .note{margin:16px 18px;color:var(--plate-mute)}
.way .note .whenbar__b{color:var(--tile-lite)}

.way__note{margin-left:auto;border:1px solid var(--tile-lite);border-radius:999px;
  background:transparent;color:var(--tile-lite);cursor:pointer;
  font:600 .82rem/1 var(--sans);min-height:32px;padding:0 12px}
.way__note:hover{background:var(--tile-lite);color:oklch(0.265 0.018 220)}
/* Over the page, not above it: a notice belongs in the reader's way when they
   ask for it and out of it while they are reading a timetable. */
.sheet{border:0;border-radius:var(--r);padding:22px;max-width:min(640px,92vw);
  background:var(--foam);color:var(--ink);box-shadow:var(--paper)}
.sheet::backdrop{background:oklch(0.265 0.018 220/.55)}
.sheet__h{margin:0 0 14px;font:500 1.3rem/1.3 var(--serif)}
.sheet__x{margin:0;float:right}
.sheet__b{border:0;background:transparent;color:var(--muted);cursor:pointer;
  font-size:1.6rem;line-height:1;min-width:44px;min-height:44px}
.way__day{display:flex;align-items:center;justify-content:space-between;gap:2px;
  padding:7px 8px 9px;background:var(--plate-sink);
  border-bottom:1px solid var(--plate-line)}
.way__day .whenbar__s{width:34px;height:34px;flex:none;background:transparent;
  border-color:var(--plate-line);color:var(--plate-ink)}
.way__day .whenbar__s:hover:not(:disabled){background:var(--plate-ink);
  color:var(--plate-sink);border-color:var(--plate-ink)}
/* The date sits between its two arrows and stays put as the words change
   length: "Wed, Sep 9" is wider than "Fri, Oct 1", and without a floor the
   arrows walked sideways every time the day changed. */
.way__d{flex:1 1 auto;min-width:0;font:600 .82rem/1.15 var(--sans);
  color:var(--plate-ink);text-align:center}

.day{list-style:none;margin:0;padding:0}
/* A departure is four facts - when it leaves, when it lands, what it costs,
   which boat - and it was written as a paragraph three lines deep with a
   button on the end. Half a phone wide, it is a grid: the times across the
   top with the fare beside them, the line underneath. */
.day__r+.day__r{border-top:1px solid var(--plate-line)}
/* The row carries the grid and the button lies under it, edge to edge. The
   line number in the row is a link to that line's timetable, and a link
   inside a button is invalid and dead - so the content sits above the button
   and passes its clicks down, and only the link keeps its own. */
.day__r{position:relative;display:grid;text-align:left;
  grid-template-columns:auto minmax(0,1fr) auto;gap:6px 10px;
  padding:14px 14px 15px;color:var(--plate-ink)}
.day__r>*{position:relative;z-index:1;pointer-events:none}
.day__pick{position:absolute;inset:0;z-index:0;width:100%;cursor:pointer;
  border:0;background:transparent;pointer-events:auto;
  -webkit-tap-highlight-color:transparent}
.day__ln a{pointer-events:auto;color:inherit;text-decoration:underline;
  text-underline-offset:3px;text-decoration-color:var(--plate-line)}
.day__ln a:hover{text-decoration-color:currentColor}
/* The mark that says this row is a choice. Empty until it is taken, and the
   tick is drawn rather than loaded, because the boards are on every crossing
   page and a second request for a checkmark is not worth making. */
.day__k{grid-column:1;grid-row:1;align-self:center;width:20px;height:20px;
  border-radius:999px;border:1.5px solid var(--plate-line);
  background:transparent;position:relative}
.day__pick:hover ~ .day__k{border-color:var(--plate-ink)}
.day__r--on .day__k{border-color:var(--plate-sink);background:var(--plate-sink)}
.day__r--on .day__k::after{content:"";position:absolute;left:6px;top:2.5px;
  width:5px;height:10px;border:solid var(--plate-ink);border-width:0 2px 2px 0;
  transform:rotate(42deg)}
/* The harbour under the place, where one boat makes the crossing and the
   rows have no reason to name it. */
.way__q{display:block;font:500 .74rem/1.3 var(--sans);font-style:normal;
  color:var(--plate-mute)}
/* Say what the board wants, until it has it. */
.way__ask{margin:0;padding:9px 14px 10px;background:var(--plate-sink);
  border-bottom:1px solid var(--plate-line);color:var(--tile-lite);
  font:700 .68rem/1.2 var(--sans);letter-spacing:.09em;text-transform:uppercase}
.day__pick:hover{background:var(--plate-lift)}
.day__t{grid-column:2/-1;grid-row:1;font:700 1.06rem/1.15 var(--sans);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.day__t i{font-style:normal;color:var(--plate-mute);padding:0 3px}
/* The fare on the line under the times, at the end of it: which boat is
   cheaper is half the choice between a 25 minute catamaran and a 90 minute
   ship, and beside the times it collided with them in half a phone. */
.day__p{grid-column:3;grid-row:2;justify-self:end;align-self:center;
  font:700 .95rem/1 var(--sans);color:var(--plate-ink);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.day__to,.day__v,.day__e{grid-column:1/-1}
.day__m{grid-column:1/3;grid-row:2;display:flex;align-items:center;
  flex-wrap:wrap;gap:4px 6px;font:500 .8rem/1.3 var(--sans);
  color:var(--plate-ink)}
.day__to{font:600 .84rem/1.25 var(--sans);color:var(--plate-ink)}
/* The calls on the way, on a screen with room for them. On a phone they were
   a third line on every row that decides nothing: the choice there is when it
   leaves, how long it takes and what it costs. They are in the trip. */
.day__v{display:none;font:400 .74rem/1.3 var(--sans);color:var(--plate-mute)}
@media(min-width:820px){.day__v{display:block}}
.day__m i,.day__v i{font-style:normal;color:var(--plate-line);padding:0 1px}
.day__e{font:600 .72rem/1.3 var(--sans);color:var(--tile-lite);margin-top:2px}
/* Whose boat it is, on a screen with room to say so. In half a phone the row
   has space for when it leaves, how long it takes and what it costs, and the
   mark was pushing itself onto a line of its own on every long crossing. The
   trip names the operator in full. */
.day__op{display:none;height:11px;width:auto;max-width:58px;object-fit:contain;
  background:var(--foam);border-radius:999px;padding:1px 3px;vertical-align:-1px}
@media(min-width:820px){.day__op{display:inline-block}}
/* The number is what the mark would have said, for a screen without room. */
.day__ln{display:none}
@media(min-width:820px){.day__ln{display:inline}}
/* Chosen. The pair of them is the trip the bar at the foot adds up. */
.day__r--on{background:var(--plate-ink)}
.day__r--on .day__t,.day__r--on .day__m,.day__r--on .day__p,
.day__r--on .day__to{color:var(--plate-sink)}
.day__r--on .day__v{color:oklch(0.252 0.044 218/.7)}
.day__r--on .day__pick:hover{background:var(--plate-ink)}
/* A boat back that leaves before the outbound lands. It stays on the board -
   the reader may be choosing the other way round - and says what is wrong. */
.day__r--early{opacity:.55}
.day__r--early.day__r--on{opacity:1}

/* The compact row is shaped by half a phone. Given a desk, it can breathe. */
@media(min-width:820px){
  .way__h{padding:15px 18px 12px;font-size:1.16rem;gap:11px}
  .way__day{padding:8px 12px 9px;justify-content:flex-start;gap:10px}
  .way__d{flex:0 0 auto;font-size:.92rem;min-width:9em;text-align:left}
  .day__r{padding:13px 18px;gap:4px 16px}
  .day__t{font-size:1.14rem}
  .day__p{font-size:1.04rem}
  .day__m{font-size:.86rem}
  .day__v{font-size:.8rem}
  .day__op{height:15px}
}

/* The trip, at the foot of the screen, from the moment there is one. */
/* The bar is fixed, so the page has to give back the height it covers or the
   last thing on it can never be read. */
body:has(.tripbar:not([hidden])){padding-bottom:76px}
.tripbar{position:fixed;left:0;right:0;bottom:0;z-index:40;
  background:var(--sea-deep);color:var(--foam);
  box-shadow:0 -8px 30px -12px oklch(0.265 0.018 220/.5);
  padding-bottom:env(safe-area-inset-bottom)}
.tripbar .wrap{display:flex;align-items:center;gap:12px;
  padding-top:9px;padding-bottom:9px}
.tripbar__s{margin:0;flex:1 1 auto;min-width:0;
  font:600 .95rem/1.3 var(--sans);font-variant-numeric:tabular-nums}
.tripbar__go{flex:none;min-height:44px;padding:0 18px;border:0;
  border-radius:999px;background:var(--tile);color:var(--foam);cursor:pointer;
  font:700 .95rem/1 var(--sans)}
.tripbar__go:hover:not(:disabled){background:var(--tile-ink)}
/* Dead until there is a trip, but present from the first look, so the reader
   knows the two boards add up to something. */
.tripbar__go:disabled{background:transparent;color:var(--foam);cursor:default;
  box-shadow:none;opacity:.42}
/* What is true of the crossing whatever day you sail it. Three facts the
   boards cannot state at a glance, and the lines they come from. */
.cx{margin:26px 0 0;padding:20px 0 0;border-top:1px solid var(--rule)}
.cx__h{margin:0 0 14px;font:500 1.2rem/1.25 var(--serif)}
.cx__f{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:14px 22px;margin:0}
.cx__f>div{margin:0}
.cx__f dt{font:600 .72rem/1 var(--sans);letter-spacing:.07em;
  text-transform:uppercase;color:var(--muted)}
.cx__f dd{margin:5px 0 0;font:600 1.05rem/1.3 var(--sans);
  font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
.cx__l{margin:18px 0 0;font-size:.95rem}
.cx__l span{color:var(--muted)}
/* Which boat, and what it takes. One row per kind of vessel on the crossing,
   because "catamaran, people only, 50 min" is the comparison the reader came
   to make and a row of line numbers is not. */
.cx__k{list-style:none;margin:8px 0 0;padding:0;display:grid;gap:10px}
.cx__k li{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 10px;
  font-size:.95rem}
.cx__kw{color:var(--muted)}
.cx__kl{flex-basis:100%}

/* And written out in full when it is asked for. */
.tripsheet{max-width:min(560px,94vw)}
.tl{padding:14px 0;border-top:1px solid var(--rule)}
.tl:first-child{border-top:0;padding-top:0}
.tl__k{margin:0 0 4px;font:600 .72rem/1 var(--sans);letter-spacing:.08em;
  text-transform:uppercase;color:var(--tile-ink)}
.tl__k i,.tl__t i,.tl__v i{font-style:normal;color:var(--muted)}
.tl__t{margin:0;font:500 1.08rem/1.35 var(--sans);color:var(--ink)}
.tl__m{margin:4px 0 0;font:500 .9rem/1.4 var(--sans);color:var(--muted)}
.tl__v{margin:3px 0 0;font:400 .86rem/1.4 var(--sans);color:var(--muted)}
.tl__stay{margin:0;padding:12px 0;border-top:1px solid var(--rule);
  font:600 1rem/1.3 var(--sans);color:var(--tile-ink)}
.tl__sum{display:flex;align-items:baseline;gap:8px;margin:14px 0 0;
  padding-top:12px;border-top:1px solid var(--rule);
  font:700 1.3rem/1 var(--sans);color:var(--ink)}
.tl__sum span{font:500 .88rem/1.3 var(--sans);color:var(--muted)}
.tl__n{margin:10px 0 0;font:400 .86rem/1.45 var(--sans);color:var(--muted)}
.tl__buy{display:inline-flex;align-items:center;min-height:44px;padding:0 18px;
  margin-top:10px;border-radius:999px;background:var(--sea-deep);
  color:var(--foam);text-decoration:none;font:700 .92rem/1 var(--sans)}
.tl__buy:hover{background:var(--ink)}

.jumpmark{height:1px;margin-bottom:-1px}
/* One strip, not two bars. The section index and the day control were stacked
   backgrounds with their own borders, 127px of chrome between the reader and
   the answer; together they are one thing that sticks. */
/* Pulled back up over the foot of the band by exactly its own height: at rest
   the chips are on the photograph, and the box still holds the space they will
   vacate when they go fixed. */
.railbox{position:relative;margin-top:calc(-1 * var(--menu))}
.rail{position:sticky;top:0;z-index:20;background:transparent}
.rail.jump--stuck{background:var(--foam)}
/* Once stuck it leaves the flow entirely, and the box keeps the height
   it had. Sticky plus a shrinking strip moved the whole page up under
   the reader at the moment it stuck. */
.rail.jump--stuck{position:fixed;left:0;right:0;top:0}
.jump{background:transparent}
.jump--stuck .jump{background:var(--foam)}
.jump .wrap{padding:0}
/* Native overflow scroll: five chips do not fit 360px and nothing here is worth
   a carousel. The gutters are padding on the row so the first and last chip can
   scroll clear of the edge. */
.jump__row{display:flex;flex-wrap:wrap;gap:4px;
  padding:14px 14px 15px;-webkit-overflow-scrolling:touch;
  transition:padding .18s var(--ease)}
.jump__row::-webkit-scrollbar{display:none}
@media(min-width:900px){.jump__row{padding:14px 20px 15px}}
.jump a{flex:0 0 auto;white-space:nowrap;text-decoration:none;
  font:600 1.06rem/1 var(--sans);color:var(--ink);opacity:.7;
  padding:15px 18px;border-radius:999px;
  transition:opacity .15s var(--ease),background-color .15s var(--ease)}
/* The chips change size when the strip sticks, but they do it at once rather
   than over 180ms: animating font-size reflows the text of the one control a
   reader is using while the page is moving under them. */
.jump a{position:relative}
/* 42px at rest, 32px once stuck: the smallest targets on the site, on the one
   control a reader uses while scrolling. The site already has a hit-zone
   helper; this is it, scoped. */
.jump a::after{content:"";position:absolute;left:0;top:50%;width:100%;height:44px;
  transform:translateY(-50%)}
.jump a:hover{opacity:1;background:var(--surface);color:var(--ink)}
.jump a[aria-current]{opacity:1;background:var(--sea-deep);color:var(--foam)}
/* Full size while it is still part of the opening screen - that is where it has
   to read as the page's contents. Once it sticks it is a wayfinder, not a menu,
   and it gives the width back to the timetable. */
.jump--stuck{box-shadow:0 1px 0 oklch(0.31 0.052 218/.10)}
/* Stuck it is one line again, and one line that does not fit scrolls: five
   chips do not fit 360px and nothing here is worth a carousel. */
.jump--stuck .jump__row{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;
  gap:2px;padding:6px 14px;
  mask-image:linear-gradient(90deg,#000 calc(100% - 28px),transparent);
  -webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 28px),transparent)}
@media(min-width:900px){.jump--stuck .jump__row{padding:6px 20px}}
.jump--stuck a{font-size:.86rem;padding:9px 12px}
/* At rest these are the only thing on the opening screen that says what else
   the page can do, and as quiet grey text under a photograph nobody read them
   as anything to press. Full-size they are buttons: filled, big, one row of
   the page's own actions. Stuck they go back to being a wayfinder. */
.rail:not(.jump--stuck) .jump__row{gap:8px;padding:16px 14px 18px}
@media(min-width:900px){.rail:not(.jump--stuck) .jump__row{padding:18px 20px}}
.rail:not(.jump--stuck) .jump a{opacity:1;font-size:1.14rem;padding:16px 24px;
  background:var(--sea-deep);color:var(--foam);
  box-shadow:0 1px 2px oklch(0.31 0.052 218/.22)}
.rail:not(.jump--stuck) .jump a{box-shadow:0 2px 10px oklch(0.20 0.04 218/.35)}
.rail:not(.jump--stuck) .jump a:hover{background:var(--ink);color:var(--foam)}
@media(max-width:600px){
  .rail:not(.jump--stuck) .jump__row{gap:6px;padding:10px 14px 14px}
  .rail:not(.jump--stuck) .jump a{font-size:1rem;padding:12px 16px}
}
.rail:not(.jump--stuck) .jump a[aria-current]{background:var(--ink)}

.jump--stuck .whenbar .wrap{padding-top:3px;padding-bottom:5px}
.jump--stuck .whenbar__s{width:32px;height:32px}
/* Anchored sections land below the sticky strip, not under it. */
/* The strip covers the top of the page once it sticks, and it is a
   different height on a page with chips than on one with only the date,
   so the browser is told what it actually measured. */
html{scroll-padding-top:calc(var(--stuck,56px) + 8px)}
:target,[id^="sec-"]{scroll-margin-top:8px}
@media(prefers-reduced-motion:no-preference){html{scroll-behavior:smooth}}

/* The count line used to sit hard against the band with no gap at all. */
/* .wrap sets padding on all four sides, and main carries both classes, so
   the element selector lost and every page ran flush against its band. */
main.wrap{padding-block:clamp(20px,4vw,30px) 76px}
main>h2:first-child{margin-top:0}
h1{font:500 clamp(2.3rem,6vw,3.7rem)/1.04 var(--serif);letter-spacing:-.015em;
  text-wrap:balance;margin:0 0 8px}
h2{font:500 clamp(1.5rem,3vw,1.9rem)/1.15 var(--serif);letter-spacing:-.01em;
  text-wrap:balance;margin:52px 0 14px}
h3{font-size:1.02rem;margin:0;font-weight:700;letter-spacing:-.008em}
p{max-width:66ch;text-wrap:pretty}
.lede{color:var(--muted);margin-top:0;font-size:1.04em}
.sub{color:var(--muted);font:400 .9rem/1.5 var(--sans);margin:0}

/* The whole question, as one object. Where from, where to, which days, and
   whether a car is coming were five separate rounded boxes with five shadows,
   sitting at four different widths: read as a row of unrelated buttons rather
   than as one form. They are rows of a single card now, divided by hairlines,
   the way the question is actually asked at a ticket desk. */
.trip{display:grid;gap:10px;margin:18px 0 0}
/* --sheet is the card ground; --seam the hairline between its rows. */
.trip{--seam:oklch(0.820 0.022 82/.85)}
.trip__ends,.dates,.trip .veh{background:var(--foam);border:1px solid var(--rule);
  border-radius:var(--r);box-shadow:var(--paper)}
/* The panel of answers hangs out of the card, so nothing here may clip. */
.trip__ends{position:relative}
.trip__ends:focus-within,.dates:focus-within{border-color:var(--sea-deep)}
.pick{position:relative;min-width:0;padding:9px 58px 10px 16px}
.pick+.pick{border-top:1px solid var(--seam)}
.pick__l{display:block;font:600 .68rem/1 var(--sans);letter-spacing:.09em;
  text-transform:uppercase;color:var(--muted);margin:0 0 5px}
.pick__i{width:100%;font:600 1.06rem/1.35 var(--sans);padding:0;min-height:28px;
  border:0;background:transparent;color:var(--ink);border-radius:0}
.pick__i{text-overflow:ellipsis}
.pick__i:focus{outline:none}
.pick__i::placeholder{color:var(--muted);font-weight:400}
.pick__x{position:absolute;right:56px;bottom:6px;width:34px;height:38px;border:0;
  background:transparent;color:var(--muted);font-size:21px;line-height:1;
  cursor:pointer;border-radius:999px}
.pick__x:hover{color:var(--ink)}
/* Reverse the trip: the same crossing read the other way round. It sits on the
   seam between the two ends, which is the line it acts on. */
.trip__swap{position:absolute;right:10px;top:50%;transform:translateY(-50%);
  width:44px;height:44px;z-index:2;border:1px solid var(--rule);
  border-radius:999px;background:var(--foam);color:var(--sea-deep);cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;
  box-shadow:0 1px 3px oklch(0.265 0.018 220/.10);
  transition:background .15s var(--ease),border-color .15s var(--ease)}
.trip__swap:hover{background:var(--sea-deep);border-color:var(--sea-deep);color:var(--foam)}
/* The one filled thing in the card, so there is never a question about what to
   press. Not yet answerable, and it says so quietly rather than by going the
   colour of the paper it sits on. */
.trip__go{min-height:56px;border:1px solid transparent;border-radius:var(--r);
  background:var(--sea-deep);color:var(--foam);cursor:pointer;
  font:700 1.04rem/1 var(--sans);letter-spacing:-.005em;
  transition:background .15s var(--ease),opacity .15s var(--ease)}
.trip__go:hover:not(:disabled){background:var(--ink)}
/* Pressed with nowhere to go: the empty end lights up, the button stays blue. */
.pick--miss{box-shadow:inset 0 0 0 2px #c0392b;border-radius:var(--r)}
.pick--miss .pick__i::placeholder{color:#a8321f;font-weight:600}
.trip__none{margin:0;font:500 .92rem/1.4 var(--sans);color:var(--tile-ink)}
/* Wide enough and the two ends sit side by side, still one card, the swap on
   the seam between them - which is now vertical. */
@media(min-width:700px){
  .trip__ends{display:grid;grid-template-columns:1fr 1fr}
  .pick+.pick{border-top:0;border-left:1px solid var(--seam)}
  .pick{padding:10px 16px 12px}
  /* The x sat over the name it clears; the name now stops short of it. */
  .trip .pick:first-of-type{padding-right:92px}
  .trip .pick:last-of-type{padding-left:40px;padding-right:52px}
  .trip__swap{right:auto;left:50%;transform:translate(-50%,-50%)}
  .pick__x{right:50px;bottom:8px}
  .trip .pick:last-of-type .pick__x{right:8px}
  .ac{left:0;right:auto;min-width:min(28rem,100%)}
  .trip .pick:last-of-type .ac{left:auto;right:0}
}

/* The list under a box. Grouped, because a harbour, a mainland town and an
   island are three different kinds of answer. */
.ac{list-style:none;margin:6px 0 0;padding:6px;position:absolute;z-index:30;
  left:0;right:0;top:100%;background:var(--foam);border:1px solid var(--rule);
  border-radius:var(--r);box-shadow:var(--paper),0 14px 34px oklch(0.31 0.052 218/.16);
  max-height:min(46vh,24rem);overflow-y:auto;overscroll-behavior:contain}
.ac__h{font:600 .68rem/1 var(--sans);letter-spacing:.09em;text-transform:uppercase;
  color:var(--tile-ink);padding:12px 12px 6px;position:sticky;top:-6px;
  background:var(--foam)}
.ac__o{display:block;width:100%;text-align:left;border:0;background:transparent;
  padding:12px;min-height:44px;border-radius:10px;cursor:pointer;
  font:500 .98rem/1.3 var(--sans);color:var(--ink)}
.ac__o:hover,.ac__o:focus-visible,.ac__o.ac--on{background:var(--surface)}
.ac__sub{display:block;margin:3px 0 0;font:400 .8rem/1.3 var(--sans);
  color:var(--muted)}

/* One way or return, asked the way an airline asks it: two opposites above
   the fields, the chosen one filled in. */
.way2{display:flex;gap:6px;padding:10px 12px 0}
.way2__b{border:1px solid var(--rule);background:transparent;color:var(--muted);
  cursor:pointer;font:600 .84rem/1 var(--sans);border-radius:999px;
  min-height:36px;padding:0 15px}
.way2__b[aria-pressed="true"]{background:var(--sea-deep);border-color:var(--sea-deep);
  color:var(--foam)}
.way2__b:hover[aria-pressed="false"]{color:var(--ink);border-color:var(--ink)}
/* One way means one date. The second pill and the second half of the calendar
   are not dimmed, they are gone: a control that cannot apply is not a hint.
   `.dates .when` sets a display of its own further down this sheet and would
   win on document order, so the date cell is named through .dates too. */
[data-way="one"] [data-cal-cell="back"],
[data-way="one"] .cal__one{display:none}
/* The way out of the list, at the head of it. The panel opens over the card's
   own button, and one end chosen is already an answer worth taking. */
.ac__top{position:sticky;top:-6px;z-index:1;background:var(--foam);
  padding:0 0 6px;margin:0 0 2px;border-bottom:1px solid var(--rule)}
.ac__go{display:block;width:100%;min-height:48px;border:0;border-radius:10px;
  background:var(--sea-deep);color:var(--foam);cursor:pointer;
  font:700 .98rem/1.25 var(--sans);padding:12px;text-align:left}
.ac__go:hover{background:var(--tile-ink)}

/* One question, asked once: are you bringing a vehicle? Two buttons reading
   "By car" and "On foot" left readers unable to say what the control did or
   which half was on. A checkbox has one state and shows it. Car is still the
   default in the markup, so scripting off is the car-ferry site exactly as
   before. */
.veh{display:inline-flex;align-items:center;gap:10px;margin:16px 0 0;
  padding:8px 14px 8px 10px;min-height:44px;border-radius:999px;
  border:1px solid transparent;background:transparent;cursor:pointer;
  font:600 .9rem/1.2 var(--sans);color:var(--ink);
  transition:border-color .15s var(--ease),background .15s var(--ease)}
.veh:hover{background:oklch(1 0 0/.4)}
.veh:has(:checked){border-color:var(--rule);background:var(--foam)}
/* A phone draws a native checkbox as a bare grey square whatever accent-color
   says, so the box is ours: same tick either way, on every browser. */
.veh__b{appearance:none;-webkit-appearance:none;width:22px;height:22px;flex:none;
  margin:0;cursor:pointer;border:1.6px solid var(--rule);border-radius:7px;
  background:var(--foam);transition:background .15s var(--ease),
  border-color .15s var(--ease)}
.veh__b:checked{background:var(--tile) no-repeat center/13px 13px;
  border-color:var(--tile);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2.5 8.5l3.5 3.5 7.5-8' fill='none' stroke='%23fff' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}
.veh:has(:focus-visible){outline:2px solid var(--tile);outline-offset:3px}
/* Inside the card it is a row like the others, not a pill floating beside it. */
.trip .veh{display:flex;margin:0;border-radius:var(--r);padding:0 16px;
  min-height:54px;font-size:.95rem}
.trip .veh:hover{background:var(--foam)}
[data-mode="car"] [data-vessel]:not([data-vessel~="ferry"]){display:none}
/* who runs the boat, and what kind of boat: a mark and a chip, never prose */
/* In a row the mark is a 15px smear with a white box round it on paper, and
   the operator is already named in words beside it, so the row keeps the words
   and the band keeps the mark. */
.op{display:none}
.head .op{display:inline-block}
/* On the band the mark sits on a paper pill: a blue logo over a dark photo is
   invisible, and an <img> cannot be recoloured, so the ground comes to it. */
.head .op{height:20px;box-sizing:content-box;padding:6px 11px;border-radius:999px;
  background:var(--foam);margin-right:0}
.head__op{margin:14px 0 0;display:flex;align-items:center;gap:8px}
/* The chip is a quiet outline: a filled terracotta block on every catamaran
   row shouted louder than the times. */
.kind{display:inline-block;font:600 .66rem/1 var(--sans);letter-spacing:.06em;
  text-transform:uppercase;padding:3px 7px 2px;border-radius:999px;margin-right:7px;
  border:1px solid var(--tile-ink);color:var(--tile-ink);vertical-align:1px}
.kind--ship,.kind--ferry{border-color:var(--muted);color:var(--muted)}
.head .op{border:1px solid var(--hair)}
.count-line{font:500 .85rem/1 var(--sans);color:var(--muted);margin:22px 0 0;
  letter-spacing:.01em}

/* typographic rows, never cards */
/* A ul, so a screen reader can announce and skip the list. */
/* A flex column so a search can reorder rows with `order` instead of moving
   nodes. */
.rows{list-style:none;padding-left:0;margin:10px 0 0;border-top:1px solid var(--rule);
  display:flex;flex-direction:column}
.row{display:flex;gap:16px;align-items:baseline;justify-content:space-between;
  padding:15px 6px;border-bottom:1px solid var(--hair);text-decoration:none;
  color:inherit;transition:background .14s var(--ease)}
.row>*{transition:transform .14s var(--ease)}
/* transform rather than padding: the row nudges without relaying out the list */
.row:hover{background:var(--surface)}
.row:hover>*{transform:translateX(5px)}
.row[hidden]{display:none}
.row .nm{flex:1;min-width:0;font-weight:600;letter-spacing:-.008em}
.row .to{display:block;font-weight:400;font-size:.88rem;color:var(--muted);
  margin-top:3px;letter-spacing:0}
.row .meta{font:500 .85rem/1 var(--sans);color:var(--muted);flex:none;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.row .no{font:500 .8rem/1 var(--sans);color:var(--muted);flex:none;min-width:3em;
  font-variant-numeric:tabular-nums}

/* the summary strip: what leaves next, per destination */
.next{margin:0;padding:clamp(22px,3.5vw,30px) 0 4px}
/* Without scripting the summary never fills, so it must not leave a hole. */
.next:has([data-next][hidden]){display:none}
.next__grid{display:block}
.onward-list{list-style:none;margin:0;padding:0;max-width:52rem;
  border-top:1px solid var(--rule)}
.onward{border-bottom:1px solid var(--hair)}
.onward__link{display:flex;align-items:baseline;gap:14px;padding:14px 4px;
  text-decoration:none;color:inherit;transition:background .14s var(--ease)}
.onward__link:hover{background:var(--surface)}
.onward__link:hover .onward__to{color:var(--tile-ink)}
.onward--none .onward__t,.onward--none .onward__to{color:var(--muted)}
/* The row also shown in the header band. Marked, not hidden: the list must
   stay complete or the "every line" heading above it is false. */
.onward--lead .onward__t{color:var(--tile-ink)}
.onward--lead .onward__link{background:var(--surface)}
.onward__go{flex:none;color:var(--muted);font-size:1.3rem;line-height:1;
  transition:transform .14s var(--ease),color .14s var(--ease)}
.onward__link:hover .onward__go{color:var(--tile-ink);transform:translateX(3px)}
.onward__to{flex:1;min-width:0;font-weight:600;letter-spacing:-.006em}
/* Every call in order. The names carry the weight, the arrows do not, so a
   six-stop catamaran reads as a route and not as a wall of bold. */
.stops{display:block;line-height:1.35}
.stops .stop{white-space:nowrap}
.stops .arrow{color:var(--tile-ink);font-weight:400;padding:0 .35em}
/* Where the boat ends up, then what it calls at. The calls used to sit in the
   same chain of arrows as the terminus, at the same weight, so a five-port
   catamaran read as five answers to one question. */
.stop--to{white-space:normal}
.stop__via{display:block;font:400 .82rem/1.35 var(--sans);color:var(--muted);
  margin-top:2px}
.onward__t{font:700 1.2rem/1 var(--sans);font-stretch:110%;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;flex:none}
.onward__in{color:var(--muted);font:500 .84rem/1 var(--sans);flex:none;
  min-width:6.6em;text-align:right;font-variant-numeric:tabular-nums}
/* A long itinerary and "No more departures today" used to sit on one line
   with nothing allowed to wrap, so on a phone with large text they were drawn
   on top of each other. Both may wrap now; the row grows instead. */
@media(max-width:480px){.onward__in{min-width:0;flex:0 1 auto;white-space:normal;
  line-height:1.25;max-width:42%}.stops .stop{white-space:normal}}
/* The port page: the camera is the page, the crossings a pane on it.
   One row per destination, the printed times, a button to the line. The pane
   folds to a pill the reader can drag out of the picture's way. */
/* The section strip under it fits on the first screen too, like the band's. */
.poster{position:relative;height:calc(100svh - var(--hdr) - var(--menu));min-height:600px;max-height:1100px;
  overflow:hidden;background:var(--sea-deep);isolation:isolate}
.poster__bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.poster__shade{position:absolute;inset:0;background:linear-gradient(180deg,rgba(0,0,0,.5) 0,rgba(0,0,0,0) 30%,rgba(0,0,0,0) 62%,rgba(0,0,0,.5) 100%)}
/* The title sits on the same glass as the pane, so it reads on a night frame too. */
.poster__top{position:absolute;left:28px;top:52px;max-width:calc(100% - 56px);padding:12px 20px 14px;border-radius:var(--r);color:var(--ink);
  background:oklch(0.99 0.006 82/.88);backdrop-filter:blur(10px);box-shadow:0 12px 40px rgba(0,0,0,.25)}
.poster__top .kicker{margin:0;font:600 .78rem/1.3 var(--sans);letter-spacing:.09em;text-transform:uppercase;color:var(--tile-ink)}
.poster__top h1{margin:2px 0 0;color:var(--sea-deep);font-size:clamp(28px,3.6vw,42px);letter-spacing:-.03em}
/* No section strip under the poster any more: nothing to leave room for. */
html:not(:has(.rail)){--menu:0px}
.poster__thumbs{position:absolute;left:28px;bottom:calc(var(--menu) + 44px);display:flex;gap:8px}
.poster__thumb{padding:0;border:2px solid #fff;border-radius:10px;overflow:hidden;background:var(--sea-deep);cursor:pointer;
  box-shadow:0 8px 24px rgba(0,0,0,.45);width:190px}
.poster__thumb img{display:block;width:100%;height:auto;aspect-ratio:16/9;object-fit:cover}
.poster__live{position:absolute;left:28px;bottom:calc(var(--menu) + 12px);margin:0;color:#fff;font:600 13px var(--sans);display:flex;gap:12px;align-items:center;
  text-shadow:0 1px 8px rgba(0,0,0,.7)}
.poster__live .live{color:#fff}.poster__live a{color:#fff;opacity:.85}
.pane-t{position:absolute;opacity:0;pointer-events:none}
/* Centred on the picture and growing both ways from the middle, like the fan itself. */
.pane{position:absolute;right:28px;top:50%;transform:translateY(-50%);width:min(680px,calc(100% - 56px));max-height:calc(100% - 48px);overflow:auto;
  background:oklch(0.99 0.006 82/.95);backdrop-filter:blur(10px);border-radius:var(--r);padding:30px 12px 10px 14px;
  box-shadow:0 12px 40px rgba(0,0,0,.35)}
.pane__min{position:absolute;right:10px;top:8px;width:26px;height:26px;border-radius:50%;border:1px solid var(--rule);
  background:var(--bg);color:var(--ink);font:700 18px/24px var(--sans);text-align:center;cursor:pointer}
.pane__min:hover{background:var(--sea-deep);color:var(--foam);border-color:transparent}
.pane__hint{margin:8px 0 0;font:400 12px/1.4 var(--sans);color:var(--muted)}
.pane__extra{margin-top:10px;padding-top:8px;border-top:1px solid var(--hair)}
.pane__extra .nocars{margin:0;font:500 13px/1.4 var(--sans)}
.fanlist{display:grid;grid-template-columns:130px minmax(0,1fr)}
.fan{position:relative}.fan svg{position:absolute;inset:0;width:100%;height:100%;display:block;fill:#0e2a3a;stroke:none}
.fan path{fill:none;stroke:var(--tile-ink);stroke-width:3.5;stroke-linecap:round}
.fan circle:not(:first-child){fill:var(--tile-ink)}
.fan .fan__later{stroke:#9aa7b4;stroke-width:2.5;stroke-dasharray:5 5;fill:#9aa7b4}
.fan path.fan__later{fill:none}
.onward-list--fan{max-width:none;border-top:0}
.onward-list--fan .onward__link{padding:8px 2px 8px 6px;min-height:56px;align-items:center}
/* One line of meta per row, cut with an ellipsis: Italian would otherwise take three. */
.onward-list--fan .onward__meta{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.onward-list--fan .onward__t{font-size:1.45rem;font-weight:800;color:var(--tile-ink)}
.onward-list--fan .onward--none .onward__t{display:none}
.onward-list--fan .onward__in{min-width:0;max-width:11em}
.onward-list--fan .onward--none .onward__in{font-size:12px;max-width:9em}
.onward__btn{flex:none;display:inline-flex;align-items:center;gap:6px;background:var(--sea-deep);color:var(--foam);border-radius:10px;
  padding:9px 12px;font:700 13px var(--sans);white-space:nowrap}
.onward__btn::after{content:"\2192"}
.onward__btn{max-width:11em}.onward__btn>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Dense: place, time, button - the line and the crossing wait on the line page. */
.pane--dense .onward-list--fan .onward__link{padding:5px 2px 5px 6px;min-height:44px}
.pane--dense .onward-list--fan .onward__meta,.pane--dense .onward-list--fan .onward__via{display:none}
.pane--dense .onward-list--fan .onward__t{font-size:1.2rem}
.pane--dense .onward-list--fan .onward__btn{padding:7px 10px;font-size:12px}
.pane--dense .onward-list--fan .onward--none .onward__in{max-width:none;white-space:nowrap}
.onward__link:hover .onward__btn{background:var(--ink)}
.pill{position:absolute;right:28px;top:140px;display:none;align-items:center;gap:8px;background:oklch(0.99 0.006 82/.95);
  backdrop-filter:blur(10px);border-radius:999px;padding:8px 10px 8px 12px;font:700 14px var(--sans);color:var(--ink);cursor:pointer;
  box-shadow:0 8px 24px rgba(0,0,0,.35);touch-action:none;user-select:none}
.pill__plus{width:24px;height:24px;border-radius:50%;background:var(--sea-deep);color:var(--foam);text-align:center;line-height:24px;font-size:16px}
.pill__grip{color:var(--muted);font-size:12px;letter-spacing:-3px;cursor:grab;margin-left:2px}
.pane-t:checked~.pane{display:none}.pane-t:checked~.pill{display:inline-flex}
.poster--nocam{height:auto;min-height:0;max-height:none;background:var(--bg);overflow:visible;padding-bottom:calc(var(--menu) + 8px)}
.poster--nocam .poster__top{position:static;max-width:none;background:none;box-shadow:none;backdrop-filter:none;padding:26px 0 12px}
.poster--nocam .poster__top .kicker{color:var(--tile-ink)}.poster--nocam .poster__top h1{color:var(--sea-deep)}
.poster--nocam .pane,.poster--nocam .pill{position:static;width:auto;max-height:none;box-shadow:none;background:var(--foam);border:1px solid var(--rule);backdrop-filter:none}
.poster--nocam .pane{padding-top:12px;transform:none}.poster--nocam .pane__min,.poster--nocam .pill{display:none!important}
/* A narrow desk: the thumbs stack in a column so the pane never sits on them. */
@media(min-width:940px) and (max-width:1279px){.poster__thumbs{flex-direction:column}.poster__thumb{width:140px}}
/* A phone: the lines and the next boat on each, the picture under them. */
@media(max-width:939px){
  .poster{height:auto;min-height:0;max-height:none;overflow:visible;background:var(--bg);display:flex;flex-direction:column;padding:14px 16px 0}
  .poster__bg{position:static;order:5;width:100%;height:auto;aspect-ratio:16/9;border-radius:var(--r);margin-top:14px}
  .poster__shade{display:none}
  .poster__top{position:static;max-width:none;background:none;box-shadow:none;backdrop-filter:none;padding:0}
  .poster__top .kicker{color:var(--tile-ink)}.poster__top h1{color:var(--sea-deep);font-size:clamp(24px,7vw,30px)}
  .pane{position:static;transform:none;width:auto;max-height:none;overflow:visible;background:none;box-shadow:none;backdrop-filter:none;padding:10px 0 0;margin-top:6px}
  .pane__min,.pill,.pane__hint{display:none!important}.pane-t:checked~.pane{display:block}
  .fanlist{grid-template-columns:minmax(0,1fr)}.fan{display:none}
  .onward-list--fan{border-top:1px solid var(--rule)}
  /* Two lines a row: the place and its line, then the time, the note and the button. */
  .onward-list--fan .onward__link{padding:12px 2px;flex-wrap:wrap;row-gap:8px}
  .onward-list--fan .onward__to{flex:1 1 100%}
  .onward-list--fan .onward__in{flex:1 1 auto;max-width:none;text-align:left}
  .onward-list--fan .onward__btn{margin-left:auto}
  .onward-list--fan .stops .stop{white-space:nowrap}
  .poster__thumbs{position:static;order:6;margin-top:8px}.poster__thumb{width:calc(50% - 4px)}
  .poster__live{position:static;order:7;color:var(--ink);text-shadow:none;margin:8px 0 0}.poster__live .live,.poster__live a{color:var(--ink)}
  .poster--nocam{padding:14px 16px calc(var(--menu) + 8px)}
}
/* The island's harbours, named before its boards. */
.harbours{margin:0 0 14px;font-size:.95rem}
.harbours span{color:var(--muted)}
.leg__where{font:600 .95rem/1.35 var(--sans);color:var(--ink);margin:0 0 4px;
  letter-spacing:-.005em}
.leg__where .from{color:var(--muted);font-weight:400}
.leg__time{font:700 clamp(2.5rem,8.5vw,3.5rem)/.95 var(--sans);font-stretch:118%;
  letter-spacing:-.035em;font-variant-numeric:tabular-nums;color:var(--ink);
  display:block}
.next__h{margin:0 0 16px;font-size:1rem;letter-spacing:.01em}
.head__leadlabel{font:600 .78rem/1 var(--sans);letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);margin:0 0 10px}
.head .next__h{display:none}
/* What is leaving after the one in big type. Tabular figures, a hairline
   between, and no second giant number: this is the tail of a hierarchy, not a
   second headline. */
.lead__more{list-style:none;margin:14px 0 0;padding:12px 0 0;
  border-top:1px solid var(--hair);display:flex;flex-direction:column;gap:9px}
.lead__more li{display:flex;gap:12px;align-items:baseline}
.lead__t{font:600 1.02rem/1 var(--sans);font-variant-numeric:tabular-nums;
  color:var(--sea-deep);flex:none}
.lead__to{color:oklch(0.355 0.026 218);font-size:.95rem;min-width:0}
.lead__to .from{color:var(--muted)}
@media(min-width:820px){
  .head__lead .lead__more li{justify-content:flex-end}
}
.leg__via{font:400 .88rem/1.45 var(--sans);color:var(--muted);margin:4px 0 0;max-width:34ch}
/* Only where the panel is right-aligned. On a phone it left the calls floating
   in the middle of the panel, reading as a stray line. */
@media(min-width:820px){.head__lead .leg__via{margin-left:auto}}
.onward__meta{display:block;font-weight:400;font-size:.82rem;color:var(--muted)}
.onward__via{font-weight:400;font-size:.82rem;color:var(--muted);
  margin-top:2px;letter-spacing:0}
.leg__in{font:600 .95rem/1.4 var(--sans);color:var(--tile-ink);margin:7px 0 0;
  font-variant-numeric:tabular-nums}
.leg__rest{list-style:none;margin:9px 0 0;padding:8px 0 0;
  border-top:1px solid var(--hair);display:grid;gap:3px}
.leg__rest li{display:flex;gap:10px;align-items:baseline;justify-content:space-between}
.leg__rest .lead__in{font:400 .85rem/1.35 var(--sans);color:var(--muted);
  font-variant-numeric:tabular-nums}
.leg__left{font:400 .85rem/1.35 var(--sans);color:var(--muted);
  font-variant-numeric:tabular-nums}
.leg__then{font:400 .9rem/1.5 var(--sans);color:var(--muted);margin:6px 0 0;
  font-variant-numeric:tabular-nums}
.leg--none .leg__time{color:var(--muted);font-size:clamp(1.1rem,3.4vw,1.35rem);
  font-stretch:100%;letter-spacing:-.01em;line-height:1.3;font-weight:600}

/* departure board */
.season{border-top:1px solid var(--ink);margin:32px 0 0;padding:13px 0 0}
.season__hd{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 12px;margin:0 0 4px}
.season__when{font:500 1.25rem/1.3 var(--serif);margin:0}
.season__tag{font:700 .68rem/1 var(--sans);letter-spacing:.09em;
  text-transform:uppercase;color:var(--bg);background:var(--tile-ink);
  padding:5px 7px;border-radius:3px}
.pair{margin:18px 0 0}
.pair__hd{font:500 1.15rem/1.35 var(--serif);margin:0 0 2px}
.pair__hd .arrow{color:var(--tile-ink);padding:0 .3em;font-weight:400}
.pair__meta{font:400 .85rem/1.4 var(--sans);color:var(--muted);margin:2px 0 0}
/* The timetable is a table. Deliberately NOT display:grid - overriding a
   table's display strips its semantics back out of the accessibility tree,
   which is the whole reason it became a table. Column headers are for screen
   readers; sighted readers already have the pair heading above. */
.days{width:100%;border-collapse:collapse;margin:8px 0 0;table-layout:auto}
.days thead th{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.days th[scope=row]{font:500 .82rem/1.9 var(--sans);color:var(--muted);
  text-align:left;vertical-align:baseline;padding:0 20px 10px 0;
  white-space:nowrap;width:1%}
.days td{padding:0 0 10px;vertical-align:baseline}
.days .times{display:flex;flex-wrap:wrap;gap:3px 5px}
@media(max-width:600px){
  .days th[scope=row]{white-space:normal;padding-right:12px}
}
.t{font:600 .98rem/1 var(--sans);font-variant-numeric:tabular-nums;
  padding:6px 7px;border-radius:5px;color:var(--ink);
  transition:background .16s var(--ease),color .16s var(--ease)}
/* A called-at port with no departures of its own gets named but not linked. */
.row--flat{color:var(--muted);cursor:default}
/* The footnote glyph beside a departure: visible, never load-bearing alone. */
.t sup{font-size:.7em;line-height:0;vertical-align:super;color:var(--tile-ink);
  font-weight:700;margin-left:1px}
.t--gone{color:var(--muted);font-weight:400}
.t--off{color:var(--muted);font-weight:400;text-decoration:line-through;opacity:.6}
.t--next{background:var(--tile-ink);color:var(--bg);font-weight:700}
.window__when{margin:14px 0 0}
/* The price list, as its own PDF prints it. A ferry has twelve vehicle rows
   and five tariff columns, which is wider than a phone; the table scrolls
   inside its own box rather than dragging the page sideways with it. */
.fare__s{font:600 1rem/1.3 var(--sans);color:var(--ink);margin:22px 0 8px}
.fare__wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;
  border:1px solid var(--hair);border-radius:var(--r);background:var(--surface)}
.fare{border-collapse:collapse;width:100%;min-width:32rem;
  font:400 .9rem/1.35 var(--sans)}
.fare th,.fare td{padding:9px 14px;text-align:right;white-space:nowrap;
  border-bottom:1px solid var(--hair)}
.fare tbody tr:last-child th,.fare tbody tr:last-child td{border-bottom:0}
.fare thead th{font-weight:600;color:var(--muted);font-size:.82rem;
  background:var(--foam);position:sticky;top:0}
.fare th[scope=row]{text-align:left;font-weight:500;color:var(--ink);
  white-space:normal;min-width:14rem}
.fare thead th:first-child{text-align:left}
.fare td{font-variant-numeric:tabular-nums;color:var(--ink)}
.fare tbody tr:hover{background:var(--foam)}
/* On a phone the same table is a stack of cards: one per vehicle, each
   tariff on its own line with its column name in front of it. The thead is
   hidden from sight only; the roles in the markup keep it a table. */
@media(max-width:600px){
  .fare{min-width:0}
  .fare thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
  .fare tbody,.fare tr,.fare th,.fare td{display:block;text-align:left;white-space:normal}
  .fare tr{padding:10px 14px;border-bottom:1px solid var(--hair)}
  .fare tbody tr:last-child{border-bottom:0}
  .fare th[scope=row]{padding:0 0 6px;border:0;min-width:0}
  .fare td{display:flex;justify-content:space-between;gap:12px;padding:2px 0;border:0}
  .fare td:empty{display:none}
  .fare td::before{content:attr(data-l);color:var(--muted)}
}

.source{margin:30px 0 0}
.season__note{margin:14px 0 0;font-size:.85rem;color:var(--muted);max-width:74ch}
/* Marks the operator's own words, which arrive in English whatever the page. */
.season__note-by{font-weight:600;color:var(--ink)}

/* multi-stop lines print every call rather than just the endpoints */
.voyages{width:100%;border-collapse:collapse;table-layout:auto}
.voyages thead th{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.voyage th[scope=row]{text-align:left;vertical-align:baseline;width:1%;
  padding-right:16px}
.voyage>*{padding-top:10px;padding-bottom:10px;border-bottom:1px solid var(--hair)}
.voyage:last-child>*{border-bottom:0}
.voyage__days{font:500 .8rem/1.4 var(--sans);color:var(--muted);margin:0 0 4px}
.voyage__calls{display:flex;flex-wrap:wrap;align-items:baseline;gap:3px 6px;
  margin:0;max-width:none}
.call{display:inline-flex;align-items:baseline;gap:6px;white-space:nowrap}
.call__p{font:400 .88rem/1.4 var(--sans);color:var(--muted)}
.voyage .arrow{color:var(--muted);padding:0 1px}

/* live queue verdict */
.verdict{border-top:3px solid var(--tile-ink);background:var(--foam);
  border-radius:0 0 var(--r) var(--r);padding:24px 22px 20px;margin:30px 0 0;
  box-shadow:var(--paper)}
.verdict .state{font:500 clamp(1.5rem,4.6vw,2.1rem)/1.15 var(--serif);
  letter-spacing:-.012em;margin:0;text-wrap:balance}
.verdict .count{font:700 clamp(2.6rem,10vw,4rem)/1 var(--sans);font-stretch:118%;
  font-variant-numeric:tabular-nums;letter-spacing:-.04em;color:var(--tile-ink);
  display:block;margin:6px 0 0}
.verdict .unit{font:500 .98rem/1 var(--sans);color:var(--muted)}
.verdict p{max-width:60ch}
.freshness{display:flex;align-items:center;gap:8px;color:var(--muted);
  font:500 .85rem/1.4 var(--sans);margin:12px 0 0;font-variant-numeric:tabular-nums}
.dot{width:8px;height:8px;border-radius:50%;background:var(--tile);flex:none}
.live .dot{animation:beat 2.6s var(--ease) infinite}
@keyframes beat{0%,100%{opacity:1}50%{opacity:.28}}
@media(prefers-reduced-motion:reduce){.live .dot{animation:none}
  *{transition-duration:.01ms!important}}
.unknown{border-top-color:var(--muted)}
.unknown .count{color:var(--muted)}
/* Nothing to report: a caption, not a headline. */
/* Queue traffic light. Named qstage, not stage: .stage is already the route
   page's opening block further down this sheet, and it won that cascade -
   the verdict came out wearing the hero's background and padding. */
.qstage{border-top-width:6px;border-top-color:var(--qc)}
.qstage--clear{--qc:#7a8ba0}
.qstage--green{--qc:#1e8f4e}
.qstage--yellow{--qc:#d99100}
.qstage--red{--qc:#c0392b}
.qstage--red .state{color:#a8321f}
/* "I don't know" - a reading we could not take, which Gal asked for in
   place of the silence that used to stand in for it. Grey like clear,
   because it is not a colour of queue and must not read as one. */
.qstage--unknown{--qc:#7a8ba0}
.verdict--quiet{border-top:0;background:none;padding:0;margin:0 0 26px}
.verdict--quiet .state{font:600 .95rem/1.4 var(--sans);color:var(--muted)}
.verdict--quiet .note,.verdict--quiet .lede{font-size:.88rem;color:var(--muted);margin:4px 0 0}
.verdict--quiet .freshness{margin:4px 0 0}
.unknown .dot{background:var(--muted)}

/* Below the board the page is a printed notice, not a stack of cards. Rank is
   carried by type size and one hairline per section; the only boxed element on
   the page is the advert, so the box means "this is paid" instead of meaning
   nothing. Five identical grey pills said every caveat mattered equally, which
   is how the whole lower half read as one flat grey area. */
.ways{margin:0 0 26px}
.ways .plain{margin:0}
/* What the front page says once the form has been answered or skipped: which
   boat is which, what happens at the port, and where the times come from.
   Under the hero, so the reader who knows what they want never meets it. */
.tell{scroll-margin-top:18px;border-top:1px solid var(--rule);margin:34px 0 0;padding:26px 0 0;
  max-width:70ch}
.tell:first-child{border-top:0;padding-top:0}
.tell h2{font:500 1.35rem/1.25 var(--serif);margin:0 0 16px}
.tell__l{display:grid;gap:16px;margin:0}
.tell__l>div{margin:0}
.tell__l dt{font:700 1rem/1.3 var(--sans);color:var(--ink)}
.tell__l dd{margin:4px 0 0;color:var(--muted);font-size:.98rem;line-height:1.5}
@media(min-width:820px){
  .tell__l{grid-template-columns:repeat(3,minmax(0,1fr));gap:22px}
  .tell{max-width:none}
  .tell h2,.tell .qa,.tell .answer,.tell .stats{max-width:70ch}
}
.qa+.qa{border-top:1px solid var(--hair);margin-top:16px;padding-top:16px}
.qa h3{font:700 1.02rem/1.35 var(--sans);margin:0 0 5px}
.qa p{margin:0;color:var(--muted);font-size:.98rem;line-height:1.55}
.tell .stats{margin:12px 0 10px}

.aside-sec{border-top:1px solid var(--rule);margin:38px 0 0;padding:24px 0 0;
  max-width:66ch}
.aside-sec h2{font:500 1.3rem/1.3 var(--serif);margin:0 0 10px}
.answer{margin:0;max-width:62ch;font-size:1.02rem}
.note{margin:8px 0 0;max-width:66ch;color:var(--muted);font-size:.93rem;
  line-height:1.5}
.fineprint{margin:10px 0 0;max-width:70ch;color:var(--muted);font-size:.8rem;
  line-height:1.5}

.booking__buy{display:inline-block;margin:16px 0 0;padding:13px 22px;border-radius:999px;
  background:var(--tile-ink);color:var(--bg);text-decoration:none;
  font-weight:600;font-size:.95rem;
  transition:background .15s var(--ease),transform .15s var(--ease)}
.booking__buy:hover{background:var(--sea-deep);color:var(--bg)}
.booking__buy:active{transform:translateY(1px)}

/* Cameras. Closed by default, and that is the mechanism rather than the
   styling: a lazy image inside a closed disclosure is never fetched, so HAK is
   asked for a frame only by a reader who wants one, and every other visit
   still costs zero third-party requests. */
.cam{margin:0 0 22px}
.cam__name{font-weight:600;font-size:1rem;margin:0 0 8px}
/* Angles sit side by side where there is room and stack where there is not,
   so three views of Split do not become three screens of scrolling. */
.cam__grid{display:grid;gap:8px;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr))}
.cam__img{display:block;width:100%;max-width:100%;height:auto;aspect-ratio:16/9;
  background:var(--surface);margin:0;border-radius:var(--r)}
.cam .fineprint{margin:8px 0 0}
/* Ships in port: a link out, for the same reason as the cameras. */
.cam-row{display:flex;flex-wrap:wrap;gap:6px 22px;margin:0}
.cam-row .cam{font-weight:600;font-size:.98rem;color:var(--sea);border:0;
  text-decoration-thickness:1px;text-underline-offset:3px}
.cam-row .cam:hover{color:var(--tile-ink)}

/* other seasons, folded away until asked for */
details.more{margin:16px 0 0}
/* Fifty-eight villages is a page of its own, not a subtitle. */
.head details.towns{margin:12px 0 0}
.head details.towns .answer{margin:8px 0 0;font-size:.95rem;color:var(--muted)}
details.more>summary{cursor:pointer;min-height:44px;font:600 .9rem/1.4 var(--sans);
  color:var(--sea);padding:12px 0;list-style:none;display:flex;align-items:center;gap:8px}
details.more>summary::-webkit-details-marker{display:none}
details.more>summary::before{content:"";width:0;height:0;flex:none;
  border-left:6px solid currentColor;border-top:4px solid transparent;
  border-bottom:4px solid transparent;transition:transform .18s var(--ease)}
details.more[open]>summary::before{transform:rotate(90deg)}
details.more>summary:hover{color:var(--tile-ink)}

/* one local advertiser block, after the answer, never before it */
.ad{margin:48px 0 0;padding:16px 18px;background:var(--surface);border-radius:var(--r);
  max-width:66ch}
.ad .tag{font:600 .7rem/1 var(--sans);letter-spacing:.09em;color:var(--muted);
  text-transform:uppercase;margin:0 0 8px}
.ad p{margin:0;font-size:.94rem}
.ad .empty{color:var(--muted);font-size:.91rem;margin:0}

/* Touch targets reach 44px without changing what the eye sees. A thumb gets a
   real target; the layout gets none of the padding that would come with it. */
.tap{position:relative}
.tap::after{content:"";position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%);width:max(100%,44px);height:44px}

.notice{margin:20px 0 0;padding:14px 16px;border-left:4px solid var(--tile-ink);
  background:var(--foam);border-radius:0 var(--r) var(--r) 0;box-shadow:var(--paper)}
.notice__kicker{margin:0;font-size:.8rem;text-transform:uppercase;letter-spacing:.06em;
  color:var(--muted)}
.notice__title{margin:4px 0 0;font:500 1.2rem/1.3 var(--serif)}
.notice__text{margin:8px 0 0;max-width:70ch;font-size:.93rem;line-height:1.5}
.notice__more{margin:6px 0 0}
.notice__lines,.notice__src{margin:8px 0 0;font-size:.9rem}
.notice__lines a{margin-right:8px}
.notice__b{margin:10px 0 0;border:1px dashed var(--rule);background:transparent;
  color:var(--sea);cursor:pointer;font:600 .86rem/1 var(--sans);
  border-radius:999px;min-height:38px;padding:0 14px}
/* 44px of hit area under a 38px button, without changing how it looks. */
.notice__b{position:relative}
.notice__b::before{content:"";position:absolute;left:0;right:0;top:50%;height:44px;
  transform:translateY(-50%)}
.notice__b:hover{color:var(--tile-ink);border-color:var(--tile-ink)}

/* The terms, out of the way until they are asked for. */
.modal{position:relative;border:0;border-radius:var(--r);padding:22px;
  max-width:min(560px,92vw);
  background:var(--foam);color:var(--ink);box-shadow:var(--paper)}
.modal::backdrop{background:oklch(0.265 0.018 220/.55)}
.modal__h{margin:4px 0 0;font:500 1.25rem/1.3 var(--serif)}
.modal__f{margin:18px 0 0;text-align:right}
.modal__x{border:1px solid var(--rule);background:transparent;color:var(--ink);
  cursor:pointer;font:600 .86rem/1 var(--sans);border-radius:999px;
  min-height:40px;padding:0 18px}
.modal__x:hover{background:var(--tile-ink);border-color:var(--tile-ink);color:var(--bg)}
/* The corner ×, not a word in the footer: a dialog whose one real action is
   Send read as two buttons of equal weight, and the Close sat where a thumb
   reaches for Send. 40px of hit area either way. */
.modal__cf{position:absolute;top:8px;right:8px;margin:0;line-height:0}
.modal__c{width:40px;height:40px;display:grid;place-items:center;border:0;
  border-radius:999px;background:transparent;color:var(--ink);opacity:.55;
  cursor:pointer;font:400 25px/1 var(--sans)}
.modal__c:hover,.modal__c:focus-visible{opacity:1;background:var(--tile-ink);
  color:var(--bg)}
.modal__h{padding-inline-end:34px}

/* One panel open at a time. `name` on <details> is the browser's own exclusive
   accordion; this only has to make the closed titles read as a list of what
   the page holds rather than as a stack of empty sections. */
.fold{border-top:1px solid var(--rule);margin:0;scroll-margin-top:12px}
.fold:last-of-type{border-bottom:1px solid var(--rule)}
.fold__s{cursor:pointer;list-style:none;display:flex;align-items:center;
  justify-content:space-between;gap:14px;padding:18px 2px;min-height:44px}
.fold__s::-webkit-details-marker{display:none}
.fold__h{margin:0;font:500 1.2rem/1.3 var(--serif)}
.fold__s:hover .fold__h{color:var(--tile-ink)}
.fold__mark{width:11px;height:11px;flex:none;border-right:2px solid var(--muted);
  border-bottom:2px solid var(--muted);transform:rotate(45deg) translate(-3px,-3px);
  transition:transform .18s var(--ease)}
.fold[open] .fold__mark{transform:rotate(225deg) translate(-2px,-2px)}
.fold__b{padding:0 2px 26px}
.fold__b>h2:first-child,.fold__b>h3:first-child{margin-top:0}
.fold__b .whenbar{margin:0 0 18px}

/* The party that is actually travelling, priced. The published table stays
   underneath: this is the answer, that is the source. */
.calc{margin:0 0 26px;padding:16px 18px 14px;background:var(--surface);
  border-radius:var(--r);border:1px solid var(--rule)}
.calc__h{margin:0 0 12px;font:600 .8rem/1 var(--sans);letter-spacing:.07em;
  text-transform:uppercase;color:var(--muted)}
.calc__g{display:grid;gap:12px}
@media(min-width:620px){.calc__g{grid-template-columns:auto auto 1fr;
  align-items:end;gap:12px 22px}}
.calc__f{display:grid;gap:6px;font:500 .9rem/1.3 var(--sans)}
.calc__f>span{color:var(--muted);font-size:.82rem;letter-spacing:.03em}
.calc__n{display:inline-flex;align-items:center;gap:2px}
.calc__s{width:36px;height:36px;flex:none;border:1px solid var(--rule);
  background:transparent;color:var(--ink);border-radius:999px;cursor:pointer;
  font:600 1.1rem/1 var(--sans);position:relative}
/* The circle stays 36px so the row keeps its shape; what you press is 44px. */
.calc__s::before{content:"";position:absolute;left:50%;top:50%;width:44px;height:44px;
  transform:translate(-50%,-50%)}
.calc__s:hover{border-color:var(--tile-ink);color:var(--tile-ink)}
.calc__n output{min-width:2.2ch;text-align:center;
  font:600 1.05rem/1 var(--sans);font-variant-numeric:tabular-nums}
.calc__v{min-height:36px;border:1px solid var(--rule);border-radius:10px;
  background:var(--bg);color:var(--ink);font:500 .92rem/1 var(--sans);
  padding:0 8px;max-width:100%}
.calc__c{display:flex;align-items:center;gap:8px;margin:12px 0 0;
  font:500 .9rem/1.3 var(--sans);cursor:pointer}
.calc__t{margin:14px 0 0;display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 12px}
.calc__t b{font:700 1.85rem/1 var(--sans);letter-spacing:-.03em;
  font-variant-numeric:tabular-nums;color:var(--tile-ink)}
.calc__t span{font:400 .88rem/1.4 var(--sans);color:var(--muted)}
.calc .fineprint{margin:6px 0 0}
.backlink{margin:40px 0 0;font-size:.95rem}
.backlink a,.source a{display:inline-block}
footer{background:var(--sea-deep);color:var(--foam);margin-top:72px;
  padding:30px 0 52px;font-size:.88rem}
footer p{max-width:66ch;margin:.45em 0;opacity:.72}
footer a{color:var(--foam)}
footer .mark{font:500 1.35rem/1 var(--serif);opacity:1;margin-bottom:12px}
.byline{margin-top:18px}
.byline a{opacity:.82;font-weight:600;text-decoration-thickness:1px;
  text-underline-offset:3px}
.byline a:hover{opacity:1;color:var(--foam)}
/* the colophon's own furniture */
.stats{margin:0 0 6px;color:var(--muted);font-size:.95rem;
  font-variant-numeric:tabular-nums}
.imp__name{margin:18px 0 6px;font-weight:700}
.imp{display:grid;grid-template-columns:auto 1fr;gap:4px 16px;margin:0;
  font-size:.92rem;max-width:52rem}
.imp dt{color:var(--muted)}
.imp dd{margin:0}
/* ---- the crossing stage -------------------------------------------------
   A route page opens on the port you are leaving from: its camera, its queue
   and its next boat, and on a desktop all of that inside one screen. The
   photograph is no longer a stock harbour behind a title - it is the ramp you
   are about to drive onto, minutes old.

   Note for anyone editing this file: the stylesheet is a Python string, and a
   backslash CSS escape is read as an octal escape by Python before CSS ever
   sees it - a right-arrow escape shipped a control character and the visible
   text "92". The string is raw now, so that cannot happen again; even so,
   prefer writing the character itself or putting it in the markup. */
.stage{background:var(--surface);border-bottom:1px solid var(--rule);padding:12px 0 16px}
/* The title never fills the width, and what is wrong today has to be read
   before anything else - so they share the top row and neither costs the
   picture a line of height. */
.stage__top{display:grid;gap:10px}
@media(min-width:940px){
  .stage__top{grid-template-columns:minmax(0,auto) minmax(340px,1fr);
    gap:22px;align-items:center}
  .stage__top .alerts{margin-top:0}
}
.stage__k{font:700 11.5px var(--sans);letter-spacing:.11em;text-transform:uppercase;
  color:var(--sea)}
.stage__h{font-size:clamp(20px,3.4vw,29px);letter-spacing:-.03em;margin:3px 0 0;
  font-family:var(--serif);font-weight:600;line-height:1.1}
.stage__op{margin:7px 0 0;display:flex;align-items:center;gap:9px}
.stage .op{display:inline-block;height:17px;width:auto;box-sizing:content-box;
  padding:5px 10px;border-radius:999px;background:var(--foam);border:1px solid var(--hair)}

/* both sides, always named, the live one unmistakable */
.seg{display:flex;gap:6px;margin-top:11px}
.seg__b{flex:1;min-width:0;min-height:52px;border:1px solid var(--rule);border-radius:12px;
  background:var(--bg);cursor:pointer;color:var(--muted);display:grid;gap:1px;
  padding:7px 13px;text-align:left;font:600 15px var(--sans);
  transition:background .16s var(--ease),color .16s,border-color .16s}
.seg__b b{font-weight:700;color:inherit;font-size:15px;letter-spacing:-.015em;
  line-height:1.2;overflow-wrap:anywhere}
.seg__b small{font-size:12.5px;font-weight:600;opacity:.9;
  font-variant-numeric:tabular-nums}
.seg__b[aria-pressed=true]{background:var(--sea-deep);color:var(--foam);
  border-color:transparent}
.seg__b[aria-pressed=true] small{color:var(--tile-lite)}

/* The stage runs wider than the reading column under it. Every HAK frame is
   640x360, and at 1060px the picture that answers the question was the
   narrowest thing on a 1920 screen. */
.stage>.wrap{max-width:1440px}
.stage__g{display:grid;gap:12px;margin-top:12px;
  grid-template-columns:minmax(0,1fr);align-items:start}
/* Between a phone and a laptop (an iPad on its side, a half-width window) the
   column beside the picture left it 620px wide and 350px tall, next to a
   column of cards 470px tall - the gap under the photograph was painted sea.
   The picture takes the width there and the two cards share the row under it. */
@media(min-width:940px) and (max-width:1149px){
  .stage__side{grid-template-columns:repeat(2,minmax(0,1fr));grid-auto-flow:row dense;align-items:start}
  .stage__side .qstrip{grid-column:1}
}
@media(min-width:1150px){
  /* The picture takes the room, the column takes what one card needs. */
  .stage__g{grid-template-columns:minmax(0,1fr) minmax(310px,350px);gap:14px;
    align-items:start}
  .stage--nocam .stage__g{grid-template-columns:minmax(0,1fr)}
  .stage--nocam .stage__side{
    grid-template-columns:repeat(auto-fit,minmax(300px,1fr));align-items:start}
  /* No scrollbar inside the column. A card taller than the picture makes the
     page longer instead - a scroll people already know how to use. Boxing it
     put the price and the buy button below a fold nobody could see. */
  .stage__side{align-self:start}
}
/* One screen, where there is a screen to fill: the picture keeps its own
   shape and the type above it tightens instead. Cropping the frame to fill a
   column was cutting the queue out of the photograph of the queue. */
@media(min-width:1150px) and (min-height:680px){
  .stage{min-height:calc(100svh - var(--hdr));display:flex;flex-direction:column;
    padding-bottom:12px}
  /* Without a picture there is no screen to fill, only cards to show. */
  .stage--nocam{min-height:0}
  .stage--nocam .stage__g{flex:0 0 auto}
  /* A flex item with auto side margins does not stretch, so the wrap sized
     itself to its content and ignored the width it was given.

     The width is also what decides the picture's height, because the picture
     is 16:9 and never cropped. Everything else on this screen is measured -
     kicker 13, title 29, operator 18, alerts 60, control 48, answers 56, plus
     the gaps and the stage's padding, 390px measured - so the wrap is capped at
     the width whose 16:9 height is exactly the screen that is left. On a
     short window the picture gets smaller instead of the page getting
     longer. 404px is the column beside it (350) plus the gap (14) and the
     wrap's own padding (40).

     The column beside it is 440-590px of cards that do not shrink (590 with a
     live reading's strip), so a picture shorter than that buys nothing: on a
     1366x768 laptop the formula cut the photograph to 317px and painted the
     160px under it dark. The floor is the width whose picture is about as
     tall as the column, and the column no longer stretches the picture's
     card: where it is still taller, the room under the picture is the page,
     not a dark box. */
  .stage>.wrap{flex:1;display:flex;flex-direction:column;min-height:0;width:100%;
    max-width:min(1760px,max(1300px,calc((100svh - var(--hdr) - 340px) * 16 / 9 + 404px)))}
  .stage--nocam>.wrap{max-width:1440px}
  .stage__g{min-height:0;padding-bottom:2px}
  /* Any height left over lands under the picture, not under the answers: the
     answers and the footnote belong on the bottom edge of the screen. */
  .answers{margin-top:auto}
  .stage__h{font-size:clamp(20px,2.5vw,26px)}
  .stage__op{margin-top:5px}
  .seg{margin-top:9px}
  .seg__b{min-height:48px}
}

/* A short window, with the column still a column.

   The two cards beside the picture want about 430px between them, and a laptop
   whose viewport is 780px tall leaves 330 - so the column grew a scrollbar and
   cut the next departure off at the top. Side by side they fitted and looked
   like two half-empty panels. So the column stays a column and the cards get
   denser instead: the departure time and the countdown share a line the way a
   departure board writes them, and the steppers give up a few pixels. Nothing
   is hidden that was not already behind a press. */
/* A laptop under 800px tall, with a live reading: the column is 467px and the
   page above the grid 223px, so with the four answers under both columns
   nothing short of hiding a line put them on screen. Gal, 11 Sept 2026: "all
   info, 0 scroll... if there is not room make stuff smaller". So on these
   screens the answers move under the picture, beside the column, and the
   picture is cut to the height that leaves them room; the masthead loses
   12px, the chips join the kicker's line, and the footnote goes under the
   fold - it is the one paragraph here that is not an action. */
@media(min-width:1150px) and (max-height:800px){
  :root{--hdr:49px}
  .masthead .wrap{height:48px}
  .stage{padding-top:6px}
  .stage__id{display:grid;grid-template-columns:auto minmax(0,1fr);column-gap:12px;
    align-items:center}
  .stage .stage__k{grid-area:1/1;margin:0}
  .stage .stage__op{grid-area:1/2;margin:0;justify-self:start}
  .stage .stage__h{grid-area:2/1/3/3;margin-top:2px}
  .stage>.wrap{display:grid;column-gap:14px;row-gap:0;align-content:start;
    grid-template-columns:minmax(0,1fr) minmax(310px,350px);
    grid-template-rows:auto auto auto 1fr auto;
    grid-template-areas:"top top" "seg seg" "shot side" "ans side" "foot foot";
    max-width:min(1760px,calc((100svh - 274px) * 16 / 9 + 404px))}
  .stage__top{grid-area:top}
  /* The notice beside the title was the taller of the two: its kicker joins
     its title's line, and the body keeps one line. */
  .stage .alert{padding:6px 34px 7px 13px;grid-template-columns:auto minmax(0,1fr);
    column-gap:8px;align-items:baseline}
  .stage .alert__s{grid-column:1/-1}
  .seg{grid-area:seg}
  .stage__g{display:contents}
  .shot{grid-area:shot;align-self:start;margin-top:9px}
  .stage__side{grid-area:side;margin-top:9px}
  .stage .answers{grid-area:ans;align-self:end;margin-top:8px;gap:8px}
  .stage .answers .ans__b{min-height:50px;padding:7px 10px}
  .stage .ans__b::after{display:none}
  /* The source line keeps one line across the foot. The lede goes: it is the
     one paragraph on this screen that repeats what the screen already shows
     (line, operator, crossing, price, ports), and it is written for crawlers. */
  .stage .stage__foot{grid-area:foot;margin-top:7px;grid-template-columns:minmax(0,1fr)}
  .stage .stage__foot .lede{display:none}
  .stage .stage__fine{text-align:left;max-width:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .stage .stage__foot .lede,.stage .stage__fine{font-size:11.5px;line-height:1.35}
}
/* A 13-inch laptop with the browser's own bars and the dock on screen leaves
   about 690px, and the buy button sat 24px under its edge. What is above the
   grid gives those pixels back: the title, the chips and the side control each
   lose a few, none loses a word. */
@media(min-width:940px) and (max-height:760px){
  .stage{padding-top:8px}
  .stage__h{font-size:clamp(20px,2.3vw,24px)}
  .stage__op{margin-top:4px}
  .seg{margin-top:7px}
  .seg__b{min-height:44px;padding:5px 13px}
  .stage__g{margin-top:9px}
  .answers{margin-top:9px}
}
@media(min-width:940px) and (max-height:900px){
  .stage__side .scard{padding:11px 14px}
  .stage__side .scard--next .head__leadlabel{margin-bottom:5px}
  .stage__side .leg{display:grid;grid-template-columns:auto minmax(0,1fr);
    column-gap:12px;align-items:baseline}
  .stage__side .leg__where{grid-column:1/-1;margin-bottom:2px}
  .stage__side .leg__shut{grid-column:1/-1}
  /* Only the time and the countdown share a row. Left to auto-place, a
     boarding line ("12:07 left 8 min early · 72 min after the one before it")
     took the auto column and squeezed "in 1 h 8 min" into one word per line. */
  .stage__side .leg__ref,.stage__side .leg__ev,.stage__side .leg__more{grid-column:1/-1}
  .stage__side .leg__ev{margin-top:4px;padding-top:4px}
  .stage__side .leg__time{grid-column:1;font-size:clamp(1.5rem,2.2vw,1.9rem)}
  .stage__side .leg__in{grid-column:2;margin:0;text-align:right}
  /* "svaki trenutak" is words, not a time, and takes the row; the side line
     goes under it instead of dropping one word per line down the right. */
  .stage__side .leg__time--word{grid-column:1/-1}
  .stage__side .leg__time--word+.leg__in{grid-column:1/-1;text-align:left;margin-top:2px}
  .stage__side .leg__rest{grid-column:1/-1;margin-top:7px;padding-top:7px}
  .stage__side .party__g{gap:3px 10px;margin-top:6px}
  .stage__side .calc__s{width:32px;height:32px}
  /* The browser's own paragraph margins were 18px of nothing under the buy
     button and 10px over the label - a third of the card's slack. */
  .stage__side .party{margin:7px 0 0;padding-top:7px}
  .stage__side .scard--party .scard__k{margin:0 0 6px}
  .stage__side .qstrip{padding-top:6px;padding-bottom:8px}
  .stage__side .leg__more{margin-top:4px;display:flex}
  .stage__side .party__n{font-size:20px}
  /* The party is spelled out in full inside the sheet the price opens. */
  .stage__side .party__l{-webkit-line-clamp:1}
}

.shot{position:relative;border-radius:var(--r);overflow:hidden;background:var(--sea-deep);
  box-shadow:var(--paper)}
/* HAK serves every camera at 640x360. The box is that shape and the picture
   is contained in it, so nothing is ever cut off the sides - a 4:3 box on a
   phone was cropping away the lanes the picture exists to show. */
.shot__f{position:relative;aspect-ratio:16/9;background:var(--sea-deep);overflow:hidden}
.shot__f img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;opacity:0}
.shot__f img.on{opacity:1}
/* Ours sits under HAK's, at the foot of the picture: their strip across the
   top carries the capture time, and two captions in one corner read as one
   broken one. */
.shot__meta{display:flex;align-items:center;gap:9px;flex-wrap:wrap;
  margin-top:9px;padding-top:9px;border-top:1px solid oklch(0.97 0.011 82/.22)}
.shot__meta b{font:700 13.5px var(--sans);white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;min-width:0}
.shot__meta .view{font:600 11.5px var(--sans);opacity:.84;flex:none;
  font-variant-numeric:tabular-nums}
.shot__age{margin-left:auto;font:600 12px var(--sans);opacity:.92;flex:none;
  position:relative;color:inherit}
/* The rule separates this line from the queue reading above it. With no
   reading to reach for there is nothing to separate, and it drew a line
   across the top of the bar for its own sake. On a phone the link also stops
   being pushed to the far edge, where it took a second line to itself. */
.shot__b:has(>[data-side-only]:not([hidden]):empty) .shot__meta{margin-top:0;
  padding-top:0;border-top:0}
@media(max-width:619px){.shot__age{margin-left:0}}
.shot__age::before{content:"";position:absolute;left:-8px;right:-8px;top:50%;height:44px;
  transform:translateY(-50%)}
/* On a phone the frame is 197px tall and this bar, over it, took a third of
   the picture the page exists to show. Below 620px it sits on the card's own
   dark paper under the picture instead of on top of it. */
.shot__b{padding:10px 13px 11px;color:var(--foam);background:var(--sea-deep)}
@media(min-width:620px){
  .shot__b{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:54px 13px 11px;
    background:linear-gradient(transparent 0%,oklch(0.15 0.03 222/.55) 34%,
      oklch(0.13 0.03 222/.94) 100%);padding-right:min(42%,200px)}
}
.shot__b .verdict{background:none;border:0;padding:0;box-shadow:none;color:inherit;
  margin:0}
.shot__b .state{font:700 clamp(16px,2.2vw,20px) var(--sans);letter-spacing:-.02em;
  color:inherit;margin:0}
.shot__b .note,.shot__b .freshness{font-size:12.5px;color:inherit;opacity:.84;
  margin:2px 0 0}
.shot__b .dot{background:currentColor}
/* Over the picture the caption strips every border, so the traffic light
   loses the one thing it is: a colour. It comes back as a lamp in front of
   the sentence, sized to read at arm's length on a phone. */
/* Never `live` on this block. That class is the red LIVE pill on the camera
   caption - inline-flex, uppercase, rounded - and putting it here turned the
   whole reading into one shouting pill whose paragraphs stacked up as
   columns across the photograph. The pulsing dot comes from qstage instead. */
.qstage .dot{animation:beat 2.6s var(--ease) infinite}
@media(prefers-reduced-motion:reduce){.qstage .dot{animation:none}}
.shot__b .qstage .state{display:flex;align-items:baseline;gap:9px}
.shot__b .qstage .state::before{content:"";flex:none;width:11px;height:11px;
  border-radius:99px;background:var(--qc);box-shadow:0 0 0 3px oklch(1 0 0/.18);
  transform:translateY(-1px)}
.shot__b .qstage--red .state{color:inherit}
/* The time-to-full is the second thing anyone reads, so it does not fade with
   the footnotes. It is not the page's .lede either: that class is the route
   page's own opening sentence, and taking it here made the queue reading the
   answer paragraph the page advertises. */
.shot__b .qfull{opacity:1;font-weight:600}
/* Smaller than a verdict, because it is a beta reading over a photograph that
   can contradict it, and the photograph is the thing the reader came for. */
.shot__b .qstage .state{font-size:clamp(15px,1.7vw,17px)}
.qbeta{display:inline-block;margin-inline-start:8px;vertical-align:middle;
  font:700 9.5px/1 var(--sans);letter-spacing:.10em;text-transform:uppercase;
  padding:3px 6px 2px;border-radius:3px;border:1px solid currentColor;opacity:.7;
  cursor:help}
/* How old the reading is, and how often it is taken. Under the line rather
   than beside it: the line is the answer and this is its provenance. */
.qwhen{margin:2px 0 0;font:500 11.5px/1.3 var(--sans);opacity:.62;
  letter-spacing:.01em}
.qwrong{margin-inline-start:8px;font:600 12px var(--sans);color:inherit;
  background:none;border:0;padding:2px 0;opacity:.72;cursor:pointer;
  text-decoration:underline;text-underline-offset:3px}
.qwrong:hover{opacity:1}
.qwrong[disabled],.qhere[disabled]{text-decoration:none;cursor:default;opacity:.8}
/* "I'm here" is the one the reader is meant to press, so it is a button and
   not a link; "doesn't match the picture?" is a correction and stays quiet. */
.qhere{margin-inline-start:10px;font:700 12px var(--sans);color:inherit;
  background:oklch(1 0 0/.13);border:1px solid oklch(1 0 0/.3);border-radius:99px;
  padding:3px 10px 2px;cursor:pointer}
.qhere:hover{background:oklch(1 0 0/.22)}
.qhow{margin-inline-start:7px;width:24px;height:24px;flex:none;border-radius:99px;
  border:1px solid currentColor;background:none;color:inherit;opacity:.6;
  font:700 11px var(--sans);line-height:1;cursor:pointer;padding:0}
.qhow:hover{opacity:1}
.qans{display:flex;flex-wrap:wrap;gap:9px;margin:14px 0 0}
.qans button{font:600 15px var(--sans);padding:9px 18px;border-radius:99px;
  border:1px solid var(--rule);background:transparent;color:var(--ink);cursor:pointer}
.qans button:hover{background:var(--tile-ink);border-color:var(--tile-ink);color:var(--bg)}
/* The reading is welded to the foot of the departure card: one card, because
   two was a column you had to scroll to read one answer. */
.scard--next:has(~ .qstrip:not([hidden])){border-end-start-radius:0;border-end-end-radius:0;
  border-bottom:0;padding-bottom:12px}
.qstrip{background:var(--surface);border:1px solid var(--rule);border-top:0;
  border-radius:0 0 var(--r) var(--r);padding:11px 15px 13px;margin:0 0 12px;
  border-inline-start:4px solid var(--qc)}
/* The weld above only squares the corners; the column is a grid, and its 10px
   gap was still drawing a seam between the two halves of one card. */
.scard--next ~ .qstrip:not([hidden]){margin:-10px 0 0}
.qstrip__a{margin:0;display:flex;align-items:center;flex-wrap:wrap;gap:10px}
.qstrip .qhere{margin:0;color:var(--bg);background:var(--tile-ink);
  border-color:var(--tile-ink);padding:5px 13px 4px;font-size:12.5px}
.qstrip .qhere:hover{background:var(--ink);border-color:var(--ink)}
.qstrip .qwrong{margin:0;color:var(--muted);font-size:11.5px}
/* The sailing the road has already closed. It stays on the card - "why not
   the 10:00" is the first thing anyone asks, and we might be wrong. */
/* Not flex: the line is a sentence with a link at the end of it, and a flex
   row squeezed "(how do we know?)" into a two-line column of its own. */
.leg__shut{margin:2px 0 0;display:block;
  font:500 .84rem/1.4 var(--sans);color:var(--muted)}
.leg__shut .dot{width:8px;height:8px;background:#c0392b;flex:none;
  display:inline-block;margin-inline-end:6px;vertical-align:middle}
.leg__shut s{text-decoration-thickness:1.5px}
/* What actually left today, above the timetable it is the check on. */
.cadence{margin:0 0 22px;padding:0 0 18px;border-bottom:1px solid var(--rule)}
.cadence p{margin:6px 0 0;max-width:62ch}
.cadence .season__note{font-variant-numeric:tabular-nums}
/* The real departures, in the page rather than behind a press. The last boat
   out is the fact; everything under it is arithmetic, and it has to look
   quieter than the fact it rests on. */
/* A panel now, not a section: .modal carries the frame, so this only sets
   its measure and makes sure the whole day fits without a scrollbar of its
   own - Gal, 10 Sept 2026: "I like when nothing is out of scope, 0
   scrolling". Everything in here is one or two lines; the room it needs is
   bounded, so the height is left to the content. */
.ran{max-width:min(620px,94vw)}
.ran .modal__b>*:first-child{margin-top:0}
.ran p{margin:6px 0 0;max-width:64ch}
.ran .season__note{font-variant-numeric:tabular-nums}
.ran__last{font:600 1.06rem/1.4 var(--sans);font-variant-numeric:tabular-nums}
.ran__all{margin:10px 0 0;font-variant-numeric:tabular-nums}
.ran__all b{font-weight:600}
.ran__all--p{color:var(--muted)}
/* The day on one rule: printed sailings above it, the ones a camera actually
   saw below it. Nothing here is paired with anything - the shape is the
   argument, and the shape is "there are more boats than the timetable". */
.dl{position:relative;height:54px;margin:16px 0 0;
  border-top:1px solid var(--rule);border-bottom:1px solid var(--hair)}
.dl i{position:absolute;transform:translateX(-50%)}
.dl__p{top:0;width:2px;height:11px;background:var(--muted);opacity:.55;border-radius:1px}
.dl__s{top:16px;width:3px;height:18px;background:var(--sea);border-radius:2px}
.dl__e{top:16px;width:3px;height:18px;border-radius:2px;
  background:repeating-linear-gradient(var(--tile) 0 3px,transparent 3px 6px)}
.dl__now{top:0;bottom:16px;width:1px;background:var(--tile-ink);opacity:.55}
.dl__h{position:absolute;left:0;right:0;bottom:0;height:14px}
.dl__h i{bottom:0;font:500 .68rem/1 var(--sans);color:var(--muted);
  font-variant-numeric:tabular-nums}
.dl__k{margin:6px 0 0 !important;display:flex;flex-wrap:wrap;gap:14px;
  font:500 .78rem/1.4 var(--sans);color:var(--muted)}
.dl__k span{display:inline-flex;align-items:center;gap:6px}
.dl__k span::before{content:"";width:3px;height:12px;border-radius:2px;
  background:var(--sea)}
.dl__kp::before{width:2px;height:9px;background:var(--muted) !important;opacity:.55}
.dl__ke::before{background:repeating-linear-gradient(
  var(--tile) 0 3px,transparent 3px 6px) !important}
.live__mode{font:500 .92rem/1.45 var(--sans)}
/* The evidence for the mode, under the claim it supports. */
.live__ev{font-variant-numeric:tabular-nums}
/* The card's own lines, when a camera has measured something the timetable
   does not say. No height and no overflow on any of them: a card decides its
   own height and a long one makes the page longer - the column beside the
   photograph earned its scrollbar once and never again
   (tests/site/test_no_inner_scroll.py). */
.leg__time--word{font-size:clamp(1.5rem,7vw,1.9rem);letter-spacing:-.01em}
.leg__st{color:var(--tile-ink);font-weight:700}
sup.leg__st{font-size:.42em;vertical-align:super;margin-inline-start:.06em}
.leg__ref{margin:1px 0 0;display:flex;align-items:center;gap:7px;
  font:400 .84rem/1.4 var(--sans);color:var(--muted);
  font-variant-numeric:tabular-nums}
.leg__ref .qm{flex:none;width:19px;height:19px;padding:0;border-radius:50%;
  border:1px solid var(--rule);background:transparent;color:var(--muted);
  font:600 .7rem/1 var(--sans);cursor:pointer}
.leg__ref .qm:hover{border-color:var(--sea);color:var(--sea)}
.leg__ev{margin:8px 0 0;padding-top:8px;border-top:1px solid var(--hair);
  font:400 .8rem/1.45 var(--sans);color:var(--muted);
  font-variant-numeric:tabular-nums}
.leg__more{margin:5px 0 0}
.leg__more button{border:0;background:transparent;padding:0;cursor:pointer;
  font:600 .8rem/1.4 var(--sans);color:var(--tile-ink);text-align:start}
.leg__more button::after{content:" \2192"}
.leg__more button:hover{text-decoration:underline;text-underline-offset:3px}
/* The boat we expected did not come. Not an alarm - a fact, in the tone of
   the rest of the block. */
.live__mode--late{color:var(--muted)}
.live__k{margin:16px 0 6px !important;font:600 .88rem/1.4 var(--sans);
  letter-spacing:.04em;text-transform:uppercase;color:var(--muted)}
.live__tag{font:500 .78rem/1 var(--sans);letter-spacing:.06em;
  padding:3px 7px;border:1px solid var(--rule);border-radius:999px;
  text-transform:uppercase;color:var(--muted);white-space:nowrap}
.live__rows{margin:0;padding:0;list-style:none;font-variant-numeric:tabular-nums}
.live__rows li{display:flex;gap:12px;align-items:baseline;
  padding:7px 0;border-top:1px solid var(--rule)}
.live__p{min-width:4.5ch;font:600 1rem/1.3 var(--sans)}
.live__e{font:600 1rem/1.3 var(--sans);color:var(--sea)}
/* A boat in no timetable is the one row nobody else can print. */
.live__x .live__p{color:var(--muted);font-weight:400}
.live__rows small{font:400 .8rem/1.3 var(--sans);color:var(--muted)}
/* The claim answers for itself, in the same line as the claim. */
.qwhy{font:inherit;font-size:.94em;color:var(--sea);background:none;border:0;
  padding:0;cursor:pointer;text-decoration:underline;text-underline-offset:3px;
  text-decoration-thickness:1px}
.leg__left button{font:inherit;color:var(--sea);background:none;border:0;padding:0;
  cursor:pointer;text-decoration:underline;text-underline-offset:3px}
.qq{margin:16px 0 0;font:600 .95rem/1.4 var(--sans)}
.qq:first-of-type{margin-top:6px}
.qans--when button{font-size:13.5px;padding:6px 13px}
.qnote{width:100%;margin:10px 0 0;font:400 15px/1.5 var(--sans);color:var(--ink);
  background:var(--bg);border:1px solid var(--rule);border-radius:10px;padding:10px;
  resize:vertical}
/* The reading in full, beside the departure card. On paper, not over the
   photograph - the photograph is the evidence for it, and print on evidence
   is how you stop people checking it. */
.qcard{border-inline-start:4px solid var(--qc)}
.qcard__h{margin:6px 0 0;font:500 clamp(1.15rem,2.6vw,1.4rem)/1.2 var(--serif);
  display:flex;align-items:center;gap:9px}
.qcard__h .dot{background:var(--qc);width:10px;height:10px}
.qcard__s{margin:3px 0 0;font:500 .92rem/1.4 var(--sans);color:var(--muted)}
.qcard__f{margin:9px 0 0;font:500 .8rem/1.4 var(--sans);color:var(--muted);
  font-variant-numeric:tabular-nums}
.qcard__a{margin:11px 0 0;display:flex;align-items:center;flex-wrap:wrap;gap:10px}
.qcard .qhere{margin:0;color:var(--bg);background:var(--tile-ink);
  border-color:var(--tile-ink);padding:5px 13px 4px;font-size:12.5px}
.qcard .qhere:hover{background:var(--ink);border-color:var(--ink)}
.qcard .qwrong{margin:0;color:var(--muted);font-size:11.5px}
/* The red LIVE badge, and only the badge. Unscoped, this rule also caught
   every verdict section - which the page marks `live` when the reading is
   fresh - and turned a whole queue reading into one uppercase pill with its
   paragraphs in columns across the photograph. */
.shot__meta .live{display:inline-flex;align-items:center;gap:6px;font:700 10.5px var(--sans);
  letter-spacing:.10em;text-transform:uppercase;background:oklch(0.55 0.19 25);
  color:oklch(0.99 0.02 25);padding:4px 8px;border-radius:99px;flex:none}
.shot__meta .live i{width:6px;height:6px;border-radius:99px;background:currentColor}

/* the same port's next view, one press away */
/* The small picture and the button it folds into share one corner. */
.pipwrap{position:absolute;right:11px;z-index:3;display:flex;
  align-items:flex-end;gap:7px;bottom:11px}
@media(max-width:619px){.pipwrap{bottom:auto;top:11px}}
.pip{position:relative;width:clamp(104px,21vw,168px);
  border:0;padding:0;border-radius:10px;overflow:hidden;cursor:pointer;
  background:var(--sea-deep);
  box-shadow:0 12px 30px -12px oklch(0.17 0.03 220/.85),0 0 0 2px oklch(0.97 0.011 82/.65)}
.pip:hover{box-shadow:0 16px 34px -12px oklch(0.17 0.03 220/.9),
  0 0 0 2px oklch(0.97 0.011 82/.95)}
.pip:active{transform:scale(.97)}
/* height:auto is not the default here: the img element's height attribute is
   a presentational hint, and without this it wins over aspect-ratio and the
   thumbnail stands 180px tall inside a 197px picture. */
.pip img{width:100%;height:auto;aspect-ratio:16/9;object-fit:cover;display:block;
  background:var(--sea-deep)}
.pip__l{position:absolute;left:0;right:0;bottom:0;padding:14px 8px 6px;color:var(--foam);
  background:linear-gradient(transparent,oklch(0.15 0.03 222/.92));
  font:700 11px var(--sans);text-align:left;line-height:1.3}
.pip__l small{display:block;font-weight:500;font-size:10px;opacity:.84}
/* Folded away, the cameras are still one press apart - the button that hides
   the picture is not the button that stops you looking at the other one. */
.pip__min{position:absolute;top:-9px;right:-9px;width:26px;height:26px;
  border-radius:999px;border:1px solid oklch(0.99 0.01 82/.28);
  background:oklch(0.17 0.03 220/.92);color:var(--foam);cursor:pointer;
  display:grid;place-items:center;padding:0;z-index:2}
.pip__min::before{content:"";position:absolute;left:50%;top:50%;width:44px;
  height:44px;transform:translate(-50%,-50%)}
.pip__min:hover{background:oklch(0.17 0.03 220/1)}
/* display on the class outranks the hidden attribute, so the fold button
   showed beside the picture it replaces. */
.pip__dot[hidden],.pip__min[hidden],.pip[hidden]{display:none}
.pip__dot{display:inline-flex;align-items:center;gap:6px;min-height:38px;
  padding:0 13px;border-radius:999px;border:1px solid oklch(0.99 0.01 82/.26);
  background:oklch(0.17 0.03 220/.88);color:var(--foam);cursor:pointer;
  font:700 12px var(--sans);backdrop-filter:blur(6px);position:relative}
.pip__dot::before{content:"";position:absolute;left:0;right:0;top:50%;height:44px;
  transform:translateY(-50%)}
.pip__dot:hover{background:oklch(0.17 0.03 220/1)}
.pip__dot:active{transform:scale(.97)}

/* The sailings where the picture would be, on a line where the picture
   answers nothing. The day is the page: one strip names it, the boats of
   that day sit under it in time order both ways, and the only thing a tap
   adds is the ticket card - 300px on a desktop, a sheet at the foot of a
   phone. */
.sails{display:grid;gap:8px;align-content:start;min-width:0}
.sails__day{display:flex;align-items:center;gap:4px}
.sails__day b{font:700 15px var(--sans);min-width:7.5em;text-align:center;
  font-variant-numeric:tabular-nums}
.sails__step{width:44px;height:44px;border-radius:999px;border:1px solid var(--rule);
  background:var(--foam);font-size:22px;line-height:1;cursor:pointer;color:var(--ink);
  transition:background .15s var(--ease)}
.sails__step:hover{background:var(--bg)}
.sails__step:active{transform:scale(.97)}
.sails__step:disabled{opacity:.35;cursor:default;transform:none}
.sails__hint,.sails__none{margin:-2px 0 0;max-width:none;font-size:13px;color:var(--muted)}
.sails__note{margin:0;max-width:none;font-size:13.5px;line-height:1.45;color:oklch(0.40 0.09 60);
  background:oklch(0.95 0.05 78);border:1px solid oklch(0.87 0.08 78);border-radius:12px;
  padding:8px 12px}
.sails__j{background:var(--foam);border:1px solid var(--rule);border-radius:var(--r);
  padding:10px 14px;transition:border-color .15s var(--ease),background .15s var(--ease)}
.sails__j:not(.sails__j--gone):hover{border-color:var(--muted)}
.sails__top{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:12px;
  align-items:center;min-height:44px;cursor:pointer;list-style:none;border-radius:8px}
.sails__top::-webkit-details-marker{display:none}
.sails__top:focus-visible{outline:2px solid var(--sea);outline-offset:4px}
.sails__t{font:800 23px/1 var(--sans);letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.sails__to{min-width:0}
.sails__to b{display:block;font-weight:700;font-size:15px;line-height:1.2}
.sails__to .arrow{margin:0 5px;opacity:.6}
.sails__to small{display:block;font-size:12.5px;color:var(--muted)}
/* The wind at the pier, one line under the calls, so the day reads at a glance. */
.sails__chip{display:inline-flex;align-items:center;gap:5px;margin-top:3px;font-size:12px;
  color:var(--muted);font-variant-numeric:tabular-nums}
.sails__chip i{width:10px;height:10px;display:inline-grid;place-items:center;
  transform:rotate(var(--r,0deg))}
.sails__chip i::before{content:"";width:0;height:0;border-left:4px solid transparent;
  border-right:4px solid transparent;border-bottom:9px solid var(--sea)}
.sails__j--gone .sails__chip{display:none}
.sails__arr{text-align:right;font-variant-numeric:tabular-nums}
.sails__arr b{display:block;font:700 17px/1 var(--sans)}
.sails__arr small{font-size:12px;color:var(--muted)}
.sails__j--gone{opacity:.5}
.sails__j--gone .sails__top{cursor:default}
.sails__j--on{border-color:var(--tile-ink);background:var(--bg)}
.sails__j--on:hover{border-color:var(--tile-ink)}
.sails__j--on .sails__t{color:var(--tile-ink)}
.sails__rail{list-style:none;margin:8px 0 2px;padding:0 0 0 6px}
.sails__rail li{position:relative;padding:5px 0 5px 18px;font-size:14px}
.sails__rail li::before{content:"";position:absolute;left:0;top:11px;width:10px;height:10px;
  border-radius:99px;background:var(--sea)}
.sails__rail li::after{content:"";position:absolute;left:4px;top:21px;bottom:-6px;width:2px;
  background:var(--rule)}
.sails__rail li:last-child::after{display:none}
.sails__rail b{font-variant-numeric:tabular-nums;margin-right:8px}
/* The card: which boat, what it costs, where it calls. It slides in from the
   right on a desktop, up from the foot of a phone, and the list keeps its
   room either way - the grid holds a 440px column open under it. */
.sails__side{display:grid;gap:10px;align-content:start}
.sails__head{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:12px;align-items:center}
.sails__ht{font:800 30px/1 var(--sans);letter-spacing:-.03em;font-variant-numeric:tabular-nums}
.sails__head>span{min-width:0}
.sails__head>span b{display:block;font-weight:700;font-size:15px;line-height:1.2}
.sails__head>span small{display:block;font-size:12.5px;color:var(--muted);margin-top:2px;
  font-variant-numeric:tabular-nums}
.sails__x{width:40px;height:40px;border:0;border-radius:999px;background:var(--foam);
  color:var(--ink);font-size:22px;line-height:1;cursor:pointer;flex:none;
  display:grid;place-items:center}
.sails__x:hover{background:var(--rule)}
.sails__x:focus-visible{outline:2px solid var(--sea);outline-offset:2px}
.sails__cross{padding-top:10px;border-top:1px solid var(--rule);display:grid;gap:8px}
.sails__cross .sails__rail{margin:0}
.sails__cross .sails__note{margin-top:4px}
.party__ask{margin:8px 0 0;font-size:12px;line-height:1.4;color:var(--muted)}
/* The forecast at the pier: three lines, a lamp, and whose word it is. */
.sails__wx{padding-top:10px;border-top:1px solid var(--rule);display:grid;gap:8px}
.sails__wxg{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:6px 10px;
  align-items:center;font-size:14px}
.sails__wxg span{color:var(--muted)}
.sails__wxg b{font-variant-numeric:tabular-nums;text-align:right;white-space:nowrap}
.sails__wxg i{width:22px;height:22px;display:grid;place-items:center;font-style:normal;
  color:var(--muted);font-size:13px}
.sails__wxa{width:22px;height:22px;display:grid;place-items:center;
  transition:transform .3s var(--ease)}
.sails__wxa::before{content:"";width:0;height:0;border-left:6px solid transparent;
  border-right:6px solid transparent;border-bottom:15px solid var(--sea)}
.sails__ok{margin:0;display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;
  align-items:start;padding:8px 10px;border-radius:10px;font-size:13.5px;line-height:1.45;
  background:var(--foam)}
.sails__ok b{display:block;font-weight:700}
.sails__lamp{width:12px;height:12px;border-radius:99px;margin-top:5px;background:var(--muted)}
.sails__wx[data-ok=go] .sails__ok{background:oklch(0.94 0.04 152)}
.sails__wx[data-ok=go] .sails__lamp{background:var(--go)}
.sails__wx[data-ok=watch] .sails__ok{background:oklch(0.95 0.05 78)}
.sails__wx[data-ok=watch] .sails__lamp{background:var(--warn)}
.sails__wx[data-ok=no] .sails__ok{background:oklch(0.95 0.04 25)}
.sails__wx[data-ok=no] .sails__lamp{background:oklch(0.55 0.18 25)}
.sails__src{margin:0;font-size:11.5px;color:var(--muted)}
.stage--sails .stage__side{position:fixed;z-index:40;background:var(--bg);overflow:auto;
  overscroll-behavior:contain;padding:16px 18px 20px;box-sizing:border-box;
  transition:transform .32s cubic-bezier(.23,1,.32,1),visibility 0s}
.stage--sails:not([data-sails-dep]) .stage__side{visibility:hidden;
  transition:transform .2s ease-in,visibility 0s .2s}
@media(min-width:940px){
  .stage--sails .stage__g{grid-template-columns:minmax(0,1fr) 440px;align-items:start}
  .stage--sails:not([data-sails-dep]) .stage__g{grid-template-columns:minmax(0,1fr)}
  .stage--sails .stage__side{top:0;right:0;bottom:0;width:min(100%,440px);height:auto;min-height:0;
    border-left:1px solid var(--rule);box-shadow:-24px 0 60px -30px oklch(0 0 0/.35)}
  .stage--sails:not([data-sails-dep]) .stage__side{transform:translateX(104%)}
  .stage--sails .party{flex-direction:column;align-items:stretch;gap:8px}
  .stage--sails .party__buy{white-space:normal}
}
@media(min-width:940px) and (min-height:680px){
  .stage--sails{min-height:0}
  .stage--sails .stage__g{flex:0 0 auto}
  .stage--sails>.wrap{max-width:1440px}
}
@media(max-width:939px){
  /* On a phone the card is a sheet at the foot of the screen, over the list. */
  .stage--sails .stage__side{left:0;right:0;bottom:0;max-height:88svh;
    border-radius:18px 18px 0 0;border-top:1px solid var(--rule);
    box-shadow:0 -10px 30px oklch(0 0 0/.18)}
  .stage--sails .stage__side{transition-duration:.45s;
    transition-timing-function:cubic-bezier(.32,.72,0,1)}
  .stage--sails:not([data-sails-dep]) .stage__side{transform:translateY(104%)}
  .stage--sails[data-sails-dep] .sails{padding-bottom:240px}
}
@media(prefers-reduced-motion:reduce){
  .stage--sails .stage__side{transition:opacity .15s,visibility 0s;transform:none!important}
  .stage--sails:not([data-sails-dep]) .stage__side{opacity:0}
}
/* the column beside the picture */
.stage__side{display:grid;gap:10px;align-content:start;min-width:0}
.scard{background:var(--foam);border:1px solid var(--rule);border-radius:var(--r);
  padding:13px 15px}
.scard__k{font:700 10.5px var(--sans);letter-spacing:.11em;text-transform:uppercase;
  color:var(--muted)}
/* Left on paper on purpose. The card is the site's own two-up lead, whose type
   colours are all ink; on a dark ground every one of them went invisible. */
.scard--next .head__leadlabel{margin:0 0 8px}
.scard--next .leg__time{font-size:clamp(1.6rem,2.6vw,2.1rem)}
.scard--next .head__lead--two{gap:10px}
.scard--next .leg__to{font-size:.92rem}
/* Two full-width rows, a price block and a dashed memo line ran this card to
   290px beside a picture. The same four controls side by side take 140. */
.party__g{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px 10px;
  margin-top:8px}
.party__row{display:grid;gap:3px;min-width:0}
.party__row>span:first-child{font-size:12.5px;color:var(--muted);line-height:1.25}
/* In a 300px column the total, "Change" and the ticket do not fit on one
   line, and none of the three will shrink - so the ticket takes a line of its
   own rather than sitting on top of the word behind it. */
.party{display:flex;align-items:center;justify-content:space-between;gap:10px 12px;
  flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid var(--hair)}
.party .party__buy{flex:0 1 auto}
.party__n{font:800 23px var(--sans);letter-spacing:-.03em;font-variant-numeric:tabular-nums}
.party__l{display:block;font-size:12px;color:var(--muted);margin-top:1px;line-height:1.35;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.party__sum{min-width:0;flex:1 1 0}
.party__top{display:flex;align-items:baseline;gap:10px;min-width:0}
/* Changing the vehicle or the cabin is the rarer half of this card, so it is a
   line of text beside the party it changes rather than a button the size of
   the ticket. The hit area is still a thumb's worth. */
.party__b{position:relative;border:0;background:none;padding:2px 0;flex:none;
  font:600 12.5px var(--sans);color:var(--sea);cursor:pointer;
  text-decoration:underline;text-underline-offset:3px}
.party__b::before{content:"";position:absolute;left:-6px;right:-6px;top:50%;
  transform:translateY(-50%);height:44px}
.party__b:hover{color:var(--ink)}
/* The ticket, where the price is. Whoever has just counted the party and read
   the total is one step from the operator's own checkout, and that step was
   two presses away inside a sheet about whether booking is needed at all. */
.party__buy{display:flex;align-items:center;justify-content:center;gap:8px;
  flex:none;min-height:46px;padding:0 16px;border-radius:12px;
  background:var(--tile-ink);color:var(--bg);text-decoration:none;text-align:center;
  font:600 14.5px var(--sans);white-space:nowrap;transition:background .15s var(--ease)}
.party__buy::after{content:"\2197";font-weight:700;opacity:.75;font-size:13px}
.party__buy:hover{background:var(--sea-deep);color:var(--bg)}
.party__buy:active{transform:translateY(1px)}
/* The memo rides on the card's own label rather than adding a line under it. */
.scard--party .scard__k{display:flex;align-items:baseline;gap:2px 8px;flex-wrap:wrap}
.party__memo{font:600 10.5px var(--sans);letter-spacing:.06em;color:var(--muted);
  text-transform:none}
.party__memo button{border:0;background:none;padding:0;font:inherit;cursor:pointer;
  color:var(--muted);text-decoration:underline;position:relative}
.party__memo button::before{content:"";position:absolute;left:-6px;right:-6px;top:50%;
  height:44px;transform:translateY(-50%)}
.stage__side .notice{margin:0}

/* what is wrong today, above everything
   A headline and one sentence; the terms, the operator's own wording and the
   link to it are behind the press, where they cost the picture no height. */
.alerts{display:flex;gap:8px;margin-top:11px;align-items:stretch;min-width:0}
.alerts .alert{flex:1;min-width:0}
.alert__more{flex:0 0 auto;display:inline-flex;align-items:center;gap:6px;
  padding:0 12px;border:1px solid var(--hair);border-radius:var(--r);
  background:var(--foam);color:var(--sea);cursor:pointer;white-space:nowrap;
  font:600 12.5px var(--sans);transition:background .16s var(--ease)}
.alert__more::after{content:"\2192";font:700 15px var(--sans);opacity:.6}
.alert__more:hover{background:var(--surface)}
.alert__more:hover::after{opacity:1}
.alert{display:grid;gap:1px;text-align:left;min-width:0;padding:8px 34px 9px 13px;
  border:1px solid var(--hair);border-left:3px solid var(--warn,oklch(0.63 0.13 62));
  border-radius:var(--r);background:var(--foam);cursor:pointer;color:var(--ink);
  position:relative;transition:background .16s var(--ease)}
.alert--stop{border-left-color:oklch(0.55 0.19 25)}
.alert:hover{background:var(--surface)}
.alert__k{font:700 10px var(--sans);letter-spacing:.11em;text-transform:uppercase;
  color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.alert__t{font:600 14.5px/1.3 var(--serif);letter-spacing:-.01em;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.alert__s{font:500 12.5px/1.35 var(--sans);color:var(--muted);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.alert::after{content:"\2192";position:absolute;right:12px;top:50%;
  transform:translateY(-50%);color:var(--sea);font:700 15px var(--sans);opacity:.55}
.alert:hover::after{opacity:1}

/* the footnotes, on one line
   The duration, the note about the queue, who published the timetable and the
   way back were four paragraphs under the answers, and they were what pushed
   this page past one screen. Nothing here is the answer to anything; they are
   a footnote, so they read as one. */
/* On a line page every answer is in a sheet, so the main element holds only
   dialogs - an empty block carrying the page's padding, between the stage and
   the footer. */
main.wrap:not(:has(> :not(dialog):not(script))){padding-top:0;padding-bottom:0}
.stage__foot{margin:9px 0 0;display:grid;gap:3px 26px}
@media(min-width:940px){
  .stage__foot{grid-template-columns:minmax(0,1.35fr) minmax(0,1fr);align-items:start}
  .stage__fine{text-align:right}
}
.stage__foot .lede{margin:0;font-size:13px;color:var(--muted);line-height:1.45}
.stage__fine{margin:0;font-size:12px;color:var(--muted);line-height:1.45;opacity:.9}
.stage__foot a{color:var(--sea)}
.stage__back{white-space:nowrap;font-weight:600}

/* the answers, on the same screen as the picture
   Four cards under the photograph meant the page scrolled to reach the
   questions it exists to answer. Each is a question with a one-line answer
   and a sheet behind it, so each is one line. */
.answers{display:grid;gap:8px;margin-top:12px;grid-template-columns:minmax(0,1fr)}
@media(min-width:620px){.answers{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(min-width:940px){.answers{grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}}
.ans__b{display:grid;gap:1px;text-align:left;min-width:0;min-height:56px;
  padding:9px 13px;border:1px solid var(--hair);border-radius:var(--r);
  background:var(--foam);cursor:pointer;color:var(--ink);position:relative;
  transition:background .16s var(--ease),border-color .16s var(--ease)}
.ans__b:hover{background:var(--surface);border-color:var(--rule)}
.ans__b:active{transform:scale(.995)}
.ans__b b{font:600 14px var(--serif);letter-spacing:-.01em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ans__b small{font:500 13px/1.3 var(--sans);color:var(--muted);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
/* The arrow is the affordance and costs no line of its own. */
.ans__b::after{content:"\2192";position:absolute;right:12px;top:50%;
  transform:translateY(-50%);color:var(--sea);font:700 15px var(--sans);
  opacity:.55;transition:opacity .16s var(--ease),transform .16s var(--ease)}
.ans__b:hover::after{opacity:1;transform:translateY(-50%) translateX(2px)}
.ans__b b,.ans__b small{padding-right:20px}

/* the port list and the vessel links, inside their sheet */
.sheet__ans{font:800 34px var(--sans);letter-spacing:-.035em;color:var(--ink);
  margin:0 0 6px}
.sheet__why{font-size:15.5px;margin:0 0 14px}
.sheet__ports{display:grid;gap:6px;margin:0}
.sheet__ports a,.sheet__ports span{display:block;font:800 21px var(--sans);
  letter-spacing:-.028em;color:var(--ink);text-decoration:none;padding:7px 0;
  min-height:44px}
.sheet__ports a small,.sheet__ports span small{display:block;
  font:400 13px var(--sans);color:var(--muted);letter-spacing:0}
.sheet__ports a:hover{color:var(--sea)}
.sheet__cap{font:700 10.5px var(--sans);letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);margin:16px 0 6px;padding-top:12px;
  border-top:1px solid var(--hair)}

/* the two long lists, out of the page and behind a press */
.sheetbig{border:0;padding:0;border-radius:18px;max-width:760px;width:calc(100% - 28px);
  max-height:86vh;background:var(--foam);color:var(--ink);box-shadow:var(--paper)}
.sheetbig::backdrop{background:oklch(0.265 0.018 220/.46)}
.sheetbig__b{padding:20px 20px 6px;overflow:auto;max-height:calc(86vh - 76px);
  overscroll-behavior:contain}
.sheetbig__h{font-family:var(--serif);font-weight:600;font-size:22px;letter-spacing:-.02em;
  margin:4px 0 12px}
.sheetbig__f{padding:12px 20px 16px;border-top:1px solid var(--hair);background:var(--foam)}
.sheetbig__x{width:100%;min-height:48px;border:0;border-radius:12px;background:var(--sea-deep);
  color:var(--foam);font:700 16px var(--sans);cursor:pointer}

/* A card in the corner, not a bar across the foot. The bar covered the buy
   button and the answers on every laptop and read as part of the page - Gal,
   11 Sept 2026: "hiding a significant part of the page without being clear it
   needs to be closed". */
/* A pill in the masthead's empty middle - the one strip of a laptop screen
   with nothing under it. On a phone the masthead is full, so there it is a
   card above the thumb. */
.cc{position:fixed;left:50%;top:7px;transform:translateX(-50%);z-index:50;
  width:max-content;max-width:calc(100vw - 20px);
  background:var(--sea);color:var(--foam);border-radius:999px;
  display:flex;align-items:center;gap:12px;
  padding:5px 6px 5px 16px;font-size:.78rem;line-height:1.3;
  box-shadow:0 8px 24px -10px oklch(0 0 0/.45),0 0 0 1px oklch(1 0 0/.08)}
.cc[hidden]{display:none}
.cc p{margin:0;max-width:none}
/* Between the wordmark and the language codes; two lines where one does not fit. */
@media(min-width:940px){.cc{max-width:min(calc(100vw - 480px),640px)} .cc p{flex:1 1 auto;min-width:0}}
@media(max-width:939px){.cc{top:auto;bottom:10px}}
@media(max-width:640px){.cc{left:10px;right:10px;transform:none;width:auto;max-width:none;
  border-radius:14px;display:grid;gap:10px;padding:12px 14px;font-size:.84rem}
  .cc p{max-width:none}}
.cc a.tap{color:var(--foam);text-decoration:underline}
.cc-btns{display:flex;gap:8px;justify-content:flex-end}
.cc button{font:inherit;font-weight:600;cursor:pointer;
  padding:5px 13px;border-radius:999px;border:1px solid var(--foam);
  background:transparent;color:var(--foam)}
.cc button.cc-yes{background:var(--tile);border-color:var(--tile);color:oklch(0.205 0.030 214)}
.cc button:hover{opacity:.88}
/* The box and the switch that changes its answer, on one line where there is
   room and stacked where there is not. Apart, the switch reads as a stray
   control at the far end of the list; together they are one question. */
/* The count and the car/foot switch sit together, on the list they describe. */
/* Two questions of the same kind, asked on one line. */
.asks{display:flex;flex-wrap:wrap;align-items:center;gap:9px 10px;margin:12px 0 0}
.asks .veh{margin:0}
/* Which day. The browser's own date control - every phone has a good one and
   a hand-built calendar would be a worse version of it. */
/* Two of them on the front page: the day out, and the day back if there is
   one. One row of the card, halved by a hairline - two dates are one question
   and were reading as two more buttons. */
/* The return cell is not removed from the row, it is closed: the column it
   sits in goes to nothing and the row clips it, so the card keeps its height
   and the change reads as one move rather than as a relayout. */
.dates{display:grid;grid-template-columns:1fr 1fr;overflow:hidden;
  transition:grid-template-columns .24s var(--ease)}
[data-way="one"] .dates{grid-template-columns:1fr 0fr}
.dates .when{min-width:0}
.dates .when--back{transition:opacity .16s var(--ease)}
[data-way="one"] .dates .when--back{opacity:0;pointer-events:none}
@media (prefers-reduced-motion:reduce){
  .dates,.dates .when--back{transition:none}}
.dates .when{display:block;min-height:62px;padding:9px 14px;border:0;
  border-radius:0;background:transparent;box-shadow:none;position:relative}
.dates .when+.when{border-left:1px solid var(--seam)}
.dates .when:hover{background:oklch(0.930 0.020 82/.45)}
.dates .when__t{display:block;font:600 .68rem/1 var(--sans);letter-spacing:.09em;
  text-transform:uppercase;color:var(--muted);margin:0 0 5px}
.dates .when__v{display:block;position:relative;min-height:28px}
.dates .when__i{font:600 1.02rem/1.35 var(--sans);width:100%;min-height:28px;
  color:var(--ink);text-align:left}
/* An empty date input draws nothing at all on a phone, so the cell read as a
   dead box. The input keeps the tap; the word says what it is for. */
.when__ph{position:absolute;inset:0;display:flex;align-items:center;
  font:500 1.02rem/1.35 var(--sans);color:var(--muted);pointer-events:none}
.has-cal .dates .when--out .when__ph,
.has-cal .dates .when--set .when__ph{color:var(--ink);font-weight:600}
/* With the calendar in play both cells print a date of our own writing, and
   the input underneath is the value rather than the display. Without it, only
   the optional one hides its input: the travelling date always has a value
   and blanking that left the cell empty. */
.when--back.when--set .when__ph{display:none}
.when--back:not(.when--set) .when__i{opacity:0}
.has-cal .dates .when__i{opacity:0}
/* The bar's own cell prints the date in the page's language, so the
   browser's 06.09.2026. underneath it has to go - it was showing through
   the wording and reading as two dates in one field. */
.js .whenbar .when__i{opacity:0}
.whenbar .when__v{position:relative;display:inline-flex;align-items:center;
  min-height:22px;min-width:7.5em}
.whenbar .when__ph{font:600 .9rem/1.2 var(--sans);color:var(--ink);
  white-space:nowrap}
.has-cal .dates .when--back.when--set .when__ph{display:flex}
.dates .when__x{position:absolute;top:6px;right:6px;min-width:30px;min-height:30px;
  font-size:1.1rem}
/* It used to be transparent until hovered, which on a phone means never: the
   date read as printed text and people did not know they could change it. It
   is a field now, drawn as one, whatever the pointer is doing. */
.when{position:relative;display:inline-flex;align-items:center;gap:8px;
  min-height:48px;cursor:pointer;
  padding:6px 14px;border-radius:999px;border:1px solid var(--rule);
  background:oklch(1 0 0/.55);font:500 .9rem/1.2 var(--sans);color:var(--ink)}
.when:hover{background:oklch(1 0 0/.85);border-color:var(--sea-deep)}
.when__t{color:oklch(0.355 0.026 218);flex:none}
.when__i{border:0;background:transparent;font:600 .9rem/1.2 var(--sans);
  color:var(--ink);min-height:36px;padding:0;flex:1 1 auto;min-width:0;
  cursor:pointer}
.when__i::-webkit-calendar-picker-indicator{cursor:pointer;opacity:.6}
.when:has(:focus-visible){outline:2px solid var(--tile);outline-offset:3px}
/* An optional date needs a way back to not having one. */
.when__x{flex:none;border:0;background:transparent;color:var(--muted);
  cursor:pointer;font-size:1.25rem;line-height:1;min-width:32px;min-height:32px}
.when__x:hover{color:var(--ink)}
/* An empty return date shows nothing at all in some browsers, so the label is
   all there is to tap: give it the room to be tapped. */
@media (max-width:400px){.dates .when{padding:8px 11px}
  .dates .when__t{letter-spacing:.06em}}
/* One calendar for both dates: a sheet on a phone, a card on a desk. Every
   range picker worth borrowing is forty kilobytes and arrives with its own
   typography; this one is the page's. */
/* display on a dialog is the whole ballgame: an author rule beats the browser's
   own dialog:not([open]){display:none}, so a flex dialog is a dialog that is
   always on the page. It shipped open, empty and on top of the form. */
.cal{display:none}
.cal[open]{border:0;padding:0;background:var(--foam);color:var(--ink);
  width:min(430px,100%);max-width:100%;max-height:92svh;
  margin:auto auto 0;border-radius:18px 18px 0 0;
  box-shadow:0 -20px 60px -24px oklch(0.265 0.018 220/.5);
  display:flex;flex-direction:column;overflow:hidden}
@media(min-width:700px){.cal[open]{margin:auto;border-radius:18px;max-height:88svh}}
.cal::backdrop{background:oklch(0.265 0.018 220/.5)}
.cal__hd{display:flex;align-items:center;justify-content:space-between;
  gap:10px;padding:14px 8px 8px 18px}
.cal__h{margin:0;font:500 1.22rem/1.2 var(--serif)}
/* What has been answered, and which half the next tap fills. */
.cal__sum{display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:0 16px 10px}
.cal__c{display:block;padding:8px 12px;border-radius:12px;cursor:pointer;
  border:1px solid var(--rule);background:transparent}
.cal__c b{display:block;font:600 .66rem/1 var(--sans);letter-spacing:.09em;
  text-transform:uppercase;color:var(--muted)}
.cal__c i{display:block;margin-top:4px;font:600 1rem/1.2 var(--sans);
  font-style:normal;min-height:1.2em}
.cal__c i.cal--soft{font-weight:500;color:var(--muted)}
.cal__c.cal--now{border-color:var(--sea-deep);background:oklch(1 0 0/.6);
  box-shadow:inset 0 0 0 1px var(--sea-deep)}
.cal__wk{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;
  padding:6px 12px;border-top:1px solid var(--rule);
  border-bottom:1px solid var(--rule);background:var(--surface);
  font:600 .7rem/1 var(--sans);color:var(--muted);text-align:center;
  text-transform:uppercase}
.cal__scroll{flex:1 1 auto;min-height:180px;overflow-y:auto;
  overscroll-behavior:contain;padding:4px 12px 12px;
  -webkit-overflow-scrolling:touch}
/* On a laptop window turned short there is no room for a serif title and two
   summary boxes above the month; the month is what the sheet is for. */
@media (max-height:620px){
  .cal__hd{padding:9px 8px 4px 16px}
  .cal__h{font-size:1.05rem}
  .cal__sum{padding:0 14px 8px}
  .cal__c{padding:6px 10px}
  .cal__ft{padding:8px 14px}
  .cal__go{min-height:44px}
}
.cal__m{padding-top:12px}
.cal__mt{margin:0 0 6px 2px;font:600 .95rem/1.2 var(--sans);color:var(--ink)}
.cal__g{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}
.cal__d{border:0;background:transparent;color:var(--ink);cursor:pointer;
  height:44px;border-radius:11px;
  font:500 .95rem/1 var(--sans);font-variant-numeric:tabular-nums}
.cal__d:hover:not(:disabled){background:var(--surface)}
.cal__d:disabled{color:oklch(0.470 0.022 218/.4);cursor:default}
/* The range: its two ends filled, the days between them tinted. */
.cal__d.cal--in{background:oklch(0.810 0.096 52/.30);border-radius:0}
.cal__d.cal--a,.cal__d.cal--b{background:var(--sea-deep);color:var(--foam);
  font-weight:700}
/* The plain hover rule carries a pseudo-class more than the chosen-day rule
   does, so it won on specificity: cream type on pale sand, the moment the
   pointer stayed where it had just clicked. The chosen day gets its own. */
.cal__d.cal--a:hover:not(:disabled),
.cal__d.cal--b:hover:not(:disabled){background:oklch(0.375 0.058 218);
  color:var(--foam)}
.cal__d.cal--a{border-radius:11px 0 0 11px}
.cal__d.cal--b{border-radius:0 11px 11px 0}
/* One day chosen and no return yet is not the open end of anything. */
.cal__d.cal--one{border-radius:11px}
.cal__ft{display:flex;align-items:center;gap:10px;padding:10px 16px;
  padding-bottom:calc(10px + env(safe-area-inset-bottom));
  border-top:1px solid var(--rule);background:var(--foam)}
.cal__one{flex:0 0 auto;min-height:46px;padding:0 14px;border:0;
  background:transparent;color:var(--tile-ink);cursor:pointer;
  font:600 .92rem/1 var(--sans);text-decoration:underline;
  text-underline-offset:3px}
.cal__go{flex:1 1 auto;min-height:50px;border:0;border-radius:var(--r);
  background:var(--sea-deep);color:var(--foam);cursor:pointer;
  font:700 1.02rem/1 var(--sans)}
.cal__go:hover{background:var(--ink)}
/* With the calendar in play the native fields are the value, not the control. */
.has-cal .dates .when__i{pointer-events:none}

/* The day control on the heading's own line: which day the timetable is for
   belongs to the timetable, not to a third strip of chrome above it. It wraps
   under the heading on a phone rather than squeezing it. */
.dayhead{display:flex;flex-wrap:wrap;align-items:center;
  justify-content:space-between;gap:6px 18px}
.dayhead h2{margin-bottom:6px}
.dayhead .whenbar{background:none;border:0;flex:1 1 auto}
.dayhead .whenbar .wrap{padding:0;justify-content:flex-start;
  max-width:none;margin:0}
@media(min-width:700px){.dayhead .whenbar .wrap{justify-content:flex-end}}
/* Quiet on today, and still loud on any other day - that announcement is the
   whole reason the control exists. */
.dayhead .whenbar:not(.whenbar--today){background:var(--tile-lite);
  border-radius:10px}
.dayhead .whenbar:not(.whenbar--today) .wrap{padding:6px 10px}

/* Says on every page that these times are for a day that is not today. A
   choice made on the front page must never quietly rewrite the departures. */
.whenbar{background:var(--tile-lite);color:oklch(0.265 0.018 220);
  font:600 .9rem/1.4 var(--sans);border-bottom:1px solid transparent;
  transition:background .18s var(--ease)}
.whenbar .wrap{display:flex;flex-wrap:wrap;align-items:center;
  justify-content:center;gap:4px 10px;padding-top:8px;padding-bottom:8px}
/* On today it is a control, not an announcement. */
.whenbar--today{background:var(--foam);border-bottom-color:var(--rule)}
.whenbar__s{width:40px;height:40px;flex:none;border:1px solid var(--rule);
  border-radius:999px;background:var(--foam);color:var(--sea-deep);cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center}
/* Both buttons carry the same glyph; the one that goes back turns it round.
   Matching on the step value alone catches the crossing page's per-direction
   buttons too, which were shipping two arrows pointing the same way. */
[data-when-step="-1"] svg,[data-way-step="-1"] svg{transform:rotate(180deg)}
.whenbar__s:hover:not(:disabled){background:var(--sea-deep);color:var(--foam);
  border-color:var(--sea-deep)}
.whenbar__s:disabled{opacity:.35;cursor:default}
.whenbar .when{background:var(--foam);border-color:var(--rule)}
.whenbar__n{margin:0;flex:0 1 auto}
.whenbar__b{font:600 .9rem/1 var(--sans);border:0;background:transparent;
  color:oklch(0.34 0.11 38);text-decoration:underline;text-underline-offset:3px;
  cursor:pointer;min-height:44px;padding:0 6px}

/* The crossings most people are here for, one tap from the question. Chips
   rather than a list: they are shortcuts past the question, not an answer to
   it, and the row of them fills the screen the band now owns. */
/* min-width:0 all the way down, or the row of chips refuses to be narrower
   than its widest chip and takes the whole page sideways with it. */
.head__title,.head__lead{min-width:0}
.quick{margin:0 0 22px;min-width:0}
.quick__l{margin:0 0 9px;font:400 .95rem/1.4 var(--sans);
  color:oklch(0.355 0.026 218)}
/* One line that scrolls, not six that stack: wrapped, these crossings were
   taller than the question they are shortcuts past. */
.quick__row{display:flex;gap:8px;min-width:0;overflow-x:auto;scrollbar-width:none;
  padding-bottom:2px;-webkit-overflow-scrolling:touch;
  mask-image:linear-gradient(90deg,#000 calc(100% - 34px),transparent);
  -webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 34px),transparent)}
.quick__row::-webkit-scrollbar{display:none}
.quick a{flex:0 0 auto;white-space:nowrap;
  display:inline-flex;align-items:center;gap:6px;min-height:44px;
  padding:9px 14px;border-radius:999px;background:var(--surface);
  border:1px solid var(--rule);color:var(--ink);text-decoration:none;
  font:600 .88rem/1.2 var(--sans);letter-spacing:-.005em;
  transition:background .15s var(--ease),border-color .15s var(--ease)}
.quick a:hover{background:var(--sea-deep);border-color:var(--sea-deep);color:var(--foam)}
.quick .arrow{color:var(--tile-ink);font-weight:400}
.quick a:hover .arrow{color:var(--tile-lite)}
/* Once the box has a place in it, the strip of coasts is the answer and the
   shortcuts are in its way. */
.quick[hidden]{display:none}

/* Where you were last time, offered once, at the top of the list. */
.recent{margin:0 0 10px}
/* This was filled in --sea-deep on --foam: the exact pairing the site uses for
   "this is the current one" on the language switcher and the section menu. A
   personal shortcut wearing the active-state colours read as a stray control -
   the owner pointed at it and asked what it was. An outline pill, the same one
   the crossing shortcuts wear, says shortcut rather than status. */
.recent a{display:inline-flex;align-items:center;gap:8px;min-height:44px;
  padding:9px 16px;border-radius:999px;background:var(--foam);
  border:1px solid var(--rule);color:var(--ink);
  font:600 .92rem/1 var(--sans);text-decoration:none;
  transition:border-color .15s var(--ease),background .15s var(--ease)}
.recent a:hover{border-color:var(--sea);background:var(--surface)}
.listhead{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:10px 16px;margin:0 0 4px}
.listhead .count-line{margin:0}
.listhead .veh{margin:0}
/* The band's next-departure card names one line, and that line has a page. */
.lead__link{display:block;text-decoration:none;color:inherit;border-radius:12px}
.lead__link:hover .leg__time{text-decoration:underline;text-underline-offset:5px}
.lead__link:focus-visible{outline:2px solid var(--tile);outline-offset:4px}
