:root{ --tar:#0d1218; --bone:#ece4d2; --rope:#c9a86a; --blood:#a83b2a; --brine:#3f8f9a; }
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%;overflow:hidden;background:var(--tar);font-family:Georgia,"Iowan Old Style","Palatino Linotype",serif;color:var(--bone)}
canvas{display:block}
/* The WebGL canvas is pinned to the same box the fixed HUD uses, so the two
   can never disagree about where the bottom of the screen is — that gap is
   what showed as a black band under the sea on mobile. */
#gl{position:fixed;top:0;left:0}
button{font:inherit;cursor:pointer}
button:focus-visible{outline:2px solid var(--bone);outline-offset:3px}
[hidden]{display:none !important}
/* ==========================================================================
   Broadside — the pirate UI system (W2-ui).

   One visual language for the hub, the HUD and every menu, built from four
   materials, each with one job:
     tarred wood  — dark plates that sit over the sea (HUD readouts, lists).
                    Readable over sunlit water is the whole brief: the brief's
                    "bone on nothing is invisible" lesson is why these exist.
     parchment    — cards you read and fill in (settings, the end card, the log).
     brass        — anything that is an instrument or a control's rim.
     sealing wax  — the one thing you commit with. There is one primary button
                    on any screen, and it is the only red thing on it.
   Ink is the text colour on parchment; bone is the text colour on wood.

   Readable first: the display face (Pirata One) is for big titles only; labels
   and buttons use an engraved small-caps face (IM Fell English SC); body text
   and every number use Alegreya Sans with tabular figures, which stays crisp
   at 11px on a 1x screen.
   ========================================================================== */
:root{
  /* ---- palette ---- */
  --tar:#0d1218; --tar-2:#151b22; --tar-3:#1e252d;
  --wood:#1b1510; --wood-2:#261d15; --wood-edge:#3a2c1d;
  --bone:#ece4d2; --bone-dim:rgba(236,228,210,.66); --bone-faint:rgba(236,228,210,.38);
  --parch:#efe2c2; --parch-hi:#f8efd8; --parch-lo:#dcc699; --parch-edge:#b89660;
  --ink:#2a1f14; --ink-2:#4b3a26; --ink-soft:rgba(42,31,20,.66); --ink-faint:rgba(42,31,20,.38);
  --brass:#c9a24e; --brass-hi:#f0d78f; --brass-lo:#86622a; --brass-deep:#5b4219;
  --rope:#c9a86a;      /* the old accent — kept, it is the "brass" of text */
  --wax:#9b1e18; --wax-hi:#cf3b2d; --wax-lo:#5e0e0b;
  --blood:#cf4a33; --brine:#57aeb8; --port:#d04a33; --stbd:#43a865; --gold:#f2c867;

  /* ---- type ---- */
  --f-display:"Pirata One","IM Fell English SC",Georgia,serif;
  --f-head:"IM Fell English SC",Georgia,"Iowan Old Style",serif;
  --f-body:"Alegreya Sans","Segoe UI",system-ui,-apple-system,sans-serif;
  --t-xs:11px; --t-s:13px; --t-m:15px; --t-l:18px; --t-xl:24px; --t-2xl:34px; --t-3xl:52px;

  /* ---- space, shape, depth ---- */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px;
  --r-s:3px; --r-m:6px; --r-l:10px; --r-pill:999px;
  --sh-plate:0 6px 18px rgba(0,0,0,.45);
  --sh-card:0 18px 50px rgba(0,0,0,.6);
  --tap:40px;

  /* ---- materials ---- */
  --m-wood:linear-gradient(180deg,rgba(38,29,21,.9),rgba(22,17,12,.92)),url("/ui/planks.webp") 0 0/256px;
  --m-wood-solid:linear-gradient(180deg,#261d15,#15100b),url("/ui/planks.webp") 0 0/256px;
  --m-parch:radial-gradient(ellipse at 50% 40%,rgba(255,250,235,.55),rgba(255,250,235,0) 70%),
            radial-gradient(ellipse at 50% 50%,rgba(0,0,0,0) 55%,rgba(120,84,36,.28) 100%),
            url("/ui/parchment.webp") 0 0/384px,var(--parch);
  --m-brass:linear-gradient(180deg,#f2d88f 0%,#d2ac58 38%,#a57b33 70%,#7c5a24 100%);
  --m-brass-ring:conic-gradient(from 200deg,#f6e2a2,#b58a3c 25%,#6f4f1d 45%,#c79c4a 65%,#f6e2a2 80%,#9b7532 92%,#f6e2a2);
  --m-wax:radial-gradient(ellipse at 38% 28%,#d8493a 0%,#a8231b 45%,#7a1310 80%,#5e0e0b 100%);
}
@media (pointer:coarse){ :root{ --tap:44px } }

/* ---- base type ---- */
body{font-family:var(--f-body);font-size:var(--t-m);line-height:1.35;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
button,input,select{font:inherit;color:inherit}
.eyebrow{font-family:var(--f-head);font-size:var(--t-s);letter-spacing:.08em;font-weight:normal;text-transform:none;color:var(--brass)}
kbd{display:inline-block;min-width:1.7em;padding:0 .4em;border-radius:var(--r-s);font:inherit;font-size:.86em;line-height:1.5;text-align:center;
  background:rgba(236,228,210,.1);border:1px solid rgba(201,162,78,.55);border-bottom-width:2px;color:var(--brass-hi)}
.ico{width:1.25em;height:1.25em;flex:none;display:inline-block;vertical-align:-.22em}

/* ==========================================================================
   Buttons. Base, then three weights: primary (the wax seal — one per screen),
   secondary (brass), quiet (an outline). `.icon` makes any of them a square.
   ========================================================================== */
.btn{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);
  min-height:var(--tap);padding:0 var(--s4);border-radius:var(--r-m);border:1px solid transparent;
  font-family:var(--f-head);font-size:var(--t-m);letter-spacing:.04em;line-height:1;white-space:nowrap;
  cursor:pointer;user-select:none;-webkit-user-select:none;-webkit-tap-highlight-color:transparent;
  transition:transform .08s ease-out,filter .12s,background-color .12s,border-color .12s,box-shadow .12s,color .12s}
.btn:active{transform:translateY(1px)}
.btn:disabled{opacity:.45;cursor:default;transform:none}
.btn small{font-family:var(--f-body);font-size:var(--t-xs);letter-spacing:0;opacity:.72}
.btn:focus-visible{outline:2px solid var(--brass-hi);outline-offset:3px}

/* Sealing wax: deep red, a hot highlight, pressed-in edge, parchment lettering. */
.btn.primary{background:var(--m-wax);color:var(--parch-hi);border-color:var(--wax-lo);
  box-shadow:inset 0 1px 0 rgba(255,190,170,.35),inset 0 -3px 6px rgba(40,0,0,.45),0 0 0 1px rgba(201,162,78,.55),0 4px 14px rgba(0,0,0,.5);
  text-shadow:0 1px 1px rgba(40,0,0,.7);font-size:var(--t-l);padding:0 var(--s5)}
.btn.primary:hover:not(:disabled){filter:brightness(1.12) saturate(1.05)}
/* The big one gets the seal itself pressed into its left end. The ship's wheel
   is part of the seal art (seal-wheel.webp), not a second layer: an icon laid
   over the wax never sat in the middle of the impression. */
.btn.primary.sealed{padding-left:62px;min-height:54px;font-size:22px;border-radius:var(--r-l)}
.btn.primary.sealed::before{content:"";position:absolute;left:-8px;top:50%;width:62px;height:62px;transform:translateY(-50%) rotate(-8deg);
  background:url("/ui/seal-wheel.webp") center/contain no-repeat;filter:drop-shadow(0 3px 4px rgba(0,0,0,.55))}

/* Brass: engraved plate, ink lettering. */
.btn.secondary{background:var(--m-brass);color:var(--ink);border-color:var(--brass-deep);
  box-shadow:inset 0 1px 0 rgba(255,245,210,.7),inset 0 -2px 3px rgba(60,40,10,.35),0 3px 8px rgba(0,0,0,.4);
  text-shadow:0 1px 0 rgba(255,240,200,.45)}
.btn.secondary:hover:not(:disabled){filter:brightness(1.08)}

/* Quiet: a brass outline. On wood by default; .onParch flips it to ink. */
.btn.quiet{background:rgba(13,18,24,.35);color:var(--bone);border-color:rgba(201,162,78,.55)}
.btn.quiet:hover:not(:disabled){background:rgba(201,162,78,.16);border-color:var(--brass)}
.onParch .btn.quiet,.card .btn.quiet{background:rgba(255,250,235,.35);color:var(--ink);border-color:rgba(134,98,42,.6)}
.onParch .btn.quiet:hover:not(:disabled),.card .btn.quiet:hover:not(:disabled){background:rgba(134,98,42,.14)}
.btn.icon{width:var(--tap);padding:0}
.btn.icon .ico{width:22px;height:22px}
/* HUD buttons: small wood plates that sit over the sea. */
.btn.hud{min-height:36px;padding:0 var(--s3);font-size:var(--t-s);color:var(--bone);background:var(--m-wood);
  border-color:rgba(201,162,78,.45);box-shadow:var(--sh-plate);opacity:.86}
.btn.hud.icon{width:36px;padding:0}
.btn.hud:hover{opacity:1;border-color:var(--brass)}

/* ==========================================================================
   Tabs: engraved labels on a wooden rail, the live one underlined in brass.
   ========================================================================== */
.tabs{display:flex;gap:2px;padding:3px;border-radius:var(--r-m);background:var(--m-wood);border:1px solid rgba(201,162,78,.4);box-shadow:var(--sh-plate)}
.tab{position:relative;min-height:calc(var(--tap) - 6px);padding:0 var(--s4);border:0;border-radius:var(--r-s);background:none;cursor:pointer;
  font-family:var(--f-head);font-size:var(--t-m);letter-spacing:.05em;color:var(--bone-dim);transition:color .12s,background-color .12s}
.tab:hover{color:var(--bone)}
.tab.on{color:var(--brass-hi);background:rgba(201,162,78,.12)}
.tab.on::after{content:"";position:absolute;left:18%;right:18%;bottom:3px;height:2px;border-radius:2px;background:var(--m-brass)}
.tab:focus-visible{outline:2px solid var(--brass-hi);outline-offset:1px}

/* Segmented control (mode, settings choices): brass when chosen. */
.seg{display:inline-flex;border-radius:var(--r-m);padding:2px;background:var(--m-wood);border:1px solid rgba(201,162,78,.4)}
.seg button{min-height:calc(var(--tap) - 4px);padding:0 var(--s3);border:0;border-radius:var(--r-s);background:none;cursor:pointer;
  font-family:var(--f-head);font-size:var(--t-s);letter-spacing:.04em;color:var(--bone-dim);white-space:nowrap}
.seg button:hover{color:var(--bone)}
.seg button.on{background:var(--m-brass);color:var(--ink);box-shadow:inset 0 1px 0 rgba(255,245,210,.6)}

/* ==========================================================================
   Surfaces. .panel is tarred wood (over the sea); .card is parchment (to read).
   .framed hangs the brass-cornered frame on either (9-slice border-image).
   ========================================================================== */
.panel{background:var(--m-wood);border:1px solid rgba(201,162,78,.42);border-radius:var(--r-m);color:var(--bone);
  box-shadow:inset 0 1px 0 rgba(255,230,180,.06),var(--sh-plate);padding:var(--s3) var(--s4)}
.plate{background:var(--m-wood);border:1px solid rgba(201,162,78,.42);border-radius:var(--r-m);color:var(--bone);box-shadow:var(--sh-plate);padding:var(--s2) var(--s3)}
.card{background:var(--m-parch);color:var(--ink);border-radius:var(--r-s);box-shadow:var(--sh-card),inset 0 0 0 1px rgba(134,98,42,.5),inset 0 0 26px rgba(120,84,36,.3);padding:var(--s5)}
.framed{border:18px solid transparent;border-image:url("/ui/frame.webp") 64 fill / 18px / 0 stretch;background-clip:padding-box}
.panel.framed{border-image:url("/ui/frame.webp") 64 / 18px / 0 stretch;border-radius:0}
.card.framed{border-image:url("/ui/frame.webp") 64 / 18px / 0 stretch;border-radius:0;background-clip:padding-box}
.cardTitle{font-family:var(--f-display);font-weight:normal;font-size:var(--t-2xl);line-height:1;color:var(--ink);letter-spacing:.01em}

/* Chips: a pill that says one thing and, tapped, takes you to change it. */
.chip{display:inline-flex;align-items:center;gap:var(--s2);min-height:var(--tap);padding:0 var(--s3) 0 var(--s2);border-radius:var(--r-pill);
  background:var(--m-wood);border:1px solid rgba(201,162,78,.45);color:var(--bone);font-size:var(--t-s);cursor:pointer;box-shadow:var(--sh-plate);max-width:100%}
.chip .ico{color:var(--brass);width:20px;height:20px}
.chip .lbl{font-family:var(--f-head);font-size:var(--t-xs);letter-spacing:.06em;color:var(--bone-faint)}
.chip b{font-weight:500;color:var(--brass-hi);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chip:hover{border-color:var(--brass)}

/* Meter: a recessed groove with a brass fill. */
.meter{height:8px;border-radius:4px;background:rgba(0,0,0,.45);box-shadow:inset 0 1px 2px rgba(0,0,0,.7),0 1px 0 rgba(255,230,180,.08);overflow:hidden}
.meter > i{display:block;height:100%;border-radius:4px;background:var(--m-brass)}

/* ==========================================================================
   Form controls, on parchment by default (settings, cards).
   ========================================================================== */
/* Toggle: a brass knob in a leather slot. Wraps a real checkbox. */
.toggle{position:relative;display:inline-block;width:46px;height:26px;flex:none;cursor:pointer}
.toggle input{position:absolute;inset:0;opacity:0;margin:0;cursor:pointer}
.toggle i{position:absolute;inset:0;border-radius:13px;background:#6c5840;box-shadow:inset 0 2px 4px rgba(0,0,0,.55);transition:background-color .15s}
.toggle i::after{content:"";position:absolute;left:3px;top:3px;width:20px;height:20px;border-radius:50%;background:var(--m-brass);
  box-shadow:0 1px 3px rgba(0,0,0,.6),inset 0 1px 0 rgba(255,245,210,.7);transition:transform .15s}
.toggle input:checked + i{background:var(--wax)}
.toggle input:checked + i::after{transform:translateX(20px)}
.toggle input:focus-visible + i{outline:2px solid var(--brass-deep);outline-offset:2px}

/* Slider: a rope-coloured groove, a brass knob. */
.slider{-webkit-appearance:none;appearance:none;width:100%;height:28px;background:none;cursor:pointer}
.slider::-webkit-slider-runnable-track{height:6px;border-radius:3px;background:linear-gradient(90deg,var(--brass-lo) var(--fill,50%),rgba(42,31,20,.25) var(--fill,50%));box-shadow:inset 0 1px 2px rgba(0,0,0,.4)}
.slider::-moz-range-track{height:6px;border-radius:3px;background:rgba(42,31,20,.25)}
.slider::-moz-range-progress{height:6px;border-radius:3px;background:var(--brass-lo)}
.slider::-webkit-slider-thumb{-webkit-appearance:none;width:20px;height:20px;margin-top:-7px;border-radius:50%;background:var(--m-brass);border:1px solid var(--brass-deep);box-shadow:0 1px 3px rgba(0,0,0,.5)}
.slider::-moz-range-thumb{width:18px;height:18px;border-radius:50%;background:var(--m-brass);border:1px solid var(--brass-deep)}
.slider:focus-visible{outline:2px solid var(--brass-deep);outline-offset:2px}

/* Select: parchment field with a brass chevron. */
.select{-webkit-appearance:none;appearance:none;min-height:36px;padding:0 32px 0 10px;border-radius:var(--r-s);
  background:rgba(255,250,235,.7) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%2386622a' stroke-width='2'/%3E%3C/svg%3E") right 10px center/12px no-repeat;
  border:1px solid rgba(134,98,42,.6);color:var(--ink);font-size:var(--t-m);cursor:pointer}
.select:focus-visible{outline:2px solid var(--brass-deep);outline-offset:1px}

/* Tooltip: [data-tip] on anything; shows on hover (where hover exists) and focus. */
[data-tip]{position:relative}
[data-tip]::after{content:attr(data-tip);position:absolute;left:50%;bottom:calc(100% + 8px);transform:translate(-50%,4px);width:max-content;max-width:240px;
  padding:6px 9px;border-radius:var(--r-s);background:var(--tar-2);border:1px solid rgba(201,162,78,.5);color:var(--bone);
  font:var(--t-s)/1.4 var(--f-body);letter-spacing:0;text-align:left;white-space:normal;pointer-events:none;
  opacity:0;visibility:hidden;transition:opacity .13s,transform .13s,visibility .13s;z-index:30}
@media (hover:hover){ [data-tip]:hover::after{opacity:1;visibility:visible;transform:translate(-50%,0)} }
[data-tip]:focus-visible::after{opacity:1;visibility:visible;transform:translate(-50%,0)}

/* Modal sheet: a dim, blurred sea behind a card. */
.sheet{position:fixed;inset:0;z-index:40;display:none;align-items:center;justify-content:center;padding:var(--s4);
  background:rgba(6,9,12,.62);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);pointer-events:auto}
.sheet.shown{display:flex}
.sheet > .card{width:min(640px,100%);max-height:calc(100% - 8px);overflow-y:auto;overscroll-behavior:contain}

/* A spinning helm, for "making ready". */
.spinner{display:inline-block;width:22px;height:22px;flex:none;background-color:var(--brass);
  -webkit-mask:url("/icons/helm.png") center/contain no-repeat;mask:url("/icons/helm.png") center/contain no-repeat;animation:helmSpin 2.4s linear infinite}
@keyframes helmSpin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){ .spinner{animation:none} }
/* ---------- the hub (client/hub/hub.js) ----------
   One globe, three views of it, switched by `data-view` on #start so the
   stylesheet decides what each shows and switching is one attribute write:
     harbour — the captain card: your name and your ship, big and central.
               This is where a player lands, and "Set sail" is one click away.
     chart   — the globe is the server browser: pick a tile, see who's there.
     log     — your record.
   The sail bar at the foot is on every view: whatever you are looking at, the
   way to sea is in the same place. */
#start{position:fixed;inset:0;pointer-events:none;user-select:none;-webkit-user-select:none;font-family:var(--f-body)}
#start > *{pointer-events:auto}
#start > #harbourVeil,#start > #tileLine,#start > #chartHint,#start > #destPin{pointer-events:none}
#hubBar,#captainCard,#startBar{transition:opacity .5s ease-out}
#start.splashing > #hubBar,#start.splashing > #captainCard,#start.splashing > #startBar{opacity:0}

/* The globe keeps turning behind the harbour, darkened where the card sits so
   the ship reads against it, and lifts entirely on the chart. */
#harbourVeil{position:absolute;inset:0;transition:opacity .35s;
  background:radial-gradient(ellipse 70% 80% at 38% 52%,rgba(8,11,15,.72) 0%,rgba(8,11,15,.5) 55%,rgba(8,11,15,.2) 100%),
             linear-gradient(180deg,rgba(8,11,15,.55) 0%,rgba(8,11,15,0) 18%,rgba(8,11,15,0) 78%,rgba(8,11,15,.65) 100%)}
#start[data-view="chart"] #harbourVeil{opacity:0}
#start[data-view="log"] #harbourVeil{opacity:.75}

/* ---- the bar across the top ---- */
#hubBar{position:absolute;top:0;left:0;right:0;display:flex;align-items:center;gap:var(--s4);
  padding:max(14px,env(safe-area-inset-top)) max(20px,env(safe-area-inset-right)) 0 max(20px,env(safe-area-inset-left));pointer-events:none}
#hubBar > *{pointer-events:auto}
#hubLogo{height:66px;width:auto;filter:drop-shadow(0 4px 10px rgba(0,0,0,.6));pointer-events:none}
#hubTabs{margin:0 auto}
/* Balances the logo so the tabs sit dead centre. */
#hubBar::after{content:"";width:calc(140px - var(--tap) - var(--s4));flex:none}

/* ---- views ---- */
#captainCard,#roomList,#tileInfo,#tileLine,#chartHint,#statsPanel{display:none}
#start[data-view="harbour"] #captainCard{display:grid}
#start[data-view="chart"] #tileInfo,#start[data-view="chart"] #tileLine,#start[data-view="chart"] #chartHint{display:block}
#start[data-view="chart"] #roomList:not(.empty){display:block}
#start[data-view="log"] #statsPanel{display:block}

/* ---- harbour: the captain card ----
   The ship is the hero: the 3D preview takes the larger column and floats on
   the darkened sea with nothing boxed around it, and everything you read is on
   one parchment card beside it — name first, since it is the first thing a
   new captain is asked. */
#captainCard{position:absolute;top:104px;bottom:112px;left:50%;transform:translateX(-50%);width:min(1240px,calc(100% - 48px));
  grid-template-columns:minmax(0,1.45fr) minmax(330px,1fr);gap:var(--s5);align-items:stretch}
/* The card's empty corners let the globe behind them take a click: a tile
   picked there is the bar's destination. The ship's stage keeps its own drag. */
#start > #captainCard{pointer-events:none}
#captainRow,#shipStage,#shipInfo{pointer-events:auto}
#fleet{display:contents}
#shipStage{position:relative;min-height:0;display:flex;align-items:center;justify-content:center}
/* No "pool of lamplight" behind the hull: with the globe turning behind the
   stage it read as a stray yellow disc half over the sea, half over space. */
#shipCanvas{position:relative;width:100%;height:100%;min-height:120px;touch-action:pan-y;cursor:grab}
.carouselNav{position:absolute;top:50%;transform:translateY(-50%);width:56px;height:56px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  border:0;color:var(--ink);cursor:pointer;background:var(--m-brass);
  box-shadow:0 0 0 2px rgba(13,18,24,.7),0 0 0 3px rgba(201,162,78,.6),0 6px 14px rgba(0,0,0,.55),inset 0 2px 0 rgba(255,245,210,.6);transition:transform .1s,filter .12s}
.carouselNav .ico{width:26px;height:26px}
.carouselNav:hover{filter:brightness(1.1)}
.carouselNav:active{transform:translateY(-50%) scale(.95)}
#shipPrev{left:8px}
#shipNext{right:8px}
#shipDots{position:absolute;left:0;right:0;bottom:4px;display:flex;justify-content:center;gap:8px}
#shipDots i{width:9px;height:9px;border-radius:50%;background:rgba(236,228,210,.25);box-shadow:inset 0 0 0 1px rgba(201,162,78,.5);transition:background-color .15s,transform .15s}
#shipDots i.on{background:var(--brass-hi);transform:scale(1.25)}

/* The parchment: one sheet, sized to what it says and centred beside the
   ship, rather than a column stretched to the height of the screen. */
#captainCard{grid-template-rows:minmax(0,1fr) auto minmax(0,auto) minmax(0,1fr);row-gap:0}
#captainCard > #captainRow{grid-column:2;grid-row:2}
#shipInfo{grid-column:2;grid-row:3}
#shipStage{grid-column:1;grid-row:1 / -1}
#captainRow{position:relative;z-index:1;padding:var(--s4) var(--s5) var(--s3);background:var(--m-parch);color:var(--ink);
  border-radius:var(--r-s) var(--r-s) 0 0;box-shadow:inset 0 0 0 1px rgba(134,98,42,.5)}
