/* knights.css - presentation for the Knights puzzle.
 *
 * Tokens live on :root and are all prefixed --kn- so they can sit alongside a
 * host site's own variables without collision. Everything else is scoped under
 * .kn. Theme handling covers all three viewer states: an explicit light or
 * dark choice stamped on the root element, and the unstamped default where
 * only prefers-color-scheme separates them.
 *
 * Palette: slate and boxwood, taken from a tournament board rather than from
 * parchment. The chrome stays deliberately quiet because the board itself is
 * the one loud thing on the page, and a saturated accent would fight the
 * twelve region hues.
 */

:root {
  --kn-bg: #f2f5f8;
  --kn-panel: #e9eef4;
  --kn-ink: #151d1a;
  --kn-ink-soft: #5a6a7a;
  --kn-edge: #141c19;          /* region boundary */
  --kn-piece: #101815;         /* knights and marks */
  --kn-grid: #a9b4c0;          /* cell separator, drawn as the grid gap */
  --kn-accent: #1a5c4d;
  --kn-accent-ink: #f8fbf9;
  --kn-danger: #b23a2c;
  --kn-danger-bg: #f4d2cc;
  --kn-good: #1a6b4a;
  --kn-line: #35485c22;
  --kn-hi-edge: #ffffff;
  --kn-hi-shade: #0f231d59;
  --kn-shadow: 0 1px 2px #0f231d12, 0 6px 20px #0f231d0d;
  --kn-radius: 10px;
  --kn-board-max: 34rem;       /* override to resize the board on your page */

  /* The site's own pairing, so the game reads as part of it rather than as a
     visitor. Source Serif 4 carries the headings on every other page here and
     Roboto the body; the two 3D games use Space Grotesk, which is their own
     register and not one a quiet grid puzzle should borrow. */
  --kn-display: "Source Serif 4", Georgia, "Times New Roman", serif;
  --kn-ui: Roboto, system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
  --kn-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* Region fills. Spread across the hue circle and kept clear of the accent,
     so a region is never mistaken for a control. */
  --kn-r0:#f0b9b0; --kn-r1:#f7d79e; --kn-r2:#e3ea9c; --kn-r3:#a9dda6;
  --kn-r4:#95dcd2; --kn-r5:#a8cdf2; --kn-r6:#bcb8ee; --kn-r7:#dcaeea;
  --kn-r8:#f4b4cf; --kn-r9:#d6cbb2; --kn-r10:#8fd3b6; --kn-r11:#f0c48c;
}

/* Unstamped default: follow the OS, unless the viewer explicitly chose light. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --kn-bg: #0d0f16;
    --kn-panel: #18202a;
    --kn-ink: #e3e9e6;
    --kn-ink-soft: #92a0b0;
    --kn-edge: #05090a;
    --kn-piece: #eef4f1;
    --kn-grid: #46524e;
    --kn-accent: #54b596;
    --kn-accent-ink: #0d1513;
    --kn-danger: #ef7466;
    --kn-danger-bg: #6b2a24;
    --kn-good: #6fc79a;
    --kn-line: #e3e9e622;
    --kn-hi-edge: #f4fbf8;
    --kn-hi-shade: #00000073;
    --kn-shadow: 0 1px 2px #00000047, 0 6px 20px #00000033;

    /* Spread on hue *and* lightness. A dozen swatches pinned to one lightness
       collapse into a single brown smear at a glance. */
    --kn-r0:#a35349; --kn-r1:#8a6b2e; --kn-r2:#5f7a2c; --kn-r3:#2f7a4e;
    --kn-r4:#1f7a76; --kn-r5:#39628f; --kn-r6:#5a52a3; --kn-r7:#8046a0;
    --kn-r8:#a34372; --kn-r9:#6d6656; --kn-r10:#3f9b7a; --kn-r11:#c08a45;
  }
}

