: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;pointer-events:none;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,#boardPanel{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}
#start[data-view="board"] #boardPanel{display:block}
#start[data-view="board"] #harbourVeil{opacity:.75}
#start[data-view="board"] #destPin,#start[data-view="harbour"] #destPin,#start[data-view="shop"] #destPin{display:none}

/* ---- 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}
/* The fit (W4-upgrades): two pickers side by side and the trade in chips. */
#shipFit{display:grid;grid-template-columns:1fr 1fr;gap:6px var(--s3)}
.fitPick{display:flex;flex-direction:column;gap:2px;min-width:0}
.fitPick .eyebrow{color:var(--brass-lo)}
.fitPick select{min-width:0;min-height:34px;padding:0 8px;border-radius:var(--r-s);font:inherit;font-size:var(--t-s);color:var(--ink);
  background:rgba(255,248,230,.55);border:1px solid rgba(134,98,42,.45);cursor:pointer}
.fitPick select:focus-visible{outline:2px solid var(--brass);outline-offset:1px}
#fitChips{grid-column:1 / -1;display:flex;flex-wrap:wrap;gap:4px;min-height:22px;align-items:center}
.fitChip{font-size:12px;line-height:1;padding:4px 7px;border-radius:999px;font-variant-numeric:tabular-nums;white-space:nowrap}
.fitChip.up{background:rgba(46,125,82,.16);color:#1f5e3b;box-shadow:inset 0 0 0 1px rgba(46,125,82,.4)}
.fitChip.down{background:rgba(160,48,36,.12);color:#8a2a1e;box-shadow:inset 0 0 0 1px rgba(160,48,36,.35)}
.fitNote{font-size:12px;color:var(--ink-soft)}
.fitNote button{font:inherit;color:var(--wax);background:none;border:0;padding:0;text-decoration:underline;cursor:pointer}

/* ---- the chandlery (client/hub/chandlery.js): the captain card's stage,
   with the shop's sheet where the ship's details were ---- */
#shopPanel{display:none}
#start[data-view="shop"] #captainCard{display:grid}
#start[data-view="shop"] #captainRow,#start[data-view="shop"] #shipInfo,
#start[data-view="shop"] #shipPrev,#start[data-view="shop"] #shipNext,#start[data-view="shop"] #shipDots{display:none}
#start[data-view="shop"] #shopPanel{display:flex}
#shopPanel{grid-column:2;grid-row:1 / -1;flex-direction:column;gap:var(--s3);min-height:0;min-width:0;pointer-events:auto;
  padding:var(--s4) var(--s5);background:var(--m-parch);color:var(--ink);border-radius:var(--r-s);
  box-shadow:inset 0 0 0 1px rgba(134,98,42,.5),var(--sh-card)}
.shopHead{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s3)}
.shopHead .cardTitle{margin:0}
.shopPurse{display:inline-flex;align-items:center;gap:6px;font-size:var(--t-l);font-variant-numeric:tabular-nums}
.shopPurse b{color:var(--ink)}
#shopPanel .coin{display:inline-block;width:16px;height:16px;border-radius:50%;flex:none;vertical-align:-2px;
  background:radial-gradient(circle at 35% 30%,#fff3c4 0 12%,#f2c867 30%,#b8862a 75%,#7a5518 100%);
  box-shadow:inset 0 0 0 1.5px rgba(122,85,24,.7)}
.shopName{margin:0;font-family:var(--f-display);font-size:var(--t-xl);color:var(--ink-2)}
.shopTabs{flex-wrap:wrap;gap:4px;background:none;padding:0;box-shadow:none}
.shopTabs button{min-height:32px;padding:0 10px;border:0;border-radius:var(--r-s);background:rgba(42,31,20,.08);color:var(--ink-2);
  font-family:var(--f-head);font-size:var(--t-s);cursor:pointer}