#captainRow .eyebrow{display:block;color:var(--brass-lo);margin-bottom:var(--s1)}
.nameField{display:flex;gap:var(--s2)}
#captainName{flex:1;min-width:0;min-height:46px;padding:0 var(--s3);border:0;border-bottom:2px solid rgba(134,98,42,.55);border-radius:0;background:transparent;
  font-family:var(--f-display);font-size:30px;color:var(--ink);outline:none;user-select:text;-webkit-user-select:text}
#captainName:focus{border-bottom-color:var(--wax)}
#captainName::placeholder{color:var(--ink-faint)}
#nameDice{background:rgba(255,250,235,.4);color:var(--ink);border-color:rgba(134,98,42,.55);width:46px;min-height:46px}
#nameDice:hover{background:rgba(134,98,42,.14)}
#nameDice.rolled .ico{animation:diceRoll .45s ease-out}
@keyframes diceRoll{from{transform:rotate(-200deg) scale(.7)}to{transform:none}}

#shipInfo{display:flex;flex-direction:column;gap:var(--s3);min-height:0;overflow-y:auto;padding:var(--s3) var(--s5) var(--s5);
  background:var(--m-parch);color:var(--ink);border-radius:0 0 var(--r-s) var(--r-s);box-shadow:inset 0 0 0 1px rgba(134,98,42,.5),var(--sh-card);
  user-select:text;-webkit-user-select:text}
#shipInfo::before{content:"";flex:none;height:1px;background:linear-gradient(90deg,transparent,rgba(134,98,42,.6),transparent);margin-bottom:var(--s1)}
.shipTitle{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s3)}
#shipName{font-family:var(--f-display);font-weight:normal;font-size:var(--t-3xl);line-height:.95;color:var(--ink)}
#shipCount{color:var(--brass-lo);font-variant-numeric:tabular-nums}
#shipStatBars{display:grid;grid-template-columns:auto 1fr;gap:7px var(--s3);align-items:center}
.statLabel{font-family:var(--f-head);font-size:var(--t-s);color:var(--ink-2);letter-spacing:.04em}
.statBar{height:10px;border-radius:5px;background:rgba(42,31,20,.16);box-shadow:inset 0 1px 2px rgba(42,31,20,.35);overflow:hidden}
.statBar i{display:block;height:100%;border-radius:5px;background:linear-gradient(180deg,#b88d3f,#7c5a24);transition:width .25s ease-out}
#shipSpecial{display:flex;gap:var(--s3);align-items:center;padding:var(--s3);border-radius:var(--r-m);
  background:rgba(42,31,20,.07);box-shadow:inset 0 0 0 1px rgba(134,98,42,.3)}
#shipSpecialIcon{width:44px;height:44px;flex:none;color:var(--wax)}
#shipSpecial b{display:block;font-family:var(--f-head);font-weight:normal;font-size:var(--t-l);color:var(--ink)}
#shipSpecialHow{display:block;font-size:var(--t-s);line-height:1.4;color:var(--ink-2)}
#shipBlurb{font-size:var(--t-s);line-height:1.5;color:var(--ink-soft);font-style:italic}
#shipTrial{align-self:flex-start;margin-top:auto}

/* ---- chart ---- */
#chartHint{position:absolute;top:96px;left:0;right:0;text-align:center;color:var(--bone-dim);text-shadow:0 1px 4px #000}
#roomList{position:absolute;left:20px;bottom:104px;width:300px;max-height:min(360px,calc(100% - 260px));overflow-y:auto}
#roomList h4{margin-bottom:var(--s2)}
.roomRow{display:flex;align-items:baseline;gap:8px;width:100%;min-height:36px;padding:6px 8px;background:none;border:0;border-radius:var(--r-s);
  color:var(--bone);font:inherit;font-size:var(--t-s);text-align:left;cursor:pointer}
.roomRow:hover{background:rgba(201,162,78,.14)}
.roomRow .tile{color:var(--brass-hi);font-family:var(--f-head)}
.roomRow .who{margin-left:auto;font-size:12px;color:var(--bone-dim);font-variant-numeric:tabular-nums}
.roomRow .far{font-size:10px;color:var(--bone-faint);text-transform:uppercase;letter-spacing:.05em}
#tileInfo{position:absolute;right:24px;top:50%;transform:translateY(-50%);width:250px;font-size:var(--t-s);line-height:1.5;min-height:56px;opacity:0;transition:opacity .2s}
#tileInfo.shown{opacity:1}
#tileInfo b{color:var(--brass-hi);font-weight:500}
/* Sized by inset alone. 100vw/100vh resolve against the *large* viewport,
   which on mobile is taller than the box the tile positions are projected
   into — that mismatch is why the connector line missed its tile. */
#tileLine{position:fixed;inset:0;pointer-events:none;overflow:visible}
#tileLine line{stroke:var(--brass-hi);stroke-width:1.5;stroke-dasharray:5 4;opacity:.8}

/* ---- log ---- */
#statsPanel{position:absolute;left:50%;top:52%;transform:translate(-50%,-50%);width:min(480px,calc(100% - 32px));
  max-height:calc(100% - 240px);overflow-y:auto;user-select:text;-webkit-user-select:text}
#statsPanel .cardTitle{margin-bottom:var(--s3)}
#statsPanel .eyebrow{color:var(--brass-lo)}
#statsPanel .spaced{margin-top:var(--s4);margin-bottom:var(--s1)}
.recRow{display:flex;justify-content:space-between;align-items:baseline;gap:12px;font-size:var(--t-m);padding:5px 0;font-variant-numeric:tabular-nums}
.recRow + .recRow{border-top:1px dotted rgba(134,98,42,.45)}
.recRow b{color:var(--ink);font-weight:700}
#worldNow{font-size:var(--t-m)}
#worldNow b{color:var(--wax)}
#statsPanel .note{margin-top:var(--s4);font-size:12px;line-height:1.5;color:var(--ink-soft)}
/* The captain's papers (client/hub/papers.js). Discord's button wears
   Discord's blurple, so it says where it goes before it's read; everything
   else is the card's own ink. */
#papers{font-size:var(--t-m)}
#papers .papersWho{margin:0 0 var(--s2)}
#papers .papersWho b{color:var(--ink)}
#papers .papersRow{display:flex;align-items:center;flex-wrap:wrap;gap:8px 12px}
#papers .papersRow .note{margin:0}
#papers .btn.discord{background:#5865f2;color:#fff;border-color:#4752c4;display:inline-flex;align-items:center;gap:8px}
#papers .btn.discord:hover{background:#4752c4}
#papers .btn.discord .ico{width:18px;height:18px}
#papers .linkish{display:block;margin-top:var(--s3);padding:0;background:none;border:0;font:inherit;font-size:12px;
  color:var(--ink-soft);text-decoration:underline;text-underline-offset:2px;cursor:pointer}
#papers .linkish.danger:hover,#papers .linkish.danger:focus-visible{color:var(--blood)}

/* ---- the sail bar: how → where → go ----
   One sentence in one flex row, so nothing can land on anything else: the
   four-way switch, the chip that says where (or takes a room code), and the
   one commit button, whose words follow the switch. `data-how` on the bar
   decides which "where" is showing. */
#startBar{position:absolute;left:50%;bottom:max(24px,env(safe-area-inset-bottom));transform:translateX(-50%);display:flex;align-items:center;gap:var(--s2);max-width:calc(100% - 24px)}
#howSeg{flex:none}
#howSeg button{min-height:calc(var(--tap) - 4px);padding:0 14px}
#howSeg button:focus-visible{outline:2px solid var(--brass-hi);outline-offset:1px}
.barArrow{flex:none;width:18px;display:flex;justify-content:center;opacity:.75}
.barArrow::before{content:"";width:8px;height:8px;border-top:2px solid var(--brass);border-right:2px solid var(--brass);transform:rotate(45deg)}
#whereSlot{display:flex;align-items:center;gap:4px;min-width:0}
#whereChip{min-width:230px;max-width:360px}
#whereChip b{flex:1;min-width:0;text-align:left}
#whereChip .caret{width:13px;height:13px;color:var(--bone-faint)}
#whereChip:focus-visible,#roomEntry:focus-within{outline:2px solid var(--brass-hi);outline-offset:2px}
.chipX{flex:none;width:28px;height:28px;border-radius:50%;padding:0;background:var(--m-wood);border:1px solid rgba(201,162,78,.45);color:var(--bone-dim);
  font-size:17px;line-height:1;cursor:pointer;box-shadow:var(--sh-plate)}
.chipX:hover{color:var(--bone);border-color:var(--brass)}
.chipX[hidden]{display:none}
#startBar[data-how="friends"] #whereChip,#startBar[data-how="friends"] #whereReset{display:none}
#startBar:not([data-how="friends"]) #roomEntry{display:none}
/* With friends: a code to join, the last room, the rules a new room opens with. */
#roomEntry{gap:6px;padding:0 4px 0 var(--s2);cursor:default}
#roomCode{width:150px;min-width:0;height:28px;padding:0 4px;border:0;border-bottom:1px dashed rgba(201,162,78,.55);border-radius:0;background:transparent;outline:none;
  font:600 var(--t-m)/1 var(--f-body);letter-spacing:.14em;text-transform:uppercase;color:var(--brass-hi);font-variant-numeric:tabular-nums;
  user-select:text;-webkit-user-select:text}
#roomCode::placeholder{letter-spacing:.02em;text-transform:none;font-weight:400;color:var(--bone-faint)}
#roomCode:focus{border-bottom-color:var(--brass-hi)}
#roomCode.bad{border-bottom:2px solid var(--blood);animation:codeShake .3s}
@keyframes codeShake{25%{transform:translateX(-4px)}75%{transform:translateX(4px)}}
.chipPill{flex:none;display:inline-flex;align-items:center;gap:5px;min-height:30px;padding:0 10px;border-radius:var(--r-pill);cursor:pointer;
  background:rgba(201,162,78,.12);border:1px solid rgba(201,162,78,.45);color:var(--bone);font-family:var(--f-head);font-size:12px;letter-spacing:.04em;white-space:nowrap}
.chipPill:hover{background:rgba(201,162,78,.24)}
.chipPill .ico{width:15px;height:15px;color:var(--brass)}
.chipPill[hidden]{display:none}
/* Wide enough that "Set sail" → "Open a room" doesn't shove the sentence about. */
#sail{min-width:218px;margin-left:var(--s1)}

/* The destination's pennant: brass, not wax — the seal is the only red thing
   on the screen. Placed by transform alone; the foot of the pole is the
   tile's centre, and it flies west so the chart's count badge (east of the
   tile) stays readable. It waves while the commit button is under the pointer. */
#destPin{position:absolute;left:0;top:0;width:36px;height:40px;margin:-38px 0 0 -28.5px;color:var(--gold);opacity:0;transition:opacity .25s;
  filter:drop-shadow(0 2px 3px rgba(0,0,0,.8)) drop-shadow(0 0 1px rgba(0,0,0,.9))}