/* An explicit dark choice wins over a light OS. */
:root[data-theme="dark"] {
  --kn-bg: #0d0f16;
  --kn-panel: #18202a;
  --kn-ink: #e3e9e6;
  --kn-ink-soft: #92a0b0;
  --kn-edge: #05090a;
  --kn-piece: #eef4f1;
  --kn-grid: #46524e;
  --kn-accent: #54b596;
  --kn-accent-ink: #0d1513;
  --kn-danger: #ef7466;
  --kn-danger-bg: #6b2a24;
  --kn-good: #6fc79a;
  --kn-line: #e3e9e622;
  --kn-hi-edge: #f4fbf8;
  --kn-hi-shade: #00000073;
  --kn-shadow: 0 1px 2px #00000047, 0 6px 20px #00000033;

  --kn-r0:#a35349; --kn-r1:#8a6b2e; --kn-r2:#5f7a2c; --kn-r3:#2f7a4e;
  --kn-r4:#1f7a76; --kn-r5:#39628f; --kn-r6:#5a52a3; --kn-r7:#8046a0;
  --kn-r8:#a34372; --kn-r9:#6d6656; --kn-r10:#3f9b7a; --kn-r11:#c08a45;
}

.kn {
  color: var(--kn-ink);
  font-family: var(--kn-ui);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  max-width: 44rem;
  margin: 0 auto;
  padding: 1.5rem 1rem 3rem;
}

.kn *, .kn *::before, .kn *::after { box-sizing: border-box; }

/* ---------------------------------------------------------- header ---- */
.kn-head { display: flex; align-items: baseline; gap: .7rem; flex-wrap: wrap; margin-bottom: .1rem; }
.kn-title {
  font-family: var(--kn-display);
  font-size: clamp(2rem, 6vw, 2.6rem); font-weight: 500;
  letter-spacing: -.015em; margin: 0; text-wrap: balance;
}
.kn-sub {
  color: var(--kn-ink-soft); font-size: .78rem;
  text-transform: uppercase; letter-spacing: .1em; font-weight: 500;
}
.kn-ruleline {
  margin: .1rem 0 .9rem; color: var(--kn-ink-soft); font-size: .88rem;
}

/* ---------------------------------------------------------- toolbar --- */
.kn-controls {
  background: var(--kn-panel); border-radius: var(--kn-radius);
  box-shadow: var(--kn-shadow); padding: .15rem .65rem; margin-bottom: .2rem;
}
.kn-bar {
  display: flex; flex-wrap: wrap; gap: .45rem; align-items: center;
  padding: .5rem 0;
}
.kn-bar + .kn-bar { border-top: 1px solid var(--kn-line); }
.kn-bar label {
  font-size: .72rem; color: var(--kn-ink-soft); display: flex; align-items: center;
  gap: .35rem; text-transform: uppercase; letter-spacing: .07em; font-weight: 500;
}
/* Board cells are buttons too, so the chrome rules must exclude them or they
   inherit a radius and a stroke that fight the region outlines. */
.kn select, .kn button:not(.kn-cell) {
  font-family: var(--kn-ui); font-size: .85rem; color: var(--kn-ink);
  background: var(--kn-bg); border: 1px solid var(--kn-line); border-radius: 7px;
  padding: .32rem .55rem; cursor: pointer;
}
.kn select { padding-right: .25rem; }
.kn button:not(.kn-cell):hover:not(:disabled) { border-color: var(--kn-accent); color: var(--kn-accent); }
.kn button:not(.kn-cell):disabled { opacity: .38; cursor: default; }
.kn button:not(.kn-cell):focus-visible, .kn select:focus-visible {
  outline: 2px solid var(--kn-accent); outline-offset: 2px;
}
.kn button.kn-on {
  background: var(--kn-accent); color: var(--kn-accent-ink);
  border-color: transparent; font-weight: 600;
}
/* Needs to outrank .kn button:not(.kn-cell):hover above, which has one more
   class than the old form of this rule and so was winning -- painting the
   label accent-green on an accent-green button. Invisible on a desktop hover,
   and stuck that way on a phone, where the hover does not end when you lift
   your finger. */
