@charset "UTF-8";
/* ==========================================================================
   Whack-a-Devil — what belongs to this game alone
   --------------------------------------------------------------------------
   Everything structural is in /biblegames/shared/shell.css: the no-scroll flex
   column, the top bar, the scoreboard, the buttons, the score card. Loaded
   before this file, so anything here overrides it.

   What is genuinely this game's own is the BOARD — nine square holes that keep
   their shape at every window size — and the flash row that carries a verse at
   every tenth devil.

   --------------------------------------------------------------------------
   THE HOLES MUST ALL BE THE SAME, AND THE CHARACTER MUST KEEP ITS SHAPE

   Those are the two things that matter, and they are not the same as "the
   board must be square". Nine identical cells is what makes aiming fair; a
   character that keeps its proportions is what stops a devil looking squashed.

   Both are had by filling the row with a uniform 3x3 grid, capping it at 34rem
   in each direction, centring it, and giving the character `object-fit:
   contain`. See the note on .board for why `aspect-ratio` was the wrong tool.

   --------------------------------------------------------------------------
   Contents
     1. Tokens
     2. The board and its holes
     3. The characters
     4. The flash row
     5. The tally on the score card
     6. Responsive
     7. Reduced motion, forced colours, more contrast, print
   ========================================================================== */

/* -------------------------------------------------------------------------- */
/* 1. Tokens                                                                  */
/* -------------------------------------------------------------------------- */

:root {
  --hole-gap: 8px;
  --hole-radius: 14px;

  /* The mouth of a hole: darker than the board so a character reads as coming
     UP out of something rather than sitting on a tile. */
  --hole-mouth: radial-gradient(ellipse 100% 70% at 50% 100%,
                                rgba(3, 2, 12, 0.85) 0%,
                                rgba(20, 13, 48, 0.55) 70%);
}

/* -------------------------------------------------------------------------- */
/* 2. The board and its holes                                                 */
/* -------------------------------------------------------------------------- */

/*
 * The board: square where there is room, uniform where there is not.
 *
 * `aspect-ratio: 1` off the WIDTH is what makes it square, and that is the
 * portrait case — which is nearly every visitor, on a phone. Left at
 * `height: 100%` the board filled a tall stage and the nine cells came out as
 * 3:2 rectangles with a square character floating in each one.
 *
 * It is not a guarantee, and that is deliberate rather than overlooked. In
 * phone landscape the stage is shorter than the board would like, `max-height`
 * clamps it, and the ratio gives way — the board goes wide and the cells go
 * with it. That is the right thing to give up: what actually matters for
 * aiming is that the nine cells are IDENTICAL TO ONE ANOTHER, which a uniform
 * 3x3 grid guarantees at any shape, and the characters keep their proportions
 * either way because of `object-fit: contain`.
 *
 * The alternative — min(width, height) — needs container queries, and the
 * whole board is not worth a feature this site's oldest browsers may not have.
 */
.board {
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  max-width: 34rem;
  max-height: 100%;
  margin: auto;

  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  gap: var(--hole-gap);
  padding: var(--hole-gap);

  border: 1px solid var(--panel-edge);
  border-radius: var(--radius);
  background: linear-gradient(160deg, rgba(255, 232, 176, 0.06), rgba(8, 6, 26, 0.4));
}

/*
 * Fallback where aspect-ratio is missing.
 *
 * @supports not, so it applies ONLY there — unguarded, `height: 100%` would
 * fight the ratio everywhere else and put the stretched cells straight back.
 */
@supports not (aspect-ratio: 1 / 1) {
  .board {
    height: 100%;
    max-height: 34rem;
  }
}

.hole {
  position: relative;
  overflow: hidden;
  padding: 0;
  border: 1px solid var(--panel-edge);
  border-radius: var(--hole-radius);
  background: var(--hole-mouth);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: border-color var(--dur) ease, background var(--dur) ease;
}

/*
 * The number, which is also the key that whacks this hole.
 *
 * Quiet, in a corner, out of the way of the character — but present, because a
 * keyboard shortcut nobody can see is not a keyboard route.
 */
.hole__num {
  position: absolute;
  top: 4px;
  left: 6px;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--text-dim);
  pointer-events: none;
}

/* ---- the moment of the whack -------------------------------------------- */

/*
 * A ring AND a glyph, never a colour on its own — one boy in twelve cannot
 * rely on the difference between the green and the orange.
 */
