/*
 * Word Grid — board, marks and keyboard.
 *
 * Every colour comes from the custom properties shared/brand.js writes out of
 * brand.config.js, so a buyer's palette reaches this game without a single
 * edit here. Nothing in this file names a brand colour.
 *
 * The only literal colours are the translucent black and white used for
 * recesses and specular top edges — lighting, not brand, exactly as the
 * shared sheet does it for .la-tray and .la-btn--primary. All four are
 * gathered into the --wg-* variables below so there is one place to tune them.
 *
 * The three results are told apart by shape as well as colour — a tick, a
 * ring and a dash — because a one-colour brand and a colour-blind player
 * would otherwise leave the board unreadable. Every state also keeps its
 * text at 4.5:1 or better, which is why "ruled out" recedes with --la-ink-soft
 * rather than fading out.
 */

.wg {
  /*
   * A definite width, because the shell's board is sized to its contents: left
   * to shrink-wrap an intrinsically fluid child it collapses to its 320px
   * floor and the game ends up a postage stamp on a desktop screen.
   *
   * The cost is that max-width cannot rescue it on a narrow screen — the
   * board's fit-content track is laid out at this width before the board's own
   * max-width clamps the box, so the game would simply hang off the edge.
   * Hence the ladder in the media queries at the foot of this file: each step
   * is a width that still fits at the narrowest viewport that reaches it,
   * allowing about 56px for the body and board padding either side.
   */
  width: 400px;
  max-width: 100%;
  display: grid;
  gap: 11px;
  justify-items: stretch;

  --wg-recess: inset 0 2px 5px rgb(0 0 0 / 0.06);
  --wg-recess-deep: inset 0 2px 5px rgb(0 0 0 / 0.09);
  /* For a pressed key, where a 9% shadow disappears under a filled face. */
  --wg-recess-bold: inset 0 2px 5px rgb(0 0 0 / 0.22);
  --wg-specular: inset 0 1px 0 rgb(255 255 255 / 0.22);
  /* The strip and the grid share one narrower column above the full-width
     keyboard, so the three read as one instrument rather than three panels. */
  --wg-inner: 344px;
}

/*
 * The board takes focus so typing has somewhere to land, but a ring around
 * the whole game says very little. Point at the row the letters will go into
 * instead — the same information, where the player is already looking.
 */
.wg:focus-visible {
  outline: none;
}

/* ---- The strip of letters the player has pinned down ------------------ */
/* The label sits above rather than beside, so the slots keep the grid's own
   columns and every pinned letter stands directly over its square. */
.wg-known {
  width: min(100%, var(--wg-inner));
  margin: 0 auto;
  display: grid;
  gap: 5px;
}
.wg-known__label {
  padding-left: 3px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--la-ink-soft);
}
/* --wg-columns is written by game.js from the word length. */
.wg-known__slots {
  display: grid;
  grid-template-columns: repeat(var(--wg-columns, 6), 1fr);
  gap: 6px;
  min-width: 0;
}
/* Empty: a recess waiting to be filled. */
.wg-slot {
  position: relative;
  height: 26px;
  display: grid;
  place-items: center;
  border: 1px solid var(--la-line);
  border-radius: 7px;
  background: var(--la-surface-sunken);
  box-shadow: var(--wg-recess);
  font-size: 13px;
  font-weight: 800;
  line-height: 1;
  text-transform: uppercase;
  color: var(--la-ink-soft);
}
/* Earned: a solid cap lifted out of the recess. */
.wg-slot--guess {
  background-color: var(--la-surface);
  background-image: linear-gradient(180deg, var(--la-surface), var(--la-surface-sunken));
  border-color: var(--la-primary);
  color: var(--la-ink);
  box-shadow: var(--la-shadow-sm), inset 0 1px 0 var(--la-surface-edge);
}
/* Bought, not earned: a dashed edge and a corner pip, so the difference
   survives a one-colour brand. */
.wg-slot--hint {
  background-color: var(--la-primary-soft);
  background-image: linear-gradient(180deg, transparent, var(--la-primary-tint));
  border-style: dashed;
  border-color: var(--la-primary);
  color: var(--la-ink);
  box-shadow: var(--la-shadow-sm);
}
.wg-slot--hint::after {
  content: "";
  position: absolute;
  top: 2px;
  right: 2px;
  width: 4px;
  height: 4px;
  border-radius: 999px;
  background: var(--la-primary);
}