#destPin.shown{opacity:1}
#destPin .ico{width:36px;height:40px;transform-origin:79% 95%}
#destPin.glow .ico{animation:pennantWave .5s ease-in-out infinite alternate}
@keyframes pennantWave{from{transform:rotate(-5deg) scale(1.08)}to{transform:rotate(4deg) scale(1.16)}}
#start[data-view="log"] #destPin{display:none}
@media (prefers-reduced-motion:reduce){ #destPin.glow .ico{animation:none;transform:scale(1.12)} }

/* ---------- narrower screens ---------- */
@media (max-width:1100px){
  #hubLogo{height:52px}
  #hubBar::after{width:calc(110px - var(--tap) - var(--s4))}
  #captainCard{grid-template-columns:minmax(0,1.1fr) minmax(300px,1fr);width:calc(100% - 32px);top:88px}
  #shipName{font-size:42px}
}
/* Tablet/phone: one column. The stage keeps what the text leaves over; the
   bar becomes two rows with Set sail full width — the thumb's own row. */
@media (max-width:760px){
  #hubBar{gap:var(--s2);padding-left:12px;padding-right:12px;padding-top:max(10px,env(safe-area-inset-top))}
  #hubLogo{height:34px}
  #hubBar::after{display:none}
  .tab{padding:0 10px;font-size:var(--t-s)}
  #captainCard{top:60px;bottom:calc(172px + env(safe-area-inset-bottom));width:calc(100% - 24px);grid-template-columns:1fr;grid-template-rows:minmax(110px,1fr) auto auto;gap:0}
  #shipStage{grid-column:1;grid-row:1}
  #captainCard > #captainRow{grid-column:1;grid-row:2;padding:var(--s2) var(--s4) var(--s2)}
  #shipInfo{grid-column:1;grid-row:3;padding:var(--s2) var(--s4) var(--s3);gap:var(--s2);max-height:none;overflow:visible}
  #captainRow .eyebrow{display:none}
  #captainName{font-size:24px;min-height:40px}
  #nameDice{min-height:40px;width:44px}
  #shipName{font-size:32px}
  #shipStatBars{gap:4px var(--s3)}
  .statBar{height:8px}
  #shipSpecial{padding:var(--s2)}
  #shipSpecialIcon{width:34px;height:34px}
  #shipSpecial b{font-size:var(--t-m)}
  #shipBlurb{display:none}
  #shipTrial{position:absolute;right:var(--s4);top:calc(var(--s2) + 2px);min-height:32px;margin:0;font-size:var(--t-s)}
  #shipTrial small{display:none}
  #shipInfo{position:relative}
  .shipTitle{padding-right:120px}
  #shipCount{display:none}
  .carouselNav{width:46px;height:46px}
  /* The sentence stacked: the switch, where, and the commit button full
     width at the bottom — the thumb's own row. (Two rows left a room code
     no room at all beside "Open a room" and "Rejoin".) */
  #startBar{left:12px;right:12px;transform:none;max-width:none;display:grid;grid-template-columns:minmax(0,1fr);grid-template-areas:"how" "where" "go";gap:var(--s2)}
  #howSeg{grid-area:how;display:flex}
  #howSeg button{flex:1;min-width:0;padding:0 4px;font-size:12px}
  .barArrow{display:none}
  #whereSlot{grid-area:where}
  #whereChip,#roomEntry{flex:1;min-width:0;max-width:none}
  #roomCode{flex:1;width:auto;font-size:14px;letter-spacing:.06em}
  #roomEntry.hasCode #rejoinBtn{display:none}
  .chipPill.rules span{display:none}
  .chipPill.rules{padding:0 8px}
  #sail{grid-area:go;min-width:0;margin:0;width:100%}
  #sail.sealed{min-height:48px;font-size:20px}
  #sail.sealed::before{width:56px;height:56px}
  #roomList{left:12px;right:12px;width:auto;bottom:168px;max-height:30%}
  #tileInfo{left:12px;right:12px;top:118px;transform:none;width:auto;min-height:0}
  #chartHint{top:58px}
  #statsPanel{top:auto;bottom:168px;transform:translateX(-50%);max-height:calc(100% - 240px)}
}
/* Short and wide (a phone on its side): back to two columns, and one bar. */
@media (max-height:520px) and (orientation:landscape){
  #hubBar{padding-top:max(6px,env(safe-area-inset-top))}
  #hubLogo{height:32px}
  #hubBar::after{display:none}
  .tab{min-height:32px;padding:0 12px;font-size:var(--t-s)}
  #hubGear{width:36px;min-height:36px}
  #captainCard{top:52px;bottom:62px;width:calc(100% - 24px);grid-template-columns:minmax(0,1fr) minmax(0,1.1fr);grid-template-rows:auto minmax(0,1fr);gap:0 var(--s3)}
  #shipStage{grid-column:1;grid-row:1 / span 2}
  #captainCard > #captainRow{grid-column:2;grid-row:1;padding:var(--s2) var(--s3) 4px}
  #shipInfo{grid-column:2;grid-row:2;padding:4px var(--s3) var(--s2);gap:6px;overflow-y:auto}
  #captainRow .eyebrow{display:none}
  #captainName{font-size:22px;min-height:36px}
  #nameDice{min-height:36px;width:40px}
  #shipName{font-size:28px}
  #shipStatBars{gap:3px var(--s3)}
  .statLabel{font-size:12px}
  .statBar{height:7px}
  #shipSpecial{padding:6px var(--s2)}
  #shipSpecialIcon{width:30px;height:30px}
  #shipSpecial b{font-size:var(--t-s)}
  #shipSpecialHow{font-size:12px}
  #shipBlurb{display:none}
  #shipTrial{min-height:32px;font-size:var(--t-s)}
  #shipTrial small{display:none}
  .carouselNav{width:40px;height:40px}
  #startBar{bottom:max(8px,env(safe-area-inset-bottom));gap:var(--s2)}
  #sail.sealed{min-height:44px;font-size:18px;padding-left:54px}
  #sail.sealed::before{width:54px;height:54px}
  #sail{min-width:176px}
  .chip,.seg button{min-height:36px}
  .chip .lbl{display:none}
  #howSeg button{padding:0 9px;font-size:12px}
  #whereChip{min-width:170px;max-width:240px}
  #roomCode{width:112px;font-size:13px;letter-spacing:.06em}
  #roomEntry > .ico{display:none}
  .chipPill.rules span{display:none}
  .barArrow{display:none}
  #roomList{bottom:62px;max-height:calc(100% - 120px);width:250px}
  #tileInfo{top:54px;transform:none;right:16px;width:240px}
  #start[data-view="chart"] #chartHint{display:none}
  #statsPanel{top:50px;bottom:60px;transform:translateX(-50%);max-height:none}
}
@media (max-width:420px){
  .seg button{padding:0 8px;font-size:12px}
  .chip{padding-right:10px}
  .chip .lbl{display:none}
}
/* ---------- game HUD ----------
   Furniture on the system in theme.css: tarred-wood plates with a brass
   hairline for anything read over the sea, brass for instruments, bone text,
   tabular figures for every number that ticks. */
#hud{position:fixed;inset:0;pointer-events:none;user-select:none;-webkit-user-select:none;display:none;font-family:var(--f-body)}

/* Top-left: the menu and (solo/private) the way home, in one row so neither
   lands on the other — or on the ?fps readout, which used to sit on top of
   "Back to the map". */
#hudCorner{position:absolute;left:14px;top:14px;display:flex;gap:8px;pointer-events:auto;z-index:6}
#leaveMatch{display:none}
#leaveMatch .narrow{display:none}

/* ?fps: out of every corner, at the foot of the screen. */
#fps{position:absolute;left:50%;bottom:4px;transform:translateX(-50%);padding:2px 8px;border-radius:var(--r-s);font:11px/1.4 ui-monospace,SFMono-Regular,Menlo,monospace;
  background:rgba(13,18,24,.7);color:var(--bone-dim);opacity:0;pointer-events:none}
#fps.shown{opacity:1}

/* The binnacle. The bowl, the ring and the card are one SVG; see
   client/hud/compass.js for why the card turns and the lubber line doesn't. */