.kn button.kn-on:not(.kn-cell):hover:not(:disabled) {
  color: var(--kn-accent-ink); border-color: transparent; filter: brightness(1.12);
}
.kn button.kn-primary {
  background: var(--kn-accent); color: var(--kn-accent-ink);
  border-color: transparent; font-weight: 600;
}
.kn button.kn-primary:hover { filter: brightness(1.12); color: var(--kn-accent-ink); }
.kn-spacer { flex: 1 1 auto; }
.kn-clock {
  font-variant-numeric: tabular-nums; font-size: 1.05rem;
  min-width: 3.4rem; text-align: right;
}

/* ------------------------------------------------------------ board --- */
/* The wrapper tracks the board's own width so the win overlay lands on the
   board instead of on the empty gutters beside it. */
.kn-boardwrap {
  position: relative;
  width: min(100%, var(--kn-board-max), 74vh);
  margin: .9rem auto 0;
}
.kn-board {
  display: grid; gap: 1px;
  width: 100%;
  aspect-ratio: 1 / 1;
  border: 4px solid var(--kn-edge); border-radius: 5px;
  background: var(--kn-grid);      /* shows through the gaps as the cell grid */
  touch-action: manipulation; user-select: none; -webkit-user-select: none;
  overflow: hidden;
}
.kn-cell {
  position: relative; display: flex; align-items: center; justify-content: center;
  min-width: 0; min-height: 0; overflow: hidden;
  padding: 0; margin: 0; border: 0; border-radius: 0;
  background: var(--kn-r0); color: var(--kn-piece); cursor: pointer;
  transition: background-color .12s ease;
}
.kn-cell:focus-visible { outline: 3px solid var(--kn-accent); outline-offset: -3px; z-index: 3; }
.kn-cell svg { width: 76%; height: 76%; display: block; pointer-events: none; }

/* Every ruled-out cell gets the same cross, whether you placed it or the board
   worked it out. They still behave differently underneath: yours persist, the
   derived ones come and go with the piece that caused them. */
.kn-cell svg.kn-mark { width: 30%; height: 30%; opacity: .66; }
.kn-mark line { stroke: currentColor; stroke-width: 4; stroke-linecap: round; }

.kn-cell.kn-bad { background: var(--kn-danger-bg) !important; color: var(--kn-danger); }

/* A highlighted square keeps its region colour but gains a bright ring and a
   wash that lifts the hue, so a marked diagonal reads as a diagonal without
   hiding what region the squares belong to. Drawn as an overlay rather than a
   border, because the region outlines already own the cell's box-shadow. */
/* Ring only: tinting the inside washed out the region colour, which is the one
   thing a player still needs to read.
   Two details that were wrong the first time. The ring is inset by the width of
   a region outline, because at inset 0 it painted straight over those outlines
   and the region shapes broke up wherever a diagonal crossed them. And the dark
   contrast line is listed first, so it paints on top of the outer edge of the
   white one and ends up outside it, which is what lets white hold against a
   pale region; listed second it landed inside and read as a hole.
   This lives on ::before so a hint outline, which uses ::after, paints over it
   rather than under. */
.kn-cell.kn-hi::before {
  content: ""; position: absolute; inset: 2px; pointer-events: none; z-index: 1;
  box-shadow: inset 0 0 0 1px var(--kn-hi-shade),
              inset 0 0 0 3px var(--kn-hi-edge);
}

.kn-cell.kn-hintwhy::after {
  content: ""; position: absolute; inset: 2px; pointer-events: none; z-index: 2;
  box-shadow: inset 0 0 0 3px var(--kn-accent);
}
/* The moves a hypothetical placement forces, on the way to the contradiction.
   Dashed so they read as steps rather than as the conclusion. */