/* ---- Grid ------------------------------------------------------------- */
.wg-grid {
  width: min(100%, var(--wg-inner));
  margin: 0 auto;
  display: grid;
  gap: 6px;
}
.wg-row {
  display: grid;
  grid-template-columns: repeat(var(--wg-columns, 6), 1fr);
  gap: 6px;
}
/* Resting state: a soft recess, hairline edged. Depth comes from the inset
   shadow, not from a heavy border. */
.wg-tile {
  position: relative;
  aspect-ratio: 1 / 1;
  min-height: 42px;
  display: grid;
  place-items: center;
  border: 1px solid var(--la-line);
  border-radius: var(--la-radius-sm);
  background-color: var(--la-surface-sunken);
  box-shadow: var(--wg-recess);
  color: var(--la-ink);
  font-size: clamp(18px, 5.2vw, 27px);
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1;
  text-transform: uppercase;
  transition:
    border-color 0.15s ease,
    box-shadow 0.15s ease,
    background-color 0.15s ease;
}

/* The row waiting for input lifts out of the deck and takes a lit edge. */
.wg-row--active .wg-tile {
  background-color: var(--la-surface);
  background-image: linear-gradient(180deg, var(--la-surface), var(--la-surface-sunken));
  border-color: var(--la-line-strong);
  box-shadow: var(--la-shadow-sm), inset 0 1px 0 var(--la-surface-edge), 0 0 0 2px var(--la-primary-tint);
}
.wg-row--active .wg-tile--filled {
  border-color: var(--la-primary);
}
.wg:focus-visible .wg-row--active .wg-tile {
  border-color: var(--la-primary);
  box-shadow: var(--la-shadow-sm), inset 0 1px 0 var(--la-surface-edge), 0 0 0 2px var(--la-primary-glow);
}

/* Where the next letter lands, blinking like a text caret. */
.wg-tile--caret::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 8px;
  transform: translateX(-50%);
  width: 40%;
  height: 3px;
  border-radius: 2px;
  background: var(--la-primary);
  animation: wg-caret 1.1s linear infinite;
}

/* ---- Scored tiles: material, not flat fills --------------------------- */
.wg-tile--exact {
  background-color: var(--la-primary);
  background-image: linear-gradient(180deg, var(--la-primary), var(--la-primary-hover));
  border-color: transparent;
  color: var(--la-on-primary);
  box-shadow: var(--la-shadow-md), var(--wg-specular);
}
/* Pale brand body, deepened toward the foot with the tint so it has weight
   of its own rather than reading as a white tile with a coloured edge. */
.wg-tile--present {
  background-color: var(--la-primary-soft);
  background-image: linear-gradient(180deg, transparent, var(--la-primary-tint));
  border-color: var(--la-primary);
  color: var(--la-ink);
  box-shadow: var(--la-shadow-sm), inset 0 1px 0 var(--la-surface-edge);
}
/* Ruled out: pressed back into the deck. Quiet, but --la-ink-soft keeps the
   letter above 4.5:1 — dimming it with opacity did not. */
.wg-tile--absent {
  background-color: var(--la-surface-sunken);
  background-image: none;
  border-color: var(--la-line);
  color: var(--la-ink-soft);
  box-shadow: var(--wg-recess-deep);
}

/* ---- Marks ------------------------------------------------------------ */
/* One stroke weight everywhere: the box shrinks on a key, the stroke is
   scaled to match so the tick, ring and dash look like one set. */
.wg-mark {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 11px;
  height: 11px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.92;
}
.wg-tile--absent .wg-mark,
.wg-key--absent .wg-mark {
  opacity: 1;
}

/* ---- Guesses left and the hint --------------------------------------- */
/* Held to the same column as the strip and the grid — it reports on them,
   and one left edge through all three is what stops the board reading as
   three stacked panels. */
.wg-bar {
  width: min(100%, var(--wg-inner));
  margin: 0 auto;
  min-height: 34px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}
.wg-left {
  margin: 0;
  font-size: 13px;
  color: var(--la-ink-soft);
}
/* .la-stat's own label colour is --la-ink-faint, which is under 4.5:1 on the
   board. Everything else about the shell figure is kept. */
