/* Neon Arena — battleship view: two 10×10 CSS-grid boards (enemy target + own
   fleet), placement editor with dock/ghosts, shot markers (miss •, hit ✚,
   sunk halo), active-board pulse, fleet pips. Loaded after game.css; reuses
   .fighter/.board-frame/.rematch-splash primitives from the chess game view. */

/* The match is one screenful. `.view-game` (game.css) is the frame — a
   `minmax(0,1fr) 340px` grid whose height is the SCENE's, written by
   `fitMatchColumn()` into `--match-h`, with the opponent bar pinned to the top
   of the board column, the board taking what is left and the player's own bar
   and the action row at the bottom. This file used to override that with a
   `display:flex` root and an inner `.bs-main` at `align-items:start`, which
   is how the column came out 946px tall inside a 660px scene at 1280×800 —
   the player's own clock clipped by the fold and the buttons below it. */

.view-bs { overflow: visible; }

/* === stage === */
/* The mock's battle stage: enemy waters take the height on the left, your own
   fleet is a 210px column on the right. Both were `1fr 1fr` grids of equal
   size before, which is what put the placement dock 286px past the fold. */
.bs-stage {
  position: relative;
  padding: 0;
  overflow: hidden;
}
.bs-boards {
  container-type: size;
  container-name: bsboards;
  display: flex;
  align-items: stretch;
  gap: 20px;
  width: 100%;
  height: 100%;
  min-height: 0;
}
.bs-enemy-frame { flex: 1 1 auto; min-width: 0; }
.bs-own-frame { flex: 0 0 210px; }
.bs-board-frame {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 7px;
  min-height: 0;
  padding: 10px;
  border-radius: var(--r-md);
  border: 1px solid var(--stroke);
  background: var(--panel-soft);
  transition: border-color var(--dur-fast), box-shadow var(--dur-med);
  min-width: 0;
}
/* Square, and driven by whichever axis runs out first.
   `min(100%, 100cqh - chrome)` and not `aspect-ratio` alone: a square whose
   height comes from a flex line cannot feed its own width, and the board came
   out 56×155 when it tried. `100cqh` is the size container declared on the row
   below, so the second term is the free HEIGHT in pixels and the subtraction
   is the frame's own chrome — 20 of padding plus 25 for the label and its
   gap. */
.bs-grid-wrap {
  position: relative;
  align-self: center;
  width: min(100%, calc(100cqh - 45px));
  aspect-ratio: 1 / 1;
}
.bs-coords {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  font-weight: 800;
  line-height: 1;
  color: rgba(var(--t-mute), 0.34);
}
.bs-coord {
  position: absolute;
  font-size: clamp(6px, 2.2%, 10px);
  transform: translate(-50%, 0);
}
.bs-coord-f { top: 2px; }
.bs-coord-r { left: 5px; transform: translate(-50%, -50%); }
.bs-board-frame.is-active-board {
  border-color: rgba(241, 193, 82, 0.55);
  box-shadow: var(--shadow-glow-gold);
  animation: bsBoardPulse 1.7s ease-in-out infinite;
}
@keyframes bsBoardPulse {
  0%, 100% { box-shadow: 0 0 8px rgba(241, 193, 82, 0.25); }
  50% { box-shadow: 0 0 24px rgba(241, 193, 82, 0.55); }
}
.bs-board-label {
  text-align: center;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--text-dim);
  margin-bottom: 8px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* === grid === */
.bs-grid {
  container-type: size;
  container-name: bsgrid;
  display: grid;
  grid-template-columns: repeat(10, minmax(0, 1fr));
  grid-template-rows: repeat(10, minmax(0, 1fr));
  gap: 2px;
  width: 100%;
  height: 100%;
  user-select: none;
  -webkit-user-select: none;
}
/* `.bs-grid` in front is load-bearing: base.css's touch floor is
   `button:not([data-tight])`, whose `:not()` carries the argument's
   specificity, so (0,1,1) beat the bare `.bs-cell` at (0,1,0) and the
   `min-height: 0` below never applied on a phone. Invisible on a tall window —
   a 340px board is 32px a cell and the ten rows still overflowed silently —
   and unmissable on a short one, where the grid is ~150px and ten 44px rows
   painted straight through the fleet. A grid square is sized by the grid. */