.kn-cell.kn-hintstep::after {
  content: ""; position: absolute; inset: 2px; pointer-events: none; z-index: 2;
  border: 2px dashed var(--kn-accent);
}
.kn-cell.kn-hintcell { animation: kn-pulse 1.1s ease-in-out 3; }
@keyframes kn-pulse {
  0%, 100% { box-shadow: inset 0 0 0 0 transparent; }
  50%      { box-shadow: inset 0 0 0 6px var(--kn-accent); }
}
@media (prefers-reduced-motion: reduce) {
  .kn-cell.kn-hintcell { animation: none; box-shadow: inset 0 0 0 5px var(--kn-accent); }
  .kn-cell { transition: none; }
}

/* ------------------------------------------------------------- win ---- */
.kn-win {
  /* Above everything the cells draw. Highlight rings and hint outlines are
     positioned with a z-index of their own, so without one here the overlay
     lands underneath them and the finished board shows through the card. */
  position: absolute; inset: 0; z-index: 5; display: none;
  align-items: center; justify-content: center;
  background: #0a12106b; backdrop-filter: blur(2px); border-radius: 4px;
}
.kn-win.kn-show { display: flex; }
.kn-wincard {
  background: var(--kn-panel); padding: 1.4rem 1.8rem; border-radius: var(--kn-radius);
  box-shadow: var(--kn-shadow); text-align: center; max-width: 20rem;
}
.kn-wincard h2 {
  margin: 0 0 .3rem; font-family: var(--kn-display); font-weight: 500;
  font-size: 1.6rem; color: var(--kn-good);
}
.kn-wincard p { margin: 0 0 1rem; color: var(--kn-ink-soft); font-size: .9rem; }

/* ----------------------------------------------------------- notes ---- */
.kn-status {
  min-height: 1.5rem; margin: .45rem 0 0; font-size: .9rem;
  color: var(--kn-ink-soft); text-align: center;
}
.kn-status.kn-err { color: var(--kn-danger); }

.kn-panel {
  margin-top: 1rem; background: var(--kn-panel); border-radius: var(--kn-radius);
  box-shadow: var(--kn-shadow); padding: .3rem 1.1rem;
}
.kn-panel summary {
  cursor: pointer; padding: .6rem 0; font-weight: 500;
  font-family: var(--kn-display); font-size: 1.1rem;
}
.kn-panel summary:focus-visible { outline: 2px solid var(--kn-accent); outline-offset: 2px; }
.kn-panel ul { margin: .2rem 0 .9rem; padding-left: 1.15rem; }
.kn-panel li { margin: .35rem 0; }
.kn-panel p { margin: .5rem 0 .9rem; color: var(--kn-ink-soft); font-size: .89rem; }
.kn-seed { font-family: var(--kn-mono); font-size: .78rem; }
.kn-seed a { color: var(--kn-accent); }

@media (max-width: 480px) {
  .kn { padding: 1rem .6rem 2rem; }
  .kn-bar { gap: .3rem; padding: .4rem; }
  .kn select, .kn button:not(.kn-cell) { font-size: .8rem; padding: .28rem .42rem; }
}

/* ------------------------------------------------- daily and board ---- */
/* The streak sits under the time, in the accent, because it is the one line
   a returning player looks for. */
.kn-streak {
  margin: -.6rem 0 1rem !important; font-family: var(--kn-display);
  color: var(--kn-good); font-size: .95rem;
}

/* Asking for a name is a form inside the win card, so it inherits the card's
   centring and needs its own left-aligned label to stop reading as a caption. */
