/* Salvo: the war-room theme for web/salvo.js, from design/salvo/*.dc.html. Phosphor
   green on near-black, amber only for hits, sunk ships and warnings, IBM Plex Mono,
   a faint scanline and glow. Everything is scoped under .table-salvo except the last
   block, which themes the page around the board while a Salvo table is open.
   The blocks run: the board's base, the pieces every view shares (readout, buttons,
   seas, cells, launch line), then each view (placing, firing, under fire, the intro,
   the display), the swap, the keyframes, and the page around the board.
   Type: body copy and buttons 16px, readouts and logs 13px or more in the mono face,
   and only the row letters, column numbers and ship names on the placing sea smaller
   (design/client.md, Salvo). */
@font-face{font-family:"IBM Plex Mono";src:url(/fonts/plex-mono-v20-400.woff2) format("woff2");font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"IBM Plex Mono";src:url(/fonts/plex-mono-v20-600.woff2) format("woff2");font-weight:600;font-style:normal;font-display:swap}

.table-salvo{
  --sv-ground:#050806;--sv-phosphor:#5cff8a;--sv-mid:#2fbf62;--sv-dim:#17633a;--sv-faint:#0d3a22;--sv-amber:#ffb020;
  --sv-glow:0 0 6px rgba(92,255,138,.6);--sv-aglow:0 0 8px rgba(255,176,32,.7);
  position:relative;isolation:isolate;overflow:hidden;
  background:var(--sv-ground);color:var(--sv-phosphor);
  font-family:"IBM Plex Mono",ui-monospace,Menlo,Consolas,monospace;font-size:16px;line-height:1.4;letter-spacing:.04em;
  display:flex;flex-direction:column;padding:14px 12px 12px;
  /* The client's chrome takes about 50px above the root and 32px below it. */
  min-height:min(780px,calc(100vh - 82px));min-height:min(780px,calc(100dvh - 82px));
}
/* The finish takes only its own height, so the client's next-game strip follows it closely. */
.table-salvo:has(>.salvo-view[data-mode=finished]){min-height:0}
/* Scanlines and vignette, at or under the mockups' strength. */
.table-salvo::before,.table-salvo::after{content:"";position:absolute;inset:0;pointer-events:none;z-index:3}
.table-salvo::before{background:repeating-linear-gradient(0deg,rgba(0,0,0,.18) 0 1px,transparent 1px 3px);mix-blend-mode:multiply}
.table-salvo::after{background:radial-gradient(ellipse at center,transparent 55%,rgba(0,0,0,.5) 100%)}
.table-salvo p,.table-salvo ol{margin:0;padding:0;max-width:none}
.table-salvo ol{list-style:none}
.table-salvo .glow{text-shadow:var(--sv-glow)}
.table-salvo .aglow{color:var(--sv-amber);text-shadow:var(--sv-aglow)}
.table-salvo .mid{color:var(--sv-mid)}
.table-salvo .lost,.table-salvo .hit:not(.cell){color:var(--sv-amber)}
.table-salvo .salvo-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.table-salvo :focus-visible{outline:2px solid var(--sv-phosphor);outline-offset:2px}

/* One view at a time, top to bottom; the foot sinks to the bottom as in the mockups. */
.table-salvo .salvo-view{flex:1;display:flex;flex-direction:column;gap:10px}
.table-salvo .salvo-view>.salvo-foot{margin-top:auto}
.table-salvo .salvo-cur{display:inline-block;width:.6em;height:1.05em;background:var(--sv-phosphor);vertical-align:-.15em;margin-left:2px;animation:salvo-blink 1.1s steps(1) infinite}
.table-salvo .salvo-cur.amber{background:var(--sv-amber)}
.table-salvo .salvo-sub{display:flex;flex-wrap:wrap;justify-content:space-between;gap:2px 10px;font-size:13px;color:var(--sv-mid);letter-spacing:.08em}
.table-salvo .salvo-sub>span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* The readout: the left half of the sub-line over a phone's sea, the mode or a volley's
   moment. It keeps its width; when the sea's figures do not fit beside it they drop to
   a second line, right-aligned, rather than lose their end. */
.table-salvo .salvo-sub>.salvo-say{flex:none;max-width:100%;color:var(--sv-phosphor)}
.table-salvo .salvo-sub>.salvo-say+span{margin-left:auto}
.table-salvo .salvo-sub>.salvo-say.aglow{color:var(--sv-amber)}