.bs-grid .bs-cell {
  position: relative;
  min-width: 0;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: 6px;
  border: 1px solid var(--stroke);
  background: rgba(124, 201, 255, 0.05);
  color: var(--text-dim);
  font-size: clamp(9px, 2.6cqmin, 15px);
  font-weight: 800;
  line-height: 1;
  transition: background var(--dur-fast), border-color var(--dur-fast), box-shadow var(--dur-fast),
    transform var(--dur-fast);
}
.bs-cell:disabled { cursor: default; }

/* target board interactivity */
.bs-cell.is-target { cursor: crosshair; }
.bs-cell.is-target:focus-visible {
  background: rgba(241, 193, 82, 0.22);
  border-color: rgba(241, 193, 82, 0.6);
  box-shadow: 0 0 10px rgba(241, 193, 82, 0.35);
  transform: scale(1.06);
}
@media (hover: hover) {
  /* Mouse only: ungated, the crosshair wash stuck to the LAST tapped water
     cell on touch and read as an aimed shot that was never taken. */
  .bs-cell.is-target:hover {
    background: rgba(241, 193, 82, 0.22);
    border-color: rgba(241, 193, 82, 0.6);
    box-shadow: 0 0 10px rgba(241, 193, 82, 0.35);
    transform: scale(1.06);
  }
}
/* Press feedback for touch — fires on the tap itself, releases on lift, so the
   thumb still sees the aim confirmed without any state surviving the shot. */
.bs-cell.is-target:active {
  background: rgba(241, 193, 82, 0.22);
  border-color: rgba(241, 193, 82, 0.6);
}

/* own fleet */
.bs-cell.is-ship {
  background: linear-gradient(135deg, rgba(124, 201, 255, 0.34), rgba(167, 139, 250, 0.3));
  border-color: rgba(124, 201, 255, 0.5);
}

/* shot markers */
.bs-cell.is-miss {
  color: var(--cool);
  font-size: clamp(11px, 3.4cqmin, 20px);
  background: rgba(124, 201, 255, 0.1);
}
.bs-cell.is-hit {
  background: rgba(255, 93, 108, 0.3);
  border-color: rgba(255, 93, 108, 0.65);
  color: #ffc2c9;
  text-shadow: 0 0 8px rgba(255, 93, 108, 0.8);
  animation: bsHitGlow 1.4s ease-in-out infinite;
}
@keyframes bsHitGlow {
  0%, 100% { box-shadow: 0 0 4px rgba(255, 93, 108, 0.3); }
  50% { box-shadow: 0 0 14px rgba(255, 93, 108, 0.7); }
}
.bs-cell.is-sunk {
  background: linear-gradient(135deg, rgba(255, 93, 108, 0.55), rgba(224, 162, 58, 0.4));
  border-color: rgba(255, 93, 108, 0.85);
  color: #fff;
  text-shadow: 0 0 10px rgba(255, 255, 255, 0.6);
  box-shadow: 0 0 16px rgba(255, 93, 108, 0.65), inset 0 0 8px rgba(0, 0, 0, 0.3);
}
.bs-cell.is-ship-sunk {
  background: linear-gradient(135deg, rgba(255, 93, 108, 0.55), rgba(224, 162, 58, 0.4));
  border-color: rgba(255, 93, 108, 0.85);
  box-shadow: 0 0 16px rgba(255, 93, 108, 0.65), inset 0 0 8px rgba(0, 0, 0, 0.3);
}

/* enemy fleet revealed after the finish */
.bs-cell.is-revealed {
  background: rgba(167, 139, 250, 0.22);
  border-color: rgba(167, 139, 250, 0.45);
}

/* === placement editor ===
   Same rule as the battle stage: the board takes the free height and the hint,
   the dock and the buttons keep their own. Before it was a plain column and
   the dock finished 286px below the scene. */
