/* Slippy Labs accessibility overrides — vision.
 * https://slippylabs.com/a11y/a11y.css
 *
 * Loaded cross-origin from the root site on every Luck Games page, the same way
 * deck.js is, so there is one copy to update rather than a 19-file sweep for
 * every tweak. It must be linked AFTER each site's own style.css: almost every
 * rule here is equal-specificity with the one it overrides and wins on source
 * order alone, which is what keeps !important out of this file.
 *
 * State lives on <html>, set by the small inline snippet in each page's <head>
 * BEFORE first paint (see a11y.js for the shared implementation of the same
 * parse). Two scalars as custom properties, two modes as data-attributes:
 *
 *   --a11y-text        1 | 1.15 | 1.3 | 1.5     text scale
 *   --a11y-card        1 | 1.15 | 1.3 | 1.5     card / board geometry scale
 *   data-a11y-contrast 0 | 1                    high contrast
 *   data-a11y-cb       0 | 1 | 2 | 3            off / deuter / prot / tritanopia
 *
 * Every default is the identity, so a page that never sets any of them renders
 * exactly as it did before this file existed. That is deliberate: the geometry
 * edits in each site's own style.css land as visual no-ops and can be deployed
 * ahead of, or independently of, the panel.
 */

/* ---- 1. text scale ---------------------------------------------------------
   Safe as one global lever because these sites size essentially everything in
   rem and not one of them sets a root font-size (checked across all 19: the
   px font-size declarations number one or two per file, inside media queries).
   Anything still in px is left alone on purpose -- see the card scale below,
   which is the separate control for the fixed geometry. */
html { font-size: calc(100% * var(--a11y-text, 1)); }


/* ---- 2. focus ring ---------------------------------------------------------
   Unconditional, not gated behind a mode. No casino stylesheet defines
   :focus-visible at all, so keyboard focus is currently invisible on every one
   of these pages -- for everybody, not only for the people this file is for.
   currentColor keeps it legible on the card faces and light modals too. */
:focus-visible {
  outline: 3px solid currentColor;
  outline-offset: 2px;
}
html[data-a11y-contrast="1"] :focus-visible {
  outline-width: 4px;
}


/* ---- 3. high contrast ------------------------------------------------------
   The two repaired tokens are DERIVED, not chosen: test/derive.js runs
   contrast-checker.slippylabs.com's own suggest() against the real panel
   colour and returns the nearest passing colour. test/assert.js re-checks the
   values below against the same oracle, so a hand-edit here that drops one
   under its target fails the test run. Measured on #0b1815:

     --hud-green-dim  #1c8a52  4.16:1  ->  #25b96e  7.13:1   (AAA; it is used
                                                   as color:, not just borders)
     --panel-border   #1b6940  2.72:1  ->  #259259  4.62:1   (was under the
                                                   3:1 non-text floor entirely)
     --text-dim       #7fa695  6.74:1  ->  #85aa9a  7.11:1   (AAA)

   #0b1815 is what the current translucent --bg-panel already composites to
   over --bg-deep, so making it opaque changes the panel's colour by nothing
   visible while removing the starfield show-through underneath it -- which was
   the real legibility problem, not the z-order. */
html[data-a11y-contrast="1"] {
  --hud-green-dim: #25b96e;
  --panel-border: #259259;
  --text-dim: #85aa9a;
  --bg-panel: #0b1815;
}

/* The moving layers go entirely. They sit behind the content rather than over
   it, but they show through the panel and add luminance noise behind small dim
   text, which is exactly what contrast sensitivity cannot cope with. */
html[data-a11y-contrast="1"] .starfield,
html[data-a11y-contrast="1"] .scanlines,
html[data-a11y-contrast="1"] .starfox-horizon,
html[data-a11y-contrast="1"] .asteroid,
html[data-a11y-contrast="1"] .asteroid-spin {
  display: none !important;
}

/* Flat body, no gradient: a gradient means the contrast ratio behind any given
   line of text depends on where it happens to sit on the page. */
html[data-a11y-contrast="1"] body {
  background: var(--bg-deep) !important;
}

/* Same shape as the perf-lite block every one of these stylesheets already
   carries -- blur and blend are the two things that soften small glyphs. */
html[data-a11y-contrast="1"] *,
html[data-a11y-contrast="1"] *::before,
html[data-a11y-contrast="1"] *::after {
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  mix-blend-mode: normal !important;
  text-shadow: none !important;
}

/* Glows read as blur at the edge of a glyph or a border. Keep the shadows that
   do structural work (the card's drop shadow, inset depth on buttons) by only
   dropping the coloured outer glows. */
html[data-a11y-contrast="1"] .hud-panel,
html[data-a11y-contrast="1"] .hud-tab,
html[data-a11y-contrast="1"] .seat-box,
html[data-a11y-contrast="1"] .hand-block,
html[data-a11y-contrast="1"] .bet-chip {
  box-shadow: none;
}
html[data-a11y-contrast="1"] .toad-avatar,
html[data-a11y-contrast="1"] .comm-portrait svg {
  filter: none;
}