.kn-namebox { margin: 0 0 .9rem; text-align: left; }
.kn-namelab {
  display: block; font-size: .78rem; letter-spacing: .04em;
  text-transform: uppercase; color: var(--kn-ink-soft); margin-bottom: .35rem;
}
.kn-namerow { display: flex; gap: .4rem; }
.kn-nameinput {
  flex: 1 1 auto; min-width: 0; font: inherit; font-size: .95rem;
  padding: .4rem .55rem; border-radius: calc(var(--kn-radius) - 2px);
  border: 1px solid var(--kn-grid); background: var(--kn-bg); color: var(--kn-ink);
}
.kn-nameinput:focus-visible { outline: 2px solid var(--kn-accent); outline-offset: 1px; }
.kn-namenote { margin: .5rem 0 0 !important; font-size: .82rem; min-height: 1.1rem; }
.kn-skip {
  display: block; margin: .5rem auto 0; background: none; border: none;
  color: var(--kn-ink-soft); font-size: .82rem; text-decoration: underline;
  cursor: pointer; padding: .2rem;
}
.kn-skip:hover { color: var(--kn-ink); }

.kn-lbcard { max-width: 22rem; width: min(22rem, 86vw); }
.kn-lbdate {
  margin: 0 0 .8rem !important; font-family: var(--kn-mono, monospace);
  font-size: .8rem; letter-spacing: .04em;
}
.kn-lbbody { min-height: 3rem; }
.kn-lbempty { margin: .6rem 0 1rem !important; }
.kn-lbrows {
  list-style: none; margin: 0 0 1rem; padding: 0; text-align: left;
  max-height: 46vh; overflow-y: auto;
  /* A long board scrolls, so it keeps a bar -- hiding it entirely would leave
     no sign the list continues. Just a slim one in the page's own muted ink
     rather than the operating system's. */
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--kn-grid) transparent;
}
.kn-lbrows::-webkit-scrollbar { width: 6px; }
.kn-lbrows::-webkit-scrollbar-track { background: transparent; }
.kn-lbrows::-webkit-scrollbar-thumb {
  background: var(--kn-grid); border-radius: 3px;
}
.kn-lbrows::-webkit-scrollbar-thumb:hover { background: var(--kn-ink-soft); }
.kn-lbrows li {
  display: grid; grid-template-columns: 1.9rem 1fr auto; align-items: baseline;
  gap: .5rem; padding: .28rem .35rem; border-radius: 4px; font-size: .92rem;
}
.kn-lbrows li + li { border-top: 1px solid var(--kn-line); }
.kn-lbmine { background: var(--kn-accent); color: var(--kn-accent-ink); }
.kn-lbrank { color: var(--kn-ink-soft); font-variant-numeric: tabular-nums; }
.kn-lbmine .kn-lbrank { color: var(--kn-accent-ink); }
/* Names wrap rather than ellipsing: a leaderboard that shows "christopher..."
   is worse than one with a two-line row, and the row grows to fit. */
.kn-lbname { overflow-wrap: anywhere; min-width: 0; }
.kn-lbrows li { align-items: start; }
.kn-lbtime { font-variant-numeric: tabular-nums; }

/* -------------------------------------------------------------- tabs ---- */
/* The two games share a page, and the selected tab is the page's title, so
   these are sized as headings rather than as controls. Each selector names the
   element as well as the class: .kn button:not(.kn-cell) above carries an
   element in it, so a pure two-class selector loses to it and the muted colour
   silently never lands. */
.kn .kn-tabs { display: flex; align-items: baseline; gap: 1.9rem; }
.kn button.kn-tab {
  font-family: var(--kn-display);
  font-size: clamp(1.9rem, 5.6vw, 2.6rem); font-weight: 500;
  letter-spacing: -.015em; line-height: 1.06;
  background: none; border: 0; border-bottom: 2px solid transparent;
  border-radius: 0; padding: 0 0 .1em; margin: 0; cursor: pointer;
  color: var(--kn-ink-soft); opacity: .55;
}
.kn button.kn-tab:hover:not(:disabled) { color: var(--kn-ink); opacity: .85; }
.kn button.kn-tab.kn-tabon {
  color: var(--kn-ink); opacity: 1; border-bottom-color: var(--kn-accent);
}
.kn button.kn-tab:focus-visible { outline: 2px solid var(--kn-accent); outline-offset: 3px; }