.bs-placement {
  display: flex;
  align-items: stretch;
  gap: 20px;
  width: 100%;
  height: 100%;
  min-height: 0;
}
/* The COLUMN never scrolls — its scroll lives in .bs-place-scroll so the
   action row below it stays on screen at every height. When the column was
   the scroller, a 1280x600 window hid «Сброс» and «В бой» below an invisible
   overlay-scrollbar fold (measured: clientHeight 226, scrollHeight 316 — the
   missing 90px were exactly those two buttons) while the board caption said
   «жми „В бой"». A live player reported the button as not existing. */
.bs-place-side {
  flex: 0 0 210px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 0;
}
.bs-place-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.bs-place-hint {
  font-size: 11px;
  line-height: 1.45;
  font-weight: 600;
  color: var(--text-dim);
  text-wrap: pretty;
}
.bs-place-wrap {
  container-type: size;
  container-name: bsboards;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  justify-content: center;
  width: 100%;
}
/* The FRAME carries the width, not the wrap inside it: the placement frame is
   a shrink-to-fit flex item, so `width:100%` on its child resolved against a
   width that was itself waiting on the child. No label here, so only the
   frame's own 20px of padding comes off the free height. */
.bs-place-frame {
  width: min(100%, calc(100cqh - 20px));
  max-width: 100%;
}
.bs-place-frame .bs-grid-wrap { width: 100%; }
.bs-place-frame { padding: 10px; }
.bs-place-grid { }
.bs-place-cell { cursor: pointer; }
.bs-place-cell:disabled { cursor: default; }
.bs-cell.ghost-ok {
  background: rgba(53, 199, 131, 0.38);
  border-color: rgba(53, 199, 131, 0.8);
  box-shadow: 0 0 10px rgba(53, 199, 131, 0.45);
}
.bs-cell.ghost-bad {
  background: rgba(255, 93, 108, 0.32);
  border-color: rgba(255, 93, 108, 0.75);
}
.bs-dock-label {
  text-align: left;
  font-size: 11px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--text-faint);
}
.bs-dock {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: 6px;
}
.bs-dock-ship {
  display: flex;
  gap: 2px;
  padding: 6px 7px;
  border-radius: 8px;
  border: 1px solid var(--stroke);
  background: var(--panel-soft);
  transition: border-color var(--dur-fast), box-shadow var(--dur-fast), opacity var(--dur-fast),
    transform var(--dur-med) var(--spring);
}
@media (hover: hover) {
  .bs-dock-ship:hover:not(:disabled) { transform: translateY(-2px); border-color: var(--stroke-strong); }
}
.bs-dock-ship.sel {
  border-color: rgba(241, 193, 82, 0.65);
  box-shadow: var(--shadow-glow-gold);
}
.bs-dock-ship.used { opacity: 0.28; cursor: default; }
.bs-dock-cell {
  width: 13px;
  height: 13px;
  border-radius: 3px;
  background: var(--cyan-grad);
  box-shadow: inset 0 0 3px rgba(0, 0, 0, 0.35);
}
.bs-place-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  margin-top: auto;
  flex: 0 0 auto;
}
.bs-place-actions .btn-primary { grid-column: 1 / -1; }
.bs-place-wait {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  border-radius: var(--r-md);
  background: rgba(6, 9, 12, 0.72);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  text-align: center;
  padding: 16px;
}
.bs-place-wait-sub { font-size: 12.5px; font-weight: 700; color: var(--text-dim); }

/* === fighter fleet pips === */
/* No `flex-wrap: wrap` here: ten ships wrapped to a second row the moment the
   fleet appeared, which grew the card 6.55px and shoved the board (see
   .fighter-caps in game.css). The pips are a reminder of what is still afloat —
   the board itself is the real answer — so the tail clips instead. */
.bs-fleet-mini { gap: 4px; }
.bs-pip {
  font-size: 9px;
  letter-spacing: 1.5px;
  color: var(--cool);
  opacity: 0.85;
  white-space: nowrap;
}
.bs-pip.sunk { color: var(--danger); opacity: 0.9; }