.shopTabs button.on{background:var(--ink);color:var(--parch,#f3e7cc)}
.shopList{display:flex;flex-direction:column;gap:4px;min-height:0;overflow-y:auto;margin:0 calc(-1 * var(--s2));padding:0 var(--s2)}
.shopRow{display:grid;grid-template-columns:36px minmax(0,1fr) auto;align-items:center;gap:var(--s3);padding:6px 8px;border-radius:var(--r-m);
  cursor:pointer;box-shadow:inset 0 0 0 1px rgba(134,98,42,.18)}
.shopRow:hover,.shopRow:focus-visible{background:rgba(134,98,42,.1);outline:none}
.shopRow.picked{box-shadow:inset 0 0 0 2px var(--brass,#c9a24e);background:rgba(242,200,103,.14)}
.shopRow.wearing .shopText b::after{content:" · wearing";font-family:var(--f-body,inherit);font-size:12px;color:var(--brass-lo)}
.shopText{display:flex;flex-direction:column;min-width:0}
.shopText b{font-family:var(--f-head);font-weight:normal;font-size:var(--t-m);color:var(--ink)}
.shopText small{font-size:12px;line-height:1.35;color:var(--ink-soft)}
.swatch{width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  box-shadow:inset 0 0 0 1.5px rgba(42,31,20,.35),0 1px 2px rgba(0,0,0,.25);color:var(--ink);font-size:16px;background:rgba(42,31,20,.08)}
.swatch.flag{border-radius:3px;width:34px;height:24px;position:relative;overflow:hidden}
.swatch.flag::after{content:"";position:absolute;inset:2px;background:var(--ink);-webkit-mask:var(--emblem) center / contain no-repeat;mask:var(--emblem) center / contain no-repeat;
  -webkit-mask-mode:luminance;mask-mode:luminance}
.swatch.set{background:linear-gradient(135deg,#1d2f6b,#14161a);color:#f2c867}
/* The bolt-on trim (client/ships/trim.js): a figurehead's portrait, a lantern
   lit, a pattern's device on a scrap of canvas. */
.swatch.figurehead{background:#2a313b center / cover no-repeat}
.swatch.lantern{background:#1b2028}
.swatch.pattern{border-radius:3px;position:relative;overflow:hidden;background-color:#e8dcc0}
.swatch.pattern.device::after{content:"";position:absolute;inset:3px;background:#3a2f25;-webkit-mask:var(--emblem) center / contain no-repeat;mask:var(--emblem) center / contain no-repeat;
  -webkit-mask-mode:luminance;mask-mode:luminance}
/* Refits and specials (W4-upgrades) */
.swatch.unlock{font-family:var(--f-display);color:var(--wax)}
.swatch.unlock .abilityIcon{width:22px;height:22px}
.swatch.unlock .ico{width:20px;height:20px}
/* Refits one hull at a time (client/hub/chandlery.js). */
.shopHulls{display:flex;flex-wrap:wrap;gap:4px;margin:0 0 var(--s2)}
.shopHulls button{min-height:28px;padding:0 9px;font-size:11px}
/* A row that scrolls sideways (phones) never gives up its height to the list
   under it, and fades at an edge that has more behind it (--fadeL/--fadeR,
   set by client/hub/chandlery.js), so Refits, Specials and Name read as there. */
.shopTabs,.shopHulls{flex:none}
.shopTabs.scrolls,.shopHulls.scrolls{-webkit-mask-image:linear-gradient(90deg,rgb(0 0 0 / var(--fadeL,1)) 0,#000 28px,#000 calc(100% - 28px),rgb(0 0 0 / var(--fadeR,1)) 100%);
  mask-image:linear-gradient(90deg,rgb(0 0 0 / var(--fadeL,1)) 0,#000 28px,#000 calc(100% - 28px),rgb(0 0 0 / var(--fadeR,1)) 100%)}
/* The rename (shared/names.js). */
.shopRow.unlocked .shopText b::after{content:" · yours";font-family:var(--f-body,inherit);font-size:12px;color:var(--brass-lo)}
.shopText small.fitChipRow{display:flex;flex-wrap:wrap;gap:4px;margin:3px 0 2px}
.shopAct{min-height:34px;padding:0 12px;white-space:nowrap;display:inline-flex;align-items:center;gap:6px;font-variant-numeric:tabular-nums}
.shopAct s{opacity:.6;font-size:12px}
.shopAct:disabled{opacity:.55;cursor:default}
#shopPanel > .note{margin:0;font-size:12px;line-height:1.5;color:var(--ink-soft)}

/* ---- 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,#boardPanel{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}
/* ---- leaderboard (client/hub/leaderboard.js) ---- */
#boardPanel{width:min(560px,calc(100% - 32px))}
#boardPanel .cardTitle{margin-bottom:var(--s3)}
.lbTitleRow{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s2);flex-wrap:wrap}
.lbTitleRow .cardTitle{flex:1 1 auto}
.lbChallenge{min-height:40px;padding:0 14px;font-size:var(--t-s)}
.lbControls{display:flex;flex-wrap:wrap;gap:var(--s2);justify-content:space-between;margin-bottom:var(--s3)}
.lbSeg button{min-height:32px;padding:0 12px;font-size:12px}
.lbRow{display:grid;grid-template-columns:2.2em minmax(0,1fr) auto;column-gap:10px;align-items:baseline;padding:6px 4px;font-variant-numeric:tabular-nums}
.lbRow + .lbRow{border-top:1px dotted rgba(134,98,42,.45)}
.lbRank{color:var(--brass-lo);font-weight:700;text-align:right}
.lbName{font-size:var(--t-m);color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lbScore{font-size:var(--t-m);color:var(--ink);text-align:right}
.lbMeta{grid-column:2 / 4;font-size:11px;color:var(--ink-soft)}
.lbHead{font-family:var(--f-head);font-size:11px;letter-spacing:.06em;color:var(--brass-lo)}
.lbHead .lbName,.lbHead .lbScore{font-size:11px;color:var(--brass-lo)}
.lbHead .lbMeta{display:none}
.lbRow.you{background:rgba(242,200,103,.28);border-radius:var(--r-s,4px)}
.lbGap{text-align:center;color:var(--ink-soft);padding:2px 0}
#boardPanel .note{margin-top:var(--s3);font-size:12px;line-height:1.5;color:var(--ink-soft)}
#boardPanel .linkish{padding:0;background:none;border:0;font:inherit;color:var(--wax);text-decoration:underline;cursor:pointer}
/* The captain's name once it is locked (client/hub/captain.js). */
#captainName.locked{cursor:default}
#nameNote{display:block;margin-top:2px;font-size:11px;color:var(--ink-soft)}
#nameNote.guestNote{color:var(--ink-2)}
#nameNote .linkish{padding:0;background:none;border:0;font:inherit;color:var(--wax);text-decoration:underline;cursor:pointer}
#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,#shopPanel .btn.discord{background:#5865f2;color:#fff;border-color:#4752c4;display:inline-flex;align-items:center;gap:8px}
#papers .btn.discord:hover,#shopPanel .btn.discord:hover{background:#4752c4}
#papers .btn.discord .ico,#shopPanel .btn.discord .ico{width:18px;height:18px}
/* A guest in the Chandlery (client/hub/chandlery.js): look, but sign in to buy. */
.shopGuest{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;margin:var(--s2) 0;padding:8px 10px;border-radius:var(--r-m);background:rgba(88,101,242,.08);box-shadow:inset 0 0 0 1px rgba(71,82,196,.35)}
.shopGuest p{margin:0;flex:1 1 220px;font-size:13px;line-height:1.4;color:var(--ink-2)}
#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}
/* One line on the way to sail, under the switch (client/hub/sailBar.js). */
#howCaption{position:absolute;left:4px;top:100%;margin-top:5px;max-width:min(560px,100vw - 32px);font-size:12px;line-height:1.3;
  color:var(--parch-hi,#f2e3bf);text-shadow:0 1px 3px rgba(0,0,0,.85);pointer-events:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#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. */
/* A tablet held upright (768-1000px) takes this layout too: five ways to sail,
   a room code and "Open a room" don't fit one row there, and the commit
   button was pushed off the right edge. */
@media (max-width:760px),(max-width:1000px) and (orientation:portrait){
  #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)}
  /* --bar-space: the height the sail bar takes at the foot, measured by
     client/hub/sailBar.js (its caption can wrap); the guess is for a first frame. */
  #captainCard{top:60px;bottom:calc(var(--bar-space,calc(172px + env(safe-area-inset-bottom))) + 6px);width:calc(100% - 24px);grid-template-columns:minmax(0,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}
  #shipFit{gap:4px var(--s2)}
  .fitPick .eyebrow{display:none}
  .fitPick select{min-height:32px}
  #fitChips{min-height:0}
  #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 chandlery: the ship keeps the top of the card to try things on, the
     shop the rest; the tabs one row that scrolls sideways. */
  #start[data-view="shop"] #captainCard{grid-template-rows:minmax(130px,.75fr) minmax(0,1.5fr)}
  #shopPanel{grid-column:1;grid-row:2;padding:var(--s3) var(--s4);gap:var(--s2)}
  .shopHead .cardTitle{font-size:26px}
  .shopName{font-size:var(--t-l)}
  .shopTabs{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}
  .shopTabs button{flex:none}
  .shopHulls{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}
  .shopHulls button{flex:none}
  #shopPanel > .note{display:none}
  /* 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" "cap" "where" "go";gap:var(--s2)}
  #howCaption{grid-area:cap;position:static;margin:-2px 0 0;white-space:normal;max-width:none;text-align:center}
  #howSeg{grid-area:how;display:flex}
  /* Five ways in one row: a two-word way wraps onto two lines rather than
     being cut off at the edge of its button. */
  #howSeg button{flex:1;min-width:0;padding:0 3px;font-size:12px;letter-spacing:.02em;white-space:normal;line-height:1.05}
  .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:calc(var(--bar-space,168px) + 6px);max-height:30%}
  #tileInfo{left:12px;right:12px;top:118px;transform:none;width:auto;min-height:0}
  #chartHint{top:58px}
  #statsPanel,#boardPanel{top:auto;bottom:calc(var(--bar-space,168px) + 8px);transform:translateX(-50%);max-height:calc(100% - var(--bar-space,168px) - 76px)}
}
/* Short and wide (a phone on its side): back to two columns, and one bar. */
@media (max-height:520px) and (orientation:landscape){
  /* The mode caption rides just above the one-row bar (owner, on an iPhone
     sideways: "you can't see the text under the game types"). */
  #howCaption{top:auto;bottom:100%;left:6px;margin:0 0 3px;font-size:11px}
  #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:74px;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)}
  /* Clear of a notch or camera cutout on either side (env() is 0 where there
     is none): the card ran under an iPhone's island, cutting off Test sail
     and the special's line (owner, 2026-10-07). */
  #captainCard{left:calc(50% + (env(safe-area-inset-left) - env(safe-area-inset-right)) / 2);
    width:calc(100% - 24px - env(safe-area-inset-left) - env(safe-area-inset-right))}
  /* The ship's dots ride above the mode caption, which sits on this strip
     just over the bar (#howCaption above): they were drawn over its words. */
  #shipDots{bottom:22px}
  #shipStage{grid-column:1;grid-row:1 / span 2}
  #captainCard > #captainRow{grid-column:2;grid-row:1;padding:4px var(--s3) 2px}
  #shipInfo{grid-column:2;grid-row:2;padding:4px var(--s3) 4px;gap:4px;overflow-y:auto}
  #captainRow .eyebrow{display:none}
  #captainName{font-size:20px;min-height:32px}
  /* No room for the name's footnote here; the Log says it (client/hub/papers.js). */
  #nameNote{display:none}
  #nameDice{min-height:36px;width:40px}
  #shipName{font-size:24px}
  #shipCount{display:none}
  /* Two stats to a row, so the card fits a phone on its side unscrolled. */
  #shipStatBars{grid-template-columns:auto 1fr auto 1fr;gap:4px var(--s2)}
  .statLabel{font-size:12px}
  .statBar{height:7px}
  #shipSpecial{padding:4px var(--s2)}
  #shipSpecialIcon{width:30px;height:30px}
  #shipSpecial b{font-size:var(--t-s)}
  #shipSpecialHow{font-size:12px;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  #shipSpecial > div{min-width:0}
  #shipBlurb{display:none}
  #shipFit{gap:3px var(--s2)}
  .fitPick .eyebrow{display:none}
  .fitPick select{min-height:28px}
  #fitChips{min-height:0}
  #shopPanel{grid-column:2;grid-row:1 / span 2;padding:var(--s2) var(--s3);gap:6px}
  .shopHead .cardTitle{font-size:22px}
  .shopName,#shopPanel > .note{display:none}
  .shopTabs{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}
  .shopTabs button{flex:none;min-height:36px}
  .shopHulls{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}
  .shopHulls button{flex:none}
  .shopRow{padding:4px 6px}
  .shopAct{min-height:30px}
  /* Test sail up beside the hull's name, and the stock fit's footnote gone
     (a refit's chips stay): the card fits unscrolled on a phone on its side. */
  #shipInfo{position:relative}
  #shipTrial{position:absolute;right:var(--s3);top:4px;min-height:30px;margin:0;font-size:var(--t-s)}
  #shipTrial small{display:none}
  .shipTitle{padding-right:112px}
  .fitNote{display:none}
  .carouselNav{width:40px;height:40px}
  /* One row again, whatever the narrow-screen block above stacked: a phone
     on its side under 760px wide (an iPhone SE is 667) took the four-row bar
     and it covered half the card. Kept inside the notch on either side. */
  #startBar{left:50%;right:auto;transform:translateX(-50%);display:flex;bottom:max(8px,env(safe-area-inset-bottom));gap:var(--s2);
    max-width:calc(100% - 16px - env(safe-area-inset-left) - env(safe-area-inset-right))}
  #howSeg{display:inline-flex;flex:none}
  #howSeg button{flex:none;white-space:nowrap;line-height:normal;letter-spacing:.04em}
  #whereSlot{flex:1 1 auto;min-width:0}
  #whereChip,#roomEntry{flex:1;min-width:110px}
  #sail{width:auto;flex:none}
  #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,#boardPanel{top:50px;bottom:74px;transform:translateX(-50%);max-height:none}
  /* Sideways a phone showed the leaderboard's title, its switches and two
     rows: the title shrinks and a row's line of detail sits beside the name. */
  #boardPanel .cardTitle,#statsPanel .cardTitle{font-size:24px;margin-bottom:6px}
  .lbControls{margin-bottom:6px}
  .lbChallenge{min-height:36px}
  .lbRow{grid-template-columns:2.2em minmax(0,auto) minmax(0,1fr) auto;padding:4px}
  .lbMeta{grid-column:3;grid-row:1;text-align:right;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .lbScore{grid-column:4;grid-row:1}
}
@media (max-height:520px) and (orientation:landscape) and (max-width:720px){
  #howSeg button{padding:0 6px;font-size:11px;letter-spacing:.02em}
  #sail{min-width:132px}
  #sail.sealed{font-size:16px}
  #whereChip{min-width:110px}
}
/* The Leaderboard tab says "Ranks" where five tabs, the gear and the logo
   can't share a phone's width (the logo goes too: the title card had it). */
.tab .narrow{display:none}
@media (max-width:520px){
  #hubLogo{display:none}
  #hubTabs{flex:1;min-width:0;margin:0}
  .tab{flex:1 1 auto;min-width:0;padding:0 4px;font-size:12px;letter-spacing:.03em}
  .tab .wide{display:none}
  .tab .narrow{display:inline}
  #hubGear{flex: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)}
/* On a desktop the hull moved to the ship gauge (below): the log plate keeps
   heading and knots. A touch screen keeps it here — its foot is the stick and
   the gun wheel, which paints its own reloads (DECISIONS 52). */
@media not (pointer:coarse){
  #hull{padding-bottom:8px}
  #hull .hullHead,#hull .hullBar{display:none}
  #hull .logRow{margin-bottom:0}
}

/* The ship gauge, bottom-centre under your own hull: the port dial, the hull,
   the starboard dial — left to right as they sit on her when you face her bow,
   and where your eye already is. The dials are the broadside dials (styled in
   hud-panels.css), moved here from the bottom-right; the special stays there. */
#shipGauge{position:absolute;left:50%;bottom:22px;transform:translateX(-50%);display:flex;align-items:center;gap:8px}
#shipGauge .cd-box{width:58px;height:58px;flex:none}
#shipGauge #cdSpecial{margin-left:14px}
.sgHull{width:200px;padding:6px 11px 8px;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);transition:border-color .12s,box-shadow .12s}
.sgHull .hullHead b{font-size:15px}
.sgHull .hullBar{position:relative;height:12px;border-radius:6px}
/* Both bars full width, scaled from the left by hud.js: transform, not width,
   so a hit never reflows. The loss bar is the bite just taken: it holds a
   moment, then drains after the fill, so you see how much that one cost. */
.sgHull .hullBar i{position:absolute;inset:0;width:auto;border-radius:6px;transform-origin:0 50%}
.sgHull .sgFill{transition:transform .12s ease-out}
.sgHull .sgLoss{background:linear-gradient(180deg,#ffd0a8,#e07a4a);opacity:.85;transition:transform .5s ease-in .35s}
#shipGauge.hurt .sgFill{background:linear-gradient(180deg,#f0d78f,#b88d3f)}
#shipGauge.critical .sgFill{background:linear-gradient(180deg,#ea6a52,#a8281b);animation:hullPulse 1s ease-in-out infinite}
#shipGauge.critical .hullHead b{color:var(--blood)}
#shipGauge.struck .sgHull{border-color:var(--bone);box-shadow:0 0 12px rgba(236,228,210,.5),var(--sh-plate)}
@media (prefers-reduced-motion:reduce){
  #hull.critical .hullBar i,#shipGauge.critical .sgFill{animation:none}
  .sgHull .sgLoss{transition:none}
}

/* 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, and whites out its
   heart (overlays.js sets the opacity and, in the heart, the colour). */
#smokeOverlay{position:absolute;inset:0;background:#cfd0ca;opacity:0;transition:opacity .3s}

#aimHint{position:absolute;left:50%;bottom:150px;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){
  /* The gun wheel shows the reloads and the log plate the hull (DECISIONS 52). */
  #shipGauge{display:none}
  #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)}
  /* On a phone "Back to the map" is only in the menu (owner: a thumb reaching
     for the binnacle dropped out of a game). Inline display is match.js's, hence !important. */
  #leaveMatch{display:none !important}
}
/* 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 #shipGauge .cd-box,#hud.boarded #fireWheel,#hud.boarded #specialBtn{opacity:.3;filter:grayscale(1)}
/* A hull with no guns or no special (the GM ship, shared/ships.js): no dial and no button for what she has not got (client/hud/hud.js showSpecial). */
#hud.unarmed #cdPort,#hud.unarmed #cdStbd,#hud.unarmed #fireWheel,#hud.nospecial #cdSpecial,#hud.nospecial #specialBtn{display:none}

/* ---- 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 chosen hull's fit (W4-upgrades): two buttons that step through it. */
#respawnPicker .fitLine{display:flex;gap:6px;flex-wrap:wrap}
#respawnPicker .fitStep{flex:1 1 0;min-width:0;min-height:30px;padding:0 10px;border-radius:6px;border:1px solid rgba(201,162,78,.35);
  background:rgba(236,228,210,.06);color:var(--bone);font:inherit;font-size:12px;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#respawnPicker .fitStep:hover:not(:disabled){background:rgba(201,162,78,.18)}
#respawnPicker .fitStep:disabled{opacity:.5;cursor:default}

/* ---- the scoreboard (Tab) ---- */
/* Over every other control while it's held open (owner, on a phone: the fort
   marker and the special button were drawn across it); under the death card. */
#scoreboard{z-index:7;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)}
/* The sea's own ships (W4-npcs): a merchantman is a prize, a frigate a hunter. */
.shipLabel.npc.merchant .name{color:#e9cf8c}
.shipLabel.npc.merchant .bar i{background:linear-gradient(180deg,#f0d27a,#b38a2e)}
.shipLabel.npc.navy .name{color:#b9c8ec}
.shipLabel.npc.navy .bar i{background:linear-gradient(180deg,#8ea6e0,#3c5596)}
/* The ghost ship: witchfire green, and her bar dims while shot goes through her. */
.shipLabel.npc.ghost .name{color:#9ff0c8;text-shadow:0 0 6px rgba(92,255,154,.45)}
.shipLabel.npc.ghost .bar i{background:linear-gradient(180deg,#8fffc4,#2f8a60)}
.shipLabel.npc.ghost.phased .bar{opacity:.45}
/* Hold the Cove's raiders: the enemy, in black and blood. */
/* The boss ships (shared/sim/bosses.js): gold names, and the Dutchman dims like the ghost ship. */
.shipLabel.npc.dutchman .name,.shipLabel.npc.revenge .name,.shipLabel.npc.fortune .name{color:#f2c867;font-weight:700}
.shipLabel.npc.dutchman .bar i,.shipLabel.npc.revenge .bar i,.shipLabel.npc.fortune .bar i{background:linear-gradient(180deg,#e0584a,#8a1c14)}
.shipLabel.npc.dutchman.phased .bar{opacity:.45}
.shipLabel.npc.fireship .name{color:#ffa060}
.shipLabel.npc.escort .name{color:#d8c8a0}
.shipLabel.npc.raider .name{color:#f0a08c}
.shipLabel.npc.raider .bar i{background:linear-gradient(180deg,#e0644c,#8a2414)}

/* 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}
/* Readability pass (DECISIONS 52): a loading sweep is bone, not brass — brass
   on a brass rim was the old dial's whole contrast problem — and only a ready
   gun turns gold, with its lamp lit. While a broadside loads its seconds take
   the middle of the dial in a bold figure and the key steps up to a tag. */
.cd-box{--sweep:360deg;--sweep-col:rgba(236,228,210,.78);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.ready{--sweep-col:var(--brass-hi)}
.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)}
/* The GM ship's salute has no icon of its own: the dial wears its key like
   the broadsides do, and the touch button its name alone. */
#hud.confetti #cdSpecial .cd-icon,#hud.confetti #specialBtn .specIcon{display:none}
#hud.confetti #cdSpecial .cd-label{position:relative;top:auto;font-size:17px}
.cd-box .cd-time{position:absolute;bottom:10px;left:0;right:0;text-align:center;font-size:11px;font-weight:700;color:var(--bone);font-variant-numeric:tabular-nums;
  text-shadow:0 1px 2px #000}
.cd-box.ready .cd-label{font-size:19px;text-shadow:0 0 6px rgba(242,200,103,.45)}
#cdPort:not(.ready) .cd-label,#cdStbd:not(.ready) .cd-label{position:absolute;top:10px;left:0;right:0;text-align:center;font-size:10px;line-height:1}
#cdPort .cd-time,#cdStbd .cd-time{bottom:auto;top:50%;transform:translateY(-36%);font-size:16px;line-height:1}
.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%);transition:opacity .15s}
.cd-box:not(.ready) .cd-lamp{opacity:.4;box-shadow:none !important}
#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)}
/* The purse (client/hud/purse.js): the match's pay as a small receipt. The
   coin is drawn in CSS — gold with a pressed rim — so it needs no asset. */
#purse{margin:0 0 12px;padding:8px 12px 6px;border-radius:var(--r-m);background:rgba(242,200,103,.12);box-shadow:inset 0 0 0 1px rgba(166,124,40,.45)}
#purse[hidden]{display:none}
/* A guest's card, where the purse would be (client/hud/endCard.js). */
.ovGuest{margin:0 0 12px;padding:8px 12px;border-radius:var(--r-m);font-size:13px;line-height:1.4;color:var(--ink-2);background:rgba(88,101,242,.08);box-shadow:inset 0 0 0 1px rgba(71,82,196,.35)}
.ovGuest[hidden]{display:none}
.purseHead{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.purseHead .coin{width:22px;height:22px;border-radius:50%;flex:none;
  background:radial-gradient(circle at 35% 30%,#fff3c4 0 12%,#f2c867 30%,#b8862a 75%,#7a5518 100%);
  box-shadow:inset 0 0 0 2px rgba(122,85,24,.7),0 1px 2px rgba(0,0,0,.35)}
.purseTotal{font-size:24px;line-height:1;color:var(--ink);font-variant-numeric:tabular-nums}
.purseHead > span:not(.coin):not(.purseBalance){color:var(--ink-soft);font-size:var(--t-s,13px)}
.purseBalance{margin-left:auto;color:var(--ink-soft);font-size:12px;font-variant-numeric:tabular-nums}
.purseLines{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));column-gap:16px;margin-top:4px}
.purseLine{display:flex;justify-content:space-between;gap:8px;font-size:12px;padding:2px 0;color:var(--ink-soft);font-variant-numeric:tabular-nums}
.purseLine span:last-child{color:var(--ink);font-weight:700}
.purseLine.cut span:last-child{color:var(--blood)}
.endCard.holding #purse{display:none}
#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)}
/* Share this match / invite friends (client/hud/endCard.js): quiet, under the
   result line, never louder than the card's one wax seal. */
.ovShare{display:flex;justify-content:center;flex-wrap:wrap;gap:8px;margin:-2px 0 12px}
.ovShare[hidden],.ovShareBtn[hidden]{display:none}
.ovShareBtn{min-height:40px;padding:0 16px;font-size:var(--t-m)}
.ovShareBtn .sh{display:none}
/* A phone on its side: the pair goes to the card's top corner, short-labelled,
   so the board keeps its rows. */
@media (max-height:520px){
  #overlay .endCard{position:relative}
  #overlay .ovShare{position:absolute;top:8px;right:12px;margin:0;z-index:1}
  #overlay .ovShareBtn{flex:none;padding:0 12px}
  .ovShareBtn .lg{display:none}
  .ovShareBtn .sh{display:inline}
}
/* ---- 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 #shipGauge,
#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 #threatFx,#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 #threatFx,#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}
  .ovShare{margin:0 0 6px;gap:6px}
  .ovShareBtn{min-height:36px;font-size:var(--t-s)}
}
@media (max-width:560px){
  .ovShareBtn{flex:1 1 0;padding:0 8px;white-space:normal;line-height:1.1}
}
@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}
}

/* Hold the Cove: the fort's badge (client/hud/coveMarker.js). */
#coveMarker{position:absolute;left:0;top:0;width:34px;height:34px;margin:-17px 0 0 -17px;border-radius:50%;pointer-events:none;
  display:flex;align-items:center;justify-content:center;background:rgba(14,40,44,.88);border:2px solid #c9a45a;color:#f2d38a;
  box-shadow:0 2px 10px rgba(0,0,0,.55);z-index:2}
#coveMarker .ico{width:20px;height:20px}
#coveMarker .cmDist{position:absolute;top:100%;left:50%;transform:translateX(-50%);margin-top:3px;white-space:nowrap;
  font:600 11px/1 var(--f-body,sans-serif);color:#f2e3bf;text-shadow:0 1px 3px #000}
#coveMarker .cmArrow{position:absolute;inset:-9px;display:none}
#coveMarker .cmArrow::after{content:"";position:absolute;right:-2px;top:50%;margin-top:-6px;border:6px solid transparent;border-left:8px solid #c9a45a}
#coveMarker.edge .cmArrow{display:block}
#hud.matchOver #coveMarker{display:none}

/* ---- which way it came from (client/hud/threatCues.js) ----
   Each node sits at 0,0 and is moved by a transform that puts its anchor (the
   arc's crown, the chevron's tip) on an ellipse just inside the frame, turned
   to face outward, toward the trouble. Opacity is the script's, slew-limited,
   so it never flickers however fast the hits come. */
#threatFx{position:absolute;inset:0;pointer-events:none;overflow:hidden}
/* The hit: a blood-red crescent, brightest at its crown and tapering at its
   horns, with a soft glow spilling inward. One ellipse's top border. */
.hitDir{position:absolute;left:0;top:0;width:260px;height:90px;margin-left:-130px;transform-origin:130px 0;opacity:0;will-change:transform,opacity}
.hitDir::before{content:"";position:absolute;left:0;top:0;width:100%;height:240px;box-sizing:border-box;border-radius:50%;
  border-top:6px solid #ff6a4e;filter:drop-shadow(0 0 4px rgba(255,80,50,.9)) drop-shadow(0 1px 1px rgba(13,18,24,.9));
  -webkit-mask-image:linear-gradient(180deg,#000 12%,transparent 34%);mask-image:linear-gradient(180deg,#000 12%,transparent 34%)}
.hitDir::after{content:"";position:absolute;left:10%;top:0;width:80%;height:70px;
  background:radial-gradient(ellipse 50% 100% at 50% 0,rgba(207,74,51,.55),rgba(168,40,27,.22) 55%,rgba(168,40,27,0) 100%)}
#threatFx.narrow .hitDir{width:170px;height:60px;margin-left:-85px;transform-origin:85px 0}
#threatFx.narrow .hitDir::before{height:150px;border-top-width:5px}
#threatFx.narrow .hitDir::after{height:46px}

/* Incoming: a small brass double chevron, steady and quiet. It says "from
   there, soon", not "panic", and points out toward the side the balls come from. */
.threatMark{position:absolute;left:0;top:0;width:0;height:0;opacity:0;will-change:transform,opacity;
  filter:drop-shadow(0 0 2px rgba(13,18,24,.95)) drop-shadow(0 0 5px rgba(242,200,103,.35))}
.threatMark::before,.threatMark::after{content:"";position:absolute;left:-10px;width:20px;height:20px;box-sizing:border-box;
  border-top:3.5px solid var(--brass-hi);border-left:3.5px solid var(--brass-hi);transform:rotate(45deg)}
.threatMark::before{top:0}
.threatMark::after{top:11px;opacity:.55}
#threatFx.narrow .threatMark::before,#threatFx.narrow .threatMark::after{left:-6px;width:12px;height:12px;border-width:2.5px 0 0 2.5px}
#threatFx.narrow .threatMark::after{top:7px}
/* ---------- 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}
}

/* ---- a phone held upright (client/ui/landscape.js) ----
   The title card again, over the globe, with the hub and its sheets hidden
   behind it; the prompt is steady (it is not waiting for a tap) and the
   handset tips onto its side over and over. Above everything but #fatal. */
#turnPhone{display:none;position:fixed;inset:0;z-index:90;align-items:center;justify-content:center;pointer-events:auto;user-select:none;-webkit-user-select:none}
html.upright #turnPhone{display:flex}
html.upright #start,html.upright .settingsSheet{visibility:hidden}
#turnPhone .veil{position:absolute;inset:0;
  background:radial-gradient(ellipse at 50% 45%, rgba(13,18,24,.35) 0%, rgba(13,18,24,.8) 62%, rgba(8,11,15,.95) 100%)}
#turnPhone img{width:min(760px,88vw);height:auto;filter:drop-shadow(0 10px 28px rgba(0,0,0,.6))}
#turnPhone .turnIco{width:64px;height:64px;margin-top:10px;color:var(--brass-hi);filter:drop-shadow(0 2px 6px rgba(0,0,0,.8))}
#turnPhone .turnHandset{transform-box:fill-box;transform-origin:center;animation:turnSideways 2.6s ease-in-out infinite}
@keyframes turnSideways{0%,25%{transform:none}55%,85%{transform:rotate(-90deg)}100%{transform:none}}
#turnPhone .prompt{margin-top:4px;padding:10px 22px;border-radius:var(--r-pill);font-family:var(--f-head);font-size:var(--t-m);letter-spacing:.1em;color:var(--brass-hi);
  background:rgba(13,18,24,.55);border:1px solid rgba(201,162,78,.5)}
@media (prefers-reduced-motion:reduce){ #turnPhone .turnHandset{animation:none;transform:rotate(-90deg)} }

/* ---- 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}
/* The host's opt-in to the Discord announcements (client/hub/roomPanel.js). */
.roomAnnounce{display:flex;align-items:flex-start;gap:12px;margin:12px 0 4px;padding:10px 0 4px;border-top:1px solid rgba(134,98,42,.35);cursor:pointer;min-height:40px}
.roomAnnounce .toggle{margin-top:2px}
.roomAnnounce b{display:block;font-family:var(--f-head);font-weight:normal;font-size:var(--t-m);color:var(--ink);letter-spacing:.03em}
.roomAnnounce small{display:block;font-size:var(--t-s);color:var(--ink-soft);line-height:1.4}

@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 first visit's question (client/hub/welcome.js): Discord or a guest's name. */
#welcome .hubCard{width:min(720px,100%)}
.wlOpts{display:grid;grid-template-columns:1fr 1fr;gap:18px}
.wlOpt{display:flex;flex-direction:column;gap:8px;padding:12px 14px;border:1px solid rgba(134,98,42,.35);border-radius:var(--r-m);background:rgba(255,250,235,.35)}
.wlOpt .hubLbl{margin:0}
.wlBig{min-height:46px;width:100%;justify-content:center}
#welcome .btn.discord{background:#5865f2;color:#fff;border-color:#4752c4;display:inline-flex;align-items:center;gap:8px;font-family:var(--f-head);font-size:var(--t-m)}
#welcome .btn.discord:hover{background:#4752c4}
#welcome .btn.discord .ico{width:20px;height:20px}
.wlName{display:flex;gap:6px;align-items:center}
.wlName .hubInput{flex:1;min-width:0}
.wlErr{min-height:1.2em;margin:0;font-size:12px;color:var(--blood)}
.wlNote{font-size:12px;line-height:1.45;color:var(--ink-soft);margin:0}
.wlWarn{color:var(--ink-2);font-weight:600}
@media (max-width:640px){ .wlOpts{grid-template-columns:1fr} }
/* ---------- 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}
/* What the in-match menu leads with (client/hud/pauseMenu.js): the line for a
   phone turned upright, then a private room's code. The wrapper gives no box
   of its own, so a hidden line leaves no gap in the card. */
.smLead{display:contents}
.smTurn{padding:8px 10px;border-radius:var(--r-m);font-size:var(--t-m);font-weight:700;color:var(--ink);
  background:rgba(155,28,28,.1);box-shadow:inset 0 0 0 1px rgba(155,28,28,.4)}
.smTurn[hidden]{display:none}
/* In a private room, the in-match menu leads with the room (client/hud/pauseMenu.js). */
.smRoom{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;padding:8px 10px;border-radius:var(--r-m);
  background:rgba(242,200,103,.14);box-shadow:inset 0 0 0 1px rgba(166,124,40,.45)}
.smRoom[hidden]{display:none}
.smRoomCode{flex:1 1 220px;font-size:var(--t-s);color:var(--ink-2)}
.smRoomCode b{font-family:var(--f-head);font-size:var(--t-l);color:var(--ink);letter-spacing:.06em;font-variant-numeric:lining-nums}
.smRoomInvite{min-height:40px;padding:0 16px}
.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);gap:6px}
  .smCard .cardTitle{font-size:var(--t-l)}
  .smClose{min-height:32px;width:36px;font-size:20px}
  /* A phone on its side (owner): every section on one row, the rows a size
     smaller, and the foot always on screen — the body scrolls, not the card. */
  .smTabs{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}
  .smTabs button{flex:none;min-height:30px;padding:0 9px;font-size:11px;letter-spacing:.03em}
  .smBody{min-height:48px}
  .smRow{min-height:36px;padding:2px 0}
  .smLabel{font-size:var(--t-s)}
  .smVal{font-size:var(--t-s)}
  .smFoot{padding-top:6px}
  .smFoot .btn{min-height:34px;font-size:var(--t-s)}
  .smRoom{padding:4px 8px;gap:8px}
  .smRoomCode b{font-size:var(--t-m)}
  .smRoomInvite{min-height:36px}
}
/* ---------- 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,#start[data-view="board"] #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}
/* The ghost ship (client/hub/chart.js): bigger, and alive. A bone skull whose
   eyes and mouth are lit green from behind, smoke curling up off it, and a
   darkness looming behind that breathes. */
.liveGlyph .gLoom{display:none}
/* A boss ship (client/hub/chart.js): bigger, gold-rimmed, a slow pulse of red
   behind her mark; the Dutchman's is ghost-green. */
.liveGlyph.boss{width:38px;height:38px;margin:-90px 0 0 -19px;background:radial-gradient(circle at 50% 55%,#5a1a14 0,#200806 60%,#0b0302 100%);
  border:2px solid #f2c867;box-shadow:0 0 14px 4px rgba(0,0,0,.75),0 0 18px rgba(242,200,103,.45);animation:bossPulse 2.4s ease-in-out infinite}
.liveGlyph.boss .ico{width:24px;height:24px;color:#f2c867;filter:drop-shadow(0 0 1px #000)}
.liveGlyph[data-kind="dutchman"]{background:radial-gradient(circle at 50% 58%,#1c5a3e 0,#06120d 55%,#020403 100%)}
.liveGlyph[data-kind="dutchman"] .ico{color:#bff5d8}
.liveGlyph[data-kind="revenge"] .ico{color:#ff8a4a;filter:drop-shadow(0 0 1px #000) drop-shadow(0 0 5px rgba(255,120,40,.7))}
@keyframes bossPulse{50%{box-shadow:0 0 14px 4px rgba(0,0,0,.75),0 0 30px rgba(224,88,74,.7)}}
@media (prefers-reduced-motion:reduce){ .liveGlyph.boss{animation:none} }
.liveGlyph[data-kind="ghost"]{width:40px;height:40px;margin:-92px 0 0 -20px;background:radial-gradient(circle at 50% 58%,#1c5a3e 0,#06120d 55%,#020403 100%);
  border-color:rgba(120,255,180,.5);box-shadow:0 0 16px 6px rgba(0,0,0,.8),0 0 22px rgba(92,255,154,.35);overflow:visible}
.liveGlyph[data-kind="ghost"] .ico{width:28px;height:28px;position:relative;z-index:2;color:#ece5cf;
  filter:drop-shadow(0 0 1px #000) drop-shadow(0 0 6px rgba(92,255,154,.7));animation:gSkull 3.2s ease-in-out infinite}
.liveGlyph[data-kind="ghost"] .gLoom{display:block;position:absolute;left:50%;top:50%;width:150px;height:150px;margin:-92px 0 0 -75px;z-index:0;pointer-events:none}
.liveGlyph[data-kind="ghost"] .gLoom::before{content:"";position:absolute;inset:0;border-radius:50%;
  background:radial-gradient(closest-side,rgba(0,0,0,.85),rgba(3,12,9,.6) 50%,rgba(0,0,0,0));filter:blur(3px);animation:gLoom 4.5s ease-in-out infinite}
.gWisp{position:absolute;left:50%;top:58%;width:30px;height:30px;margin:-15px 0 0 -15px;border-radius:50%;
  background:radial-gradient(closest-side,rgba(200,235,220,.75),rgba(110,200,160,.3) 55%,rgba(0,0,0,0));filter:blur(2.5px);opacity:0;
  animation:gWisp 3.6s ease-out infinite}
.gWisp:nth-child(2){animation-delay:1.2s;margin-left:-24px}
.gWisp:nth-child(3){animation-delay:2.4s;margin-left:-6px}
@keyframes gWisp{0%{opacity:0;transform:translate(0,6px) scale(.5)}18%{opacity:.95}100%{opacity:0;transform:translate(10px,-62px) scale(2.4)}}
@keyframes gLoom{0%,100%{transform:scale(.9);opacity:.85}50%{transform:scale(1.1);opacity:1}}
@keyframes gSkull{0%,100%{transform:translateY(0)}50%{transform:translateY(-2px)}}
@media (prefers-reduced-motion:reduce){.liveGlyph[data-kind="ghost"] .ico,.liveGlyph[data-kind="ghost"] .gLoom::before,.gWisp{animation:none}.gWisp{opacity:.4}}
#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,#shipGauge,#hudBottomRight,#matchState,#killFeed,#touch,#shipLabels){opacity:0 !important}
#hud.cineOut > :is(#hudCorner,#compass,#hull,#shipGauge,#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)}
.rcCove{width:32px;height:32px;margin:-16px 0 0 -16px;background:rgba(14,40,44,.9);border:2px solid var(--brass,#c9a45a);color:#f2d38a;box-shadow:0 2px 10px 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:76px;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:124px;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:96px;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;width:max-content;max-width:calc(100% - 24px)}
.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}
/* Hold the Cove: the fort's bar sits where the kraken's does, and the beast's
   drops under it while there is a cove. */
.hzCove{position:absolute;top:56px;left:50%;transform:translateX(-50%);width:min(340px,70vw);display:none;
  align-items:center;gap:8px;padding:3px 10px;border-radius:var(--r-pill);
  background:rgba(20,16,12,.55);border:1px solid rgba(201,162,78,.55);box-shadow:var(--sh-plate)}
.hzCove.shown{display:flex}
.hzCove .hzKName{color:var(--rope)}
.hzCove .hzKBar i{background:linear-gradient(180deg,#e9c46a,#a67c2a)}
.hzCove.enraged .hzKBar i{background:var(--blood);animation:hzPulse .8s ease-in-out infinite}
#hzLayer.cove .hzKraken{top:88px}
/* The sea serpent shares the bar (client/hud/hazardHud.js). */
.hzKraken.serpent .hzKName{color:#9fe6c9}
.hzKraken.opening .hzKNote{color:#ffd36e;opacity:1}
/* A boss ship (shared/sim/bosses.js) takes the bar over while she is near. */
.hzKraken.boss .hzKName{color:#f2c867;letter-spacing:.04em}
.hzKraken.boss .hzKBar i{background:linear-gradient(180deg,#e0584a,#8a1c14)}
.hzKraken.boss.phased .hzKBar i{background:linear-gradient(180deg,#9ff0c8,#3f7a62);opacity:.55}
.hzKraken.boss.phased .hzKNote{color:#9ff0c8;opacity:1}
@keyframes hzPulse{50%{opacity:.55}}
/* One line where it fits and wrapped where it doesn't: a boss's sighting runs
   to ~70 characters, which ran off both sides of a phone. */
.hzCallout{position:absolute;top:28%;left:50%;transform:translateX(-50%);width:max-content;max-width:calc(100% - 24px);text-align:center;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.boss{color:#f2c867;font-size:23px;text-shadow:0 0 10px rgba(224,88,74,.45),0 2px 6px rgba(0,0,0,.85)}
.hzCallout.ghost{color:#9ff0c8;text-shadow:0 0 8px rgba(92,255,154,.35),0 1px 2px rgba(0,0,0,.7)}
.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}
  /* A thumb's target, drawn no bigger: the ring is the button, the × stays small. */
  #guide .gSkip{width:40px;height:40px;margin:-6px -6px -4px 0}
}
@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}
  /* The keyboard's words mean nothing to a thumb; the touch line says how a
     thumb throws (a tap on the sea is the throw: client/match/input.js). */
  #aimHint .wide{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}
}
/* ---- the hub under a thumb (mobile pass, 2026-09-27) ----
   The captain card's refit/special pickers, the leaderboard's switches and the
   Chandlery's tabs, hull chips and buy buttons were drawn for a mouse at
   28-34px. A thumb wants ~44; a phone on its side has the height for 36. */
@media (pointer:coarse){
  .fitPick select{min-height:40px}
  .lbSeg button{min-height:40px}
  .shopTabs button,.shopHulls button{min-height:40px}
  .shopAct{min-height:40px}
}
@media (pointer:coarse) and (max-height:520px) and (orientation:landscape){
  .fitPick select,.shopTabs button,.shopHulls button,.shopAct{min-height:36px}
}
/* A phone held upright is only this short with its keyboard up (Android
   shrinks the page for it). The sail bar — four rows at the foot — would then
   take half of what's left and sit on the field being typed in (the
   Chandlery's new name, the welcome card's), so it steps aside until the
   keyboard goes, unless the field is its own room code. --bar-space is what
   the cards above it stop at (client/hub/sailBar.js measures it). */
@media (pointer:coarse) and (orientation:portrait) and (max-height:540px){
  #start:not(:has(#startBar:focus-within)) #startBar{visibility:hidden}
  #start:not(:has(#startBar:focus-within)){--bar-space:0px !important}
}
/* The sea's bars (client/hud/hazardHud.js: the cove's fort, the kraken, the
   serpent, a boss) hang top-centre, which on an upright phone is under the
   binnacle and across the match banner. There they go under the banner, beside
   the binnacle column, with the kill feed stepping down beneath them. Sideways
   the top is the banner and the kill feed, which ran straight across them, so
   they go to the foot between the stick and the gun wheel (above the first
   match's guide while it's up), and a callout keeps clear of the banner and the feed. */
@media (pointer:coarse) and (orientation:portrait){
  #hzLayer .hzCove,#hzLayer .hzKraken{top:98px;left:128px;right:12px;width:auto;transform:none}
  #hzLayer.cove .hzKraken{top:126px}
  #hud.compact #hzLayer .hzCove,#hud.compact #hzLayer .hzKraken{left:100px}
  #hzLayer .hzKName{letter-spacing:.08em}
  .hzCallout{font-size:17px}
  .hzCallout.boss{font-size:19px}
  .hzCallout small{font-size:12px}
  #hud:has(.hzCove.shown) #killFeed,#hud:has(.hzKraken.shown) #killFeed{top:130px}
  #hud:has(.hzCove.shown):has(.hzKraken.shown) #killFeed{top:158px}
}
@media (pointer:coarse) and (orientation:landscape){
  #hzLayer .hzCove,#hzLayer .hzKraken{top:auto;bottom:calc(12px + env(safe-area-inset-bottom));width:min(300px,calc(100% - 420px))}
  #hzLayer.cove .hzKraken{top:auto;bottom:calc(42px + env(safe-area-inset-bottom))}
  #hud:has(#guide.shown) #hzLayer .hzCove,#hud:has(#guide.shown) #hzLayer .hzKraken{bottom:calc(78px + env(safe-area-inset-bottom))}
  #hud:has(#guide.shown) #hzLayer.cove .hzKraken{bottom:calc(108px + env(safe-area-inset-bottom))}
  .hzCallout{top:122px;font-size:18px}
  /* ...and the feed keeps its two newest rows, so a callout has the band under
     it: a phone on its side is ~360px tall. */
  #killFeed .killRow:nth-last-child(n+3){display:none}
  .hzCallout.boss{font-size:20px}
  .hzCallout small{font-size:12px}
}
/* The respawn globe: "Choose your water" clears the 44px menu row an upright
   phone has (it sat 8px into the Map button), and the refit/special steppers
   on the death card are thumb-sized. */
@media (pointer:coarse) and (orientation:portrait){
  .rcHead{top:max(62px,calc(env(safe-area-inset-top) + 54px))}
}
@media (pointer:coarse){
  #respawnPicker .fitStep{min-height:40px}
}
@media (pointer:coarse) and (orientation:landscape) and (max-height:520px){
  #respawnPicker .fitStep{min-height:34px}
}
#aimHint .narrow{display:none}
@media (pointer:coarse){ #aimHint .narrow{display:inline} }
/* The mortar armed: the button says so, rather than looking merely ready. */
#specialBtn.armed{box-shadow:0 0 0 3px var(--brass-hi),0 0 0 4px rgba(60,40,10,.6),0 0 18px 4px rgba(242,200,103,.7);animation:specArmed 1s ease-in-out infinite alternate}
@keyframes specArmed{to{box-shadow:0 0 0 3px var(--brass-hi),0 0 0 4px rgba(60,40,10,.6),0 0 6px 1px rgba(242,200,103,.35)}}
@media (prefers-reduced-motion:reduce){ #specialBtn.armed{animation:none} }

/* Small leftovers from the mobile pass (DECISIONS 35):
   - the death card's hull buttons: no keyboard hint on a touch screen (keys
     1-8 mean nothing there), so a Brigantine's name isn't cut to "Brigant…";
   - "More in the Chandlery" on the captain card: a 40px target round a small link. */
@media (pointer:coarse){
  #respawnPicker .shipRowBtn kbd{display:none}
  #respawnPicker .shipRowBtn{padding:0 7px;gap:5px}
  .fitNote button{display:inline-block;padding:12px 6px;margin:-12px -6px}
}

/* A private room's chip on a phone on its side: it sat on the menu button (the
   way to the room's invite, and out of the match), so it moves to the right
   under Scores, clear of the banner and above the gun wheel. */
@media (pointer:coarse) and (orientation:landscape){
  #roomChip{left:auto;right:max(12px,env(safe-area-inset-right));top:62px;transform:none}
}