.wg-left.la-stat {
  color: var(--la-ink-soft);
}
.wg-left .la-stat__value {
  font-size: 18px;
  font-weight: 800;
}
.wg-bar__actions {
  display: flex;
  gap: 8px;
}
.wg-bar button[hidden] {
  display: none;
}

/* The hint is a purchase, so it carries a price tag rather than looking like
   another neutral button. */
.wg-hint {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding-right: 9px;
}
.wg-hint__cost {
  display: inline-flex;
  align-items: center;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--la-primary-tint);
  color: var(--la-ink);
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.04em;
}
/* Spent: sunken, struck through and at rest. The shell's disabled rule fades
   buttons to 45%, which would put this under contrast, so it is overridden
   and the "spent" reading carried by shape instead. */
.wg-hint[disabled] {
  opacity: 1;
  cursor: default;
  background-image: none;
  background-color: var(--la-surface-sunken);
  border-color: var(--la-line);
  color: var(--la-ink-soft);
  box-shadow: var(--wg-recess);
  padding-right: 15px;
}
.wg-hint[disabled] .wg-hint__label {
  text-decoration: line-through;
  text-decoration-thickness: 1.5px;
}

/* ---- On-screen keyboard ---------------------------------------------- */
.wg-keys {
  width: 100%;
  padding-top: 2px;
  display: grid;
  gap: 6px;
}
.wg-keyrow {
  display: flex;
  gap: 5px;
  justify-content: center;
}
/* The home row is inset by half a key, the way a real keyboard staggers. */
.wg-keyrow--home {
  padding: 0 5%;
}
/* A keycap: gradient face, light top edge, soft shadow under it. */
.wg-key {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  min-height: 46px;
  padding: 0 2px;
  font: inherit;
  font-size: clamp(13px, 3.3vw, 16px);
  font-weight: 700;
  text-transform: uppercase;
  border: 1px solid var(--la-line);
  border-radius: calc(var(--la-radius-sm) - 2px);
  background-color: var(--la-surface);
  background-image: linear-gradient(180deg, var(--la-surface), var(--la-surface-sunken));
  color: var(--la-ink);
  box-shadow: var(--la-shadow-sm), inset 0 1px 0 var(--la-surface-edge);
  cursor: pointer;
  transition:
    transform 0.09s ease,
    box-shadow 0.12s ease,
    border-color 0.15s ease,
    background-color 0.15s ease;
}
.wg-key:focus-visible {
  z-index: 1;
  outline-offset: 2px;
}

/* Enter and Delete are controls, not letters: flat sunken face, a stronger
   edge, a chunky bottom lip and small letterspaced type. */
.wg-key--wide {
  flex: 1.62 1 0;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.07em;
  background-image: none;
  background-color: var(--la-surface-sunken);
  border-color: var(--la-line-strong);
  box-shadow: var(--la-shadow-sm), inset 0 -2px 0 var(--la-line);
}

.wg-key--exact {
  background-color: var(--la-primary);
  background-image: linear-gradient(180deg, var(--la-primary), var(--la-primary-hover));
  border-color: transparent;
  color: var(--la-on-primary);
  box-shadow: var(--la-shadow-md), var(--wg-specular);
}
.wg-key--present {
  background-color: var(--la-primary-soft);
  background-image: linear-gradient(180deg, transparent, var(--la-primary-tint));
  border-color: var(--la-primary);
  color: var(--la-ink);
  box-shadow: var(--la-shadow-sm), inset 0 1px 0 var(--la-surface-edge);
}
/* Ruled out recedes into the deck rather than shouting: the cap is gone and
   a well is left behind — no lift, no light edge, no edge at all. The ink
   still holds 4.5:1, which fading the whole key with opacity did not, and
   the dash keeps it readable without colour. */
.wg-key--absent {
  background-color: var(--la-surface-sunken);
  background-image: none;
  border-color: transparent;
  color: var(--la-ink-soft);
  box-shadow: var(--wg-recess-deep);
}