/* --------------------------------------------------- leaderboard call ---- */
/* Pushed to the far right of the head, opposite the game's name, and sized
   like a destination rather than like the row of small tools below it. The
   margin-left is what does the pushing, so the tabs keep their natural width
   and the button does not need a wrapper of its own. */
.kn button.kn-lbbig {
  margin-left: auto;
  align-self: center;
  display: inline-flex; align-items: center; gap: .45rem;
  font-family: var(--kn-ui); font-size: .92rem; font-weight: 600;
  letter-spacing: .01em;
  padding: .5rem .85rem;
  border-radius: 9px;
  border: 1px solid var(--kn-accent);
  background: var(--kn-accent); color: var(--kn-accent-ink);
}
.kn button.kn-lbbig svg { width: 1.05rem; height: 1.05rem; flex: 0 0 auto; }
.kn button.kn-lbbig:hover:not(:disabled) {
  color: var(--kn-accent-ink); border-color: var(--kn-accent);
  filter: brightness(1.1);
}
.kn button.kn-lbbig:focus-visible {
  outline: 2px solid var(--kn-accent); outline-offset: 3px;
}
/* On a narrow screen the head wraps, and a button carrying auto margin in a
   wrapped flex row lands alone on its own line pushed right, which reads as a
   stray. Full width is the honest layout there. */
@media (max-width: 560px) {
  /* Right-aligned on its own line rather than stretched across it. Full width
     made it the loudest thing on the page and spent a whole row of height the
     board wanted. */
  .kn button.kn-lbbig { margin-left: auto; width: auto; }
}

/* The status line is now only ever a hint, so it can be quiet until there is
   one rather than holding a gap open under the board. */
/* The line keeps its height whether or not it holds a hint, and is bounded
   above as well. It used to collapse when empty, so a hint appearing moved
   everything below it; then it was only floored, so a long hint on a narrow
   screen grew past its reservation and ran into the link underneath. Bounded
   both ways, the box never changes size, and a hint too long for it scrolls
   inside rather than pushing the page around. */
.kn-status {
  /* Two full lines, which is what every hint the ladder writes comes to.
     2.6rem was three pixels short of that, so each one was quietly clipped. */
  min-height: 3rem; max-height: 3rem;
  overflow-y: auto; overscroll-behavior: contain;
  /* The bar is suppressed the same way the rest of the site suppresses it.
     A scroll bar on two lines of text reads as a broken box, and the line can
     still be scrolled by wheel or touch on the rare hint that overruns. */
  scrollbar-width: none;
}
.kn-status::-webkit-scrollbar { display: none; }
@media (max-width: 560px) {
  .kn-status {
    font-size: .82rem; line-height: 1.4;
    min-height: 3.7rem; max-height: 3.7rem;
  }
}
.kn-subline { margin: .35rem 0 0; }

/* --------------------------------------------------------- start gate ---- */
/* The daily arrives covered so it cannot be read before the clock runs. The
   blur is on the board rather than the overlay because a backdrop-filter over
   a still-legible grid leaves the region shapes readable, which is most of
   what you would want to see early. */
.kn-board.kn-veiled {
  filter: blur(9px) saturate(.75);
  pointer-events: none;
  user-select: none;
}
.kn-gate { background: #0a121038; backdrop-filter: none; }
.kn-gatecard { max-width: 17rem; }
.kn-gateday {
  margin: 0 0 .15rem !important;
  font-family: var(--kn-ui); font-size: .72rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--kn-ink-soft);
}
.kn-gatecard h2 { color: var(--kn-ink) !important; text-transform: capitalize; }
/* The negative margin tucked this under a piece count that is no longer there. */
.kn-gatedone { color: var(--kn-good) !important; }

/* The pair that chooses which kind of board you are on. Styled as a segmented
   choice rather than as two buttons, because only one of them is ever true and
   the bar should say which. kn-on is the shared selected state. */