/* Buttons. The page's own button rules are overridden here, hover and disabled included;
   cells are buttons too, with their own hover below. */
.table-salvo button{font:inherit;border-radius:0;background:transparent;color:var(--sv-phosphor);cursor:pointer}
.table-salvo button:not(.cell):hover:not(:disabled){background:var(--sv-faint);border-color:var(--sv-phosphor)}
.table-salvo button:disabled{opacity:.55;cursor:default}
.table-salvo .salvo-btn{font-size:16px;letter-spacing:.08em;min-height:48px;padding:0 14px;border:1px solid var(--sv-mid)}
.table-salvo .salvo-place,.table-salvo .salvo-fire{width:100%;min-height:56px;border:2px solid var(--sv-phosphor);font-weight:600;text-shadow:0 0 8px rgba(92,255,138,.6)}
.table-salvo .salvo-place{font-size:18px;letter-spacing:.16em}
.table-salvo .salvo-fire{font-size:20px;letter-spacing:.2em}

/* A sea. Its width follows the room left on screen once the rest of the view is laid
   out (--reserve, per view), so a tall sea still fits a 390 by 844 phone. */
.table-salvo .salvo-view{--reserve:470px}
.table-salvo .salvo-view[data-mode=firing]{--reserve:540px}
.table-salvo .salvo-view[data-mode=underfire],.table-salvo .salvo-view[data-mode=finished]{--reserve:460px}
.table-salvo .salvo-view[data-mode=waiting]{--reserve:400px}
.table-salvo .salvo-sea{align-self:center;width:100%;
  max-width:max(240px,calc((100vh - var(--reserve) - 16px) * var(--w) / var(--h) + 24px));
  max-width:max(240px,calc((100dvh - var(--reserve) - 16px) * var(--w) / var(--h) + 24px))}
/* On a phone held upright the sea takes the whole width and the view scrolls below it:
   a cell is a tap target first, so it is as large as the screen allows. */
@media (max-width:600px) and (orientation:portrait){
  .table-salvo:not(.salvo-tv){padding-left:0;padding-right:0}
  .table-salvo:not(.salvo-tv) .salvo-sea{max-width:none}
}
.table-salvo .salvo-sea.out,.table-salvo .salvo-mini.out{opacity:.4}
.table-salvo .salvo-cols{display:grid;grid-template-columns:22px repeat(var(--w),minmax(0,1fr));gap:2px;margin-bottom:2px}
.table-salvo .salvo-body{display:grid;grid-template-columns:22px minmax(0,1fr);gap:2px}
.table-salvo .salvo-rows{display:grid;grid-template-rows:repeat(var(--h),minmax(0,1fr));gap:2px}
.table-salvo .salvo-cols span,.table-salvo .salvo-rows span{font-size:11px;color:var(--sv-mid);display:flex;align-items:center;justify-content:center;letter-spacing:0;line-height:1}
.table-salvo .salvo-sea.dense .salvo-cols span,.table-salvo .salvo-sea.dense .salvo-rows span{font-size:8px}
.table-salvo .salvo-cells{display:grid;grid-template-columns:repeat(var(--w),minmax(0,1fr));gap:2px;position:relative}
.table-salvo .salvo-sea.dense .salvo-cells,.table-salvo .salvo-sea.dense .salvo-cols,.table-salvo .salvo-sea.dense .salvo-rows{gap:1px}
.table-salvo .salvo-cells[data-grid]{cursor:crosshair;touch-action:manipulation}

/* Cells: misses a dim dot, hits amber with a dark diamond, picks a bright square. A
   sea that takes taps has a button per cell, kept at the size the sea allows. The
   base rule outweighs the page's button hover, which would otherwise tint open water
   and stay stuck after a tap on a touch screen. */