/* Borders at 1px in a dim green were the least visible thing on these pages.
   The token repair above fixes the colour; this gives them enough width to be
   seen at all. */
html[data-a11y-contrast="1"] .hud-panel,
html[data-a11y-contrast="1"] .seat-box,
html[data-a11y-contrast="1"] .bet-cell,
html[data-a11y-contrast="1"] .hud-tab,
html[data-a11y-contrast="1"] .game-btn {
  border-width: 2px;
}


/* ---- 4. colour-blind modes -------------------------------------------------
   Redundancy, never simulation. Where colour already has a companion cue the
   surface is left alone: chess and checkers differ by luminance and shape,
   minesweeper's cells carry the digit itself, horse rows are labelled by name
   and number, and bingo already ships its own daub-colour picker.

   That leaves three real gaps: card suits, roulette's bet cells, and sudoku's
   given/conflict cells.

   The three deck palettes are SEARCHED, not picked: test/suits.js simulates
   each dichromacy (Vienot-Brettel-Mollon) and requires every pair of suits to
   stay at least 25 dE apart in CIELAB afterwards, while every colour still
   clears 4.5:1 on the card face. That check is the reason clubs are teal and
   not green under deuteranopia, and the reason hearts shift toward burnt
   orange under protanopia -- a deep red is very dark to a protanope and
   collapses onto spades. Hue families are constrained so the deck still reads
   as a deck rather than as whatever maximises separation.

   Two selectors per suit: most games put the suit in a class, crazy8s already
   emitted data-suit before this and needs no JS change. The `i` flag matters
   -- that attribute carries an uppercase letter. */