.kn .kn-choice { font-weight: 500; }
.kn .kn-choice + .kn-choice { margin-left: -1px; }

.kn-postedbox { margin-bottom: .4rem; }

/* One veil at a time. The board is already blurred behind the start card, so
   an overlay opened on top of it must add neither a second blur nor a second
   scrim: the blur was the obvious half, but the darkening stacked too, and
   going from the gate's light tint to the leaderboard's heavier one over an
   already-blurred board is what read as doubling up. Same weight as the gate. */
.kn-boardwrap.kn-noblur .kn-win {
  backdrop-filter: none;
  background: #0a121038;
}

/* The finished card says the time, so the time is the thing to look at. */
.kn-wintime {
  font-family: var(--kn-display); font-size: 2.1rem; line-height: 1.1;
  color: var(--kn-ink) !important; margin: 0 0 1rem !important;
  font-variant-numeric: tabular-nums;
}


/* ---------------------------------------------------- controls, redone ---- */
/* The bar is a surface the board sits under, not a panel competing with it, so
   it takes the page's own panel tone and a hairline instead of a shadow. */
.kn-controls {
  background: var(--kn-panel);
  box-shadow: none;
  border: 1px solid var(--kn-line);
}

/* Sentence case at a readable size. Small uppercase letter-spaced text is for
   labelling a thing once, not for two switches you read every visit. */
.kn-bar label {
  font-size: .84rem; text-transform: none; letter-spacing: 0; font-weight: 400;
  gap: .45rem; cursor: pointer; user-select: none;
}

/* A checkbox in the game's own accent rather than whatever the browser paints,
   which was a red tick sitting alone on a green and blue page. */
.kn .kn-bar input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  width: 1.05rem; height: 1.05rem; margin: 0; flex: 0 0 auto;
  border: 1px solid var(--kn-grid); border-radius: 5px;
  background: var(--kn-bg); cursor: pointer;
  display: inline-grid; place-content: center;
  transition: background-color .12s, border-color .12s;
}
.kn .kn-bar input[type="checkbox"]::before {
  content: ""; width: .62rem; height: .62rem; transform: scale(0);
  transition: transform .12s ease-out;
  background: var(--kn-accent-ink);
  clip-path: polygon(14% 47%, 0 61%, 39% 100%, 100% 22%, 86% 9%, 38% 71%);
}
.kn .kn-bar input[type="checkbox"]:checked {
  background: var(--kn-accent); border-color: var(--kn-accent);
}
.kn .kn-bar input[type="checkbox"]:checked::before { transform: scale(1); }
.kn .kn-bar input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--kn-accent); outline-offset: 2px;
}
.kn-bar label:hover input[type="checkbox"]:not(:checked) { border-color: var(--kn-accent); }

/* ------------------------------------------------ leaderboard, redone ---- */
.kn-lbcard h2 { color: var(--kn-ink) !important; }
.kn-lbdate {
  margin: 0 0 1rem !important; font-family: var(--kn-ui);
  font-size: .78rem; letter-spacing: .06em; text-transform: uppercase;
}
/* The first three get their number in the accent. Nothing more: a medal per
   row would be three more colours on a page that already carries twelve. */
.kn-lbrows li:nth-child(-n+3) .kn-lbrank { color: var(--kn-accent); font-weight: 600; }
/* ...except on your own row, which is already painted in the accent. Left to
   the rule above, a first place of your own drew the number in the same colour
   as the strip behind it and the rank vanished. */
.kn-lbrows li.kn-lbmine .kn-lbrank { color: var(--kn-accent-ink); }
.kn-lbrows li { padding: .34rem .4rem; }
.kn-lbempty {
  color: var(--kn-ink-soft); font-style: italic;
}


/* --------------------------------------------------------- on a phone ---- */
/* The board is the point and the controls are not, so on a small screen the
   board takes the width back off the margins and the menu gives up some of
   its padding. Nothing is removed -- the same controls, closer together. */