/* === moves log === */
.bs-moves { max-height: 300px; }
.bs-move-row {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 4px 8px;
  border-radius: var(--r-sm);
  font-size: 12.5px;
}
.bs-move-row:nth-child(odd) { background: var(--panel-soft); }
.bs-move-ico { font-size: 13px; }
.bs-move-coord { font-weight: 800; font-variant-numeric: tabular-nums; min-width: 30px; }
.bs-move-who {
  font-weight: 600;
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bs-move-res { font-size: 11px; color: var(--text-faint); font-weight: 700; }

/* === responsive === */
/* WHERE THE TWO BOARDS STOP FITTING SIDE BY SIDE, AND IT IS NOT 620.
   This block used to start at the view's own one-column threshold, which is a
   number about the SIDEBAR and says nothing about a row of two 10x10 boards.
   Above that threshold the board column is the scene minus the sidebar and
   the gutters — `scene - 390` at every width — and the row spends a rigid 210
   on `.bs-own-frame` plus a 20px gap before the enemy board gets anything. So
   the enemy frame is exactly `scene - 620` wide: ZERO at the width the row
   used to switch on, and smaller than the fleet card beside it for another
   200px above that. Measured on /arcade/battleship, authed, window height 800:

     scene  622   enemy frame   22   .bs-grid    0   cell  2.0
     scene  646   enemy frame   26   .bs-grid    4   cell  2.0   (1024x768)
     scene  722   enemy frame  102   .bs-grid   80   cell  6.2
     scene  822   enemy frame  202   .bs-grid  180   cell 16.2   (1200x800)
     scene  872   enemy frame  252   .bs-grid  230   cell 21.2

   830 is where the enemy frame first matches the fleet column's 210 — the
   arrangement this file's header describes, enemy waters taking the height
   with the fleet a 210px column beside them. Below it the row has inverted
   its own purpose: the board you shoot at is smaller than the board you only
   read. So the boards stack, and the stack is width-bound and legible.

   THE BUG THAT FOUND IT WAS A SPECTATOR'S, and those 210 extra pixels of
   threshold are the fix. `#ctx.shell-ctx` is REMOVED for a signed-out visitor
   (`ui/shell.js` `renderCtx()` — removed and not hidden, so the grid track
   goes back to the scene), which makes the scene ~250px wider at an identical
   window. At 844x390 that is a 688px scene against the authed player's 436:
   the player got this block and a 35.84px cell, the guest got the row, and
   because `.bs-boards` is a size container and contributes no height,
   `.bs-stage` resolved its `flex: 1 1 auto` basis to 0 inside an
   over-subscribed column and shrank to nothing — `.bs-grid` measured 0x18, no
   board at all. Asking the scene for the number the ROW needs, instead of the
   number the view's one-column switch needs, is what makes the two answer the
   same. */
@container scene (max-width: 829px) {
  /* One column: 210px of dock beside a board leaves the board 140px on a
     390px phone, which is 14px a cell. The board goes full width and the dock
     goes under it, and the size containers go back to normal so the frames
     stop asking a height that no longer exists. */
  .bs-boards, .bs-placement { flex-direction: column; gap: 10px; }
  .bs-boards, .bs-place-wrap { container-type: normal; }
  .bs-enemy-frame, .bs-own-frame, .bs-place-side, .bs-place-wrap { flex: 0 0 auto; width: 100%; }
  .bs-place-side { overflow: visible; }
  /* One column: the page is the scroller, an inner 0-height scroll trap would
     swallow the dock. */
  .bs-place-scroll { flex: 0 0 auto; overflow: visible; }
  .bs-grid-wrap, .bs-place-frame .bs-grid-wrap { width: 100%; }
  .bs-place-frame { width: 100%; max-width: 460px; margin: 0 auto; }
  .bs-place-actions { grid-template-columns: repeat(3, 1fr); }
  .bs-place-actions .btn-primary { grid-column: 1 / -1; }
}
/* THE SINGLE-COLUMN SWITCH IS THE @container BLOCK ABOVE, and it always was.
   What used to sit here — `@media (max-width: 700px) { .bs-boards {
   grid-template-columns: 1fr } }` — set a GRID property on a flex container:
   `.bs-boards` is `display: flex` (see its rule at the head of this file) and
   has been for as long as the placement dock has stacked under the board.
   `grid-template-columns` on a flex box is inert; the stacking is done 80px
   away by `flex-direction: column` in the `@container scene` block above.
   Measured at a 390px window before removal: computed `grid-template-columns:
   1fr` on a `display: flex` element, `flex-direction: column` — and every rect
   on the route identical with the rule gone. Removed rather than converted,
   because `@container scene (max-width: 700px)` would have read as a
   threshold and disagreed with the real one, which was 619 then and is 829
   now. */

/* === the stage may be small; it may not be absent ===
   THE STAGE'S HEIGHT HAD NO FLOOR, and that is the second half of the guest
   bug above. `.bs-boards` is a size container, so it contributes NO height to
   its parent's intrinsic size; `.bs-stage` is `flex: 1 1 auto` (game.css,
   `.g-board-col > .board-frame`) and resolves that `auto` basis to 0. In a
   column with more fixed rows than height the only shrinkable item is the
   stage, and it shrinks to exactly nothing — not to a small board, to no
   board. Measured at 1280x400, BOTH roles, after the threshold above was
   fixed: `.bs-stage` 0.00 tall, `.bs-grid` 0x18, cell 2.0. The threshold
   alone does not reach this: 858 is a wide scene and the row is the right
   layout for it; there is simply no height.

   `--board-cap` is the answer the app already computes — `fitMatchColumn()`
   in ui/board.js measures the fixed rows and floors what is left at
   `MATCH_FIT_MIN_BOARD` (160). Chess, checkers and nardy all size their board
   from it; battleship asked `100cqh` instead, which is the flex outcome and
   therefore the very number that had collapsed. Same floor, same source, and
   no feedback loop: `--board-cap` is derived only from rows whose height does
   not depend on the board (the fitter's own header states this, and the
   frame is deliberately excluded from what it observes).

   A FLOOR HAS TO BE ABLE TO OVERFLOW THE COLUMN or it is not a floor, so the
   column grows and the scene scrolls — which is what battleship already does
   below 830, and what the authed player at 844x390 has always got. Two things
   that were measured the hard way getting there:

   1. `min-height` on `.bs-stage` does nothing. game.css's
      `.g-board-col > .board-frame { min-height: 0 }` is (0,2,0) and a bare
      `.bs-stage` is (0,1,0), so the floor lost the cascade and the stage
      still measured 0.00 at 1280x400.
   2. Growing the column by `height: auto` alone takes the row layout apart.
      `.bs-boards { height: 100% }` needs a definite parent, and a flex item
      inside an auto-height column is not one — `100cqh` resolved to 0,
      `min(100%, calc(100cqh - 45px))` went negative and clamped, and every
      battleship board from 830 up measured `.bs-grid` 0 wide. So the
      stage takes `--board-cap` as a HEIGHT rather than as a minimum: a stated
      length is definite whatever the column does, and when the fitter is not
      floored `used + cap + gaps` is `--match-h` exactly, so the desktop
      column comes out the same height it always did and does not scroll.
      (`60vh` is the fallback game.css already uses for `--board-cap`.)

   Stacked, the stage is its content instead — game.css says the same thing at
   its own threshold, which only covers the part of this range below 620.

   NOTHING IS SAID HERE ABOUT `.g-side-col`, and an earlier draft that did was
   wrong twice over. Left to stretch, it keeps exactly the height it has today
   at every width — the grid row is the board column's, and the sidebar's
   `height: 100%` against an auto row resolves to `auto` and is then stretched
   back to the row, so its `overflow-y: auto` still bounds a long spectator
   list to one screenful. Capping it with `max-height: var(--match-h)` instead
   also fired below 620, where game.css has deliberately made the sidebar a
   full-height block UNDER the board: measured at 844x390 authed, the column
   went 401 -> 187 and the share card hung out of the bottom of the view.

   All of it is scoped to `.view-bs`, and that scoping is measured rather than
   assumed: /game, checkers, nardy, durak, arcomage and typing_race were driven
   at 844x390, 1024x768 and 1200x800 in both roles, and every rect in the match
   column and the sidebar came out byte-identical before and after. What those
   six do when their own column is over-subscribed is not settled here — the
   six views still disagree about it — and none of them shares this one's
   `100cqh`. */
.view-bs.view-game { height: auto; }
.view-bs > .g-board-col { height: auto; min-height: var(--match-h, 0); }
.view-bs > .g-board-col > .bs-stage { flex: 0 0 auto; height: var(--board-cap, 60vh); }
@container scene (max-width: 829px) {
  .view-bs > .g-board-col > .bs-stage { height: auto; }
}
/* Board density on a phone. Asked of the scene now, like the block above
   (shell.css «WINDOW CLASSES»). 520 stays as the number: upright the two
   units agree at it — below 800px scene width == window width, and the
   narrowest scene a wider window produces is 527 — and 390 / 905 / 1280
   measure byte-identical before and after.
   THE PHONE SIDEWAYS IS WHERE IT WAS WRONG, and this is the board that shows
   it. A notched landscape phone spends 47px of window on each ear plus 61–77
   on the rail: 844x390 leaves a 436px scene, 932x430 leaves 460. The board was
   taking the desktop density in that box because the window was 844. Measured
   at 844x390 before and after: `.bs-coord` 6px -> 8.5px (the rank and file
   labels printed over a 36px cell at SIX pixels), `.bs-grid` gap 2 -> 1.5,
   `.bs-stage` padding 0 -> 8, `.bs-board-frame` 10 -> 7, `.bs-dock-cell`
   13 -> 11, cell 36.39 -> 35.84. No new overflow on the route.
   Worth knowing and NOT changed here: board density does not track scene
   width at all. Measured cell sizes — scene 390: 32.4px, scene 527: 45.5px,
   scene 858: 19.8px (two boards side by side in a height-bound row). So the
   6px `.bs-coord` a 527px scene still draws over a 45.5px cell is not this
   threshold's doing and is not this lane's to move. */
@container scene (max-width: 520px) {
  .bs-stage { padding: 8px; }
  .bs-board-frame { padding: 7px; }
  /* ELEVEN COLUMNS FOR A TEN-COLUMN BOARD. This carried a leading `13px`
     gutter for the rank labels, and the labels do not live in the grid —
     `gridWrap()` puts them in a sibling `.bs-coords` overlay positioned in
     percentages. So below 520px the 100 auto-placed cells filled rows of
     ELEVEN: display row 0 held (0,0)…(0,9) plus (1,0), row 1 started at (1,1),
     and the last ten cells fell off the bottom entirely. Every phone shot at a
     board whose squares did not match the А…К / 1…10 printed over them.
     Measured at 390: `grid-template-columns` resolved to `13px` + ten `31px`.
     Only the gap belongs here. */
  .bs-grid { gap: 1.5px; }
  .bs-coord { font-size: 8.5px; }
  .bs-dock-cell { width: 11px; height: 11px; }
}

/* === phone landscape ===
   The stacked boards scroll sideways-held phones by design (a side-by-side
   row in a ~330px scene would mean ~17px cells — strictly worse); the two
   fighter bars and the resign/tools row are the same transient chrome every
   other game sheds here, and dropping them shortens that scroll by ~150px.
   The placement controls (`.bs-place-actions`) and the docks stay — they ARE
   the game in that phase. Everything returns on rotation. */
@media (orientation: landscape) and (max-height: 500px) {
  .view-bs .g-board-col > .fighter-slot { display: none; }
  .view-bs .g-board-col > .g-actions-row { display: none; }
}

/* === reduced motion === */
@media (prefers-reduced-motion: reduce) {
  .bs-board-frame.is-active-board { animation: none; box-shadow: var(--shadow-glow-gold); }
  .bs-cell.is-hit { animation: none; }
}
