/* Martha's Vineyard Live
   Palette borrows from the Eldridge Tide & Pilot Book (buff paper, navy ink,
   vermilion accents) and NOAA raster nautical charts (chart buff, magenta
   aids-to-navigation, land tan). */

:root {
  --paper:      #f2e9d8;   /* Eldridge cover buff */
  --paper-2:    #e8dcc4;
  --paper-3:    #ddcfb2;
  --chart-sea:  #dcefe8;   /* NOAA chart shallow water */
  --ink:        #10293d;   /* deep navy */
  --ink-2:      #24455e;
  --ink-soft:   #5c7386;
  --rule:       #c2b294;
  --accent:     #a8301c;   /* vermilion */
  --accent-2:   #c9552f;
  --magenta:    #b5187f;   /* chart ATON magenta */
  --green:      #1f6b4a;
  --amber:      #b07a12;
  --shadow:     rgba(16, 41, 61, 0.14);

  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  --sans:  "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono:  "SF Mono", "IBM Plex Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0; height: 100%;
  overflow: hidden;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-size: 15px;
  -webkit-font-smoothing: antialiased;
}

/* Subtle laid-paper texture, like the printed book. */
body::before {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 9999;
  opacity: .035;
  background-image:
    repeating-linear-gradient(0deg, transparent 0 3px, var(--ink) 3px 4px),
    repeating-linear-gradient(90deg, transparent 0 3px, var(--ink) 3px 4px);
}

a { color: var(--ink-2); text-decoration-color: var(--rule); text-underline-offset: 2px; }
a:hover { color: var(--accent); }

