/* ============================================================================
   Weblotery Turbo — an instrument, laid out like one.

   The page used to be a single 900px column: a 3rem ⚡ over a centred title, a
   centred engine status, then the configuration form, then the readout, then
   the console — about 400px of chrome before the first control, and the live
   figures always below the fold. It is a tool, so at >=1024px it is now two
   panes: the controls in a rail and the running instrument in the main column,
   with the engine's state moved into the head row where it costs no height.

   Controls come first in the DOM. On a phone there is nothing to watch until
   you have configured something, so the single column reads config -> readout
   -> console; the grid areas move the rail to the inline end only once there
   is width for it, and because they are grid areas rather than floats they
   flip correctly under dir="rtl".

   Colour follows the system rather than the old sheet's habits. --accent was
   on the preset pills, on all three stat figures and on the console's warn
   level; orange is money and the primary action, so it is now spent on the
   start button alone. The stat figures are ink, the presets are neutral with a
   fill step for the pressed one, and the engine dot carries teal only while a
   search is actually running — always next to the word that says so.

   Namespaced .wl-* throughout. The sheet this replaces declared .page-header,
   .page-title, .stat-card, .stat-label, .stat-value, .input-field, .btn and
   .card-title at the top level.
   ========================================================================= */

.wl {
  padding-block: var(--sp-8) var(--sp-16);
}

/* ---------------------------------------------------------------------------
   Head — title, one line of what this is, and the engine's state. The state
   belongs here: it is the fact that decides whether anything below can run.
   ------------------------------------------------------------------------ */

.wl__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3) var(--sp-6);
  margin-block-end: var(--sp-6);
}

.wl__head-text {
  min-width: 0;
  flex: 1 1 28rem;
}

.wl__title {
  font-size: var(--fs-3xl);
  font-weight: 700;
  line-height: var(--lh-tight);
  letter-spacing: var(--tr-display);
  color: var(--ink-050);
}

.wl__subtitle {
  margin-block-start: var(--sp-2);
  max-width: 64ch;
  font-size: var(--fs-md);
  line-height: var(--lh-body);
  color: var(--ink-300);
  text-wrap: pretty;
}

.wl-engine {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  flex: none;
  padding: 0.3125rem var(--sp-3);
  background: var(--ink-850);
  border: 1px solid var(--line);
  border-radius: var(--r-full);
  font-size: var(--fs-sm);
  color: var(--ink-300);
}

.wl-engine__dot {
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: var(--r-full);
  background: var(--ink-500);
}

.wl-engine__dot--loading {
  background: var(--ink-400);
  animation: wl-pulse 1.4s var(--ease) infinite;
}

.wl-engine__dot--ready {
  background: var(--solved);
}

/* Teal is this system's "live". It appears only while a search is running,
   and the word beside it says the same thing. */
.wl-engine__dot--running {
  background: var(--open);
  animation: wl-pulse 2.4s var(--ease) infinite;
}

.wl-engine__dot--error {
  background: var(--danger);
}

@keyframes wl-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.35;
  }
}

/* ---------------------------------------------------------------------------
   The two panes.
   ------------------------------------------------------------------------ */

.wl__grid {
  display: grid;
  gap: var(--sp-6);
  align-items: start;
}

@media (min-width: 1024px) {
  .wl__grid {
    grid-template-columns: minmax(0, 1fr) 360px;
    grid-template-areas: "live config";
    column-gap: var(--sp-8);
  }

  .wl-config {
    grid-area: config;
    position: sticky;
    top: calc(var(--h-header) + var(--sp-6));
  }

  .wl-live {
    grid-area: live;
  }
}

.wl-live {
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
  min-width: 0;
}

/* ---------------------------------------------------------------------------
   Controls.
   ------------------------------------------------------------------------ */

.wl-config__body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
}

/* All 160 wallets, where four used to sit in a wrapping row. At that count the
   row is the wrong container twice over: 27 lines of chips would push the
   start button off a 360px rail, and a hunter looking for one of the 77 open
   ones would read past 83 claimed numbers to find it. So the set gets a filter
   above it and a box of its own to scroll in, and the chips go on a grid — a
   two-digit and a three-digit number cannot share a rail otherwise, and a
   ragged last row of a wrapping flex reads as missing data rather than as the
   end of the list. */

.wl-presets {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

/* A segmented control, the same one the 1000 BTC ledger filters with. */
.wl-presets__filters {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  padding: 3px;
  background: var(--ink-900);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.wl-presets__filter {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  flex: 1 1 auto;
  justify-content: center;
  min-height: 28px;
  padding-inline: var(--sp-2);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--ink-300);
  background: none;
  border: 0;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background-color var(--dur-1) var(--ease),
    color var(--dur-1) var(--ease);
}

.wl-presets__filter:hover {
  background: var(--ink-800);
  color: var(--ink-050);
}

.wl-presets__filter[aria-pressed="true"] {
  background: var(--ink-750);
  color: var(--ink-050);
  box-shadow: var(--sh-1);
}

.wl-presets__count {
  font-size: var(--fs-xs);
  color: var(--ink-400);
}

.wl-presets__filter[aria-pressed="true"] .wl-presets__count {
  color: var(--ink-300);
}

/* Six rows deep at rail width: enough that the list reads as a long one and
   invites the scroll, short enough that the start button stays on screen with
   it. `overscroll-behavior` keeps that scroll off the page behind it — the
   grid is a third of the rail's height, and a flick that ran through to the
   document would move the panel out from under the finger. */
.wl-presets__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(2.75rem, 1fr));
  gap: var(--sp-2);
  max-height: 13.75rem;
  padding-inline-end: var(--sp-1);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.wl-preset {
  min-height: 32px;
  padding: 0.375rem var(--sp-1);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink-300);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background-color var(--dur-1) var(--ease),
    border-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}