@media (max-width: 560px) {
  /* The two names are the title of the page and were reading as a label.
     8.6vw puts them at about 32px on a 375 screen instead of 30, and lets them
     keep growing on a larger phone rather than stopping at the floor. */
  /* Sized so the two names and the leaderboard share one row. Any larger and
     the button wraps, which costs a whole line on the screen with the least of
     it -- and bishops needs that line, since its extra controls wrap the bar. */
  .kn button.kn-tab { font-size: clamp(1.75rem, 7.1vw, 2.3rem); }
  .kn .kn-tabs { gap: 1.05rem; }
  .kn button.kn-lbbig { font-size: .8rem; padding: .38rem .6rem; gap: .35rem; }
  .kn button.kn-lbbig svg { width: .95rem; height: .95rem; }
  .kn-controls { padding: .1rem .5rem; border-radius: 8px; }
  .kn-bar { gap: .35rem; padding: .38rem 0; }
  .kn-bar label { font-size: .78rem; gap: .35rem; }
  .kn .kn-bar input[type="checkbox"] { width: .95rem; height: .95rem; }
  /* Not the tabs. This ties with .kn button.kn-tab on specificity and comes
     later in the file, so without the exclusion it silently shrank the two
     names to .8rem -- which is why they read as a label rather than a title. */
  .kn select, .kn button:not(.kn-cell):not(.kn-tab) {
    font-size: .8rem; padding: .26rem .45rem;
  }
  .kn button.kn-lbbig { font-size: .86rem; padding: .42rem .7rem; }
  .kn-clock { font-size: .95rem; }
  .kn-ruleline { font-size: .8rem; margin-bottom: .55rem; }
  .kn-subline { margin-top: .25rem; }

  /* The card was 86vw, which left a finger's width of blurred board down each
     side and squeezed the longer names. */
  .kn-lbcard { width: min(24rem, 94vw); max-width: none; padding: 1.1rem 1rem; }
  .kn-lbrows li { grid-template-columns: 1.6rem 1fr auto; gap: .4rem; }
}


/* ------------------------------------------------------ hints, in order ---- */
/* A hint is told a step at a time, so each mark arrives rather than appearing:
   the supposition first, then what it forces, then the region it empties, then
   the conclusion. The order is the argument. */
@keyframes kn-hintin {
  from { opacity: 0; transform: scale(.8); }
  to   { opacity: 1; transform: scale(1); }
}
.kn-cell.kn-hinttry::after,
.kn-cell.kn-hintwhy::after,
.kn-cell.kn-hintstep::after,
.kn-cell.kn-hintcell::after { animation: kn-hintin .26s ease-out both; }

/* The square the argument supposes a piece on. Grey rather than accent, and
   open rather than filled, so it reads as the question and not the answer --
   the same square turns accent at the end when it becomes the conclusion. */
.kn-cell.kn-hinttry::after {
  content: ""; position: absolute; inset: 2px; pointer-events: none; z-index: 2;
  box-shadow: inset 0 0 0 3px var(--kn-ink-soft);
}

/* The conclusion keeps its ring after the pulse has run. It used to fade back
   to nothing, which was fine when the hint cleared itself after six seconds
   and is not now that it waits to be dismissed. */
.kn-cell.kn-hintcell::after {
  content: ""; position: absolute; inset: 2px; pointer-events: none; z-index: 3;
  box-shadow: inset 0 0 0 4px var(--kn-accent);
}

/* While a hint is up the board does not take pieces, so it stops offering to:
   the text goes to full ink to show it is the live thing on the screen. */
.kn-hinting .kn-board { cursor: default; }
.kn-hinting .kn-status { color: var(--kn-ink); }

@media (prefers-reduced-motion: reduce) {
  .kn-cell.kn-hinttry::after,
  .kn-cell.kn-hintwhy::after,
  .kn-cell.kn-hintstep::after,
  .kn-cell.kn-hintcell::after { animation: none; }
}