/* ---------- masthead ---------- */
.masthead {
  display: flex; align-items: baseline; gap: 18px;
  padding: 10px 20px;
  background: var(--ink);
  color: var(--paper);
  border-bottom: 3px double var(--rule);
}
.masthead h1 {
  font-size: 21px; margin: 0; letter-spacing: .06em;
  font-variant: small-caps; font-weight: 600; white-space: nowrap;
}
.masthead .sub {
  font-size: 11px; color: #b8c9d6; letter-spacing: .14em;
  text-transform: uppercase; font-family: var(--sans);
}
.masthead .contact {
  font-family: var(--sans); font-size: 11px; letter-spacing: .06em;
  color: #b8c9d6; text-decoration: none; white-space: nowrap;
  border: 1px solid #3d566b; border-radius: 3px; padding: 4px 9px;
  transition: background .15s, color .15s;
}
.masthead .contact:hover { background: #1b3547; color: var(--paper); }

.masthead .clock {
  margin-left: auto; font-family: var(--mono); font-size: 13px;
  color: var(--paper); text-align: right; line-height: 1.35; white-space: nowrap;
}
.masthead .clock .tz { color: #8fa8ba; font-size: 10.5px; letter-spacing: .1em; }

/* ---------- nav ---------- */
.masthead h1 a { color: inherit; text-decoration: none; }
.nav { display: flex; gap: 2px; font-family: var(--sans); }
.nav a {
  font-size: 11.5px; letter-spacing: .08em; text-transform: uppercase;
  color: #9db4c4; text-decoration: none; padding: 5px 11px; border-radius: 3px;
}
.nav a:hover { color: var(--paper); background: #1b3547; }
.nav a.on { color: var(--ink); background: var(--paper); font-weight: 600; }

/* Menu button + rail toggles: hidden on desktop, shown on narrow screens. */
.railtoggle { display: none; background: transparent; border: 0; color: var(--paper);
  font-size: 19px; line-height: 1; padding: 2px 8px 2px 0; cursor: pointer; }
.railbtn { display: none; position: absolute; bottom: 14px; z-index: 600;
  box-shadow: 0 2px 8px var(--shadow); font-size: 11px; }
.railbtn-l { left: 10px; }
.railbtn-r { right: 10px; }

/* ---------- views ---------- */
.view[hidden] { display: none; }

/* Transparent click-catcher over a grid tile: keeps YouTube's hover chrome
   from appearing and routes the click to our own lightbox instead. */
.shield { position: absolute; inset: 0; z-index: 3; cursor: pointer; background: transparent; }
.cw-cell .shield { top: 28px; }   /* leave the remove button clickable */

/* ---------- cams page ---------- */
.cams-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 16px; background: var(--ink); color: var(--paper);
  font-family: var(--sans); border-bottom: 3px double var(--rule);
}
.cams-title { font-size: 13px; font-weight: 600; letter-spacing: .04em; }
.cams-count { font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; color: #8fa8ba; }
.cams-filters { display: flex; gap: 4px; flex-wrap: wrap; margin-left: auto; }
.cams-filters button {
  font-family: var(--sans); font-size: 11px; padding: 3px 9px; cursor: pointer;
  border: 1px solid #3d566b; background: transparent; color: #b8c9d6; border-radius: 3px;
}
.cams-filters button:hover { background: #1b3547; color: var(--paper); }
.cams-filters button.on { background: var(--paper); color: var(--ink); border-color: var(--paper); font-weight: 600; }
/* Partly-selected town: readable as "some, not all" without a third control. */
.cams-filters button.some { border-color: var(--paper); color: var(--paper); }
.cams-filters button i { font-style: normal; opacity: .55; font-size: 9.5px; margin-left: 3px; }
.cams-bar .btn.ghost { color: var(--paper); border-color: #3d566b; }
.cams-bar .btn.ghost:hover { background: #1b3547; }

/* ---------- cam picker ---------- */
.cams-picker {
  display: grid; gap: 4px 22px; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  padding: 12px 16px; background: #16293a; color: var(--paper);
  border-bottom: 1px solid var(--rule); max-height: 42vh; overflow-y: auto;
}
.pick-town h4 {
  font-family: var(--sans); font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase;
  color: #8fa8ba; margin: 0 0 4px; border-bottom: 1px solid #2c4559; padding-bottom: 3px;
}
.pick-row {
  display: flex; align-items: center; gap: 7px; cursor: pointer;
  font-family: var(--sans); font-size: 12px; padding: 2px 0; color: #dce7ef;
}
.pick-row:hover { color: #fff; }
.pick-row input { accent-color: var(--paper); cursor: pointer; }

/**
 * Cover for a stalled player. YouTube paints its title ("GOMV.COM …"), share
 * and watch-later chrome over any embed that isn't playing, with the pause
 * glyph in the centre — so it cannot be masked at the edges, only covered.
 * Hidden by default and shown ONLY on positive evidence of a stall. Defaulting
 * to covered would mean any failure of the postMessage handshake — an old
 * browser, a blocked frame — buries working video under a black card, which is
 * far worse than the chrome it was meant to hide.
 */
.stall {
  position: absolute; inset: 0; z-index: 2; display: none;
  flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  background: #0b1a26; color: var(--paper); font-family: var(--sans); text-align: center;
  padding: 10px; pointer-events: none;
}
.stall b { font-size: 12px; font-weight: 600; letter-spacing: .03em; }
.stall span { font-size: 10px; letter-spacing: .12em; text-transform: uppercase; color: #7f9bb0; }
/* Wording comes from the state: a first load is connecting, a drop-out is
   reconnecting. Saying "reconnecting" on a fresh page load reads as a fault. */
.stall span::before { content: "Reconnecting…"; }
[data-state="loading"] .stall span::before { content: "Connecting…"; }
.stall::before {
  content: ""; width: 15px; height: 15px; border-radius: 50%; margin-bottom: 3px;
  border: 2px solid #2c4559; border-top-color: var(--paper); animation: spin 1s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
[data-state="stalled"] .stall,
[data-state="loading"] .stall { display: flex; }

/* Remove-from-wall button, revealed on hover so the tiles stay clean. */
.cams-drop {
  position: absolute; top: 5px; right: 5px; z-index: 4; width: 21px; height: 21px;
  border: 0; border-radius: 3px; cursor: pointer; opacity: 0; transition: opacity .12s;
  background: rgba(8,20,30,.78); color: var(--paper); font-size: 11px; line-height: 21px; padding: 0;
}
.cams-cell:hover .cams-drop, .cams-drop:focus { opacity: 1; }
.cams-drop:hover { background: var(--accent); }

.cams-grid {
  display: grid; gap: 8px; padding: 12px 16px 20px;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  background: var(--paper);
  /* Flex child rather than a calc() height: the picker and the alert ribbon
     both change the space above this, and a hard-coded offset gets it wrong. */
  flex: 1; min-height: 0; overflow-y: auto; align-content: start;
}
.cams-cell { position: relative; background: #000; border: 1px solid var(--rule); aspect-ratio: 16/9; overflow: hidden; }
/* The shield takes the pointer, so YouTube never sees a hover and never draws
   its title/share overlay over the tile. */
.cams-cell iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; pointer-events: none; }
.cams-cell .lbl {
  position: absolute; left: 0; bottom: 0; z-index: 2; pointer-events: none;
  background: rgba(8,20,30,.82); color: var(--paper); font-family: var(--sans);
  font-size: 10.5px; letter-spacing: .05em; padding: 3px 8px;
}
.cams-cell .lbl b { font-weight: 400; opacity: .6; }
.cams-empty { grid-column: 1/-1; text-align: center; padding: 50px 20px; color: var(--ink-soft); font-family: var(--sans); }

/* ---------- ask box ---------- */
.ask {
  flex: 1 1 auto; max-width: 460px; margin-left: 20px;
  display: flex; align-items: stretch; gap: 0;
  border: 1px solid #3d566b; border-radius: 3px; background: rgba(255,255,255,.07);
  transition: border-color .15s, background .15s;
}
.ask:focus-within { border-color: var(--paper-3); background: rgba(255,255,255,.12); }
.ask input {
  flex: 1; min-width: 0; background: transparent; border: 0; outline: none;
  color: var(--paper); font-family: var(--sans); font-size: 12.5px; padding: 6px 10px;
}
.ask input::placeholder { color: #7f98aa; }
.ask-go {
  border: 0; background: transparent; color: #9db4c4; cursor: pointer;
  font-size: 15px; padding: 0 11px; line-height: 1;
}
.ask-go:hover { color: var(--paper); }
.ask-go[disabled] { opacity: .4; cursor: default; }

/* ---------- chat panel ---------- */
.chat.as-page {
  position: static; width: auto; border-left: 0; box-shadow: none;
  height: calc(100vh - 47px);
}
.chat.as-page .chat-log { max-width: 780px; margin: 0 auto; width: 100%; padding-top: 18px; }
.chat.as-page .chat-suggest { justify-content: center; }
/* Closing is meaningless on a dedicated page — it's not an overlay there. */
.chat.as-page #chatClose { display: none; }
.chat.as-page .chat-bar { padding-left: 16px; padding-right: 16px; }
.chat {
  position: fixed; right: 0; top: 47px; bottom: 0; width: 420px; z-index: 3000;
  background: var(--paper); border-left: 1px solid var(--ink);
  box-shadow: -6px 0 26px var(--shadow);
  display: flex; flex-direction: column;
}
.chat[hidden] { display: none; }
.chat-bar {
  display: flex; align-items: center; gap: 9px; padding: 8px 12px;
  background: var(--ink); color: var(--paper); font-family: var(--sans);
}
.chat-title { font-size: 12.5px; font-weight: 600; letter-spacing: .04em; }
.chat-sub { font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase; color: #8fa8ba; margin-right: auto; }
.chat-bar .btn.ghost { color: var(--paper); border-color: #3d566b; }
.chat-bar .btn.ghost:hover { background: #1b3547; }

.chat-log { flex: 1; overflow-y: auto; padding: 12px; }
.chat-turn { margin-bottom: 13px; }
.chat-turn .who {
  font-family: var(--sans); font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-soft); margin-bottom: 3px;
}
.chat-turn.you .who { color: var(--accent); }
.chat-turn .msg { font-size: 13.5px; line-height: 1.55; }
.chat-turn.you .msg {
  background: var(--paper-2); border-left: 2px solid var(--accent);
  padding: 6px 9px; font-family: var(--sans); font-size: 13px;
}
.chat-turn .msg p { margin: 0 0 7px; }
.chat-turn .msg p:last-child { margin-bottom: 0; }
.chat-turn .msg ul { margin: 0 0 7px; padding-left: 18px; }
.chat-turn .msg li { margin-bottom: 3px; }
.chat-turn .msg strong { font-weight: 700; }
.chat-turn .msg code {
  font-family: var(--mono); font-size: 12px; background: var(--paper-2); padding: 0 3px;
}
.chat-turn .meta { font-family: var(--mono); font-size: 9.5px; color: var(--ink-soft); margin-top: 4px; }
.chat-turn .meta .free { color: var(--green); font-weight: 600; }
.chat-turn.intro .msg { color: var(--ink); }
.chat-turn.err .msg { color: var(--accent); font-family: var(--sans); font-size: 12.5px; }

.chat-cursor::after {
  content: '▌'; color: var(--accent); animation: blink 1s steps(2) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

/* The masthead search is fine as an entry point, but a panel this size needs
   its own composer — especially as a full page, where the masthead box reads
   as site search rather than the chat input. */
.chat-compose {
  display: flex; gap: 6px; padding: 9px 12px 0; background: var(--paper);
}
.chat.as-page .chat-compose { max-width: 780px; margin: 0 auto; width: 100%; }
.chat-compose input {
  flex: 1; min-width: 0; font-family: var(--sans); font-size: 13px;
  padding: 8px 10px; border: 1px solid var(--rule); background: #fff; color: var(--ink);
  border-radius: 3px; outline: none;
}
.chat-compose input:focus { border-color: var(--ink); }
.chat-compose .btn { padding: 8px 14px; }

.chat-suggest { padding: 9px 12px; border-top: 1px solid var(--rule); background: var(--paper-2); display: flex; flex-wrap: wrap; gap: 5px; }
.chat-suggest button {
  font-family: var(--sans); font-size: 11px; padding: 4px 8px; cursor: pointer;
  border: 1px solid var(--rule); background: var(--paper); color: var(--ink-2); border-radius: 2px;
}
.chat-suggest button:hover { background: var(--ink); color: var(--paper); border-color: var(--ink); }

.chat-setup { font-family: var(--sans); font-size: 12.5px; line-height: 1.5; }
/* Beats `.chat-turn .msg code`, which would otherwise wash this out. */
.chat-turn .msg .chat-setup code {
  display: block; font-family: var(--mono); font-size: 11px;
  background: var(--ink); color: var(--paper);
  padding: 7px 9px; margin: 7px 0; overflow-x: auto;
}



/* ---------- alert ribbon ---------- */
#alertBar { display: none; background: var(--accent); color: #fff; font-family: var(--sans); }
#alertBar.on { display: block; }
#alertBar .wrap { display: flex; gap: 10px; align-items: center; padding: 7px 20px; flex-wrap: wrap; }
#alertBar .tag {
  background: rgba(0,0,0,.25); padding: 2px 8px; border-radius: 2px;
  font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; font-weight: 700;
}
#alertBar .msg { font-size: 13px; }
#alertBar .msg strong { font-weight: 700; }

/* ---------- layout ---------- */
body { display: flex; flex-direction: column; }
.view { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.view[hidden] { display: none; }
.shell {
  display: grid;
  grid-template-columns: 330px minmax(0, 1fr) 340px;
  flex: 1; min-height: 0;
}

.rail, .news {
  overflow-y: auto; background: var(--paper);
  scrollbar-width: thin; scrollbar-color: var(--rule) transparent;
}
.rail { border-right: 1px solid var(--rule); }
.news { border-left: 1px solid var(--rule); }
.rail::-webkit-scrollbar, .news::-webkit-scrollbar { width: 8px; }
.rail::-webkit-scrollbar-thumb, .news::-webkit-scrollbar-thumb { background: var(--rule); }

/* ---------- panels ---------- */
.panel { border-bottom: 1px solid var(--rule); }
.panel > h2 {
  margin: 0; padding: 7px 14px;
  font-size: 11px; letter-spacing: .16em; text-transform: uppercase;
  font-family: var(--sans); font-weight: 700; color: var(--ink);
  background: var(--paper-2);
  border-bottom: 1px solid var(--rule);
  display: flex; align-items: center; gap: 8px;
}
.panel > h2 .badge {
  margin-left: auto; font-size: 9.5px; letter-spacing: .08em; padding: 1px 6px;
  border-radius: 2px; background: var(--ink); color: var(--paper); font-weight: 600;
}
.panel > h2 .badge.warn { background: var(--accent); }
.panel > h2 .badge.good { background: var(--green); }
.panel .body { padding: 11px 14px 13px; }

/* ---------- data rows ---------- */
.row { display: flex; justify-content: space-between; gap: 10px; padding: 3px 0; align-items: baseline; }
.row + .row { border-top: 1px dotted var(--paper-3); }
.row .k { color: var(--ink-soft); font-size: 12.5px; font-family: var(--sans); }
.row .v { font-family: var(--mono); font-size: 13px; font-weight: 600; text-align: right; }
.row .v.big { font-size: 17px; }

.stat-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px; background: var(--rule); border: 1px solid var(--rule); }
.stat { background: var(--paper); padding: 7px 9px; }
.stat .lbl { font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-soft); font-family: var(--sans); }
.stat .val { font-family: var(--mono); font-size: 18px; font-weight: 700; line-height: 1.25; }
.stat .val small { font-size: 11px; font-weight: 500; color: var(--ink-soft); }

.pill {
  display: inline-block; padding: 1px 7px; border-radius: 9px; font-size: 10.5px;
  font-family: var(--sans); font-weight: 600; letter-spacing: .04em;
  border: 1px solid currentColor;
}
.pill.vfr   { color: var(--green); }
.pill.mvfr  { color: #1863a8; }
.pill.ifr   { color: var(--accent); }
.pill.lifr  { color: var(--magenta); }
.pill.open  { color: var(--green); }
.pill.shut  { color: var(--accent); }

.note {
  font-size: 11.5px; color: var(--ink-soft); font-family: var(--sans);
  line-height: 1.45; margin-top: 8px; padding-left: 9px;
  border-left: 2px solid var(--paper-3);
}
.err { color: var(--accent); font-size: 11.5px; font-family: var(--sans); }
.muted { color: var(--ink-soft); }

button.btn {
  font-family: var(--sans); font-size: 11.5px; font-weight: 600;
  background: var(--ink); color: var(--paper); border: 0; border-radius: 2px;
  padding: 6px 11px; cursor: pointer; letter-spacing: .04em;
}
button.btn:hover { background: var(--ink-2); }
button.btn.ghost { background: transparent; color: var(--ink); border: 1px solid var(--rule); }
button.btn.ghost:hover { background: var(--paper-2); }
button.btn[disabled] { opacity: .45; cursor: default; }

/* ---------- tide chart ---------- */
.tide-wrap { position: relative; }
#tideChart { width: 100%; height: 108px; display: block; }
.tide-events { display: flex; gap: 6px; margin-top: 7px; flex-wrap: wrap; }
.tide-ev {
  flex: 1 1 0; min-width: 62px; border: 1px solid var(--rule); background: var(--paper-2);
  padding: 4px 6px; text-align: center;
}
.tide-ev .t { font-size: 9.5px; letter-spacing: .08em; text-transform: uppercase; font-family: var(--sans); color: var(--ink-soft); }
.tide-ev .h { font-family: var(--mono); font-size: 13px; font-weight: 700; }
.tide-ev.high .t { color: var(--accent); }
.tide-ev.now { outline: 2px solid var(--ink); }

select.station {
  font-family: var(--sans); font-size: 11px; border: 1px solid var(--rule);
  background: var(--paper); color: var(--ink); padding: 2px 4px; margin-left: auto;
}

/* ---------- map ---------- */
.mapwrap { position: relative; }
#map { position: absolute; inset: 0; background: var(--chart-sea); }

.maptools {
  position: absolute; top: 10px; right: 10px; z-index: 600;
  display: flex; flex-direction: column; gap: 5px; align-items: flex-end;
}
.layertoggle { box-shadow: 0 2px 8px var(--shadow); }
.layerbox {
  background: var(--paper); border: 1px solid var(--ink); box-shadow: 0 2px 8px var(--shadow);
  padding: 8px 10px; font-family: var(--sans); font-size: 11.5px; min-width: 156px;
}
.layerbox[hidden] { display: none; }
.layerbox h4 {
  margin: 0 0 5px; font-size: 9.5px; letter-spacing: .13em; text-transform: uppercase;
  color: var(--ink-soft); font-weight: 700;
}
.layerbox label { display: flex; align-items: center; gap: 6px; padding: 2px 0; cursor: pointer; }
.layerbox input { accent-color: var(--ink); }
.layerbox .sep { border-top: 1px solid var(--rule); margin: 6px 0 5px; }

/* chart-style markers */
.mk { display: grid; place-items: center; border-radius: 50%; font-family: var(--sans); font-weight: 700; color: #fff; box-shadow: 0 1px 4px var(--shadow); }
.mk-cam   { background: var(--magenta); width: 22px; height: 22px; font-size: 11px; border: 2px solid #fff; }
.mk-buoy  { background: var(--amber);   width: 20px; height: 20px; font-size: 10px; border: 2px solid #fff; }
.mk-surf  { background: var(--green);   width: 20px; height: 20px; font-size: 10px; border: 2px solid #fff; }
.mk-tide  { background: var(--ink-2);   width: 18px; height: 18px; font-size: 9px;  border: 2px solid #fff; }
.mk-plane { background: transparent; width: 0; height: 0; box-shadow: none; position: relative; }
.mk-plane svg, .mk-ship svg { display: block; filter: drop-shadow(0 1px 2px var(--shadow)); }
/* Callsign / vessel-name tags riding beside their marker. */
.mk-plane .tag, .mk-ship .tag {
  position: absolute; left: 50%; top: 100%; transform: translateX(-50%);
  white-space: nowrap; font-family: var(--mono); font-size: 9px; font-weight: 600;
  color: var(--ink); background: rgba(242,233,216,.82); padding: 0 3px; border-radius: 2px;
  pointer-events: none; letter-spacing: -.02em;
}

.leaflet-popup-content-wrapper {
  background: var(--paper); color: var(--ink); border-radius: 2px;
  border: 1px solid var(--ink); box-shadow: 0 4px 16px var(--shadow);
}
.leaflet-popup-tip { background: var(--paper); border: 1px solid var(--ink); }
.leaflet-popup-content { margin: 0; font-family: var(--serif); }
.pop { width: 330px; }
/* Long names used to wrap under the town label and shove it out of line.
   Keep the title on one line with an ellipsis and pin the town to the right. */
.pop h3 {
  margin: 0; padding: 7px 11px; font-size: 13px; background: var(--ink); color: var(--paper);
  letter-spacing: .03em; display: flex; align-items: baseline; gap: 10px;
  font-weight: 600; font-family: var(--sans);
}
.pop h3 .nm { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pop h3 .where {
  flex: 0 0 auto; font-size: 9.5px; color: #9db4c4; font-family: var(--sans);
  letter-spacing: .1em; text-transform: uppercase;
}
.pop .inner { padding: 9px 11px 11px; }
.pop .frame { position: relative; width: 100%; aspect-ratio: 16/9; background: #000; margin-bottom: 8px; }
.pop .frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.pop .acts { display: flex; gap: 6px; margin-top: 8px; }

/* ---------- cam lightbox ---------- */
.lightbox { position: fixed; inset: 0; z-index: 4000; background: rgba(8, 20, 30, .93); display: flex; flex-direction: column; }
.camwall  { position: fixed; inset: 0; z-index: 4000; background: #081420; display: flex; flex-direction: column; }
.lightbox[hidden], .camwall[hidden] { display: none; }

.lb-inner { margin: auto; width: min(1400px, 94vw); }
.lb-bar, .cw-bar {
  display: flex; align-items: center; gap: 12px; padding: 9px 4px;
  color: var(--paper); font-family: var(--sans);
}
.lb-title, .cw-title { font-size: 16px; font-weight: 600; letter-spacing: .02em; }
.lb-town, .cw-count {
  font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: #8fa8ba;
}
.lb-acts, .cw-acts { margin-left: auto; display: flex; gap: 6px; }
.lightbox .btn.ghost, .camwall .btn.ghost { color: var(--paper); border-color: #3d566b; }
.lightbox .btn.ghost:hover, .camwall .btn.ghost:hover { background: #1b3547; }

.lb-stage { position: relative; width: 100%; aspect-ratio: 16/9; background: #000; border: 1px solid #2b4459; }
.lb-stage iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.lb-stage .none { color: #8fa8ba; font-family: var(--sans); font-size: 13px; display: grid; place-items: center; height: 100%; text-align: center; padding: 20px; }

/* ---------- cam wall ---------- */
.cw-bar { padding: 10px 16px; border-bottom: 1px solid #2b4459; }
/* Column count is set from JS to suit the number of cams, so four cams tile
   2×2 at full size rather than squeezing into one thin row. */
.cw-grid {
  flex: 1; min-height: 0; display: grid; gap: 6px; padding: 10px 16px 16px; overflow: hidden;
  grid-template-columns: repeat(var(--cols, 2), 1fr);
  grid-template-rows: repeat(var(--rows, 2), 1fr);
}
/* Cells share the available height rather than forcing 16:9, so the whole wall
   always fits the viewport with no scrolling. */
.cw-cell { position: relative; background: #000; border: 1px solid #2b4459; min-height: 0; }
.cw-cell iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; pointer-events: none; }
.cw-cell .lbl {
  position: absolute; left: 0; bottom: 0; z-index: 2;
  background: rgba(8,20,30,.82); color: var(--paper); font-family: var(--sans);
  font-size: 10.5px; letter-spacing: .06em; padding: 3px 8px; pointer-events: none;
}
.cw-cell .drop {
  position: absolute; right: 4px; top: 4px; z-index: 3; cursor: pointer;
  background: rgba(8,20,30,.8); color: var(--paper); border: 0; border-radius: 2px;
  font-size: 12px; width: 22px; height: 22px; line-height: 1;
}
.cw-cell .drop:hover { background: var(--accent); }
.cw-empty { color: #8fa8ba; font-family: var(--sans); font-size: 13px; padding: 40px; text-align: center; grid-column: 1/-1; }

.cw-picker {
  position: absolute; right: 16px; top: 54px; z-index: 10; width: 300px; max-height: 70vh; overflow-y: auto;
  background: var(--paper); border: 1px solid var(--ink); box-shadow: 0 6px 24px rgba(0,0,0,.4); padding: 9px 11px;
}
.cw-picker[hidden] { display: none; }
.cw-picker label {
  display: flex; align-items: center; gap: 7px; padding: 3px 0; cursor: pointer;
  font-family: var(--sans); font-size: 12px;
}
.cw-picker .tw { margin-left: auto; font-size: 9.5px; color: var(--ink-soft); text-transform: uppercase; letter-spacing: .08em; }

.camwall-btn {
  position: absolute; left: 10px; bottom: 14px; z-index: 600;
  box-shadow: 0 2px 8px var(--shadow);
}

/* ---------- forecast ---------- */
button.btn.tiny { padding: 2px 7px; font-size: 10px; }
.fc-days { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--rule); border: 1px solid var(--rule); }
.fc-day { background: var(--paper); padding: 6px 7px; text-align: center; }
.fc-day .d { font-size: 9.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-soft); font-family: var(--sans); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fc-day .t { font-family: var(--mono); font-size: 17px; font-weight: 700; }
.fc-day .s { font-size: 10px; color: var(--ink-soft); font-family: var(--sans); line-height: 1.25; min-height: 24px; }
.fc-day .p { font-size: 10px; color: #1863a8; font-family: var(--mono); }
.fc-detail { font-size: 12.5px; line-height: 1.5; margin-top: 9px; }
.fc-detail strong { font-family: var(--sans); font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--accent); display: block; }
.fc-hours { display: flex; gap: 0; overflow-x: auto; border: 1px solid var(--rule); }
.fc-hr { flex: 0 0 52px; text-align: center; padding: 5px 2px; border-right: 1px solid var(--paper-3); background: var(--paper); }
.fc-hr:last-child { border-right: 0; }
.fc-hr .h { font-size: 9.5px; color: var(--ink-soft); font-family: var(--sans); }
.fc-hr .t { font-family: var(--mono); font-size: 13px; font-weight: 700; }
.fc-hr .w { font-size: 9px; color: var(--ink-soft); font-family: var(--mono); }
.fc-hr .p { font-size: 9px; color: #1863a8; font-family: var(--mono); }

/* ---------- lighthouse & ship markers ---------- */
.mk-light { background: #f0c020; width: 16px; height: 16px; font-size: 9px; border: 2px solid var(--ink); color: var(--ink); }
.mk-ship  { background: transparent; box-shadow: none; }
#lightCanvas { position: absolute; inset: 0; pointer-events: none; z-index: 450; }
/* When the lights are lit, drop the chart to dusk so the beams actually read. */
.mapwrap.night .leaflet-tile-pane { filter: brightness(.40) saturate(.35) contrast(1.1); }
.mapwrap .leaflet-tile-pane { transition: filter .6s ease; }
/* Cool the dimmed chart toward navy instead of letting the tan land read sepia. */
.mapwrap.night::after {
  content: ""; position: absolute; inset: 0; z-index: 449; pointer-events: none;
  background: linear-gradient(180deg, rgba(10,26,44,.55), rgba(8,20,36,.65));
  mix-blend-mode: multiply;
}

.lh-row { display: flex; align-items: baseline; gap: 8px; padding: 4px 0; font-size: 12px; font-family: var(--sans); cursor: pointer; }
.lh-row + .lh-row { border-top: 1px dotted var(--paper-3); }
.lh-row:hover { background: var(--paper-2); }
.lh-row .sw { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; border: 1px solid var(--ink); }
.lh-row .nm { flex: 1; }
.lh-row .ch { font-family: var(--mono); font-size: 11px; color: var(--ink-soft); }

/* ---------- composite indices ---------- */
.ix + .ix { margin-top: 9px; border-top: 1px dotted var(--paper-3); padding-top: 8px; }
.ix-head { display: flex; align-items: baseline; gap: 7px; font-family: var(--sans); }
.ix-name { font-size: 12px; font-weight: 600; flex: 1; }
.ix-lvl { font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.ix-score { font-family: var(--mono); font-size: 14px; font-weight: 700; min-width: 26px; text-align: right; }
.ix-bar { height: 5px; background: var(--paper-3); margin: 4px 0 5px; border: 1px solid var(--rule); }
.ix-bar i { display: block; height: 100%; }
.ix-why { display: flex; flex-wrap: wrap; gap: 3px 9px; font-family: var(--sans); font-size: 10.5px; color: var(--ink-soft); }
.ix-why b { font-family: var(--mono); color: var(--ink); }
.ix-why em { font-style: normal; opacity: .75; }

/* ---------- station mesh pins ---------- */
.mesh-pin {
  background: rgba(242,233,216,.94); border: 2px solid var(--ink); border-radius: 3px;
  width: 34px; height: 26px; display: grid; place-items: center; line-height: 1;
  font-family: var(--mono); box-shadow: 0 1px 4px var(--shadow);
}
.mesh-pin b { font-size: 12px; font-weight: 700; color: var(--ink); }
.mesh-pin span { font-size: 8px; color: var(--ink-soft); letter-spacing: -.02em; }

/* ---------- news ---------- */
.news-item { padding: 9px 14px; border-bottom: 1px solid var(--paper-3); }
.news-item:hover { background: var(--paper-2); }
.news-item .meta {
  display: flex; gap: 7px; align-items: center; font-family: var(--sans);
  font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-soft);
  margin-bottom: 3px;
}
.news-item .outlet { color: var(--accent); font-weight: 700; }
.news-item h3 { margin: 0 0 3px; font-size: 14px; line-height: 1.32; font-weight: 600; }
.news-item h3 a { text-decoration: none; }
.news-item p { margin: 0; font-size: 12.5px; line-height: 1.45; color: var(--ink-soft); }

.filters { display: flex; gap: 4px; padding: 7px 14px; background: var(--paper-2); border-bottom: 1px solid var(--rule); }
.filters button {
  font-family: var(--sans); font-size: 10.5px; letter-spacing: .05em; padding: 3px 8px;
  border: 1px solid var(--rule); background: var(--paper); color: var(--ink-soft);
  cursor: pointer; border-radius: 2px;
}
.filters button.on { background: var(--ink); color: var(--paper); border-color: var(--ink); }

/* ---------- ferry / trips ---------- */
.trip { display: flex; gap: 8px; font-size: 12px; padding: 3px 0; align-items: baseline; font-family: var(--sans); }
.trip + .trip { border-top: 1px dotted var(--paper-3); }
.trip .leg { flex: 1; }
.trip .st { font-size: 10px; font-weight: 700; letter-spacing: .04em; white-space: nowrap; }
.trip.cx .leg { text-decoration: line-through; color: var(--ink-soft); }
.trip.cx .st { color: var(--accent); }
.trip.ok .st { color: var(--green); }

.scroller { max-height: 220px; overflow-y: auto; }

/* ---------- flights / list ---------- */
.flight { display: grid; grid-template-columns: 1fr auto; gap: 2px 8px; padding: 4px 0; font-family: var(--sans); font-size: 12px; }
.flight + .flight { border-top: 1px dotted var(--paper-3); }
.flight .id { font-family: var(--mono); font-weight: 700; font-size: 12.5px; }
.flight .sub { grid-column: 1 / -1; font-size: 10.5px; color: var(--ink-soft); }
.flight .ph { font-size: 10px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; }
.flight .ph.arr { color: var(--green); }
.flight .ph.dep { color: var(--accent); }

.cam-list { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; }
.cam-chip {
  font-family: var(--sans); font-size: 11px; text-align: left; padding: 5px 7px;
  border: 1px solid var(--rule); background: var(--paper-2); cursor: pointer; line-height: 1.25;
}
.cam-chip:hover { background: var(--ink); color: var(--paper); }
.cam-chip .tw { display: block; font-size: 9px; letter-spacing: .08em; text-transform: uppercase; opacity: .65; }

.loading { padding: 16px 14px; color: var(--ink-soft); font-size: 12px; font-family: var(--sans); }




/* ═══════════════ RESPONSIVE ═══════════════
   Desktop keeps three columns. Below 1240px the news rail becomes a slide-over.
   Below 860px both rails do, the map takes the full screen, and the masthead
   collapses to a menu button — so the map is never squeezed into a sliver. */

@media (max-width: 1240px) {
  .shell { grid-template-columns: 300px minmax(0, 1fr); }
  .news {
    position: fixed; right: 0; top: 47px; bottom: 0; width: min(360px, 88vw);
    z-index: 1200; box-shadow: -6px 0 22px var(--shadow);
    transform: translateX(100%); transition: transform .22s ease;
  }
  .news.open { transform: translateX(0); }
  .railbtn-r { display: block; }
}

@media (max-width: 860px) {
  .masthead { gap: 10px; padding: 8px 12px; flex-wrap: nowrap; }
  .masthead h1 { font-size: 15px; letter-spacing: .03em; }
  .masthead .clock, .masthead .contact { display: none; }
  .railtoggle { display: block; }

  /* Nav collapses behind the menu button. */
  .nav {
    position: fixed; top: 47px; left: 0; right: 0; z-index: 1400;
    flex-direction: column; gap: 0; background: var(--ink);
    border-bottom: 3px double var(--rule); display: none;
  }
  .nav.open { display: flex; }
  .nav a { padding: 12px 16px; font-size: 13px; border-bottom: 1px solid #1b3547; }

  .ask { max-width: none; margin-left: 0; }
  .ask input { font-size: 16px; }   /* 16px stops iOS zooming on focus */

  /* Map fills the screen; both rails slide over it. */
  .shell { grid-template-columns: 1fr; }
  .rail {
    position: fixed; left: 0; top: 47px; bottom: 0; width: min(330px, 88vw);
    z-index: 1200; border-right: 1px solid var(--ink);
    box-shadow: 6px 0 22px var(--shadow);
    transform: translateX(-100%); transition: transform .22s ease;
  }
  .rail.open { transform: translateX(0); }
  .railbtn { display: block; }

  /* Scrim behind an open rail. */
  .scrim { position: fixed; inset: 47px 0 0; background: rgba(8,20,30,.45); z-index: 1100; }
  .scrim[hidden] { display: none; }

  /* Keep the ribbon to one scrollable line so it can't eat the map. */
  #alertBar .wrap {
    padding: 6px 12px; gap: 6px; flex-wrap: nowrap;
    overflow-x: auto; -webkit-overflow-scrolling: touch;
  }
  #alertBar .wrap::-webkit-scrollbar { display: none; }
  #alertBar .msg { font-size: 12px; white-space: nowrap; }
  #alertBar .tag { flex: 0 0 auto; }

  .chat { width: 100%; top: 47px; }
  .chat.as-page { height: calc(100dvh - 47px); }
  .cams-grid { grid-template-columns: 1fr; padding: 10px; height: auto; }
  .cams-bar { padding: 8px 10px; }
  .cams-filters { margin-left: 0; width: 100%; }
  .cw-grid { grid-template-columns: 1fr !important; grid-template-rows: none !important; overflow-y: auto; }
  .cw-cell { aspect-ratio: 16/9; }
  .lb-inner { width: 96vw; }
  /* Leaflet's attribution wraps to two lines on a phone and swallows the
     buttons, so compress it and stack the controls above it. */
  .leaflet-control-attribution {
    font-size: 8.5px; max-width: 62vw; white-space: nowrap;
    overflow: hidden; text-overflow: ellipsis;
  }
  .railbtn { bottom: 30px; }
  .camwall-btn { bottom: 72px; }
}

/* Very small screens: drop the search box into its own row. */
@media (max-width: 560px) {
  .masthead { flex-wrap: wrap; }
  .masthead h1 { font-size: 14px; }
  .ask { order: 3; width: 100%; flex-basis: 100%; margin-top: 6px; }
  .railbtn { font-size: 10.5px; padding: 5px 8px; }
}