.wl-preset:hover {
  background: var(--ink-750);
  border-color: var(--line-hi);
  color: var(--ink-100);
}

/* A claimed wallet recedes rather than disappears. Its key is public, so it is
   the only thing here a search can actually finish on — that is worth keeping
   loadable, and worth never mistaking for an open one. */
.wl-preset.is-solved {
  color: var(--ink-400);
  background: none;
}

.wl-preset.is-solved:hover {
  background: var(--ink-800);
  color: var(--ink-200);
}

/* The loaded preset is marked with a fill step, never with the accent: this is
   a current-item state, and the same rule governs the current nav row. */
.wl-preset.is-active,
.wl-preset.is-solved.is-active {
  background: var(--ink-700);
  border-color: var(--line-hard);
  color: var(--ink-050);
}

/* The filter hides, it never rebuilds the grid: a preset loaded under "todos"
   keeps its pressed state while a narrower filter is on and is still marked
   when the filter widens again. */
.wl-presets[data-filter="open"] .wl-preset.is-solved,
.wl-presets[data-filter="solved"] .wl-preset:not(.is-solved) {
  display: none;
}

.wl-select {
  position: relative;
  display: block;
}

.wl-select__control {
  appearance: none;
  padding-inline-end: var(--sp-10);
}

.wl-select__chevron {
  position: absolute;
  inset-inline-end: var(--sp-3);
  top: 50%;
  transform: translateY(-50%);
  color: var(--ink-400);
  pointer-events: none;
}

.wl-config__actions {
  display: flex;
  gap: var(--sp-3);
}

.wl-config__start {
  flex: 1 1 auto;
}

.wl-config__stop {
  flex: none;
}

/* ---------------------------------------------------------------------------
   Readout — the ledger strip: cells separated by a 1px gap over the rule
   colour, so the separators resolve on both axes and in both directions. The
   key spans the row because it is an identifier, not a figure, and 64 hex
   characters have no business sharing a track with a two-digit number.
   ------------------------------------------------------------------------ */

.wl-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
}

.wl-stats__cell {
  min-width: 0;
  padding: var(--sp-3) var(--sp-5);
  background: var(--ink-850);
}

.wl-stats__cell--key {
  grid-column: 1 / -1;
}

.wl-stats__value {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  margin: var(--sp-1) 0 0;
  font-size: var(--fs-xl);
  font-weight: 600;
  line-height: var(--lh-tight);
  color: var(--ink-050);
}

.wl-stats__unit {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--ink-400);
}

/* A padded key's head is all zeros, so an ellipsis would hide the only part
   that changes. It wraps instead. */
.wl-stats__value--key {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 400;
  line-height: var(--lh-body);
  color: var(--ink-200);
  overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------------------
   Console.
   ------------------------------------------------------------------------ */

.wl-console__output {
  height: clamp(200px, 34vh, 380px);
  overflow-y: auto;
  padding: var(--sp-3) var(--sp-5);
  background: var(--ink-900);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
  font-size: var(--fs-xs);
  line-height: 1.7;
}

.wl-console__empty {
  color: var(--ink-400);
}

.wl-console__entry {
  display: flex;
  gap: var(--sp-3);
  padding-block: 1px;
}

.wl-console__time {
  flex: none;
  color: var(--ink-400);
}

/* Isolated so a hex run inside a Hebrew message cannot reorder the line around
   it, and vice versa. */
.wl-console__message {
  min-width: 0;
  overflow-wrap: anywhere;
  unicode-bidi: isolate;
}

.wl-console__entry--info .wl-console__message {
  color: var(--ink-300);
}

.wl-console__entry--success .wl-console__message {
  color: var(--solved);
}

.wl-console__entry--error .wl-console__message {
  color: var(--danger);
}

/* There is no warning hue in this system and inventing one is not worth a
   token. A warning is louder than a note and is not a failure, so it steps up
   the ink ramp instead of reaching for orange, which is money. */
.wl-console__entry--warn .wl-console__message {
  color: var(--ink-050);
}

/* ---------------------------------------------------------------------------
   The hit.
   ------------------------------------------------------------------------ */

/* The system's one sanctioned rgba() outside tokens.css: a state border is
   written as the token hue at a bespoke alpha, because no --solved-line exists. */
.wl-found {
  border-color: rgba(91, 196, 122, 0.4);
}

.wl-found__header {
  justify-content: flex-start;
  gap: var(--sp-2);
}

.wl-found__icon,
.wl-found__title {
  color: var(--solved);
}

.wl-found__record {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
}

.wl-found__value {
  display: block;
  margin-block-start: var(--sp-1);
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
  color: var(--solved);
  overflow-wrap: anywhere;
}

@media (max-width: 599px) {
  .wl-stats {
    grid-template-columns: minmax(0, 1fr);
  }

  .wl-config__actions {
    flex-direction: column;
  }

  .wl-config__stop {
    flex: 1 1 auto;
  }
}