.table-salvo .salvo-cells .cell{aspect-ratio:1;min-width:0;min-height:0;padding:0;margin:0;background:transparent;border:1px solid var(--sv-faint);position:relative;display:flex;align-items:center;justify-content:center;-webkit-tap-highlight-color:transparent;user-select:none;-webkit-user-select:none}
.table-salvo .cell:focus-visible{z-index:1}
.table-salvo .cell.ship{background:var(--sv-dim);border-color:var(--sv-mid)}
.table-salvo .cell.miss::after{content:"";width:22%;height:22%;border-radius:50%;background:var(--sv-dim)}
.table-salvo .cell.ship.miss::after{background:var(--sv-ground)}
.table-salvo .cell.hit{background:var(--sv-amber);border-color:var(--sv-amber);box-shadow:0 0 8px var(--sv-amber)}
.table-salvo .cell.hit::after{content:"";width:26%;height:26%;background:var(--sv-ground);transform:rotate(45deg)}
.table-salvo .cell.pick{border-color:var(--sv-phosphor);box-shadow:inset 0 0 0 1px var(--sv-phosphor)}
.table-salvo .cell.pick::after{content:"";width:20%;height:20%;background:var(--sv-phosphor)}
.table-salvo .cell.cursor{outline:2px solid var(--sv-phosphor);outline-offset:2px;z-index:1}
.table-salvo .cell.incoming{outline:2px dashed var(--sv-amber);outline-offset:2px;z-index:1;animation:salvo-pulse .3s ease-in-out infinite alternate}
/* The flash lasts as long as salvo.js waits on it: --salvo-flash comes from its TIMING.
   --salvo-step-at is how long ago the volley's step began, so a redraw mid-step carries
   the flash, the launch line and the sinking pulse on instead of starting them over. */
.table-salvo .cell.flash{animation:salvo-flash var(--salvo-flash,.44s) ease-out;animation-delay:var(--salvo-step-at,0ms)}
.table-salvo .cell.flash.hit{animation-name:salvo-flash-hit}
/* A ship sunk: every hit on that sea pulses amber together through the hold
   (--salvo-sink is TIMING.sinkMs). */
.table-salvo .sinking .cell.hit{animation:salvo-sink var(--salvo-sink,.9s) ease-in-out both;animation-delay:var(--salvo-step-at,0ms)}

/* The launch line, drawn on in cell units over the sea. */
.table-salvo .salvo-launch{position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none;z-index:2}
.table-salvo .salvo-launch path{fill:none;stroke:var(--sv-phosphor);stroke-width:.1;stroke-linecap:round;stroke-dasharray:1 1;stroke-dashoffset:1;animation:salvo-draw var(--salvo-launch,.36s) ease-out forwards;animation-delay:var(--salvo-step-at,0ms)}
.table-salvo .salvo-launch.above path{stroke:var(--sv-amber)}
.table-salvo .salvo-launch circle{fill:var(--sv-phosphor);animation:salvo-pulse .3s ease-in-out infinite alternate}
.table-salvo .salvo-launch.above circle{fill:var(--sv-amber)}

/* Placing, and waiting for the other fleets: ships drawn where they lie, a ship that
   may not lie there amber, the one moving bright. While placing, the bow carries the
   turn glyph (a tap turns the ship about it). Only ship cells stop the page scrolling
   under a finger, so a drag moves the ship and open water still scrolls. */