/* deuteranopia — worst pair 28.8 dE */
html[data-a11y-cb="1"] .pcard.s-h, html[data-a11y-cb="1"] .pcard[data-suit="h" i] { color: #c62828; }
html[data-a11y-cb="1"] .pcard.s-d, html[data-a11y-cb="1"] .pcard[data-suit="d" i] { color: #1565c0; }
html[data-a11y-cb="1"] .pcard.s-c, html[data-a11y-cb="1"] .pcard[data-suit="c" i] { color: #00695c; }
html[data-a11y-cb="1"] .pcard.s-s, html[data-a11y-cb="1"] .pcard[data-suit="s" i] { color: #1a1a1a; }

/* protanopia — worst pair 32.8 dE */
html[data-a11y-cb="2"] .pcard.s-h, html[data-a11y-cb="2"] .pcard[data-suit="h" i] { color: #a84300; }
html[data-a11y-cb="2"] .pcard.s-d, html[data-a11y-cb="2"] .pcard[data-suit="d" i] { color: #1565c0; }
html[data-a11y-cb="2"] .pcard.s-c, html[data-a11y-cb="2"] .pcard[data-suit="c" i] { color: #00695c; }
html[data-a11y-cb="2"] .pcard.s-s, html[data-a11y-cb="2"] .pcard[data-suit="s" i] { color: #1a1a1a; }

/* tritanopia — worst pair 38.5 dE; this is the classic four-colour deck */
html[data-a11y-cb="3"] .pcard.s-h, html[data-a11y-cb="3"] .pcard[data-suit="h" i] { color: #c62828; }
html[data-a11y-cb="3"] .pcard.s-d, html[data-a11y-cb="3"] .pcard[data-suit="d" i] { color: #1565c0; }
html[data-a11y-cb="3"] .pcard.s-c, html[data-a11y-cb="3"] .pcard[data-suit="c" i] { color: #2e7d32; }
html[data-a11y-cb="3"] .pcard.s-s, html[data-a11y-cb="3"] .pcard[data-suit="s" i] { color: #1a1a1a; }

/* Roulette. The number is the label; red/black/green is a background tint and
   nothing else, so the board is unreadable the moment those two tints converge.
   A texture is the cue that survives every deficiency. */
html[data-a11y-cb]:not([data-a11y-cb="0"]) .bet-cell.red {
  background-image: repeating-linear-gradient(45deg,
    rgba(255,255,255,0.28) 0 3px, transparent 3px 7px);
}
html[data-a11y-cb]:not([data-a11y-cb="0"]) .bet-cell.green {
  background-image: repeating-linear-gradient(-45deg,
    rgba(255,255,255,0.34) 0 2px, transparent 2px 6px);
}
/* .bet-cell.black stays flat -- "no texture" is the third state, and adding a
   pattern to all three would make them harder to tell apart, not easier. */

/* Sudoku. A given and a conflict differ only by hue today. Weight separates the
   given (it is the one cell you can never type into), and a corner mark plus a
   ring separates the conflict. */
html[data-a11y-cb]:not([data-a11y-cb="0"]) .sk-cell.given {
  font-weight: 900;
  text-decoration: underline;
  text-underline-offset: 2px;
}
html[data-a11y-cb]:not([data-a11y-cb="0"]) .sk-cell.conflict {
  outline: 2px solid currentColor;
  outline-offset: -2px;
  position: relative;
}
html[data-a11y-cb]:not([data-a11y-cb="0"]) .sk-cell.conflict::after {
  content: "!";
  position: absolute;
  top: 0;
  right: 2px;
  font-size: 0.6em;
  line-height: 1;
  font-weight: 900;
}


/* ---- 5. the panel ----------------------------------------------------------
   Self-contained on purpose. The obvious move was to reuse each site's
   .rules-modal / .game-btn styling, but six of the nineteen pages (the hub,
   bingo, minesweeper, sudoku, solitaire, freecell) define neither -- they never
   had a rules modal. What all nineteen DO share is the :root token block and
   .hud-panel, so the panel is built from tokens and degrades to sane literals
   if a future page lacks them.

   The trigger chip is the exception: it is given the site's own .rules-link and
   .logout-link classes so it looks native in the header, and anything this file
   adds to it is wrapped in :where() -- zero specificity -- so the site's own
   rules always win. */
:where(.sla11y-btn) {
  font: inherit;
  cursor: pointer;
  background: none;
}

/* [hidden] with !important, and never the sites' own .hidden class.
   Twice on this estate a modal has been hidden by a class that a later
   display: rule silently outranked, leaving a full-viewport invisible layer
   swallowing every click on the page underneath. This cannot lose. */
.sla11y-modal[hidden] { display: none !important; }

.sla11y-modal {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(2, 6, 9, 0.72);
  overflow-y: auto;
}
.sla11y-card {
  position: relative;
  width: min(460px, 100%);
  max-height: 90vh;
  overflow-y: auto;
  padding: 20px 20px 24px;
  background: var(--bg-panel, #0b1815);
  border: 1px solid var(--panel-border, #259259);
  border-radius: 6px;
  color: var(--text-main, #d9fbe8);
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  font-size: 0.9rem;
  line-height: 1.5;
}
.sla11y-card h2 {
  margin: 0 0 4px;
  font-size: 1rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--hud-green, #39ff8f);
}
.sla11y-lede {
  margin: 0 0 16px;
  color: var(--text-dim, #7fa695);
  font-size: 0.8rem;
}
.sla11y-close {
  position: absolute;
  top: 10px;
  right: 10px;
  min-width: 44px;
  min-height: 44px;
  border: 1px solid var(--panel-border, #259259);
  border-radius: 4px;
  background: none;
  color: var(--text-main, #d9fbe8);
  font: inherit;
  font-size: 1rem;
  cursor: pointer;
}
.sla11y-close:hover { color: var(--hud-green, #39ff8f); }

.sla11y-group { margin: 0 0 16px; border: 0; padding: 0; }
.sla11y-group legend {
  padding: 0;
  margin-bottom: 6px;
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim, #7fa695);
}
.sla11y-options { display: flex; flex-wrap: wrap; gap: 6px; }
.sla11y-options label { flex: 1 1 auto; display: flex; cursor: pointer; }
/* The radio is visually hidden but still focusable and still hit-testable
   (opacity, not display:none) -- the chip next to it is the visible control,
   so the styling hangs off the adjacent sibling rather than :has(), which
   keeps this working on older engines too. */
.sla11y-options input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.sla11y-options span {
  flex: 1 1 auto;
  /* 44px, the same thumb target the rest of these pages settled on. */
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px 12px;
  border: 1px solid var(--panel-border, #259259);
  border-radius: 4px;
  text-align: center;
  white-space: nowrap;
}
.sla11y-options label:hover span { border-color: var(--hud-green, #39ff8f); }
/* The selected state is a border AND a background AND a weight change, never
   colour alone. This is, after all, the colour-blind settings panel. */
.sla11y-options input:checked + span {
  border-color: var(--hud-green, #39ff8f);
  background: rgba(57, 255, 143, 0.16);
  color: var(--hud-green, #39ff8f);
  font-weight: bold;
}
.sla11y-options input:focus-visible + span {
  outline: 3px solid currentColor;
  outline-offset: 2px;
}

.sla11y-sample {
  display: flex;
  gap: 6px;
  margin: -6px 0 16px;
}
.sla11y-note {
  margin: 16px 0 0;
  font-size: 0.72rem;
  color: var(--text-dim, #7fa695);
}
.sla11y-reset {
  margin-top: 12px;
  min-height: 44px;
  padding: 4px 14px;
  border: 1px solid var(--panel-border, #259259);
  border-radius: 4px;
  background: none;
  color: var(--text-main, #d9fbe8);
  font: inherit;
  cursor: pointer;
}
.sla11y-reset:hover { color: var(--hud-green, #39ff8f); border-color: var(--hud-green, #39ff8f); }