#compass{position:absolute;left:14px;bottom:14px;width:150px;height:150px}
#compass svg{width:100%;height:100%;overflow:visible;filter:drop-shadow(0 4px 8px rgba(0,0,0,.6))}
.cBowl{fill:#0f1319}
.cTrack{fill:none;stroke:rgba(8,10,13,.92);stroke-width:3.4}
/* The log ring is sea-glass, not gold: brass on a brass bowl disappeared.
   Butt caps, not round: a round cap on a zero-length dash still paints a dot,
   which at rest looks like a bead of speed stuck on the bezel. */
.cFill{fill:none;stroke:#8fe3e0;stroke-width:3.4;stroke-linecap:butt;transition:stroke-dasharray .12s linear;filter:drop-shadow(0 0 1.5px rgba(120,230,225,.9))}
.cFace{fill:url(#cCardGrad);stroke:rgba(90,65,25,.8);stroke-width:.6}
.cTick{stroke:rgba(42,31,20,.55);stroke-width:.7}
.cTick.maj{stroke:rgba(42,31,20,.95);stroke-width:1.2}
.cPt{fill:var(--ink);font:7.5px "IM Fell English SC",Georgia,serif;text-anchor:middle;dominant-baseline:central}
.cPt.n{fill:#a81f16;font-size:10px}
.cLubber{fill:#b8231a;stroke:#3a0b08;stroke-width:.6;stroke-linejoin:round}
.cLubberLine{stroke:#b8231a;stroke-width:.9;stroke-linecap:round;opacity:.9}
.cPivot{fill:#c9a24e;stroke:#5b4219;stroke-width:.6}
.cGlass{fill:url(#cGlass);pointer-events:none}

/* The log plate: heading, knots and hull on one wooden plate beside the
   binnacle — where you're already looking. On a plate, not bone-on-nothing:
   the first pass of the hull bar was invisible over sunlit water (brief). */
#hull{position:absolute;left:172px;bottom:20px;width:168px;padding:8px 10px 9px;border-radius:var(--r-m);
  background:var(--m-wood);border:1px solid rgba(201,162,78,.5);box-shadow:var(--sh-plate),inset 0 1px 0 rgba(255,230,180,.07)}
.logRow{display:flex;align-items:baseline;gap:5px;margin-bottom:6px;font-variant-numeric:tabular-nums lining-nums;line-height:1}
.logRow b{font-weight:700;font-size:20px;color:var(--parch-hi)}
.logRow span{font-family:var(--f-head);font-size:12px;color:var(--brass)}
.logRow #headingPoint{margin-right:auto;min-width:1.6em}
.hullHead{display:flex;justify-content:space-between;align-items:baseline;font-family:var(--f-head);font-size:12px;
  letter-spacing:.05em;color:var(--bone-dim);margin-bottom:4px}
.hullHead b{font-family:var(--f-body);font-weight:700;font-size:13px;color:var(--bone);letter-spacing:0;font-variant-numeric:tabular-nums}
.hullBar{height:10px;border-radius:5px;background:rgba(0,0,0,.55);box-shadow:inset 0 1px 2px rgba(0,0,0,.8),0 0 0 1px rgba(201,162,78,.35);overflow:hidden}
.hullBar i{display:block;height:100%;width:100%;border-radius:5px;background:linear-gradient(180deg,#f3ead4,#cdbf9c);transition:width .18s ease-out}
/* Planking holds until it doesn't: amber is "taking water", red is "one more
   broadside". The pulse is only on the last band, so it means something. */
#hull.hurt .hullBar i{background:linear-gradient(180deg,#f0d78f,#b88d3f)}
#hull.critical .hullBar i{background:linear-gradient(180deg,#ea6a52,#a8281b);animation:hullPulse 1s ease-in-out infinite}
#hull.critical .hullHead b{color:var(--blood)}
@keyframes hullPulse{0%,100%{opacity:1}50%{opacity:.45}}
#hull.struck{border-color:var(--bone);box-shadow:0 0 12px rgba(236,228,210,.5),var(--sh-plate)}

/* Being hit: flashed by hud.js in proportion to the damage, and held low while
   the hull is critical. Blood at the edges, clear in the middle. */
#damageVignette{position:absolute;inset:0;pointer-events:none;opacity:0;transition:opacity .45s ease-out;
  background:radial-gradient(ellipse at center, rgba(120,16,8,0) 40%, rgba(110,14,6,.55) 78%, rgba(70,6,2,.95) 100%)}

/* Kill feed: small wooden slips, the rule on the left says whose. */
#killFeed{position:absolute;right:14px;top:14px;display:flex;flex-direction:column;align-items:flex-end;gap:4px;max-width:46%}
.killRow{font-size:13px;padding:5px 10px;border-radius:var(--r-s);background:rgba(20,16,12,.82);border-left:3px solid rgba(201,162,78,.5);
  box-shadow:0 2px 6px rgba(0,0,0,.35);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%;animation:killIn .18s ease-out}
.killRow.fading{opacity:0;transition:opacity .6s ease-in}
.killRow .b{font-weight:500;color:var(--bone)}
.killRow .mine{font-weight:700;color:var(--brass-hi)}
.killRow .verb{color:var(--bone-faint);font-family:var(--f-head);font-size:12px}
.killRow.you{border-left-color:var(--brass-hi);background:rgba(60,44,16,.86)}
.killRow.death{border-left-color:var(--blood)}
.killRow.death .mine{color:var(--blood)}
.killRow.sea{border-left-color:var(--brine)}
@keyframes killIn{from{opacity:0;transform:translateX(14px)}to{opacity:1;transform:none}}

/* Where the match stands: a small banner, top-centre. */
#matchState{position:absolute;left:50%;top:14px;transform:translateX(-50%);display:flex;align-items:baseline;gap:12px;
  font-size:var(--t-s);padding:6px 16px;border-radius:var(--r-m);background:var(--m-wood);border:1px solid rgba(201,162,78,.45);
  box-shadow:var(--sh-plate);transition:opacity .2s;white-space:nowrap}
#matchState.hidden{opacity:0}
#matchLead{font-weight:500;font-size:var(--t-m);color:var(--parch);font-variant-numeric:tabular-nums lining-nums}
#matchState i{font-style:normal;color:var(--brass-hi);font-weight:700;font-variant-numeric:tabular-nums}

/* Smoke Screen: fogs whichever ship is inside a smoke zone (overlays.js). */
#smokeOverlay{position:absolute;inset:0;background:#cfd0ca;opacity:0;transition:opacity .3s}

#aimHint{position:absolute;left:50%;bottom:110px;transform:translateX(-50%);font-size:var(--t-s);opacity:0;transition:opacity .15s;pointer-events:none;white-space:nowrap;padding:8px 14px}
#aimHint.shown{opacity:1}

/* "Making ready…" / "Hailing the fleet…": the helm turning on a plate. */
#netStatus{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:flex;align-items:center;gap:12px;
  font-family:var(--f-head);font-size:var(--t-l);padding:14px 22px;opacity:0;transition:opacity .2s;pointer-events:none;max-width:calc(100% - 32px)}
#netStatus .spinner{display:none;width:28px;height:28px}
#netStatus.busy .spinner{display:inline-block}
#netStatus.shown{opacity:1}
/* ---- touch layout -------------------------------------------------------
   These live *after* every rule they override, and that is load-bearing
   rather than tidiness. A media query adds no specificity, so while this
   block sat further up the file the plain #hull / #killFeed / #matchState /
   #fps rules below it won every property they happened to re-declare. The
   hull kept `bottom:22px` from the desktop rule while taking `top` from here,
   so on a phone it stretched from under the compass to the bottom of the
   screen; the kill feed kept `right:14px` and `align-items:flex-end` and so
   drifted into the middle, on top of the leader bar. Both were reported from
   a real device, neither is visible on a desktop, and one move fixes them. */
/* On touch layouts the bottom-left corner is the steering stick, so the
   binnacle moves to the top-left — under the menu row — and shrinks, with
   the log plate under it at its own width. */
@media (pointer:coarse){
  #hudCorner{left:12px;top:max(10px,env(safe-area-inset-top))}
  #compass{top:58px;bottom:auto;left:12px;width:108px;height:108px}
  #hull{left:12px;top:172px;bottom:auto;width:108px;padding:5px 7px 6px}
  #hull .logRow{margin-bottom:4px;gap:3px}
  #hull .logRow b{font-size:14px}
  #hull .logRow span{font-size:10px}
  #hull .hullHead{font-size:10px;margin-bottom:3px}
  #hull .hullHead b{font-size:11px}
  #hull .hullBar{height:7px}
  #killFeed{top:62px;max-width:58%}
  .killRow{font-size:12px;padding:4px 8px}
  #matchState{top:14px;font-size:11px;padding:4px 10px}
  #matchLead{font-size:var(--t-s)}
  #leaveMatch{min-height:36px}
  #leaveMatch .wide{display:none}
  #leaveMatch .narrow{display:inline}
}
/* Landscape is short and wide: the menu row sits beside the binnacle rather
   than above it, and the column climbs back to the top. */
@media (pointer:coarse) and (orientation:landscape){
  #hudCorner{left:128px;top:10px}
  #compass{top:10px;width:104px;height:104px}
  #hull{top:120px;width:104px}
  /* The fire wheel, special and brace climb most of the way up the right side
     of a ~360px-tall phone — the band a right-aligned feed would occupy. Use
     the strip beside the binnacle. */
  #killFeed{right:auto;left:128px;top:58px;align-items:flex-start;max-width:44%}
}
/* ---------- HUD panels: boarding, the death card, the scoreboard, labels,
   the dials, the end card and its awards ---------- */

/* Boarded: helm, guns and special gone at once. Above the ship, not on it. */
#boardedNotice{position:absolute;left:50%;top:34%;transform:translate(-50%,-50%);text-align:center;
  display:none;flex-direction:column;gap:3px;pointer-events:none;padding:12px 30px;border-radius:var(--r-m);
  background:linear-gradient(180deg,rgba(80,14,8,.9),rgba(46,8,4,.9));border:1px solid rgba(207,74,51,.85);box-shadow:var(--sh-plate)}
#hud.boarded #boardedNotice{display:flex}
#boardedNotice b{font-family:var(--f-display);font-size:30px;font-weight:normal;color:#ff9b82;letter-spacing:.02em;line-height:1}
#boardedNotice span{font-size:var(--t-s);color:var(--bone-dim)}
#boardedNotice i{font-style:normal;font-size:var(--t-s);font-weight:700;color:var(--brass-hi);font-variant-numeric:tabular-nums}
#hud.boarded #cooldowns,#hud.boarded #fireWheel,#hud.boarded #specialBtn{opacity:.3;filter:grayscale(1)}

/* ---- the death card (client/hud/deathCard.js) ----
   Who, with what, how hurt they are, when you're back, and what you sail
   next. Low and central: the sinking is still worth watching above it. */
#deathCard{position:absolute;left:50%;top:58%;transform:translate(-50%,-50%);width:min(600px,calc(100% - 24px));
  display:none;flex-direction:column;align-items:center;gap:8px;padding:16px 20px 14px;border-radius:var(--r-m);text-align:center;
  background:linear-gradient(180deg,rgba(26,14,10,.92),rgba(14,10,8,.94)),url("/ui/planks.webp") 0 0/256px;
  border:1px solid rgba(207,74,51,.65);box-shadow:0 0 0 1px rgba(0,0,0,.5),var(--sh-card);pointer-events:auto;animation:deathIn .35s ease-out}
#deathCard.shown{display:flex}
@keyframes deathIn{from{opacity:0;transform:translate(-50%,-44%)}to{opacity:1;transform:translate(-50%,-50%)}}
.dcHead{display:flex;align-items:center;gap:10px;color:#ff8f75}
.dcHead .ico{width:30px;height:30px}
#dcTitle{font-family:var(--f-display);font-size:40px;line-height:1;color:#ff8f75;text-shadow:0 2px 0 rgba(0,0,0,.6)}
#dcBy{font-size:var(--t-m);color:var(--bone);line-height:1.4}
#dcBy b{font-weight:700;color:var(--brass-hi)}
#dcBy .how{font-family:var(--f-head);color:var(--bone-dim)}
#dcFoe{display:flex;align-items:center;gap:10px;width:min(320px,100%);font-size:12px;color:var(--bone-dim)}
#dcFoe span{font-family:var(--f-head);white-space:nowrap}
#dcFoe .meter{flex:1}
#dcFoe .meter i{background:linear-gradient(180deg,#f3ead4,#cdbf9c);transition:width .25s}
#dcFoe.low .meter i{background:linear-gradient(180deg,#ea6a52,#a8281b)}
#dcFoe b{min-width:3.2em;text-align:right;font-size:var(--t-s);color:var(--bone);font-variant-numeric:tabular-nums}
#dcCountdown{display:flex;align-items:center;gap:10px;margin-top:2px}
#dcCountdown .eyebrow{color:var(--bone-dim)}
#dcCountdown b{display:flex;align-items:center;justify-content:center;width:48px;height:48px;border-radius:50%;
  font-size:24px;font-weight:700;color:var(--parch-hi);font-variant-numeric:tabular-nums;
  background:radial-gradient(circle at 40% 35%,#2a2118,#120d09);box-shadow:0 0 0 3px #b58a3c,0 0 0 4px #5b4219,0 3px 8px rgba(0,0,0,.6)}
#dcPicker{width:100%}
#dcPicker:empty{display:none}
/* The respawn hull picker, folded in (client/hub/respawnPicker.js). */
#respawnPicker{display:none;flex-direction:column;align-items:stretch;gap:6px;width:100%;margin-top:4px;padding-top:10px;border-top:1px solid rgba(201,162,78,.25)}
#respawnPicker.shown{display:flex}
#respawnPicker .lbl{font-family:var(--f-head);font-size:var(--t-s);letter-spacing:.06em;color:var(--brass)}
#respawnPicker .shipRowBtn{background:rgba(236,228,210,.06);border-color:rgba(201,162,78,.35);color:var(--bone)}
#respawnPicker .shipRowBtn:hover:not(:disabled){background:rgba(201,162,78,.18)}
#respawnPicker .shipRowBtn.on{background:var(--m-brass);color:var(--ink);border-color:var(--brass-deep)}
#respawnPicker .shipRowBtn kbd{background:rgba(0,0,0,.25);color:inherit;border-color:rgba(201,162,78,.4)}

/* ---- the scoreboard (Tab) ---- */
#scoreboard{position:absolute;left:50%;top:14px;transform:translateX(-50%);width:min(560px,calc(100% - 24px));opacity:0;transition:opacity .15s;pointer-events:none;padding:6px 10px 8px}
#scoreboard.shown{opacity:1}
#scoreboard h4{margin-bottom:6px;text-align:center;font-size:var(--t-l);color:var(--brass-hi)}
/* A board, not a list: a rank column, tabular figures so the columns stop
   jittering, and the player's own row marked with a rule as well as the gold.
   The 8px of left padding keeps the "me" rule off the rank digit. */
.scoreRow,.scoreHead{display:grid;grid-template-columns:22px minmax(0,1fr) minmax(0,.8fr) 30px 30px 44px;gap:8px;align-items:baseline;font-size:var(--t-s);
  padding:4px 4px 4px 8px;font-variant-numeric:tabular-nums lining-nums}
.scoreRow > span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.scoreHead{font-family:var(--f-head);font-size:12px;color:var(--brass);border-bottom:1px solid rgba(201,162,78,.3);margin-bottom:2px}
.scoreRow .cls{font-size:12px;color:var(--bone-faint)}
.scoreRow .rank{color:var(--bone-faint);font-size:12px}
.scoreRow:first-child .rank{color:var(--brass-hi)}
.scoreRow:nth-child(even){background:rgba(255,255,255,.035)}
.scoreRow.me{color:var(--brass-hi);box-shadow:inset 3px 0 0 var(--brass-hi);background:rgba(201,162,78,.1)}
.scoreRow.me .rank,.scoreRow.me .cls{color:inherit;opacity:.8}
.scoreRow.down .nm{opacity:.55}
.scoreRow .dmg{color:var(--bone-dim)}
.teamHead{display:flex;justify-content:space-between;align-items:baseline;gap:10px;margin:10px 0 4px;
  font-family:var(--f-head);font-size:var(--t-s);letter-spacing:.05em;border-bottom:1px solid rgba(201,162,78,.3);padding-bottom:3px}
.teamHead:first-child{margin-top:0}
.teamHead b{font-family:var(--f-body);font-weight:700;font-size:15px;letter-spacing:0;font-variant-numeric:tabular-nums}
.teamHead.ours{color:var(--brine)}
.teamHead.theirs{color:var(--blood)}
.scoreRow span:nth-child(n+4),.scoreHead span:nth-child(n+4){text-align:right}

/* Floating name/health over each ship, placed each frame by transform
   (client/hud/hud.js); the transform-origin keeps a shrinking label on its
   masthead. */
#shipLabels{position:fixed;inset:0;pointer-events:none}
.shipLabel{position:absolute;left:0;top:0;transform-origin:50% 100%;will-change:transform,opacity;
  text-align:center;white-space:nowrap;font-family:var(--f-head);font-size:13px;color:var(--parch);
  text-shadow:0 1px 2px #000,0 0 4px rgba(0,0,0,.9)}
.shipLabel .name{margin-bottom:3px}
.shipLabel .bar{width:74px;height:6px;margin:0 auto;border-radius:3px;background:rgba(10,12,15,.85);box-shadow:0 0 0 1px rgba(0,0,0,.6),0 0 0 2px rgba(201,162,78,.3);overflow:hidden}
.shipLabel .bar i{display:block;height:100%;width:100%;background:var(--bone);transition:width .15s}
.shipLabel.enemy .bar i{background:linear-gradient(180deg,#ea6a52,#b3301f)}
/* In a team match the question changes from "is that me" to "is that us". */
.shipLabel.ally .name{color:#9fe0e6}
.shipLabel.ally .bar i{background:linear-gradient(180deg,#8fd6de,#3f8f9a)}

/* Bottom-right: the dials above the help, stacked by one flex column instead
   of each guessing the other's height. */
#hudBottomRight{position:absolute;right:14px;bottom:14px;display:flex;flex-direction:column;align-items:flex-end;gap:10px}
#help{position:static;font-size:12px;line-height:1.75;max-width:300px;opacity:.9;transition:opacity 1s ease-out;padding:8px 12px}
#help kbd{font-size:11px;margin-right:1px}
/* Learned the ropes — see createRopesHelp() in client/match/input.js. Opacity
   only, so the dials above don't jump when the text goes. */
#help.gone{opacity:0}

/* Ability icons (assets/icons/*.png) are alpha-only masks: the ink is
   currentColor, wherever they're placed (brief §5). */
.abilityIcon{display:inline-block;background-color:currentColor;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-position:center;mask-position:center;
  -webkit-mask-size:contain;mask-size:contain}

/* Cooldown dials: brass gun-port rims matching the binnacle. The rim is a
   conic brass gradient; ::before is the reload sweep (a CSS variable, painted
   by hud.js only when it moves); ::after is the dark face. Each broadside
   dial carries its navigation light — red to port, green to starboard, on the
   side of the dial it belongs to, as on a hull when you face forward. */
#cooldowns{position:static;display:flex;gap:12px}
.cd-box{--sweep:360deg;--sweep-col:var(--brass-hi);position:relative;width:62px;height:62px;border-radius:50%;background:var(--m-brass-ring);
  display:flex;align-items:center;justify-content:center;box-shadow:0 3px 8px rgba(0,0,0,.6),inset 0 0 0 1px rgba(60,40,10,.6)}
.cd-box::before{content:"";position:absolute;inset:4px;border-radius:50%;
  background:conic-gradient(var(--sweep-col) 0 var(--sweep),rgba(10,12,15,.92) var(--sweep) 360deg);box-shadow:inset 0 0 0 1px rgba(0,0,0,.6)}
.cd-box::after{content:"";position:absolute;inset:9px;border-radius:50%;background:radial-gradient(circle at 40% 32%,#2c241b,#120e0a 75%);box-shadow:inset 0 2px 4px rgba(0,0,0,.8)}
.cd-box.draining{--sweep-col:#ff9b5a}
.cd-box .cd-label,.cd-box .cd-time,.cd-box .cd-icon{position:relative;z-index:1}
.cd-box .cd-label{font-family:var(--f-head);font-size:17px;color:var(--bone-dim)}
.cd-box.ready .cd-label{color:var(--brass-hi)}
/* On the special the ability is the thing worth recognising, so it takes the
   middle and the key shrinks to a tag above it. Lifted clear of .cd-time. */
#cdSpecial .cd-icon{width:24px;height:24px;color:var(--bone-dim);margin-bottom:6px}
#cdSpecial .cd-label{position:absolute;top:10px;left:0;right:0;text-align:center;font-size:10px}
#cdSpecial.ready .cd-icon{color:var(--brass-hi)}
.cd-box .cd-time{position:absolute;bottom:11px;left:0;right:0;text-align:center;font-size:10px;font-weight:700;color:var(--bone);font-variant-numeric:tabular-nums}
.cd-lamp{position:absolute;top:50%;width:11px;height:11px;border-radius:50%;z-index:2;border:1px solid rgba(0,0,0,.6);transform:translateY(-50%)}
#cdPort .cd-lamp{left:-5px;background:radial-gradient(circle at 35% 30%,#ff9a86,#c0402c 60%);box-shadow:0 0 8px rgba(208,74,51,.85)}
#cdStbd .cd-lamp{right:-5px;background:radial-gradient(circle at 35% 30%,#9ff0b6,#3f9a5e 60%);box-shadow:0 0 8px rgba(67,168,101,.85)}
.cd-box.ready{box-shadow:0 3px 8px rgba(0,0,0,.6),0 0 10px rgba(242,200,103,.35)}
.cd-box.flash{animation:cdFlash .4s ease-out}
@keyframes cdFlash{0%{box-shadow:0 0 0 0 rgba(242,200,103,.95)}100%{box-shadow:0 0 18px 7px rgba(242,200,103,0)}}
@media (max-width:560px){ .cd-box{width:50px;height:50px} }

/* ---- end of match: the headline, the awards, the board, the way out ---- */
#overlay{position:absolute;inset:0;z-index:9;display:none;align-items:center;justify-content:center;background:rgba(6,9,12,.72);pointer-events:auto;padding:16px;overflow-y:auto}
#overlay .endCard{text-align:center;width:min(700px,100%);max-height:100%;display:flex;flex-direction:column;padding:14px 22px 16px;overflow:hidden}
#overlay h2{font-family:var(--f-display);font-size:52px;font-weight:normal;line-height:1;color:var(--wax);letter-spacing:.01em;text-shadow:0 1px 0 rgba(255,250,235,.6)}
#overlay p{font-size:var(--t-m);color:var(--ink-2);margin:6px 0 10px;padding-bottom:10px;border-bottom:1px solid rgba(134,98,42,.4)}
#awards{display:grid;grid-template-columns:repeat(auto-fit,minmax(112px,1fr));gap:8px;margin-bottom:12px}
.award{display:flex;flex-direction:column;align-items:center;gap:1px;padding:6px 4px 8px;border-radius:var(--r-m);background:rgba(42,31,20,.06);box-shadow:inset 0 0 0 1px rgba(134,98,42,.3)}
.award.mine{background:rgba(155,30,24,.1);box-shadow:inset 0 0 0 1px rgba(155,30,24,.45)}
.awardSeal{position:relative;width:54px;height:54px;display:flex;align-items:center;justify-content:center;margin-bottom:3px;
  background:url("/ui/seal.webp") center/contain no-repeat;filter:drop-shadow(0 2px 3px rgba(0,0,0,.35));color:rgba(255,220,200,.9)}
.awardSeal .ico{width:24px;height:24px;margin-top:-2px}
.awardTitle{font-family:var(--f-head);font-size:var(--t-s);color:var(--brass-lo);letter-spacing:.03em}
.awardWho{font-weight:700;font-size:var(--t-m);color:var(--ink);max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.awardVal{font-size:12px;color:var(--ink-soft);font-variant-numeric:tabular-nums}
#finalScores{text-align:left;overflow-y:auto;margin-bottom:12px;min-height:0}
#finalScores .scoreHead{color:var(--brass-lo);border-bottom-color:rgba(134,98,42,.45)}
#finalScores .scoreRow{font-size:var(--t-m);color:var(--ink)}
#finalScores .scoreRow .cls,#finalScores .scoreRow .rank,#finalScores .scoreRow .dmg{color:var(--ink-soft)}
#finalScores .scoreRow:first-child .rank{color:var(--wax)}
#finalScores .scoreRow:nth-child(even){background:rgba(42,31,20,.05)}
#finalScores .scoreRow.me{color:var(--wax);box-shadow:inset 3px 0 0 var(--wax);background:rgba(155,30,24,.08)}
#finalScores .teamHead.ours{color:#2f7d86}
#finalScores .teamHead.theirs{color:var(--wax)}
#ovFooter{display:flex;align-items:center;justify-content:center;gap:16px;flex-wrap:wrap;padding-top:10px;border-top:1px solid rgba(134,98,42,.4)}
/* ---- between battles (client/hud/endCard.js): the countdown, the count, and
   the big "Ready" seal. The status line takes the footer's rule; the buttons
   sit under it. ---- */
.ovStatus{font-family:var(--f-head);font-size:var(--t-l);color:var(--ink-2);letter-spacing:.03em;font-variant-numeric:tabular-nums lining-nums;
  padding-top:10px;border-top:1px solid rgba(134,98,42,.4)}
.ovStatus:empty{display:none}
.ovStatus:empty + #ovFooter{border-top:1px solid rgba(134,98,42,.4)}
#ovFooter.ovWays{border-top:0}
.ovReady,.ovAgain{min-width:min(340px,100%)}
.ovReady{flex-direction:column;gap:3px;line-height:1.05}
.ovReady small{color:var(--parch-hi)}
/* Signed on: the seal turns brass, and stays pressable to stand down. */
.ovReady.on{background:var(--m-brass);color:var(--ink);border-color:var(--brass-deep);text-shadow:0 1px 0 rgba(255,240,200,.45)}
.ovReady.on small{color:var(--ink);opacity:.8}
.ovReady small:empty{display:none}
.endCard.sailing .ovStatus{color:var(--wax)}
/* A tick by each captain on the board: signed on, or not yet. */
.rdyTick{display:inline-block;width:1.3em;margin-right:4px;font-style:normal;font-weight:700;text-align:center;color:var(--ink-faint)}
.rdyTick.on{color:#2f7d4a}
/* A captain who came aboard between matches: nothing of the last one to read. */
.endCard.holding #awards,.endCard.holding #finalScores{display:none}
.endCard.holding h2{font-variant-numeric:tabular-nums lining-nums}
.endCard.holding .ovStatus,.endCard.holding .ovStatus:empty + #ovFooter{border-top:0;padding-top:0}
/* News over the map (client/hud/toast.js): "The fleet sailed without you". */
.toast{position:fixed;left:50%;top:max(84px,calc(env(safe-area-inset-top) + 64px));z-index:60;max-width:calc(100% - 32px);transform:translate(-50%,-12px);opacity:0;
  padding:10px 20px;border-radius:var(--r-m);background:var(--parch);color:var(--ink);font-family:var(--f-head);font-size:var(--t-l);letter-spacing:.03em;
  text-align:center;box-shadow:inset 0 0 0 1px var(--brass-lo),0 6px 22px rgba(0,0,0,.55);pointer-events:none;transition:opacity .3s,transform .3s}
.toast.shown{opacity:1;transform:translate(-50%,0)}
@media (max-width:560px){
  .ovStatus{font-size:var(--t-m)}
  #ovFooter.ovWays{gap:8px}
  #ovFooter.ovWays .ovReady,#ovFooter.ovWays .ovAgain{order:-1;flex:1 1 100%;min-width:0;font-size:18px;letter-spacing:.02em;padding-right:12px;white-space:normal;text-align:center}
  #ovFooter.ovWays .btn.quiet{flex:1 1 0;padding:0 10px}
}
@media (max-height:620px){
  .ovStatus{font-size:var(--t-m);padding-top:6px}
  .ovReady,.ovAgain{min-height:44px}
}
/* The card follows the finale, so it arrives rather than appears. */
#overlay{animation:ovIn .45s ease-out}
#overlay .endCard{animation:ovCardIn .5s cubic-bezier(.2,.8,.3,1)}
@keyframes ovIn{from{background:rgba(6,9,12,0)}}
@keyframes ovCardIn{from{opacity:0;transform:translateY(14px) scale(.97)}}

/* ---- the finale (client/match/finale.js): the beat before the card ----
   --fg is the grade (desaturate + vignette), --ft the title, both 0..1 and
   written by the finale each frame. The grade is a backdrop filter over the
   canvas rather than a post pass, because the low graphics preset has no post
   pass to put it in. */
/* The title sits high: the shot centres on the wreck, and the words shouldn't
   be what hides it. */
#finale{position:absolute;inset:0;z-index:8;display:none;pointer-events:none;--fg:0;--ft:0;
  align-items:center;justify-content:flex-start;flex-direction:column;padding-top:max(min(12vh,90px),calc(env(safe-area-inset-top) + 10px))}
#finale.shown{display:flex}
#finale::before{content:"";position:absolute;inset:0;opacity:var(--fg);
  -webkit-backdrop-filter:saturate(.45) contrast(1.06);backdrop-filter:saturate(.45) contrast(1.06);
  background:radial-gradient(ellipse at center,rgba(0,0,0,0) 45%,rgba(4,6,9,.55) 100%)}
/* A soft pool of shade behind the words, so a bright sea can't wash out the line under the title. */
.finaleWords{position:relative;text-align:center;opacity:var(--ft);transform:scale(calc(1.08 - var(--ft) * .08));padding:10px 48px 14px;
  background:radial-gradient(ellipse at center,rgba(6,9,12,.45) 0%,rgba(6,9,12,.25) 45%,rgba(6,9,12,0) 72%)}
.finaleTitle{font-family:var(--f-display);font-size:clamp(44px,min(12vw,15vh),120px);line-height:1;letter-spacing:.02em;color:var(--gold);
  text-shadow:0 2px 0 rgba(60,30,6,.9),0 0 30px rgba(242,200,103,.35),0 6px 22px rgba(0,0,0,.75)}
#finale[data-tone="defeat"] .finaleTitle{color:var(--wax-hi);text-shadow:0 2px 0 rgba(40,6,4,.9),0 0 28px rgba(207,59,45,.3),0 6px 22px rgba(0,0,0,.75)}
#finale[data-tone="even"] .finaleTitle{color:var(--bone)}
.finaleSub{margin-top:6px;font-family:var(--f-head);font-size:clamp(14px,min(3.2vw,4.5vh),24px);color:var(--parch-hi);letter-spacing:.04em;text-shadow:0 1px 3px rgba(0,0,0,.9)}
.finaleSkip{position:absolute;bottom:max(18px,env(safe-area-inset-bottom));left:0;right:0;text-align:center;font-family:var(--f-head);font-size:var(--t-s);
  color:var(--bone-dim);opacity:calc(var(--ft) * .8);text-shadow:0 1px 2px rgba(0,0,0,.9)}
/* The chrome steps back for the moment: the controls, dials, binnacle and
   labels fade; the kill feed stays, because its last line is the blow. */
#hud.finale #touch,#hud.finale #cooldowns,#hud.finale #help,#hud.finale #compass,#hud.finale #hull,
#hud.finale #shipLabels,#hud.finale #aimHint{opacity:0;transition:opacity .3s;pointer-events:none}
/* From the winning blow until the next match (the finale, the end card, the
   intermission's holding card) the chips that are about sailing this match go
   quietly: the wind, the bounty's arrow, banner and "you carry" plate, the
   brace plate and salvage buffs, hit markers and damage numbers, the kraken's
   bar and the sea's call-outs, the first-match guide and the keyboard help. Opacity only, so
   they come back exactly as they were when the class goes
   (client/match/finale.js sets #hud.matchOver). */
#hud.matchOver .windInd,#hud.matchOver .bountyArrow,#hud.matchOver .bountySelf,#hud.matchOver .bountyBanner,
#hud.matchOver .braceInd,#hud.matchOver .mechBuffs,#hud.matchOver #hitFx,#hud.matchOver #hzLayer,
#hud.matchOver #guide,#hud.matchOver #help{opacity:0;visibility:hidden;transition:opacity .4s ease-out,visibility 0s linear .4s}
@media (prefers-reduced-motion:reduce){
  #hud.matchOver .windInd,#hud.matchOver .bountyArrow,#hud.matchOver .bountySelf,#hud.matchOver .bountyBanner,
  #hud.matchOver .braceInd,#hud.matchOver .mechBuffs,#hud.matchOver #hitFx,#hud.matchOver #hzLayer,
  #hud.matchOver #guide,#hud.matchOver #help{transition:none}
}
/* Short screens (a phone on its side): each award becomes a seal with three
   lines beside it, so the board underneath still gets rows. */
@media (max-height:620px){
  #overlay{padding:8px}
  #overlay h2{font-size:32px}
  #overlay p{margin:2px 0 6px;padding-bottom:6px;font-size:var(--t-s)}
  #awards{grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:6px;margin-bottom:8px}
  .award{display:grid;grid-template-columns:34px minmax(0,1fr);column-gap:6px;align-items:center;justify-items:start;text-align:left;padding:4px 6px}
  .awardSeal{grid-row:1 / span 3;width:34px;height:34px;margin:0}
  .awardSeal .ico{width:15px;height:15px}
  .awardTitle{font-size:11px;line-height:1.1}
  .awardWho{font-size:var(--t-s);line-height:1.2}
  .awardVal{font-size:11px;line-height:1.1}
  #finalScores{margin-bottom:8px}
  #finalScores .scoreRow{font-size:var(--t-s);padding:2px 4px 2px 8px}
  #ovFooter{padding-top:6px}
  #ovFooter .btn{min-height:38px}
}
@media (max-width:560px){
  #awards{grid-template-columns:repeat(2,1fr);gap:6px}
  .award{display:grid;grid-template-columns:38px minmax(0,1fr);column-gap:6px;align-items:center;justify-items:start;text-align:left;padding:5px 6px}
  .awardSeal{grid-row:1 / span 3;width:38px;height:38px;margin:0}
  .awardSeal .ico{width:17px;height:17px}
  .awardTitle{font-size:12px;line-height:1.15}
  .awardWho{font-size:var(--t-s);line-height:1.2}
  .awardVal{font-size:11px}
  #overlay h2{font-size:40px}
  .scoreRow,.scoreHead{grid-template-columns:18px minmax(0,1fr) 26px 26px 38px;gap:6px}
  .scoreRow .cls,.scoreHead span:nth-child(3){display:none}
}
@media (prefers-reduced-motion:reduce){
  #overlay,#overlay .endCard{animation:none}
  .finaleWords{transform:none}
}
/* ---------- hit feedback (client/hud/hitFeedback.js) ----------
   Hit markers and floating damage numbers. Every node is absolutely placed at
   0,0 and moved by a transform each frame, so nothing here reflows the HUD.
   Linked before touch.css, which must stay last. */
#hitFx{position:absolute;inset:0;pointer-events:none;overflow:hidden}

/* The marker: four short ticks round the impact, an X with its centre left
   open so the ship stays visible through it. */
.hitMark{position:absolute;left:0;top:0;width:0;height:0;display:none;will-change:transform,opacity}
.hitMark i{position:absolute;left:-1.5px;top:-11px;width:3px;height:8px;border-radius:1px;
  background:var(--bone);box-shadow:0 0 0 1px rgba(13,18,24,.75),0 0 6px rgba(255,236,190,.55);
  transform-origin:1.5px 11px}
.hitMark i:nth-child(1){transform:rotate(45deg)}
.hitMark i:nth-child(2){transform:rotate(135deg)}
.hitMark i:nth-child(3){transform:rotate(225deg)}
.hitMark i:nth-child(4){transform:rotate(315deg)}
/* The sinking blow: bigger, blood-red, with a ring — unmistakably different. */
.hitMark.fatal i{top:-19px;height:13px;width:4px;left:-2px;transform-origin:2px 19px;
  background:#e2533b;box-shadow:0 0 0 1px rgba(13,18,24,.8),0 0 10px rgba(255,90,50,.8)}
.hitMark.fatal::after{content:"";position:absolute;left:-15px;top:-15px;width:30px;height:30px;border-radius:50%;
  border:2px solid rgba(226,83,59,.9);box-shadow:0 0 10px rgba(255,90,50,.6)}

/* Damage numbers: bone on a tar outline, like the rest of the HUD's type. */
.dmgNum{position:absolute;left:0;top:0;display:none;white-space:nowrap;will-change:transform,opacity;
  font-family:var(--f-body);font-weight:700;text-align:center;font-variant-numeric:tabular-nums;
  transform-origin:0 0}
.dmgNum b{display:block;transform:translate(-50%,-100%);font-size:20px;line-height:1;color:var(--bone);
  text-shadow:0 0 3px #0d1218,0 1px 2px #0d1218,1px 0 2px #0d1218,-1px 0 2px #0d1218,0 -1px 2px #0d1218}
.dmgNum.big b{font-size:26px;color:#ffd98a}
.dmgNum.fatal b{font-size:30px;color:#ff7a5c}
.dmgNum .rake{display:none;transform:translate(-50%,-100%) rotate(-6deg);margin-top:-2px;font-size:13px;letter-spacing:.14em;
  color:var(--rope);text-shadow:0 0 3px #0d1218,0 1px 2px #0d1218}
.dmgNum.raked .rake{display:block}
.dmgNum.raked b{color:#ffd98a}

@media (max-width:700px){
  .dmgNum b{font-size:16px}
  .dmgNum.big b{font-size:21px}
  .dmgNum.fatal b{font-size:24px}
}
/* ---------- hub furniture: splash, the "other ways to sail" card, join card,
   room plate, settings panel, ship rows (client/hub/*) ----------
   On the system in theme.css: cards are parchment with the brass frame, and
   their buttons are the same wax / brass / quiet three as everywhere else.
   Linked before touch.css, which stays last (brief §5). */
/* ---- splash ---- */
#splash{position:fixed;inset:0;z-index:20;display:flex;align-items:center;justify-content:center;
  pointer-events:auto;cursor:pointer;transition:opacity .55s ease}
#splash.leaving{opacity:0;pointer-events:none}
#splash .veil{position:absolute;inset:0;
  background:radial-gradient(ellipse at 50% 45%, rgba(13,18,24,.3) 0%, rgba(13,18,24,.75) 62%, rgba(8,11,15,.94) 100%);
  animation:veilBreathe 9s ease-in-out infinite alternate}
/* The engraved rose, turning very slowly behind the logo. */
#splash .veil::after{content:"";position:absolute;left:50%;top:47%;width:min(86vmin,900px);aspect-ratio:1;transform:translate(-50%,-50%);
  background-color:var(--brass);opacity:.1;-webkit-mask:url("/ui/rose.webp") center/contain no-repeat;mask:url("/ui/rose.webp") center/contain no-repeat;
  animation:roseTurn 240s linear infinite}
@keyframes roseTurn{to{transform:translate(-50%,-50%) rotate(360deg)}}
@keyframes veilBreathe{from{opacity:.92}to{opacity:1}}
.splashInner{position:relative;display:flex;flex-direction:column;align-items:center;gap:14px;padding:0 16px;text-align:center}
#splash img{width:min(760px,88vw);height:auto;filter:drop-shadow(0 10px 28px rgba(0,0,0,.6));
  animation:logoIn 1.1s cubic-bezier(.2,.7,.2,1) both, logoBob 6s ease-in-out 1.1s infinite alternate}
#splash .wordmark{display:none;font-family:var(--f-display);font-size:clamp(56px,12vw,120px);color:var(--brass-hi);letter-spacing:.02em;
  text-shadow:0 3px 0 #5b4520,0 8px 24px rgba(0,0,0,.7)}
#splash.noLogo img{display:none}
#splash.noLogo .wordmark{display:block}
#splash .tagline{font-family:var(--f-head);font-size:var(--t-l);letter-spacing:.06em;color:var(--parch);text-shadow:0 1px 6px rgba(0,0,0,.9);animation:fadeIn 1s .5s both}
#splash .prompt{margin-top:18px;padding:10px 26px;border-radius:var(--r-pill);font-family:var(--f-head);font-size:var(--t-m);letter-spacing:.14em;color:var(--brass-hi);
  background:rgba(13,18,24,.55);border:1px solid rgba(201,162,78,.5);
  animation:fadeIn .8s .9s both, promptPulse 2.2s ease-in-out 1.7s infinite}
#splash .prompt .narrow{display:none}
@media (pointer:coarse){#splash .prompt .wide{display:none}#splash .prompt .narrow{display:inline}}
/* A returning captain has seen the show: shorter, and no pulsing invitation. */
#splash.returning img{animation:logoIn .5s ease-out both}
#splash.returning .prompt,#splash.returning .tagline{animation:fadeIn .3s both}
@keyframes logoIn{from{opacity:0;transform:translateY(14px) scale(.96)}to{opacity:1;transform:none}}
@keyframes logoBob{from{transform:translateY(0) rotate(-.4deg)}to{transform:translateY(-6px) rotate(.4deg)}}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
@keyframes promptPulse{0%,100%{opacity:1}50%{opacity:.5}}
@media (prefers-reduced-motion:reduce){
  #splash img,#splash .prompt,#splash .veil,#splash .veil::after{animation:none}
}

/* ---- sheets and cards (friends/skirmish, join card, room settings) ---- */
.hubSheet,#roomSheet{position:fixed;inset:0;z-index:30;display:none;align-items:center;justify-content:center;
  padding:16px;background:rgba(6,9,12,.6);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);pointer-events:auto}
.hubSheet.shown,#roomSheet.shown{display:flex}
.hubCard{position:relative;width:min(640px,100%);max-height:calc(100% - 8px);overflow-y:auto;overscroll-behavior:contain;
  background:var(--m-parch);color:var(--ink);font-family:var(--f-body);
  border:18px solid transparent;border-image:url("/ui/frame.webp") 64 / 18px / 0 stretch;background-clip:padding-box;
  box-shadow:var(--sh-card);padding:14px 18px 14px;text-align:left;user-select:text;-webkit-user-select:text}
.hubCard h3{font-family:var(--f-display);font-size:var(--t-2xl);font-weight:normal;line-height:1.05;color:var(--ink);margin-bottom:4px}
.hubSub{font-size:var(--t-s);color:var(--ink-soft);line-height:1.45;margin-bottom:12px}
.hubHead{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.hubHead h3{margin:0}
.hubClose{margin-left:auto;width:38px;height:38px;border-radius:var(--r-m);border:1px solid rgba(134,98,42,.6);background:rgba(255,250,235,.35);color:var(--ink);font-size:22px;line-height:1;flex:none}
.hubClose:hover{background:rgba(134,98,42,.15)}
.hubLbl{display:block;font-family:var(--f-head);font-size:var(--t-s);letter-spacing:.06em;color:var(--brass-lo);margin:10px 0 6px}
.hubLbl.spaced{margin-top:18px;padding-top:14px;border-top:1px solid rgba(134,98,42,.35)}
.hubInput{display:block;width:100%;margin-top:5px;min-height:42px;padding:0 12px;font:inherit;font-family:var(--f-body);font-size:var(--t-m);color:var(--ink);border-radius:var(--r-s);
  background:rgba(255,250,235,.75);border:1px solid rgba(134,98,42,.6);outline:none;text-transform:none;letter-spacing:normal}
.hubInput:focus{border-color:var(--brass-deep);background:#fffdf4}
.hubInput.code{margin-top:0;text-transform:uppercase;letter-spacing:.18em;font-size:18px;font-variant-numeric:tabular-nums}
.hubInput.code::placeholder{letter-spacing:.04em;text-transform:none}
/* The card's own commit button is the wax seal too; everything else quiet. */
.hubPrimary{min-height:42px;padding:0 22px;border-radius:var(--r-m);font-family:var(--f-head);font-size:var(--t-m);letter-spacing:.04em;
  background:var(--m-wax);color:var(--parch-hi);border:1px solid var(--wax-lo);text-shadow:0 1px 1px rgba(40,0,0,.7);
  box-shadow:inset 0 1px 0 rgba(255,190,170,.35),inset 0 -3px 6px rgba(40,0,0,.45),0 3px 8px rgba(0,0,0,.35)}
.hubPrimary:hover{filter:brightness(1.1)}
.hubPrimary:disabled{opacity:.5;cursor:default;filter:none}
.hubQuiet{min-height:42px;padding:0 16px;border-radius:var(--r-m);font-family:var(--f-head);font-size:var(--t-m);background:rgba(255,250,235,.35);color:var(--ink);border:1px solid rgba(134,98,42,.6)}
.hubQuiet:hover{background:rgba(134,98,42,.14)}
.hubErr{color:#8e2d1f;font-size:12px;min-height:0}
.hubErr:empty{display:none}
.hubFoot{display:flex;align-items:center;justify-content:flex-end;gap:10px;margin-top:16px;flex-wrap:wrap}
.hubFoot .hubErr{margin-right:auto}
.hubCard :focus-visible{outline:2px solid var(--brass-deep);outline-offset:2px}

/* ---- the settings panel (client/hub/settingsPanel.js) ---- */
.settingsPanel{display:flex;flex-direction:column;gap:12px}
.spGrid{display:grid;grid-template-columns:1fr 1fr;gap:10px 16px}
.spField{display:flex;flex-direction:column;gap:5px;min-width:0}
.spField.wide{grid-column:1 / -1}
.spLabel{font-family:var(--f-head);font-size:var(--t-s);letter-spacing:.04em;color:var(--ink-2);display:flex;align-items:baseline;gap:10px}
.spSeg{display:flex;border-radius:var(--r-m);padding:2px;background:rgba(42,31,20,.1);box-shadow:inset 0 0 0 1px rgba(134,98,42,.45)}
.spSeg button{flex:1;min-height:34px;padding:0 8px;background:none;border:0;border-radius:var(--r-s);color:var(--ink-2);font-family:var(--f-head);font-size:var(--t-s);white-space:nowrap}
.spSeg button:hover{color:var(--ink)}
.spSeg button.on{background:var(--m-brass);color:var(--ink);box-shadow:inset 0 1px 0 rgba(255,245,210,.6),0 1px 2px rgba(0,0,0,.25)}
.spSelect{width:100%;min-height:36px;padding:0 8px;font:inherit;font-size:var(--t-m);color:var(--ink);border-radius:var(--r-s);background:rgba(255,250,235,.75);border:1px solid rgba(134,98,42,.6)}
.spRange{display:flex;align-items:center;gap:10px}
.spRange input{flex:1;accent-color:var(--brass-deep)}
.spRange output{min-width:2ch;text-align:right;font-variant-numeric:tabular-nums;font-size:var(--t-m);font-weight:700}
.spToggles{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:6px 14px}
.spToggle{display:flex;align-items:center;gap:8px;font-size:var(--t-m);cursor:pointer;min-height:30px}
.spToggle input,.spHull input{accent-color:var(--wax);width:17px;height:17px}
.spToggle.sub{padding-left:14px}
.spToggle.off{opacity:.45}
.spHulls{display:grid;grid-template-columns:repeat(4,1fr);gap:4px 10px}
.spHull{display:flex;align-items:center;gap:6px;font-size:var(--t-s);cursor:pointer;white-space:nowrap;min-height:28px}
.spLink{padding:0;background:none;border:0;color:var(--wax);font-size:11px;letter-spacing:.06em;text-decoration:underline}

/* ---- ship rows (join card, respawn picker) ---- */
.shipRow{display:grid;grid-template-columns:repeat(4,1fr);gap:6px}
.shipRowBtn{position:relative;display:flex;align-items:center;gap:7px;min-height:38px;padding:0 9px;font-size:var(--t-s);text-align:left;border-radius:var(--r-m);
  background:rgba(255,250,235,.45);border:1px solid rgba(134,98,42,.45);color:var(--ink)}
.shipRowBtn .abilityIcon{width:17px;height:17px;flex:none}
.shipRowBtn .nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.shipRowBtn kbd{margin-left:auto;font-size:10px;min-width:1.5em;padding:0 .3em;background:rgba(42,31,20,.1);border-color:rgba(134,98,42,.5);color:var(--ink-2)}
.shipRowBtn.on{background:var(--m-brass);color:var(--ink);border-color:var(--brass-deep);box-shadow:inset 0 1px 0 rgba(255,245,210,.6)}
.shipRowBtn:disabled{opacity:.35;cursor:not-allowed}

/* ---- in a private room: the room plate ---- */
#roomChip{position:absolute;left:14px;top:62px;display:none;align-items:center;gap:8px;padding:5px 6px 5px 12px;font-size:var(--t-s);pointer-events:auto;z-index:6}
#roomChip.shown{display:flex}
#roomChip .code{font-family:var(--f-head);color:var(--brass-hi);letter-spacing:.06em;white-space:nowrap;font-variant-numeric:tabular-nums}
#roomChip button{min-height:30px;padding:0 10px;border-radius:var(--r-s);font-family:var(--f-head);font-size:12px;background:rgba(201,162,78,.12);color:var(--bone);border:1px solid rgba(201,162,78,.45)}
#roomChip button:hover{background:rgba(201,162,78,.25)}
#roomChip .note{font-size:12px;color:var(--bone-dim);white-space:nowrap}
#roomChip .note:empty{display:none}
#roomSheet{z-index:34}

@media (max-width:640px){
  .spGrid{grid-template-columns:1fr}
  .spHulls,.shipRow{grid-template-columns:repeat(2,1fr)}
  .hubCard{padding:10px 10px 10px;border-width:14px;border-image-width:14px;max-height:100%}
  .hubCard h3{font-size:26px}
  .hubSheet,#roomSheet{padding:6px}
  .spSeg button{padding:0 4px;font-size:12px}
  .hubFoot button{flex:1}
  #roomChip{left:50%;transform:translateX(-50%);top:54px;font-size:12px}
  #roomChip .note{display:none}
}
/* ---------- the settings menu (client/ui/settingsMenu.js) ----------
   Parchment in the brass frame, sections as a segmented rail, one row per
   setting: label left, control right. The same sheet is the in-match menu.
   Linked before touch.css, which stays last (brief §5). */
.settingsSheet{z-index:50}
.smCard{display:flex;flex-direction:column;gap:var(--s3);width:min(660px,100%);max-height:min(720px,calc(100% - 8px));padding:var(--s4) var(--s5) var(--s4)}
.smHead{display:flex;align-items:center;gap:var(--s3)}
.smHead .cardTitle{flex:1}
.smClose{font-size:24px;line-height:1;font-family:var(--f-body)}
.smNote{font-size:var(--t-s);color:var(--ink-soft);margin-top:-6px}
.smTabs{flex-wrap:wrap;background:rgba(42,31,20,.1);border-color:rgba(134,98,42,.45)}
.smTabs button{color:var(--ink-2)}
.smTabs button:hover{color:var(--ink)}
.smBody{flex:1 1 auto;min-height:120px;overflow-y:auto;overscroll-behavior:contain;padding-right:4px}
.smHint{font-size:var(--t-s);color:var(--ink-soft);margin-bottom:var(--s2)}
.smRow{display:grid;grid-template-columns:minmax(0,1fr) minmax(170px,1.1fr);align-items:center;gap:var(--s4);min-height:48px;padding:4px 0}
.smRow + .smRow{border-top:1px dotted rgba(134,98,42,.4)}
.smLabel{font-size:var(--t-m);color:var(--ink)}
.smCtl{display:flex;align-items:center;justify-content:flex-end;gap:var(--s3)}
.smCtl .slider{flex:1}
.smVal{min-width:3.4em;text-align:right;font-variant-numeric:tabular-nums;font-weight:700;color:var(--ink)}
.smCtl .select{min-width:150px}
.smKey{min-width:96px;min-height:38px;padding:0 var(--s3);border-radius:var(--r-m);font-family:var(--f-head);font-size:var(--t-m);
  background:rgba(255,250,235,.6);color:var(--ink);border:1px solid rgba(134,98,42,.6);border-bottom-width:3px}
.smKey:hover{background:rgba(134,98,42,.12)}
.smKey.listening{background:var(--m-wax);color:var(--parch-hi);border-color:var(--wax-lo);animation:promptPulse 1.2s ease-in-out infinite}
.smFoot{display:flex;align-items:center;justify-content:flex-end;gap:var(--s2);flex-wrap:wrap;padding-top:var(--s3);border-top:1px solid rgba(134,98,42,.35)}
.smRestore{margin-right:auto;padding:0;background:none;border:0;color:var(--wax);font-size:var(--t-s);text-decoration:underline;text-underline-offset:3px}
@media (max-width:560px){
  .smCard{padding:var(--s3) var(--s3);border-width:14px;border-image-width:14px}
  .smRow{grid-template-columns:1fr;gap:4px;padding:6px 0}
  .smCtl{justify-content:flex-start}
  .smFoot .btn{flex:1}
  .smRestore{flex-basis:100%;text-align:left;margin-bottom:4px}
}
@media (max-height:520px){
  .settingsSheet{padding:6px}
  .smCard{max-height:100%;padding:var(--s2) var(--s4)}
  .smCard .cardTitle{font-size:var(--t-xl)}
  .smRow{min-height:40px}
}
/* ---------- the globe as the heart of spawning (W3-globe) ----------
   Set sail dives into the globe (client/transition/sailIn.js); a sinking
   rises out of the sea to it and dives back in (client/transition/
   matchCine.js); the chart reads at a glance (client/hub/chart.js).

   Everything that has to beat a rule elsewhere does it by specificity
   (#hud.onGlobe #deathCard beats #deathCard, media query or not), not by
   coming later — touch.css stays last (brief §5). */

/* ---- the hub lets go on Set sail ---- */
#start.departing > *{opacity:0 !important;pointer-events:none !important;transition:opacity .42s ease-in !important}

/* Held at the bottom of the dive while the match finishes making ready. */
#diveHint{position:fixed;left:50%;bottom:max(28px,env(safe-area-inset-bottom));transform:translateX(-50%);z-index:40;
  display:flex;align-items:center;gap:10px;padding:8px 16px;font-family:var(--f-head);font-size:var(--t-m);color:var(--bone);
  animation:cineIn .5s ease-out}
@keyframes cineIn{from{opacity:0}to{opacity:1}}

/* ---- the chart at a glance ---- */
#liveBadges{position:absolute;inset:0;pointer-events:none;display:none}
#start[data-view="chart"] #liveBadges{display:block}
.liveBadge{position:absolute;left:0;top:0;display:flex;align-items:center;gap:3px;padding:2px 7px 2px 5px;margin:-30px 0 0 8px;
  border-radius:var(--r-pill);background:rgba(20,12,8,.82);border:1px solid rgba(242,140,70,.75);color:#ffd9b0;
  font:700 12px/1.1 var(--f-body);font-variant-numeric:tabular-nums;white-space:nowrap;opacity:0;transition:opacity .25s;
  box-shadow:0 2px 8px rgba(0,0,0,.5)}
.liveBadge.shown{opacity:1}
.liveBadge .ico{width:12px;height:12px;color:#f2a868}
#globeTip{position:absolute;left:0;top:0;margin:14px 0 0 14px;padding:6px 10px;font-size:var(--t-s);line-height:1.45;color:var(--bone);
  pointer-events:none;white-space:pre-line;max-width:min(360px,calc(100vw - 40px));opacity:0;transition:opacity .15s;display:none;font-variant-numeric:tabular-nums}
#start[data-view="chart"] #globeTip,#start[data-view="harbour"] #globeTip{display:block}
/* A kraken or a storm over a live tile (client/hub/chart.js): a small engraved
   glyph on a tar disc, standing above the tile. Under the cards. */
#liveGlyphs{position:absolute;inset:0;pointer-events:none}
#start[data-view="log"] #liveGlyphs{display:none}
.liveGlyph{position:absolute;left:0;top:0;width:24px;height:24px;margin:-66px 0 0 -12px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  background:rgba(13,18,24,.82);border:1px solid rgba(201,162,78,.6);box-shadow:0 2px 6px rgba(0,0,0,.6);opacity:0;transition:opacity .3s}
.liveGlyph.shown{opacity:1}
.liveGlyph .ico{width:16px;height:16px}
.liveGlyph[data-kind="kraken"] .ico{color:#e2706a}
.liveGlyph[data-kind="storm"] .ico{color:#a9c4e6}
#globeTip.shown{opacity:1}

/* ---- the match's HUD while the camera flies ---- */
/* Gone while the camera is high (a HUD drawn over a sea seen from a hundred
   units up labels nothing), back with an animation rather than a transition
   so no element's own transitions are touched.
   Only the always-on instruments: the overlays (smoke, damage vignette, aim
   hint, scoreboard) are invisible by their own state, and an opacity
   animation on them would flash them up. */
#hud.cine:not(.onGlobe) > :is(#hudCorner,#compass,#hull,#hudBottomRight,#matchState,#killFeed,#touch,#shipLabels){opacity:0 !important}
#hud.cineOut > :is(#hudCorner,#compass,#hull,#hudBottomRight,#matchState,#killFeed,#touch,#shipLabels){animation:cineIn .5s ease-out}

/* ---- the respawn globe ---- */
/* The globe is the view: the instruments that belong to a ship at sea step
   aside; the match banner, kill feed, menu and the death card stay. */
#hud.onGlobe > :not(#hudCorner):not(#matchState):not(#killFeed):not(#scoreboard):not(#deathCard):not(#netStatus):not(#overlay):not(#fps):not(#respawnChart):not(#cineToast){visibility:hidden}
#hud.onGlobe #deathCard{left:max(16px,env(safe-area-inset-left));top:auto;bottom:max(16px,env(safe-area-inset-bottom));transform:none;
  width:min(480px,calc(100% - 32px));animation:none;gap:6px;padding:12px 16px 12px}
#hud.onGlobe #deathCard .dcHead .ico{width:22px;height:22px}
/* The hull row, tighter, and allowed to shrink: grid items keep their
   content's width by default and the row ran out of the card. */
#hud.onGlobe #respawnPicker .shipRow{grid-template-columns:repeat(4,minmax(0,1fr));gap:5px}
#hud.onGlobe #respawnPicker .shipRowBtn{min-height:32px;padding:0 7px;gap:5px;font-size:12px}

#respawnChart{position:absolute;inset:0;pointer-events:none;display:none}
#respawnChart.shown{display:block;animation:cineIn .45s ease-out}
.rcHead{position:absolute;left:50%;top:max(58px,calc(env(safe-area-inset-top) + 50px));transform:translateX(-50%);text-align:center;
  padding:8px 18px 9px;border-radius:var(--r-m);background:var(--m-wood);border:1px solid rgba(201,162,78,.45);box-shadow:var(--sh-plate);
  max-width:calc(100% - 24px)}
.rcHead h3{margin:0;font:400 var(--t-xl)/1.05 var(--f-display);color:var(--gold);letter-spacing:.02em}
.rcSub{margin:3px 0 0;font-size:var(--t-s);color:var(--bone-dim)}
.rcLegend{position:absolute;right:max(16px,env(safe-area-inset-right));bottom:max(16px,env(safe-area-inset-bottom));display:flex;flex-direction:column;gap:5px;
  padding:9px 12px;border-radius:var(--r-m);background:rgba(13,18,24,.78);border:1px solid rgba(201,162,78,.3);font-size:var(--t-xs);color:var(--bone-dim)}
.rcLegend span{display:flex;align-items:center;gap:7px}
.rcLegend .ico{width:14px;height:14px;color:var(--bone)}
.rcLegend .lg{display:inline-block;width:14px;height:14px;flex:none;border-radius:3px}
.rcLegend .lg.safe{border:2px solid #ffc34d;clip-path:polygon(25% 0,75% 0,100% 50%,75% 100%,25% 100%,0 50%);background:rgba(255,195,77,.18)}
.rcLegend .lg.fight{border-radius:50%;background:radial-gradient(circle,#ffb070 0,#e0561b 55%,rgba(224,86,27,0) 72%)}
.rcLegend .lg.ally{border-radius:50%;background:var(--side,#1f4fb0);border:2px solid var(--bone)}
#respawnChart:not(.tdm) .tdmOnly{display:none}

.rcPins{position:absolute;inset:0}
.rcPin,.rcOffer{position:absolute;left:0;top:0;visibility:hidden;will-change:transform}
/* A tap target over each offered tile: the hex itself is a fingertip wide
   at best on a phone. */
.rcOffer{width:48px;height:48px;margin:-24px 0 0 -24px;border-radius:50%;pointer-events:auto;cursor:pointer;padding:0;
  display:flex;align-items:center;justify-content:center;color:var(--ink);
  background:var(--m-brass);border:2px solid var(--brass-deep);box-shadow:0 0 0 3px rgba(255,195,77,.35),0 4px 12px rgba(0,0,0,.55);
  transition:box-shadow .2s,background .2s}
.rcOffer .ico{width:24px;height:24px}
.rcOffer:hover,.rcOffer:focus-visible{box-shadow:0 0 0 5px rgba(255,195,77,.55),0 4px 14px rgba(0,0,0,.6);outline:none}
.rcOffer.on{background:var(--m-wax);color:#fbeede;border-color:var(--wax-lo);box-shadow:0 0 0 4px rgba(255,236,200,.8),0 0 0 9px rgba(207,59,45,.35),0 4px 16px rgba(0,0,0,.6)}
/* Never `scale` on these: the individual transform properties apply outside
   `transform`, so a scaled pin scales its own translate and flies off its tile. */
.rcOffer.on .ico{transform:scale(1.15)}
#respawnChart.diving .rcOffer:not(.on),#respawnChart.diving .rcLegend,#respawnChart.diving .rcHead{opacity:0;transition:opacity .3s}
#respawnChart.diving .rcOffer{pointer-events:none}
.rcPin{width:28px;height:28px;margin:-14px 0 0 -14px;border-radius:50%;display:flex;align-items:center;justify-content:center;pointer-events:none}
.rcPin .ico{width:18px;height:18px}
.rcWreck{background:rgba(20,8,6,.85);border:2px solid var(--blood);color:#ffb3a3;box-shadow:0 2px 8px rgba(0,0,0,.6)}
.rcKraken{background:rgba(40,6,14,.85);border:2px solid #e0303c;color:#ff9aa2}
.rcAlly{width:16px;height:16px;margin:-8px 0 0 -8px;background:var(--pin,#1f4fb0);border:2px solid var(--bone);box-shadow:0 1px 5px rgba(0,0,0,.6)}

#cineToast{position:absolute;left:50%;top:max(120px,calc(env(safe-area-inset-top) + 110px));transform:translate(-50%,-6px);padding:8px 16px;
  border-radius:var(--r-m);background:rgba(26,14,10,.92);border:1px solid rgba(207,74,51,.65);color:#ffd7cc;font-size:var(--t-m);
  opacity:0;transition:opacity .3s,transform .3s;pointer-events:none;max-width:calc(100% - 24px);text-align:center}
#cineToast.shown{opacity:1;transform:translate(-50%,0)}

/* Phones: the card is a sheet along the foot of the screen (the globe is
   lifted above it), the legend folds away, the heading gets smaller. */
@media (max-width:700px),(max-height:520px){
  #hud.onGlobe #deathCard{left:8px;right:8px;width:auto;bottom:max(8px,env(safe-area-inset-bottom));max-height:40vh;overflow-y:auto;padding:8px 10px}
  .rcLegend{display:none}
  .rcHead{top:max(46px,calc(env(safe-area-inset-top) + 40px));padding:6px 12px 7px}
  .rcHead h3{font-size:var(--t-l)}
  .rcSub{font-size:var(--t-xs)}
}
@media (orientation:landscape) and (max-height:520px){
  #hud.onGlobe #deathCard{left:auto;right:8px;width:min(360px,46%);max-height:calc(100% - 16px)}
}
/* ---------- HUD indicators: wind, brace & salvage buffs, bounty, hazards ----------
   Each built by its own module in client/hud/ (windIndicator.js,
   braceIndicator.js, bountyIndicator.js, hazardHud.js), which used to inject
   these rules itself. Linked before touch.css, which stays last (brief §5). */

/* ---- the wind (client/hud/windIndicator.js) ----
   Above the heading/hull plate beside the compass (it used to sit where that
   plate is now), in the theme's wood-and-brass chip. */
.windInd{position:absolute;left:172px;bottom:134px;display:none;align-items:center;gap:10px;
  padding:4px 14px 4px 4px;border-radius:var(--r-pill);background:var(--m-wood);
  border:1px solid rgba(201,162,78,.45);box-shadow:var(--sh-plate);color:var(--bone);
  font:600 15px/1.2 "Alegreya Sans", system-ui, sans-serif;letter-spacing:.03em;pointer-events:none}
.windInd.shown{display:flex}
/* Sized up after the first playtest: "UI is a little small for the wind". The
   point of sail is what explains a slow ship, so it gets the weight. */
.windInd svg{width:54px;height:54px;flex:none}
.windInd .wArrow{transform-origin:50% 50%;transform-box:view-box}
.windInd .wForce{display:flex;gap:2px;margin-top:3px}
.windInd .wForce i{display:block;width:13px;height:5px;border-radius:1px;background:rgba(232,220,192,.22)}
.windInd .wForce i.on{background:#e8dcc0}
.windInd .wPos{opacity:.95;font-weight:700;font-size:15px}
.windInd.irons .wPos{color:#ff8a6a}
.windInd.best .wPos{color:#9fe0a0}
@media (pointer:coarse){ .windInd{left:max(10px,env(safe-area-inset-left));top:128px;bottom:auto;font-size:13px} .windInd svg{width:44px;height:44px} .windInd .wPos{font-size:13px} }
/* Portrait stacks the compact compass under the top buttons, with the heading
   plate below it: sit under that, not on it. */
@media (pointer:coarse) and (orientation:portrait){ .windInd{top:166px} }

/* ---- brace & repair, and the salvage buffs (client/hud/braceIndicator.js) ---- */
.braceInd{position:absolute;left:50%;bottom:92px;transform:translateX(-50%);display:none;min-width:170px;
  padding:6px 10px;border-radius:6px;background:rgba(14,18,22,.6);color:#e8dcc0;text-align:center;
  font:600 12px/1.3 system-ui,sans-serif;letter-spacing:.04em;pointer-events:none}
.braceInd.shown{display:block}
.braceInd.hint{opacity:.7;min-width:0;padding:3px 9px;font-weight:500}
.braceInd .bTitle kbd{display:inline-block;min-width:16px;padding:0 4px;margin-right:6px;border:1px solid rgba(232,220,192,.6);border-radius:3px;font:inherit}
.braceInd .bBar{height:5px;margin:5px 0 3px;border-radius:2px;background:rgba(232,220,192,.18);overflow:hidden}
.braceInd .bBar i{display:block;height:100%;width:0;background:#9fe0a0}
.braceInd.bracing .bBar i{background:#e8dcc0}
.braceInd.blocked .bBar i{background:#ff8a6a}
.braceInd .bNote{font-weight:500;opacity:.8;font-size:11px}
.braceInd.hint .bBar,.braceInd.hint .bNote{display:none}
.mechBuffs{position:absolute;left:50%;bottom:62px;transform:translateX(-50%);display:flex;gap:6px;pointer-events:none}
.mechBuffs .chip{padding:2px 8px;border-radius:10px;background:rgba(14,18,22,.6);color:#e8dcc0;font:600 11px/1.4 system-ui,sans-serif}
.mechBuffs .chip.powder{box-shadow:inset 0 0 0 1.5px #e0482f}
.mechBuffs .chip.quick{box-shadow:inset 0 0 0 1.5px #f2c14e}
@media (pointer:coarse){ .braceInd{bottom:auto;top:64px} .mechBuffs{bottom:auto;top:40px} .braceInd .bTitle kbd{display:none} }

/* ---- the bounty (client/hud/bountyIndicator.js) ---- */
.bountyArrow{position:absolute;left:0;top:0;display:none;width:44px;height:44px;margin:-22px 0 0 -22px;pointer-events:none}
.bountyArrow.shown{display:block}
.bountyArrow svg{width:100%;height:100%;filter:drop-shadow(0 1px 3px rgba(0,0,0,.7))}
.bountyArrow .bRot{transform-origin:22px 22px}
.bountyArrow .bVal{position:absolute;left:0;right:0;top:13px;text-align:center;color:#f3e2b8;font:700 12px/1 Georgia,serif}
.bountySelf{position:absolute;left:50%;top:44px;transform:translateX(-50%);display:none;padding:3px 10px;border-radius:4px;
  background:rgba(120,20,16,.7);color:#f3e2b8;font:600 12px/1.3 system-ui,sans-serif;letter-spacing:.04em;pointer-events:none}
.bountySelf.shown{display:block}
.bountyBanner{position:absolute;left:50%;top:22%;transform:translateX(-50%);opacity:0;transition:opacity .3s;
  padding:6px 14px;border-radius:5px;background:rgba(14,18,22,.65);color:#f3e2b8;font:600 15px/1.3 Georgia,serif;
  text-align:center;pointer-events:none;white-space:nowrap}
.bountyBanner.shown{opacity:1}

/* ---- the sea's hazards (client/hud/hazardHud.js) ---- */
#hzLayer{position:absolute;inset:0;pointer-events:none;overflow:hidden}
.hzFlash{position:absolute;inset:0;background:#e8eeff;opacity:0}
.hzKraken{position:absolute;top:56px;left:50%;transform:translateX(-50%);width:min(300px,64vw);display:none;
  align-items:center;gap:8px;padding:3px 10px;border-radius:var(--r-pill);
  background:rgba(20,16,12,.5);border:1px solid rgba(168,59,42,.45);box-shadow:var(--sh-plate)}
/* One slim row, not a card: at kraken-fighting range the old two-line box sat
   right over the creature's head — the very thing you are trying to watch. */
.hzKraken.shown{display:flex}
.hzKName{font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:#ffae98;flex:none;text-shadow:0 1px 2px rgba(0,0,0,.6)}
.hzKBar{flex:1;height:6px;border-radius:3px;overflow:hidden;background:rgba(236,228,210,.12);border:1px solid rgba(236,228,210,.2)}
.hzKBar i{display:block;height:100%;width:100%;background:var(--blood);transition:width .15s ease-out}
.hzKraken.enraged .hzKBar i{animation:hzPulse .8s ease-in-out infinite}
.hzKNote{font-size:11px;color:var(--bone);opacity:.8;flex:none;max-width:40%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hzKNote:empty{display:none}
.hzKraken.hunted .hzKNote{color:var(--rope);opacity:1}
@keyframes hzPulse{50%{opacity:.55}}
.hzCallout{position:absolute;top:28%;left:50%;transform:translateX(-50%);white-space:nowrap;font-size:20px;
  color:var(--bone);text-shadow:0 2px 6px rgba(0,0,0,.8);opacity:0;transition:opacity .2s}
.hzCallout.warn{color:#dfe8ff}
.hzCallout.gold{color:var(--rope)}
.hzCallout small{display:block;font-size:13px;opacity:.85;text-align:center}
/* ---------- quick chat (client/hud/quickChat.js) ----------
   The call-out wheel: eight tarred-wood chips round a brass hub, the picked one
   brass. Mid-screen, over the sea, and never in the way of the pointer until
   it is open. The bubbles over ships are parchment — something said, to be
   read — with the ship's label colours on their rim. */
#chatWheel{position:fixed;inset:0;display:none;pointer-events:none;z-index:6;--r:170px}
#chatWheel.shown{display:block}
/* Touch: the backdrop takes the tap that closes it. */
#chatWheel.touch{pointer-events:auto;background:radial-gradient(circle at 50% 50%,rgba(8,10,12,.45),rgba(8,10,12,.15) 60%);
  touch-action:none;-webkit-tap-highlight-color:transparent}
.cwRing{position:absolute;left:50%;top:50%;width:0;height:0}
.cwHub{position:absolute;left:0;top:0;width:118px;height:118px;transform:translate(-50%,-50%);border-radius:50%;
  display:flex;align-items:center;justify-content:center;text-align:center;padding:12px;box-sizing:border-box;
  background:radial-gradient(circle at 40% 32%,rgba(38,29,21,.94),rgba(13,18,24,.94));
  box-shadow:0 0 0 3px var(--brass-lo),0 0 0 5px rgba(201,162,78,.55),0 8px 22px rgba(0,0,0,.5);
  font:var(--t-s)/1.15 var(--f-head);color:var(--bone);letter-spacing:.03em;text-shadow:0 1px 2px rgba(0,0,0,.8)}
/* A brass notch on the hub's rim, turned toward the pick: it runs from the
   centre and is clipped to its last few pixels, just outside the hub. */
.cwPointer{position:absolute;left:0;top:0;width:16px;height:78px;margin-left:-8px;transform-origin:50% 0;
  transform:rotate(calc(var(--ang,0rad) + 180deg));background:var(--brass-hi);
  clip-path:polygon(0 83%,100% 83%,50% 100%);opacity:0;transition:opacity .12s}
.cwPointer.shown{opacity:.9}
.cwSlice{position:absolute;left:0;top:0;pointer-events:auto;cursor:pointer;
  transform:translate(-50%,-50%) translate(calc(var(--x) * var(--r)),calc(var(--y) * var(--r)));
  display:flex;align-items:center;gap:7px;padding:7px 13px 7px 8px;border-radius:var(--r-m);white-space:nowrap;
  background:var(--m-wood);border:1px solid rgba(201,162,78,.5);box-shadow:var(--sh-plate);
  font:var(--t-m)/1 var(--f-head);letter-spacing:.03em;color:var(--bone);text-shadow:0 1px 2px rgba(0,0,0,.8);
  transition:transform .08s ease-out,background-color .08s}
.cwSlice b{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;
  font:600 var(--t-xs)/1 var(--f-body);color:var(--brass-hi);background:rgba(0,0,0,.35);box-shadow:inset 0 0 0 1px rgba(201,162,78,.55);text-shadow:none}
.cwSlice.on{background:var(--m-brass);border-color:var(--brass-deep);color:var(--ink);text-shadow:none;
  transform:translate(-50%,-50%) translate(calc(var(--x) * var(--r)),calc(var(--y) * var(--r))) scale(1.08)}
.cwSlice.on b{color:var(--ink);background:rgba(255,255,255,.3);box-shadow:inset 0 0 0 1px rgba(42,31,20,.4)}
/* Over the limit: the chips go dim, the hub says how long. */
#chatWheel.quiet .cwSlice{opacity:.45;filter:saturate(.3)}
#chatWheel.quiet .cwHub{color:var(--brass-hi)}
#chatWheel.refused .cwHub{animation:cwNo .35s ease-in-out}
@keyframes cwNo{0%,100%{transform:translate(-50%,-50%)}25%{transform:translate(calc(-50% - 6px),-50%)}75%{transform:translate(calc(-50% + 6px),-50%)}}

/* The bubbles. Positioned by transform alone, like the labels (hud.js). */
#chatBubbles{position:fixed;inset:0;pointer-events:none}
.chatBubble{position:absolute;left:0;top:0;transform-origin:50% 100%;will-change:transform,opacity;
  padding:5px 11px 6px;border-radius:var(--r-l);white-space:nowrap;
  background:var(--m-parch);color:var(--ink);font:600 var(--t-m)/1.1 var(--f-body);
  box-shadow:0 0 0 1.5px var(--parch-edge),0 4px 12px rgba(0,0,0,.45)}
.chatBubble::after{content:"";position:absolute;left:50%;bottom:-7px;width:12px;height:12px;margin-left:-6px;transform:rotate(45deg);
  background:var(--parch-lo);box-shadow:1.5px 1.5px 0 0 var(--parch-edge)}
.chatBubble.ally{box-shadow:0 0 0 2px #3f8f9a,0 4px 12px rgba(0,0,0,.45)}
.chatBubble.ally::after{box-shadow:2px 2px 0 0 #3f8f9a}
.chatBubble.mine{box-shadow:0 0 0 2px var(--brass),0 4px 12px rgba(0,0,0,.45)}
.chatBubble.mine::after{box-shadow:2px 2px 0 0 var(--brass)}
.chatBubble.pop{animation:cbPop .22s cubic-bezier(.3,1.6,.5,1)}
@keyframes cbPop{from{scale:.6}to{scale:1}}

/* The feed line: a name, and what they said in parchment. */
.killRow.say{border-left-color:var(--parch-edge)}
.killRow.say .said{color:var(--parch)}
.killRow.say .ally{color:#9fe0e6}
.killRow.say.you{border-left-color:var(--brass-hi)}

/* Under the dive, with the rest of the HUD (transition.css). */
#hud.cine:not(.onGlobe) > :is(#chatWheel,#chatBubbles){opacity:0 !important}

/* The touch button: a speech bubble left of Scores. Hidden (with #touch) on
   anything without a touch screen. */
#chatBtn{--a:var(--ta-rest);transition:--a .7s ease;position:absolute;
  right:calc(max(12px,env(safe-area-inset-right)) + 86px);top:max(10px,env(safe-area-inset-top));
  width:44px;height:44px;border-radius:var(--r-m);display:flex;align-items:center;justify-content:center;
  background:rgb(34 24 16 / calc(.25 + var(--a) * .7));border:1px solid rgb(201 162 78 / calc(.25 + var(--a) * .3));
  box-shadow:0 2px 8px rgb(0 0 0 / calc(var(--a) * .5))}
#chatBtn svg{width:24px;height:24px;fill:var(--bone);filter:drop-shadow(0 1px 1px rgba(0,0,0,.7))}
#chatBtn svg circle{fill:rgb(34 24 16)}
#chatBtn.on{--a:.95;transition-duration:.08s;background:var(--m-brass);border-color:var(--brass-deep)}
#chatBtn.on svg{fill:var(--ink)}
#chatBtn.on svg circle{fill:var(--brass-hi)}
@media (pointer:coarse){
  #chatWheel{--r:min(122px,30vw)}
  .cwHub{width:92px;height:92px;font-size:var(--t-xs)}
  .cwPointer{height:60px}
  .cwSlice{font-size:var(--t-s);padding:9px 10px 9px 7px;min-height:var(--tap);box-sizing:border-box}
  .cwSlice b{display:none}
}
/* A phone held upright has no room for the ring's width: the chips stack in
   two columns instead, in pairs under the hub. */
@media (pointer:coarse) and (orientation:portrait) and (max-width:520px){
  #chatWheel{--r:0px}
  .cwRing{left:12px;right:12px;top:26%;width:auto;height:auto;display:grid;grid-template-columns:1fr 1fr;gap:10px}
  .cwHub{position:static;grid-column:1 / -1;justify-self:center;transform:none;width:auto;height:auto;border-radius:var(--r-pill);padding:10px 18px}
  .cwPointer{display:none}
  .cwSlice,.cwSlice.on{position:static;transform:none;justify-content:center}
  #chatWheel.refused .cwHub{animation:none}
}
/* ---------- The first-match guide (client/hud/guide.js) ----------
   One parchment chip, high and centred: under the match banner (14px) and the
   kraken's bar (56px), over sky rather than the ship or the water the
   broadsides fall on. Parchment because it is something to read; a brass rim
   because it sits over the sea like the other plates. Linked before touch.css,
   which stays last (brief §5). */
#guide{position:absolute;left:50%;top:92px;transform:translate(-50%,-6px);display:flex;align-items:center;gap:10px;
  width:max-content;max-width:min(560px,calc(100vw - 32px));padding:7px 8px 7px 8px;border-radius:var(--r-l);
  background:var(--m-parch);color:var(--ink);border:1px solid var(--brass-lo);
  box-shadow:0 0 0 1px rgba(240,215,143,.35) inset,var(--sh-plate);
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .35s ease-out,transform .35s ease-out,visibility 0s linear .35s}
#guide.shown{opacity:1;visibility:visible;transform:translate(-50%,0);transition:opacity .35s ease-out,transform .35s ease-out,visibility 0s}
/* The step: a brass disc with "2/4", a tick once it is done. */
#guide .gStep{flex:none;display:grid;place-items:center;width:34px;height:34px;border-radius:50%;
  background:var(--m-brass-ring);color:var(--ink);font:700 12px/1 var(--f-body);font-variant-numeric:tabular-nums;
  box-shadow:0 0 0 2px rgba(42,31,20,.55) inset,0 1px 2px rgba(0,0,0,.35);transition:transform .25s ease-out}
#guide.ticked .gStep{background:radial-gradient(circle at 40% 35%,#8fd49a,#3f8f52 70%,#2a6639);color:#f6ffef;font-size:18px;transform:scale(1.08)}
#guide[data-step="brace"] .gStep{font-size:17px}
#guide .gText{display:flex;flex-direction:column;gap:1px;min-width:0}
#guide .gTitle{font:normal var(--t-l)/1.15 var(--f-head);letter-spacing:.02em;color:var(--ink)}
#guide.ticked .gTitle{color:#2f6b3c}
#guide .gHow{font-size:var(--t-s);line-height:1.45;color:var(--ink-2)}
#guide .gHow:empty{display:none}
#guide kbd,.smControls kbd{background:rgba(134,98,42,.12);border-color:rgba(91,66,25,.55);color:var(--ink);font-weight:700}
.smControls kbd{margin:0 3px 0 0}
#guide.note .gStep{font-size:17px}
/* Skip: quiet, but a real target. The only part of the chip that takes a click. */
#guide .gSkip{flex:none;align-self:flex-start;width:28px;height:28px;margin:-2px -2px 0 2px;border:0;border-radius:50%;
  background:none;color:var(--ink-soft);font-size:18px;line-height:1;cursor:pointer;pointer-events:auto}
#guide .gSkip:hover,#guide .gSkip:focus-visible{background:rgba(134,98,42,.16);color:var(--ink)}
#guide.ticked .gSkip,#guide.note .gSkip{visibility:hidden}

/* While the guide teaches bracing, the brace plate's own one-line hint would
   say it twice; the plate still shows the bracing itself. */
#hud.guideBrace .braceInd.hint{visibility:hidden}

/* The keyboard help panel stands down while the guide is teaching (it would be
   the same lesson twice), keeping its box so the dials above it don't jump. */
#help.guided{opacity:0}

/* The settings menu's Help page (client/ui/settingsMenu.js "action"/"info"). */
.smAction{min-height:38px}
.smSaid{font-size:var(--t-s);color:var(--ink-soft);font-style:italic}
.smRow.smInfo{align-items:start;grid-template-columns:minmax(0,.55fr) minmax(0,1.45fr)}
.smControls{display:flex;flex-direction:column;gap:4px;width:100%;font-size:var(--t-s);color:var(--ink-2)}
.smCtlRow{display:grid;grid-template-columns:minmax(92px,auto) 1fr;gap:10px;align-items:baseline}
.smCtlRow > span:first-child{white-space:nowrap}

/* Phones: smaller. Upright, under the compass and the wind (top-left) and
   over the horizon, above the masthead. On its side the top row is the
   compass, the match banner and the buttons, so it drops to the foot of the
   screen between the stick and the fire wheel, over the wake. */
@media (pointer:coarse){
  #guide{gap:8px;padding:5px 6px;max-width:min(420px,calc(100vw - 24px))}
  #guide .gStep{width:28px;height:28px;font-size:11px}
  #guide .gTitle{font-size:var(--t-m)}
  #guide .gHow{font-size:12px;line-height:1.35}
  #guide .gSkip{width:32px;height:32px}
}
@media (pointer:coarse) and (orientation:portrait){
  #guide{top:228px}
}
@media (pointer:coarse) and (orientation:landscape){
  #guide{top:auto;bottom:calc(10px + env(safe-area-inset-bottom));max-width:min(460px,calc(100vw - 360px))}
}
@media (prefers-reduced-motion:reduce){
  #guide,#guide.shown{transform:translate(-50%,0);transition:opacity .2s linear,visibility 0s}
  #guide .gStep,#guide.ticked .gStep{transition:none;transform:none}
}
/* ---------- touch controls ----------
   LAST in the cascade, on purpose (brief §5): a media query adds no
   specificity, so every touch override has to come after the rule it beats.
   New touch-only rules for anything above go at the bottom of this file. */
/* touch-action/user-select/callout together stop iOS treating a held
   control as a text selection and popping the magnifier bubble over it. */
#touch{position:absolute;inset:0;display:none;pointer-events:none;
  touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;-webkit-tap-highlight-color:transparent}
#touch>*{pointer-events:auto;touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}

/* ---- see-through at rest ----
   The controls are glass over the sea until a thumb is on them or they have
   something to say. `--a` is each control's body opacity: the player's "Touch
   control opacity" setting at rest (--ta-rest, written by client/hud/touch.js),
   near-solid while pressed (.on/.active) or for a beat after a gun reloads or
   the special comes ready (.hot). Only the *body* fades — backgrounds, rims,
   shadows. The things read at a glance (the nav lights, the ready arrows, the
   reload scrim, the special's ready ring) keep their own strength, so
   readiness never gets quieter along with the chrome.
   Registered so it can transition: in fast, out slow. Browsers without
   @property simply switch. */
@property --a{syntax:"<number>";inherits:true;initial-value:1}
#touch{--ta-rest:.45}
#stick,#fireWheel,#specialBtn,#braceBtn,#scoresBtn{--a:var(--ta-rest);transition:--a .7s ease}
#stick.active,#fireWheel.on,#fireWheel.hot,#specialBtn.on,#specialBtn.hot,#braceBtn.on,#scoresBtn.on{--a:.95;transition-duration:.08s}

/* The helm: a brass-rimmed well with a faint ship's wheel on its floor (under
   the knob, not on it: the knob is pushed, a wheel on it would promise a twist
   that does nothing). Tucked into the corner so the thumb finds it without
   the well eating into the sea. */
#stick{position:absolute;left:max(14px,env(safe-area-inset-left));bottom:max(14px,env(safe-area-inset-bottom));width:144px;height:144px;border-radius:50%;
  background:radial-gradient(circle,rgb(13 18 24 / calc(var(--a) * .5)) 58%,rgb(13 18 24 / calc(var(--a) * .8)) 100%);
  box-shadow:0 0 0 3px rgb(201 162 78 / calc(.3 + var(--a) * .35)),0 0 0 4px rgb(60 40 10 / calc(var(--a) * .6)),0 6px 16px rgb(0 0 0 / calc(var(--a) * .45)),inset 0 3px 10px rgb(0 0 0 / calc(var(--a) * .5));
  display:flex;align-items:center;justify-content:center}
#stick::before{content:"";position:absolute;inset:12px;background-color:var(--brass);opacity:calc(.08 + var(--a) * .2);
  -webkit-mask:url("/icons/helm.png") center/contain no-repeat;mask:url("/icons/helm.png") center/contain no-repeat}
#stickKnob{width:60px;height:60px;border-radius:50%;background:var(--m-brass);opacity:calc(.5 + var(--a) * .5);
  box-shadow:0 3px 8px rgba(0,0,0,.55),inset 0 2px 0 rgba(255,245,210,.7),inset 0 -3px 6px rgba(60,40,10,.4);
  will-change:transform;transition:transform .06s linear}
#stick.active #stickKnob{transition:none}

/* One cannonball split down the middle: port to the left of the seam,
   starboard to the right, both broadsides one thumb-roll apart — cast iron
   with the light off its upper left, and an arrow on each half pointing the
   way that side fires. A control that looks like the thing it does needs
   less label. */
#fireWheel{position:absolute;right:max(14px,env(safe-area-inset-right));bottom:max(14px,env(safe-area-inset-bottom));width:172px;height:172px;display:flex;
  border-radius:50%;
  background:radial-gradient(circle at 33% 26%, rgb(185 191 199 / calc(var(--a) * .9)) 0%, rgb(123 129 138 / var(--a)) 8%, rgb(74 79 87 / var(--a)) 22%, rgb(38 41 47 / var(--a)) 45%, rgb(20 22 26 / var(--a)) 70%, rgb(10 12 15 / var(--a)) 100%);
  box-shadow:0 0 0 3px rgb(201 162 78 / calc(.3 + var(--a) * .35)),0 0 0 4px rgb(60 40 10 / calc(var(--a) * .6)), inset 0 -18px 30px rgb(0 0 0 / calc(var(--a) * .7)),
             inset 0 12px 20px rgb(255 255 255 / calc(var(--a) * .05)), 0 6px 16px rgb(0 0 0 / calc(var(--a) * .55))}
.fireHalf{position:relative;flex:1;overflow:hidden;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:5px;color:var(--bone);font-family:var(--f-head);font-size:13px;
  letter-spacing:.06em;text-shadow:0 1px 2px rgba(0,0,0,.8)}
#fireP{border-radius:86px 0 0 86px}
/* The casting seam, on the starboard half so it lands dead centre. */
#fireS{border-radius:0 86px 86px 0;box-shadow:inset 1px 0 0 rgb(0 0 0 / calc(.2 + var(--a) * .3)), inset 2px 0 0 rgba(255,255,255,.05)}
/* Which way this half fires. Chunky, so it survives a thumb over it. */
.fireHalf::after{content:"";width:0;height:0;border-top:13px solid transparent;border-bottom:13px solid transparent;
  position:relative;z-index:1;opacity:.7;transition:opacity .12s;filter:drop-shadow(0 1px 2px rgba(0,0,0,.7))}
#fireP::after{border-right:15px solid var(--bone)}
#fireS::after{border-left:15px solid var(--bone)}
.fireHalf.ready::after{border-right-color:var(--brass-hi);border-left-color:var(--brass-hi);opacity:1}
.fireHalf .lbl{opacity:calc(.55 + var(--a) * .45)}
.fireHalf.ready .lbl,#specialBtn.ready .lbl{color:var(--brass-hi)}
/* Each half carries its side's navigation light, as the desktop dials do —
   red to port, green to starboard, hung on the outboard edge. A dim lamp is
   a gun still loading; lit and glowing is a broadside ready to go. This is
   the at-a-glance read, so it never fades with the body. */
.fireHalf::before{content:"";position:absolute;top:50%;width:11px;height:11px;margin-top:-5.5px;border-radius:50%;z-index:1;
  opacity:.4;box-shadow:inset 0 1px 1px rgba(255,255,255,.35),0 0 0 1.5px rgba(10,8,4,.7);transition:opacity .15s,box-shadow .15s}
#fireP::before{left:11px;background:var(--port)}
#fireS::before{right:11px;background:var(--stbd)}
#fireP.ready::before{opacity:1;box-shadow:inset 0 1px 1px rgba(255,255,255,.45),0 0 0 1.5px rgba(10,8,4,.7),0 0 10px 2px var(--port)}
#fireS.ready::before{opacity:1;box-shadow:inset 0 1px 1px rgba(255,255,255,.45),0 0 0 1.5px rgba(10,8,4,.7),0 0 10px 2px var(--stbd)}
.fireHalf.on,#specialBtn.on,#braceBtn.on{background:rgba(201,162,78,.35)}
/* The wash is the *unavailable* part: a dark scrim that drains away as the gun
   reloads, so ready is clean iron. A running ability keeps a warm wash,
   because there the shrinking bar is time you still have. Stronger than the
   body at rest, so a loading gun reads as loading even through glass. */
.fill{position:absolute;left:0;right:0;bottom:0;height:0%;background:rgb(6 8 11 / calc(.42 + var(--a) * .24));pointer-events:none;transition:height .1s linear}
.draining .fill{background:rgba(201,162,78,.34)}
.lbl,.cd{position:relative;z-index:1}
.cd{position:absolute;bottom:12px;font-family:var(--f-body);font-size:12px;font-weight:700;opacity:.9;z-index:1;font-variant-numeric:tabular-nums;text-shadow:0 1px 2px rgba(0,0,0,.8)}

/* The special rides the thumb's arc up and inboard of the wheel, rather than
   stacked above it, so the right edge of the screen stays sea. */
#specialBtn{position:absolute;right:calc(max(14px,env(safe-area-inset-right)) + 150px);bottom:calc(max(14px,env(safe-area-inset-bottom)) + 142px);width:72px;height:72px;border-radius:50%;overflow:hidden;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;
  background:radial-gradient(circle at 34% 27%, rgb(67 71 78 / var(--a)) 0%, rgb(42 45 51 / var(--a)) 45%, rgb(21 23 27 / var(--a)) 100%);
  box-shadow:0 0 0 3px rgb(201 162 78 / calc(.3 + var(--a) * .35)),0 0 0 4px rgb(60 40 10 / calc(var(--a) * .6)),0 6px 14px rgb(0 0 0 / calc(var(--a) * .5));
  color:var(--bone);font-size:8px;letter-spacing:.04em;text-transform:uppercase}
/* Ready is a full-strength ring and glow whatever the body is doing. */
#specialBtn.ready{box-shadow:0 0 0 3px var(--brass-hi),0 0 0 4px rgba(60,40,10,.6),0 0 14px rgba(242,200,103,.5),0 6px 14px rgb(0 0 0 / calc(var(--a) * .5))}
#specialBtn .fill{border-radius:0}
#specialBtn .specIcon{position:relative;z-index:1;width:38px;height:38px;color:var(--bone);opacity:calc(.55 + var(--a) * .45);filter:drop-shadow(0 1px 2px rgba(0,0,0,.8))}
#specialBtn.ready .specIcon{color:var(--brass-hi);opacity:1}
#specialBtn .lbl{display:none}
#specialBtn .cd{bottom:7px}

/* Brace (built by client/hud/touch.js when the room has repair on): straight
   above the wheel, the other end of the thumb's arc from the special. */
#braceBtn{display:none;position:absolute;right:calc(max(14px,env(safe-area-inset-right)) + 58px);bottom:calc(max(14px,env(safe-area-inset-bottom)) + 184px);
  width:56px;height:56px;border-radius:50%;
  background:rgb(20 26 30 / calc(var(--a) * .7));box-shadow:0 0 0 2px rgb(214 196 150 / calc(.35 + var(--a) * .4)),0 4px 10px rgb(0 0 0 / calc(var(--a) * .45));
  color:var(--bone);font:600 11px/56px var(--f-head);text-align:center;letter-spacing:.06em;text-transform:uppercase;text-shadow:0 1px 2px rgba(0,0,0,.8)}
#braceBtn.shown{display:block}

#scoresBtn{position:absolute;right:max(12px,env(safe-area-inset-right));top:max(10px,env(safe-area-inset-top));min-height:44px;display:flex;align-items:center;padding:0 14px;border-radius:var(--r-m);
  font-family:var(--f-head);font-size:var(--t-s);background:rgb(34 24 16 / calc(.25 + var(--a) * .7));border:1px solid rgb(201 162 78 / calc(.25 + var(--a) * .3));color:var(--bone);
  text-shadow:0 1px 2px rgba(0,0,0,.8);box-shadow:0 2px 8px rgb(0 0 0 / calc(var(--a) * .5))}
#scoresBtn.on{background:var(--m-brass);border-color:var(--brass-deep);color:var(--ink);text-shadow:none}

/* On a touch device every control paints its own cooldown, so the desktop
   dials and the keyboard help are both redundant. */
@media (pointer:coarse){ #touch{display:block} #help,#cooldowns{display:none} }

/* ---- touch overrides for the W2-ui panels (after everything they beat) ---- */
@media (pointer:coarse){
  #aimHint{bottom:auto;top:96px;white-space:normal;max-width:calc(100% - 24px);text-align:center}
  #aimHint kbd{display:none}
  /* Over the controls while sunk: there is nothing to steer, and the next
     hull is the one thing worth tapping. */
  #deathCard{top:44%;padding:12px 14px 10px;gap:6px;z-index:8}
  #fps{white-space:nowrap}
  #dcTitle{font-size:32px}
  #dcBy{font-size:var(--t-s)}
  #respawnPicker .shipRowBtn kbd{display:none}
  #scoreboard{top:60px}
  #roomChip{top:auto;bottom:auto}
}
/* Portrait: the top row is the menu, the way home and Scores, with no room
   left between them for the banner — so it moves under the row, beside the
   binnacle, and the feed steps down under it. Four hulls a row, icon over
   name, keeps the death card short enough to leave the sinking visible. */
@media (pointer:coarse) and (orientation:portrait){
  #matchState{left:128px;top:62px;transform:none;max-width:calc(100% - 140px)}
  #matchLead{overflow:hidden;text-overflow:ellipsis}
  #killFeed{top:100px}
  #respawnPicker .shipRow{grid-template-columns:repeat(4,1fr);gap:5px}
  #respawnPicker .shipRowBtn{flex-direction:column;justify-content:center;gap:3px;min-height:54px;padding:4px 2px;font-size:11px;text-align:center}
  #respawnPicker .shipRowBtn .abilityIcon{width:20px;height:20px}
  #respawnPicker .shipRowBtn .nm{white-space:normal;line-height:1.1}
}
@media (pointer:coarse) and (orientation:landscape){
  #deathCard{top:50%;width:min(520px,calc(100% - 300px));max-height:calc(100% - 16px);overflow-y:auto}
  #deathCard .dcHead .ico{width:22px;height:22px}
  #dcTitle{font-size:26px}
  #dcCountdown b{width:38px;height:38px;font-size:19px}
  #respawnPicker .shipRow{grid-template-columns:repeat(4,1fr)}
  #respawnPicker .shipRowBtn{min-height:32px;font-size:12px;padding:0 6px}
  #respawnPicker .lbl{display:none}
  #scoreboard{top:10px;max-height:calc(100% - 20px);overflow:hidden}
  #overlay .endCard{padding:8px 14px 10px}
}
/* ---- compact HUD (setting "Compact HUD", on by default) --------------------
   The playtest on a phone: the binnacle and log plate were two opaque slabs
   in the top-left, a quarter of the screen with the controls. Compact keeps
   what is read mid-fight — the card turning, heading and knots, a hull bar
   whose colour says how bad it is — and drops what is not: the compass-point
   name (the card shows it) and the "Hull 70%" line (the bar and its amber/red
   say it). The plate turns to smoked glass. #hud.compact is set by
   client/hud/touch.js; it only means anything on a coarse pointer, so a
   desktop never sees it. */
@media (pointer:coarse){
  #hud.compact #compass{top:max(58px,calc(env(safe-area-inset-top) + 48px));left:max(12px,env(safe-area-inset-left));width:76px;height:76px}
  #hud.compact #hull{top:max(140px,calc(env(safe-area-inset-top) + 130px));left:max(12px,env(safe-area-inset-left));width:76px;padding:4px 6px 5px;
    background:rgba(24,17,11,.5);border-color:rgba(201,162,78,.3);box-shadow:none}
  #hud.compact #hull .logRow{margin-bottom:4px;gap:2px;text-shadow:0 1px 2px rgba(0,0,0,.8)}
  #hud.compact #hull .logRow b{font-size:12px}
  #hud.compact #hull .logRow span{font-size:9px}
  #hud.compact #headingPoint{display:none}
  #hud.compact #headingText{margin-right:auto}
  #hud.compact #hull .hullHead{display:none}
  #hud.compact #hull .hullBar{height:4px}
  #hud.compact #matchState{background:rgba(24,17,11,.55)}
  #hud.compact .killRow{background:rgba(24,17,11,.5)}
}
@media (pointer:coarse) and (orientation:portrait){
  #hud.compact #matchState{left:100px;max-width:calc(100% - 112px)}
}
@media (pointer:coarse) and (orientation:landscape){
  #hud.compact #hudCorner{left:max(98px,calc(env(safe-area-inset-left) + 86px))}
  #hud.compact #compass{top:10px}
  #hud.compact #hull{top:92px}
  #hud.compact #killFeed{left:max(98px,calc(env(safe-area-inset-left) + 86px))}
}
/* The menu and way-home plates go to smoked glass with the rest, and grow to
   a full 44px thumb target while they're at it. */
@media (pointer:coarse){
  #hud.compact #hudCorner .btn.hud{min-height:44px;background:rgba(24,17,11,.45);border-color:rgba(201,162,78,.3);box-shadow:none;opacity:1;text-shadow:0 1px 2px rgba(0,0,0,.8)}
  #hud.compact #hudCorner .btn.hud.icon{width:44px}
}