.hole.is-hit {
  border-color: var(--ok);
  background: radial-gradient(ellipse 100% 70% at 50% 100%, #1b4630 0%, #123021 70%);
}

.hole.is-spared {
  border-color: var(--warn);
  background: radial-gradient(ellipse 100% 70% at 50% 100%, #4a1d10 0%, #33150b 70%);
}

/* The glyph that says which of the two it was. */
.hole__mark {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(1.6rem, 9vw, 2.6rem);
  font-weight: 800;
  line-height: 1;
  pointer-events: none;
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.8);
}

.hole.is-hit    .hole__mark { color: var(--ok); }
.hole.is-spared .hole__mark { color: var(--warn); }

/* -------------------------------------------------------------------------- */
/* 3. The characters                                                          */
/* -------------------------------------------------------------------------- */

/*
 * A character rises out of the hole rather than appearing in it, which is the
 * whole charm of the game. `overflow: hidden` on .hole is what does the hiding.
 *
 * pointer-events: none so a tap always lands on the BUTTON underneath and never
 * on the image — otherwise the hit target changes shape as the character moves,
 * and a child who aims correctly is told they missed.
 */
.character {
  position: absolute;
  left: 5%;
  bottom: 0;
  width: 90%;
  height: 88%;
  object-fit: contain;
  object-position: bottom;
  pointer-events: none;
  transform: translateY(100%);
  transition: transform 170ms ease-out;
}

.character.is-up { transform: translateY(0); }

/* Struck: drops away rather than sliding politely back down. */
.character.is-struck {
  transform: translateY(110%) scale(0.82);
  transition: transform 200ms ease-in;
}

/* -------------------------------------------------------------------------- */
/* 4. The flash row                                                           */
/* -------------------------------------------------------------------------- */

/*
 * FIXED height, and that is the important part. This row changes several times
 * a round — a verdict on every whack, a verse at every tenth devil — and if it
 * grew from one line to two the board above it would jump upwards and move
 * every hole a child was aiming at.
 */
.flash {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  height: 3.3em;
  margin: 0;
  padding: 0 10px;
  overflow: hidden;
  border-radius: var(--radius);
  border: 1px solid var(--panel-edge);
  background: rgba(8, 6, 26, 0.55);
  text-align: center;
  font-size: clamp(0.74rem, 2.8vw, 0.9rem);
  line-height: 1.35;
  color: var(--text);
  transition: border-color var(--dur) ease;
}

.flash.is-right { border-color: rgba(134, 230, 168, 0.55); }
.flash.is-wrong { border-color: rgba(255, 156, 110, 0.55); }

/* A verse, not a verdict — gold, and set as scripture. */
.flash.is-verse {
  border-color: rgba(255, 204, 51, 0.5);
  background: rgba(26, 18, 58, 0.7);
}

.flash__mark {
  flex: 0 0 auto;
  font-size: 1.15em;
  font-weight: 800;
  line-height: 1;
}

.flash.is-right .flash__mark { color: var(--ok); }
.flash.is-wrong .flash__mark { color: var(--warn); }
.flash.is-verse .flash__mark { color: var(--gold-2); }

/* The verse itself, in the display face and italic, so it reads as scripture
   and not as more of the game's own chatter. */
.flash__verse {
  font-family: var(--font-display);
  font-style: italic;
  color: #fdf6e3;
}

.flash__ref {
  font-size: 0.82em;
  font-weight: 700;
  font-style: normal;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--gold-2);
  white-space: nowrap;
}

/* -------------------------------------------------------------------------- */
/* 5. The tally on the score card                                             */
/* -------------------------------------------------------------------------- */

.tally {
  margin: 14px 0 0;
  padding: 0;
  list-style: none;
  text-align: left;
}

.tally__item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 5px 0;
  border-top: 1px solid rgba(255, 214, 130, 0.14);
  font-size: 0.9rem;
}

.tally__item:first-child { border-top: 0; }

.tally__label { color: var(--text-dim); }

.tally__count {
  font-family: var(--font-display);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--gold-1);
}

.tally__item.is-good .tally__count { color: var(--ok); }
.tally__item.is-bad  .tally__count { color: var(--warn); }

/* -------------------------------------------------------------------------- */
/* 6. Responsive                                                              */
/* -------------------------------------------------------------------------- */

@media (hover: hover) {
  .hole:hover { border-color: rgba(255, 214, 130, 0.75); }
}

@media (max-width: 420px) {
  :root { --hole-gap: 6px; }

  .flash { height: 3.6em; padding: 0 8px; }
}

/*
 * Phone landscape.
 *
 * shell.css hides .hud, .hint and .progress here. This game needs the clock —
 * a timed round whose countdown you cannot see is not a countdown — so the
 * progress bar comes back. It is six pixels tall.
 *
 * The board is the thing that must keep its space, and being square it is
 * limited by the height, so everything else tightens around it.
 */
@media (max-height: 460px) and (orientation: landscape) {
  .progress { display: block; }

  .flash { height: 2.3em; font-size: 0.72rem; }

  .hole__num { font-size: 0.6rem; }
}

/*
 * Below 300px the shell stops being a fixed-height column and the page scrolls
 * (Standards.md §5). A square board with no height to work from would collapse,
 * so it is given a floor and allowed to be the size it needs.
 */
@media (max-height: 299px) {
  .board { height: 220px; min-height: 220px; }

  .flash { height: auto; min-height: 3.3em; }
}

/* -------------------------------------------------------------------------- */
/* 7. Reduced motion, forced colours, more contrast, print                    */
/* -------------------------------------------------------------------------- */

/*
 * Reduced motion.
 *
 * The blanket rule in theme.css already reduces every transition to almost
 * nothing, which is exactly right here: a character APPEARS rather than rising,
 * and the game is otherwise identical. Nothing is lost, because the rising was
 * decoration and the popping up was the mechanic.
 *
 * The transform still has to be cancelled explicitly — a transform with no
 * duration still jumps to its end position, and here that end position is
 * "hidden below the hole", which would make characters invisible.
 */
@media (prefers-reduced-motion: reduce) {
  .character {
    transition: none;
    transform: translateY(100%);
  }

  .character.is-up { transform: translateY(0); }

  .character.is-struck { transform: translateY(100%); }
}

/*
 * Windows High Contrast. The system throws the palette away, which would make
 * a hit hole identical to a spared one. The glyphs survive because they are
 * text; these bring the borders back.
 */
@media (forced-colors: active) {
  .board,
  .hole,
  .flash {
    border: 1px solid CanvasText;
  }

  .hole.is-hit    { outline: 4px solid Highlight; outline-offset: -4px; }
  .hole.is-spared { outline: 4px dotted CanvasText; outline-offset: -4px; }

  .hole__mark { color: CanvasText; }
}

@media (prefers-contrast: more) {
  .hole__num { color: var(--text); }

  .tally__label { color: var(--text); }
}

@media print {
  .board,
  .flash {
    display: none !important;
  }
}