.table-salvo [data-grid=place] .cell.ship{touch-action:none;cursor:grab}
.table-salvo .salvo-turn{flex:none;width:60%;height:auto;aspect-ratio:1;color:var(--sv-phosphor);pointer-events:none}
.table-salvo .cell.ship.no{background:#4a3206;border-color:var(--sv-amber)}
.table-salvo .cell.ship.no .salvo-turn{color:var(--sv-amber)}
.table-salvo .cell.ship.moving{border-color:var(--sv-phosphor);box-shadow:0 0 8px rgba(92,255,138,.6);z-index:1}
.table-salvo .cell.ship.no.moving{border-color:var(--sv-amber);box-shadow:0 0 8px rgba(255,176,32,.7)}
/* A placed ship's name lies in the cells' grid over the cells behind its bow
   (salvo.js sets the grid area), out of the cells' flow so no button moves, above a
   moving ship's cells, and lets taps and drags through to them. Down ships stack
   upright letters. Smaller than a readout, like the row letters: it is part of the
   sea's picture, and each cell's button names its ship. A dense sea has no room. */
.table-salvo .salvo-name{position:absolute;inset:0;z-index:1;pointer-events:none;display:flex;align-items:center;justify-content:center;overflow:hidden;
  font-size:10px;font-weight:600;line-height:1;letter-spacing:.06em;white-space:nowrap;color:var(--sv-phosphor);text-shadow:0 0 2px var(--sv-ground)}
.table-salvo .salvo-name.down{writing-mode:vertical-rl;text-orientation:upright;letter-spacing:0}
.table-salvo .salvo-name.no{color:var(--sv-amber)}
.table-salvo .salvo-sea.dense .salvo-name{display:none}
.table-salvo .salvo-line{min-width:0;font-size:14px;letter-spacing:.06em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.table-salvo .salvo-list li{display:flex;justify-content:space-between;gap:10px;font-size:14px;padding:3px 0;border-bottom:1px solid var(--sv-faint);color:var(--sv-phosphor)}
.table-salvo .salvo-list li.done{color:var(--sv-mid)}
.table-salvo .salvo-list li.no{color:var(--sv-amber)}
.table-salvo .salvo-list li span:last-child{text-align:right;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.table-salvo .salvo-actions{display:flex;flex-direction:column;gap:8px;margin-top:auto}
.table-salvo .salvo-note{font-size:16px;color:var(--sv-mid);margin-top:auto}

/* Firing: the enemy tabs (a tab per sea, or one name against a single enemy), the salvo
   readout, and the foot with the small sea. */
.table-salvo .salvo-tabs{display:flex;gap:6px}
.table-salvo .salvo-tab{flex:1 1 0;min-width:0;min-height:44px;padding:2px 6px;border:1px solid var(--sv-dim);color:var(--sv-mid);font-size:16px;letter-spacing:.06em;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.table-salvo .salvo-tab.on{border-color:var(--sv-phosphor);color:var(--sv-phosphor);background:var(--sv-faint)}
.table-salvo .salvo-tab small{display:block;font-size:13px;letter-spacing:0;color:var(--sv-mid)}
.table-salvo .salvo-tab.one{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:0 10px}
.table-salvo .salvo-tab.one small{display:inline}
.table-salvo .salvo-salvo{display:flex;justify-content:space-between;align-items:baseline;flex-wrap:wrap;gap:4px 12px;border-top:1px solid var(--sv-faint);padding-top:8px}
.table-salvo .salvo-count{font-size:18px;font-weight:600;letter-spacing:.1em}
.table-salvo .salvo-picks{font-size:13px}
.table-salvo .salvo-foot{display:flex;gap:14px;align-items:flex-start}
.table-salvo .salvo-mini{flex:none;width:min(150px,calc(150px * var(--w) / var(--h)))}
.table-salvo .salvo-mini .salvo-cells{gap:1px}
.table-salvo .salvo-mini .cell.hit{box-shadow:none}
.table-salvo .salvo-mini .cell.hit::after{display:none}
.table-salvo .salvo-fleet{flex:1;min-width:0;font-size:13px;line-height:1.45;letter-spacing:.04em;overflow-wrap:anywhere}
.table-salvo .salvo-fleet p:first-child{margin-bottom:4px}
.table-salvo .salvo-fleet p:last-child:not(:first-child){margin-top:6px}
/* The enemy fleet under the large enemy sea: the same rows in two columns, the afloat
   count last. A ship lost is struck through in amber in every fleet list. */
.table-salvo .salvo-efleet{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));grid-template-rows:repeat(3,auto);grid-auto-flow:column;gap:0 14px;font-size:13px;line-height:1.45;letter-spacing:.04em;white-space:nowrap}
.table-salvo .salvo-efleet>*{min-width:0;overflow:hidden;text-overflow:ellipsis}
.table-salvo :is(.salvo-fleet,.salvo-efleet,.salvo-dfleet) .lost{text-decoration:line-through;text-decoration-thickness:2px;text-decoration-color:var(--sv-amber)}

/* Under fire: the volley log. */
.table-salvo .salvo-log{border-top:1px solid var(--sv-faint);padding-top:8px;font-size:14px;line-height:1.55;letter-spacing:.04em}

/* The intro: typed once, then the sea. */
.table-salvo .salvo-intro{flex:1;display:flex;flex-direction:column;gap:28px;padding:26px 12px 4px}
.table-salvo .salvo-type{font-size:17px;line-height:1.6;letter-spacing:.04em}
.table-salvo .salvo-type .big{font-size:24px;font-weight:600;line-height:1.3}
.table-salvo .salvo-type .gap{height:20px}
.table-salvo .salvo-type .line{display:block}
.table-salvo .salvo-intro .salvo-skip{align-self:flex-end;margin:-14px -4px 0 0;min-width:0;min-height:44px;padding:0 14px}

/* The finish on a phone: the result, the fleets ranked, the seas small and revealed. */
.table-salvo .salvo-finish{display:flex;flex-direction:column;gap:12px;padding-top:8px;letter-spacing:.04em}
.table-salvo .salvo-finish>p.mid{margin:0;font-size:13px;letter-spacing:.1em}
.table-salvo .salvo-finish h2{margin:0;font-size:28px;font-weight:600;line-height:1.15}
.table-salvo .salvo-ladder{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.table-salvo .salvo-rung{display:grid;grid-template-columns:28px minmax(0,1fr) auto;gap:10px;align-items:center;font-size:15px;padding:8px 10px;border:1px solid var(--sv-faint)}
.table-salvo .salvo-rung.first{border:2px solid var(--sv-phosphor);background:var(--sv-faint)}
.table-salvo .salvo-rung .n{font-size:22px;font-weight:600}
.table-salvo .salvo-rung .who{min-width:0}.table-salvo .salvo-rung .who b{font-weight:600}
.table-salvo .salvo-rung small{display:block;font-size:13px;color:var(--sv-mid);letter-spacing:.04em;margin-top:2px}
.table-salvo .salvo-rung .right{font-size:13px;letter-spacing:.08em;text-align:right}
.table-salvo .salvo-stats{display:flex;flex-direction:column;font-size:14px}
.table-salvo .salvo-stats div{display:flex;justify-content:space-between;gap:12px;padding:5px 0;border-bottom:1px solid var(--sv-faint)}
.table-salvo .salvo-reveal{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
.table-salvo .salvo-reveal.n3,.table-salvo .salvo-reveal.n4,.table-salvo .salvo-reveal.n5,.table-salvo .salvo-reveal.n6{grid-template-columns:repeat(3,minmax(0,1fr))}
.table-salvo .salvo-reveal .salvo-mini{width:100%}
.table-salvo .salvo-reveal-sea p{margin:4px 0 0;font-size:13px;letter-spacing:.08em}
/* The display at the finish: the result and the ladder left, every sea right. */
.table-salvo .salvo-dmain.finish{grid-template-columns:minmax(0,1fr) minmax(0,1.1fr)}
.table-salvo .salvo-result>p.mid{margin:0;font-size:clamp(13px,.85vw,16px);letter-spacing:.12em}
.table-salvo .salvo-result h2{margin:10px 0 0;font-size:clamp(40px,3.8vw,72px);font-weight:600;line-height:1.05;letter-spacing:.04em}
.table-salvo .salvo-ladder.big{margin-top:clamp(16px,2.5vh,36px);max-width:760px}
.table-salvo .salvo-ladder.big .salvo-rung{font-size:clamp(16px,1.15vw,22px);padding:14px 18px;grid-template-columns:40px minmax(0,1fr) auto}
.table-salvo .salvo-ladder.big .salvo-rung .n{font-size:clamp(22px,1.6vw,30px)}
.table-salvo .salvo-ladder.big .salvo-rung small{font-size:clamp(13px,.8vw,15px)}
.table-salvo .salvo-ladder.big .salvo-rung .right{font-size:clamp(13px,.95vw,18px)}
.table-salvo .salvo-display.finish .salvo-seas{grid-template-columns:repeat(2,minmax(0,1fr))}
.table-salvo .salvo-display.finish .salvo-dsea.out{opacity:.7}

/* The display: every sea on one board. Two seas side by side, three or four in a row,
   five or six in two rows; the readout column stays while there is room. */
.table-salvo.salvo-tv{padding:clamp(16px,2.6vw,40px) clamp(16px,3.4vw,64px);min-height:calc(100vh - 50px);min-height:calc(100dvh - 50px);background:#040705}
/* --sea-h is the height a row of seas may take: the screen less the client's top bar,
   the padding, the header, each sea's name and foot, and the log. */
.table-salvo .salvo-display{--cols:2;--sea-h:calc(100dvh - 450px);flex:1;position:relative;display:flex;flex-direction:column;gap:clamp(14px,2.6vh,32px)}
.table-salvo .salvo-display.n3{--cols:3}
.table-salvo .salvo-display.n4{--cols:4}
.table-salvo .salvo-display.n5,.table-salvo .salvo-display.n6{--cols:3;--sea-h:calc((100dvh - 530px) / 2)}
.table-salvo.salvo-tv .salvo-display::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:-1;opacity:.35;
  background-image:linear-gradient(var(--sv-faint) 1px,transparent 1px),linear-gradient(90deg,var(--sv-faint) 1px,transparent 1px);background-size:80px 80px}
.table-salvo .salvo-dhead{font-size:clamp(13px,.75vw,14px);letter-spacing:.14em}
.table-salvo .salvo-dmain{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(20px,3vw,60px);align-items:start}
.table-salvo .salvo-seas{display:grid;grid-template-columns:repeat(var(--cols),minmax(0,1fr));gap:clamp(16px,3vh,40px) clamp(16px,3vw,60px);align-items:start}
.table-salvo .salvo-dsea{display:flex;flex-direction:column;gap:clamp(6px,.8vw,14px);min-width:0}
.table-salvo .salvo-dsea.out{opacity:.35}
.table-salvo .salvo-dsea .salvo-cells{width:min(100%,calc(var(--sea-h) * var(--w) / var(--h)));gap:3px}
.table-salvo .salvo-dname{display:flex;justify-content:space-between;align-items:baseline;gap:10px;font-size:clamp(13px,.75vw,14px)}
.table-salvo .salvo-dname .name{font-size:clamp(16px,1.15vw,22px);letter-spacing:.14em;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.table-salvo .salvo-dsea.firing .name{text-shadow:0 0 10px rgba(92,255,138,.65)}
.table-salvo .salvo-dfoot{font-size:clamp(13px,.75vw,14px);letter-spacing:.08em;min-height:1.4em}
.table-salvo .salvo-dfleet{display:flex;flex-wrap:wrap;gap:2px 12px;font-size:clamp(13px,.75vw,14px);letter-spacing:.08em}
.table-salvo .salvo-readout{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:20px 28px;font-size:clamp(14px,.85vw,16px)}
.table-salvo .salvo-readout p.mid{margin-bottom:8px;letter-spacing:.08em}
.table-salvo .salvo-readout .salvo-say{grid-column:1/-1;font-size:clamp(16px,1.15vw,22px);letter-spacing:.12em}
.table-salvo .salvo-status-grid{display:grid;grid-template-columns:1fr auto;gap:6px 16px;letter-spacing:.06em;border-top:1px solid var(--sv-faint);padding-top:10px}
.table-salvo .salvo-dlog{margin-top:auto;border-top:1px solid var(--sv-dim);padding-top:clamp(10px,1vw,18px);font-size:clamp(13px,.95vw,18px);letter-spacing:.08em}
.table-salvo .salvo-arcs{position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none;z-index:2}
.table-salvo .salvo-arcs path{fill:none;stroke-linecap:round}
.table-salvo .salvo-arcs .hit{stroke:var(--sv-amber);stroke-width:2.5;opacity:.55}
.table-salvo .salvo-arcs .miss{stroke:var(--sv-mid);stroke-width:2;opacity:.45}
.table-salvo .salvo-arcs .flight{stroke:var(--sv-phosphor);stroke-width:3;stroke-dasharray:1 1;stroke-dashoffset:1;animation:salvo-draw .32s ease-out forwards}
.table-salvo .salvo-arcs circle{fill:var(--sv-phosphor)}
@media (min-width:1100px){
  .table-salvo.salvo-tv .salvo-dmain{grid-template-columns:minmax(0,1fr) minmax(240px,22%)}
  .table-salvo.salvo-tv .salvo-readout{grid-template-columns:1fr;align-content:start}
}
/* A phone watching without a seat: two seas a row, the readout under them. */
.table-salvo .salvo-display.watch{--cols:2}
.table-salvo .salvo-display.watch .salvo-dsea .salvo-cells{width:100%;gap:1px}
.table-salvo .salvo-display.watch .salvo-dname{flex-direction:column;align-items:flex-start;gap:0}

/* The swap: the main slot changes hands with the turn. The new large sea grows from
   where the small one was while the new small sea shrinks from the main slot, along the
   same path (salvo.js measures it into --grow-* and --shrink-*); the rest of the view
   fades in, and one sweep line crosses the screen. --salvo-swap is TIMING.swapMs and
   --salvo-swap-at keeps a redraw mid-swap from starting it over. Transform and opacity only. */
.table-salvo .salvo-view.swap>.salvo-sea{z-index:2;transform-origin:0 0;animation:salvo-grow var(--salvo-swap,.35s) ease-out both;animation-delay:var(--salvo-swap-at,0ms)}
.table-salvo .salvo-view.swap .salvo-mini{z-index:1;transform-origin:0 0;animation:salvo-shrink var(--salvo-swap,.35s) ease-out both;animation-delay:var(--salvo-swap-at,0ms)}
.table-salvo .salvo-view.swap>:not(.salvo-sea):not(.salvo-sub):not(.salvo-foot):not(.salvo-sweep),.table-salvo .salvo-view.swap .salvo-foot>:not(.salvo-mini){animation:salvo-fade var(--salvo-swap,.35s) ease-out both;animation-delay:var(--salvo-swap-at,0ms)}
.table-salvo .salvo-sweep{position:absolute;inset:0;z-index:2;pointer-events:none;transform:translateY(-100%);opacity:0;
  background:linear-gradient(to top,rgba(92,255,138,.9) 0 2px,rgba(92,255,138,.14) 2px,transparent 56px);
  animation:salvo-sweep var(--salvo-swap,.35s) linear both;animation-delay:var(--salvo-swap-at,0ms)}

@keyframes salvo-blink{50%{opacity:0}}
@keyframes salvo-pulse{from{opacity:1}to{opacity:.45}}
@keyframes salvo-draw{to{stroke-dashoffset:0}}
@keyframes salvo-flash{from{background:var(--sv-phosphor);border-color:var(--sv-phosphor);box-shadow:0 0 16px var(--sv-phosphor)}}
@keyframes salvo-flash-hit{from{box-shadow:0 0 24px 4px var(--sv-amber)}}
@keyframes salvo-sink{0%,50%,100%{opacity:1;transform:none}25%,75%{opacity:.35;transform:scale(.8)}}
@keyframes salvo-grow{from{transform:translate(var(--grow-x,0px),var(--grow-y,0px)) scale(var(--grow-s,1));opacity:.6}}
@keyframes salvo-shrink{from{transform:translate(var(--shrink-x,0px),var(--shrink-y,0px)) scale(var(--shrink-s,1));opacity:.6}}
@keyframes salvo-fade{from{opacity:0}}
@keyframes salvo-sweep{from{transform:translateY(-100%);opacity:1}85%{opacity:1}to{transform:translateY(0);opacity:0}}
@media (prefers-reduced-motion:reduce){
  .table-salvo *,.table-salvo *::before,.table-salvo *::after{animation:none!important;transition:none!important}
  .table-salvo .salvo-launch path,.table-salvo .salvo-arcs .flight{stroke-dashoffset:0}
}

/* The page around the board. salvo.js puts salvo-theme on the body from mount to
   unmount, so the page keeps the theme while the board is hidden behind the people
   screen or the pass cover: the theme's ground, the mono face, and the client's own
   screens (header, cover, lobby, errors, finished card, notices) in its colours through
   the page's tokens, --alert among them. The display uses the whole width. */
html:has(body.salvo-theme),body.salvo-theme{background:#050806}
body.salvo-theme{--ground:#050806;--plate:#0d3a22;--ink:#5cff8a;--muted:#2fbf62;--rule:#17633a;--accent:#5cff8a;--tint:#0d3a22;--alert:#ffb020;color:#5cff8a;color-scheme:dark;
  font-family:"IBM Plex Mono",ui-monospace,Menlo,Consolas,monospace}
body.salvo-theme h1{font-family:inherit;font-stretch:normal;font-weight:600;letter-spacing:.04em}
body.salvo-theme main:has(>.table-salvo.salvo-tv){max-width:none;padding:0}
/* The client's header (design/client.md, "The header"), in the theme: the game's name
   left in the mono face, the status centred with a blinking block cursor after it,
   phosphor when calm and amber when the client marks it alert, Share and Game right in
   outlined phosphor. The status may take two lines on a phone rather than lose words. */
body.salvo-theme .table-top{grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;min-height:48px;padding-bottom:6px;border-bottom:1px solid #0d3a22}
body.salvo-theme .table-top .game-name{font:600 16px/1.2 "IBM Plex Mono",ui-monospace,Menlo,Consolas,monospace;font-stretch:normal;letter-spacing:.14em;text-transform:uppercase;color:#5cff8a;text-shadow:0 0 6px rgba(92,255,138,.6);text-decoration:none}
body.salvo-theme .table-top .active-turn{justify-self:center;max-width:100%;font:400 13px/1.25 "IBM Plex Mono",ui-monospace,Menlo,Consolas,monospace;letter-spacing:.06em;text-transform:uppercase;text-align:center;color:#5cff8a;text-decoration:none;
  white-space:normal;overflow-wrap:anywhere;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
body.salvo-theme .table-top .active-turn::after{content:"";display:inline-block;width:.6em;height:1.05em;margin-left:3px;vertical-align:-.15em;background:currentColor;animation:salvo-blink 1.1s steps(1) infinite}
body.salvo-theme .table-top .active-turn[data-tone=alert]{color:var(--alert);text-shadow:0 0 8px rgba(255,176,32,.7)}
body.salvo-theme main:has(>.table-salvo.salvo-tv)>.table-top{padding:8px clamp(16px,3.4vw,64px)}
body.salvo-theme .table-top .tools{gap:6px;flex-wrap:nowrap}
body.salvo-theme .table-top .tools button{min-height:44px;padding:0 8px;border:1px solid #2fbf62;background:transparent;color:#5cff8a;font-family:inherit;font-size:16px;letter-spacing:.06em;text-transform:uppercase;text-decoration:none}
body.salvo-theme .table-top .tools button:hover:not(:disabled),body.salvo-theme .table-top .tools button[aria-expanded=true]{border-color:#5cff8a;background:#0d3a22;color:#5cff8a;text-decoration:none}
/* The rules page from rules(), in the mono face. */
body.salvo-theme .table-rules{font-size:16px;line-height:1.55}
body.salvo-theme .table-rules h2{font-size:20px;letter-spacing:.12em;text-transform:uppercase}
body.salvo-theme .table-rules h3{margin:20px 0 6px;font-size:16px;letter-spacing:.12em;text-transform:uppercase;color:#2fbf62}
body.salvo-theme .table-rules ul{margin:0 0 12px;padding-left:1.2em}
/* The TV's tray in the game's look: phosphor buttons on the screen's black. */
body.salvo-theme .tv-tray{background:#050806;border-color:#17633a}
body.salvo-theme .tv-tray button,body.salvo-theme .tv-tray button:hover{border:1px solid #2fbf62;background:transparent;color:#5cff8a;-webkit-text-fill-color:#5cff8a;font:400 16px/1.3 "IBM Plex Mono",ui-monospace,Menlo,Consolas,monospace;letter-spacing:.08em;text-transform:uppercase}
body.salvo-theme .tv-tray button:focus{background:#5cff8a!important;color:#050806!important;-webkit-text-fill-color:#050806!important;border-color:#5cff8a;outline-color:#5cff8a}
/* The corner QR stays up mid-game for a phone joining late (an unheld seat, a watcher,
   a dead battery), drawn as part of the screen: its modules in the phosphor on the
   screen's own black, no caption, in the empty corner above the log line. The inline
   SVG (table.js inlineCornerQR) takes the colours; the img it replaces is filtered
   towards them meanwhile. */
body.salvo-theme .table-corner{right:clamp(16px,3.4vw,64px);bottom:clamp(88px,9.3vh,104px);gap:0}
body.salvo-theme .table-corner figcaption{display:none}
body.salvo-theme .table-corner img{width:clamp(72px,7vmin,104px);filter:invert(1) sepia(1) saturate(3) hue-rotate(75deg) brightness(1.05)}
body.salvo-theme .table-corner svg{display:block;width:clamp(72px,7vmin,104px);height:auto;filter:drop-shadow(0 0 3px rgba(92,255,138,.55))}
body.salvo-theme .table-corner svg [fill]:not([fill="none"]){fill:#5cff8a}
body.salvo-theme .table-corner svg [stroke]{stroke:#5cff8a}
body.salvo-theme .table-corner svg>rect[rx][fill]{fill:#040705;stroke:#17633a;stroke-width:.5}
@media (prefers-reduced-motion:reduce){body.salvo-theme .table-top .active-turn::after{animation:none}}