/* Interaction last, so it wins over the state fills above. */
.wg-key:hover {
  border-color: var(--la-line-strong);
  box-shadow: var(--la-shadow-md), inset 0 1px 0 var(--la-surface-edge);
}
.wg-key--exact:hover,
.wg-key--present:hover {
  border-color: var(--la-primary);
}
.wg-key--absent:hover {
  border-color: var(--la-line);
  box-shadow: var(--wg-recess-deep);
}
.wg-key--wide:hover {
  box-shadow: var(--la-shadow-md), inset 0 -2px 0 var(--la-line);
}
/* A real press: the cap goes down into its own shadow. */
.wg-key:active {
  transform: translateY(1px);
  background-image: linear-gradient(180deg, var(--la-surface-sunken), var(--la-surface));
  box-shadow: var(--wg-recess-deep);
}
.wg-key--exact:active {
  background-image: linear-gradient(180deg, var(--la-primary-hover), var(--la-primary));
  box-shadow: var(--wg-recess-bold);
}
/* These two already sit in a well at rest, so the press has to dig deeper to
   register at all. */
.wg-key--wide:active,
.wg-key--absent:active {
  background-image: none;
  box-shadow: var(--wg-recess-bold);
}

.wg-key .wg-mark {
  top: 3px;
  right: 3px;
  width: 9px;
  height: 9px;
  stroke-width: 2.65;
}

/* ---- Motion ----------------------------------------------------------- */
/* The reveal: each tile swings into place 60ms after the one before it, so a
   six-letter row has finished inside 600ms. */
@keyframes wg-flip {
  from {
    transform: perspective(340px) rotateX(-86deg);
    opacity: 0.5;
  }
  55% {
    opacity: 1;
  }
  to {
    transform: perspective(340px) rotateX(0deg);
    opacity: 1;
  }
}
@keyframes wg-caret {
  0%,
  50% {
    opacity: 1;
  }
  50.01%,
  100% {
    opacity: 0.14;
  }
}
@keyframes wg-nudge {
  20% {
    transform: translateX(-5px);
  }
  40% {
    transform: translateX(4px);
  }
  60% {
    transform: translateX(-3px);
  }
  80% {
    transform: translateX(2px);
  }
}
.wg-tile--reveal {
  animation: wg-flip 250ms cubic-bezier(0.25, 0.8, 0.35, 1) both;
}
.wg-row--rejected {
  animation: wg-nudge 300ms ease-in-out both;
}

@media (prefers-reduced-motion: reduce) {
  .wg-tile--reveal,
  .wg-row--rejected,
  .wg-tile--caret::after {
    animation: none;
  }
  .wg-tile--reveal {
    transform: none;
    opacity: 1;
  }
  .wg-key,
  .wg-tile {
    transition: none;
  }
  .wg-key:active {
    transform: none;
  }
}

/*
 * The width ladder. Each step is the widest the game can be and still fit at
 * the narrowest viewport that reaches that step, once about 56px of body and
 * board padding is taken off. Below 390px the game goes fluid and the board
 * settles on its own 320px floor.
 */
@media (max-width: 470px) {
  .wg {
    width: 368px;
  }
}
@media (max-width: 430px) {
  .wg {
    width: 332px;
  }
}
@media (max-width: 390px) {
  .wg {
    width: 100%;
  }
}

/*
 * The keyboard is the tight case at every step down, and ENTER and DELETE are
 * the tight case within it: the row of ten shrinks evenly, but a six-letter
 * word cannot. Each band gives the two word keys a little more of the row and
 * takes a little off their type, so the labels never spill their caps.
 */
@media (max-width: 430px) {
  .wg-keyrow {
    gap: 4px;
  }
  .wg-key--wide {
    flex: 1.75 1 0;
    font-size: 9.5px;
    letter-spacing: 0.02em;
  }
}

@media (max-width: 390px) {
  .wg {
    gap: 9px;
  }
  .wg-tile {
    min-height: 38px;
    border-radius: 8px;
  }
  .wg-slot {
    height: 24px;
  }
  .wg-keys {
    gap: 4px;
  }
  .wg-keyrow {
    gap: 3px;
  }
  .wg-key {
    min-height: 42px;
    padding: 0 1px;
  }
  .wg-key--wide {
    flex: 1.8 1 0;
    font-size: 9px;
    letter-spacing: 0;
  }
  .wg-keyrow--home {
    padding: 0 3%;
  }
  .wg-known {
    gap: 4px;
  }
}
