@import url("https://fonts.cdnfonts.com/css/clear-sans");*,::before,::after{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgba(0,0,0,0);--un-ring-shadow:0 0 rgba(0,0,0,0);--un-shadow-inset: ;--un-shadow:0 0 rgba(0,0,0,0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgba(147,197,253,0.5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: ;}::backdrop{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgba(0,0,0,0);--un-ring-shadow:0 0 rgba(0,0,0,0);--un-shadow-inset: ;--un-shadow:0 0 rgba(0,0,0,0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgba(147,197,253,0.5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: ;}.absolute{position:absolute;}.fixed{position:fixed;}.relative{position:relative;}.m-8{margin:2rem;}.my,.my-4{margin-top:1rem;margin-bottom:1rem;}.mt-2{margin-top:0.5rem;}.mt-4{margin-top:1rem;}.mt-5{margin-top:1.25rem;}.h-full{height:100%;}.w-full{width:100%;}.flex{display:flex;}.flex-1{flex:1 1 0%;}.flex-col{flex-direction:column;}.transform{transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));}.items-center{align-items:center;}.justify-end{justify-content:flex-end;}.justify-center{justify-content:center;}.gap-2{grid-gap:0.5rem;gap:0.5rem;}.gap-4{grid-gap:1rem;gap:1rem;}.gap-5{grid-gap:1.25rem;gap:1.25rem;}.border{border-width:1px;border-style:solid;}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}

:root {
  --unknown: #87898a;
  --unknown-light: #57698c;
  --almost: #b8a346;
  --almost-light: #d1b94f;
  --bingo: #5b9257;
  --bingo-light: #70b36b;
  --nope: #444447;
  --nope-light: #5d5d61;
  --outline: #444447;
  --primary: #5b9257;
  --primary-hover: #70b36b;
  --primary-active: #70b36b;
  --dead: #de5353;
  --text-color: #fefefe;
  --background: #212122;
}

[data-contrast="high"] {
  --almost: #8bc1f9;
  --almost-light: #9bc9fa;
  --bingo: #ef7d43;
  --bingo-light: #ff8547;
  --primary: #ef7d43;
  --primary-hover: #ff8547;
  --primary-active: #ff8547;
  --dead: #999999;
}

html {
  /* Squordle is a permanently dark app (no light mode), so declare it: the
       browser then paints its own surfaces -- scrollbars, form controls, and
       the canvas behind the page -- in dark too. This also kills the white
       status-bar / overscroll bands on mobile (body alone left html white). */
  background: var(--background);
  color-scheme: dark;
}

html,
body,
* {
  color: #fefefe;
  margin: 0;
  padding: 0;
  font-size: min(min(2.3vh, 3vw), 125%);
}

body {
  font-family: "Clear Sans", "Helvetica Neue", Geneva, sans-serif;
  background: var(--background);
  touch-action: manipulation;
  font-size: min(min(2.3vh, 3vw), 125%);
}

/* App root: full viewport, using dvh so the layout fits between mobile
   Safari's chrome and doesn't jump when the address bar hides/shows.
   Desktop is unaffected (dvh == vh with no dynamic toolbar). */

.app-root {
  width: 100vw;
  height: 100vh;
  height: 100dvh;
}

/* ── Phone layout seam (<=600px) ──────────────────────────────────────
   Phone-only overrides live in @media (max-width: 600px) blocks here and
   in the component .module.css files. Desktop (>600px) is frozen.
   See tracking issue #20 and slices #22-#26.

   The 600 is written here and in PHONE_BREAKPOINT_PX (src/util/viewport.tsx).
   That duplication is deliberate: breakpoint.test.ts fails if the two ever
   disagree, so no build step is needed to keep them together. Adding another
   phone block is fine and needs no ceremony; changing the number means
   changing it everywhere the test lists. See ADR-0003. */

@media (max-width: 600px) {
  /* Neutralize the global vh/vw font-clamp: a fixed root size so rem-based
       sizes stop shrinking to make the fixed-width header fit. Component
       classes that set explicit rem sizes still win over this * fallback. */
  html,
  body,
  * {
    font-size: 16px;
  }

  /* App-shell: header pins to the top, keyboard docks at the bottom, the
       board fills the space between. Scoped under .app-root so these win over
       UnoCSS utility classes (justify-center, gap-5) regardless of load order. */
  .app-root .game-shell {
    height: 100dvh;
    justify-content: flex-start;
    gap: 0.5rem;
    padding: 0.25rem 0 env(safe-area-inset-bottom);
  }
  .app-root .board-area {
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    /* clip horizontal board-slide animations; scroll vertically only on a
           freakishly short viewport that can't fit the board */
    overflow: hidden auto;
  }
}

.center {
  display: flex;
  flex-direction: column;
  align-items: center;
}

a,
b,
span {
  font-size: inherit;
}
._sampleSize_1lcb6_1 {
  width: 100px;
  height: 100px;
}

._flipCard_1lcb6_6 {
  background-color: transparent;
  perspective: 1000px;
}

._flipCardInner_1lcb6_11 {
  position: relative;
  width: 100%;
  height: 100%;
  text-align: center;
  /* the caller sets the duration inline, from the same constant that times
       its clock, so the two can't disagree. Deliberately absent here. */
  transition-property: transform;
  transform-style: preserve-3d;
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
}

._flipCardFront_1lcb6_23,
._flipCardBack_1lcb6_24 {
  position: absolute;
  width: 100%;
  height: 100%;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

._flipCardFront_1lcb6_23 {
}

._flipCardBack_1lcb6_24 {
  transform: rotateX(-180deg);
}

._flipped_1lcb6_39 {
  transform: rotateX(-180deg);
}
._letterCard_ngjao_1 {
  width: 3.2rem;
  height: 3.2rem;
  margin: 0.25rem;
}

._letter_ngjao_1 {
  width: 100%;
  height: 100%;
  border-radius: 0;
  font-size: 2rem;
  text-align: center;
  font-weight: 700;
  border: 2px solid var(--outline);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: Clear Sans, sans-serif;
}

._almost_ngjao_21 {
  background: var(--almost);
  border-color: var(--almost);
}
._bingo_ngjao_25 {
  background: var(--bingo);
  border-color: var(--bingo);
}
._nope_ngjao_29 {
  background: var(--nope);
  border-color: var(--nope);
}

._wordCount_ngjao_34 {
  width: 4.75rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-end;
  font-size: 0.6rem;
  padding-bottom: 0.4em;
  padding-left: 0.55rem;
}

._boardHeaderRow_ngjao_45 {
  display: flex;
  align-items: flex-end;
  width: 100%;
}

._boardHeader_ngjao_45 {
  flex: 1;
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  padding: 0 0 0 0.25rem;
}

._roundLabel_ngjao_59 {
  font-size: 1.4rem;
  font-weight: 700;
  color: white;
  line-height: 1;
  transition: opacity 0.4s ease-out;
}

._totalScore_ngjao_67 {
  font-size: 1.4rem;
  font-weight: 700;
  color: white;
  line-height: 1;
}

._skull_ngjao_74 {
  font-size: 1.6rem;
  line-height: 1;
}

._swell_ngjao_79 {
  /* the duration is set inline, from the constant that also times the
       clock -- see timings.ts. Deliberately not repeated here. */
  animation-name: _swell_ngjao_79;
  animation-timing-function: ease-out;
  transform-origin: center;
  display: inline-block;
}

@keyframes _swell_ngjao_79 {
  0% {
    transform: scale(1);
  }
  40% {
    transform: scale(1.6);
  }
  100% {
    transform: scale(1);
  }
}

/* Desktop: stats column beside the mini-chart (unchanged). Phone overrides
   to a compact vertical stack in the @media block below. */
._summary_ngjao_102 {
  width: 4.75rem;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;
  gap: 0.3rem;
  padding-right: 0.25rem;
}

/* The figures beside the mini-chart: guess ratio, hard-mode 💪, score. Stacked
   as a column on desktop; the phone block turns them into one line. */
._summaryStats_ngjao_114 {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  gap: 1px;
  font-size: 0.55rem;
  line-height: 1.05;
}

/* Desktop wants no wrapper here — the figures and the mini-chart are siblings
   in .summary's row. It exists for the phone, which shrink-wraps it to the
   mini-chart's width so the figures stretch to the mini-chart's edges. */
._summaryInner_ngjao_127 {
  display: contents;
}

._hardFlag_ngjao_131 {
  font-size: 0.55rem;
}

._guessRatio_ngjao_135 {
  color: gray;
}

._score_ngjao_139 {
  font-size: 0.8rem;
  font-weight: 700;
  color: white;
  line-height: 1;
}

._miniChart_ngjao_146 {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

._miniChartRow_ngjao_152 {
  display: flex;
  flex-direction: row;
  gap: 1px;
}

._miniChartCell_ngjao_158 {
  width: 5px;
  height: 5px;
  background: transparent;
  border: 1px solid var(--outline);
  box-sizing: border-box;
}

._miniChartCell_ngjao_158._bingo_ngjao_25 {
  background: var(--bingo);
  border-color: var(--bingo);
}

._miniChartCell_ngjao_158._almost_ngjao_21 {
  background: var(--almost);
  border-color: var(--almost);
}

._miniChartCell_ngjao_158._nope_ngjao_29 {
  background: var(--nope);
  border-color: var(--nope);
}

/* ── Phone (<=600px): fluid letter cells + shrunk gutters ───────────────
   With the global font-clamp neutralized, cells no longer shrink off a
   viewport-scaled root. Size them off viewport width with a cap so they get
   as large as fits; the vw term is offset for the (shrunk) side gutters so
   the whole row fits within the viewport. aspect-ratio keeps cells square;
   the board's slide animations read live row heights, so they adapt. */
@media (max-width: 600px) {
  ._letterCard_ngjao_1 {
    width: clamp(2.4rem, calc(19vw - 1.35rem), 3.4rem);
    height: auto;
    aspect-ratio: 1 / 1;
    margin: 0.25rem;
  }
  ._letter_ngjao_1 {
    font-size: clamp(1.3rem, 7.5vw, 2rem);
  }
  /* Shrink the mostly-empty gutters (4.75rem each) to hand width back to
       the cells, keeping the solved-board mini-chart summaries and the
       (optional) word counts. The summary becomes a compact vertical stack —
       the figures on one line above the mini-chart, the guess ratio dropped.
       The rules below are the whole of that difference; the markup is one
       tree at both widths. */
  /* The two gutters must come out the same width or the board sits
       off-centre — the rows are one flex line, so any difference between
       them shifts every Tile by half of it. They pad on opposite sides, so
       border-box here keeps that padding inside the number that has to
       match, rather than leaving two totals to add up by hand. */
  ._summary_ngjao_102,
  ._wordCount_ngjao_34 {
    box-sizing: border-box;
    width: 2.5rem;
  }
  ._summary_ngjao_102 {
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.15rem;
  }
  /* The wrapper comes back for the phone, shrink-wrapped to the mini-chart. */
  ._summaryInner_ngjao_127 {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: fit-content;
    gap: 0.1rem;
  }
  /* ...so the figures can stretch to its edges, on one line rather than three. */
  ._summaryStats_ngjao_114 {
    flex-direction: row;
    align-self: stretch;
    align-items: center;
    justify-content: flex-end;
    gap: 0.15rem;
  }
  ._hardFlag_ngjao_131 {
    line-height: 1;
  }
  ._wordCount_ngjao_34 {
    padding-left: 0.25rem;
  }
  /* The global `* { font-size: 16px }` phone reset matches the inner <p>
       directly, and a declared value beats an inherited one -- so a size on
       .wordCount alone never reaches the number. Set it on the <p> too. */
  ._wordCount_ngjao_34,
  ._wordCount_ngjao_34 p {
    font-size: 0.7rem;
  }
}
._key_jic80_1 {
  padding: 0;
  margin: 2px;
  width: 2.75rem;
  height: 4rem;
  background-color: var(--unknown);
  border: none;
  border-radius: 4px;
  text-align: center;
  font-size: 1rem;
  text-transform: uppercase;
  display: flex;
  align-items: center;
  justify-content: center;
  user-select: none;
  touch-action: manipulation;
  font-family: Clear Sans, sans-serif;
}

._key_jic80_1:hover,
._key_jic80_1:active {
  cursor: pointer;
  background-color: var(--unknown-light);
}

._bigKey_jic80_26 {
  font-size: 0.8rem;
  width: 5.5rem;
}
._keyboard_jic80_30 {
  display: flex;
  flex-direction: column;
  align-items: center;
}

._almost_jic80_36 {
  background-color: var(--almost);
}
._almost_jic80_36:hover,
._almost_jic80_36:active {
  background-color: var(--almost-light);
}
._bingo_jic80_43 {
  background-color: var(--bingo);
}
._bingo_jic80_43:hover,
._bingo_jic80_43:active {
  background-color: var(--bingo-light);
}
._nope_jic80_50 {
  background-color: var(--nope);
}
._nope_jic80_50:hover,
._nope_jic80_50:active {
  background-color: var(--nope-light);
}

._almost_jic80_36,
._bingo_jic80_43,
._nope_jic80_50 {
  transition-property: background-color;
  transition-delay: 2s;
}

/* ── Phone (<=600px): Wordle-style fixed-width keyboard ─────────────────
   One standard key width, set by the 10-key top row filling the keyboard
   width. Rows 2 and 3 use that same width and center (half-key margins).
   Enter and Delete split the leftover space in the bottom row. Expressing
   the keyboard width as one calc-able value lets the key width derive from
   it in pure CSS, so every row's letters line up. */
@media (max-width: 600px) {
  ._keyboard_jic80_30 {
    --kb-gap: 5px;
    --kb-width: min(100vw - 8px, 500px);
    --key-width: calc((var(--kb-width) - 9 * var(--kb-gap)) / 10);
    box-sizing: border-box;
    width: var(--kb-width);
    margin: 0 auto var(--kb-gap);
    padding: 0;
  }
  ._row_jic80_81 {
    width: 100%;
    justify-content: center;
    gap: var(--kb-gap);
  }
  ._key_jic80_1 {
    flex: 0 0 auto;
    width: var(--key-width);
    min-width: 0;
    height: 3.5rem;
    margin: 3px 0;
    font-size: 1.1rem;
  }
  /* Enter & Delete grow from a zero basis to split the bottom row's
       leftover space into two equal widths (not equal shares added to
       differing text/icon content widths). */
  ._bigKey_jic80_26 {
    flex: 1 1 0;
    width: auto;
    font-size: 0.8rem;
  }
}
/* ── Vocabulary ─────────────────────────────────────────────────────────
   `Modal` renders two elements. `.backdrop` is the outer layer: it covers the
   viewport, carries the dim, and eats the clicks that dismiss. `.dialog` is
   the inner box you read. Both names are the platform's — a modal `<dialog>`
   gets a `::backdrop` — so if this element ever takes `role="dialog"
   aria-modal="true"`, the attribute and the class already agree.

   *Modal* is the whole assembly, which is what the component is named and
   what every comment below means by it. *Sheet* means the phone form
   specifically — flush on three sides, rounded on top, sliding up. It is not
   another name for `.dialog`: the desktop form is a centred card. See #39. */

._backdrop_1czza_2 {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  /* The dim lives here. Desktop keeps the blur on top of it; the phone
       block turns the blur off, so there the dim is the whole effect. */
  background-color: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(2px);
  z-index: 4000;
}

._dialog_1czza_3 {
  margin: 1em;
  padding: 1.5em;
  background-color: var(--nope);
  box-shadow: rgba(0, 0, 0, 0.24) 0 3px 8px;
  border-radius: 0.5em;
  width: 45ch;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  z-index: 4000;
}

/* Everything the caller passed, in one box. On desktop it is inert — the
   dialog's own flex column would lay these children out identically. It
   earns its keep on phone, where it is the thing that scrolls. */
._content_1czza_46 {
  width: 100%;
  /* the phone block gives this padding; without border-box that padding lands
       outside the 100% and the box overflows the dialog by exactly its padding */
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Help and Settings are narrower than the 45ch default. Stated here rather
   than inline on those components so the phone block below can override it
   with an ordinary rule: same specificity, later in the same stylesheet. */
._narrow_1czza_59 {
  width: 25rem;
}

._closeButton_1czza_63 {
  position: absolute;
  right: 1em;
  top: 1em;
  cursor: pointer;
}

/* ── Phone (<=600px): modals become bottom sheets ───────────────────────
   Flush to left, right and bottom, rounded only on top, growing to fit
   their content. The cards (25rem / 45ch) would clip on a narrow phone,
   and an inset card would cost 2rem of width the Stats distribution row
   can't spare (#29) — so the sheet goes edge to edge instead. Desktop
   keeps the centered cards. */
@media (max-width: 600px) {
  ._backdrop_1czza_2 {
    position: fixed;
    height: 100dvh;
    /* a full-screen blur behind something someone is reading is the
           expensive kind; the dim carries it here */
    backdrop-filter: none;
    /* the sheet sits on the bottom edge */
    align-items: flex-end;
  }
  ._dialog_1czza_3 {
    width: 100%;
    max-width: 100%;
    /* content-driven: short content sits low with the game above it,
           tall content fills the screen */
    height: auto;
    max-height: 100dvh;
    margin: 0;
    border-radius: 0.75rem 0.75rem 0 0;
    box-sizing: border-box;
    overflow: hidden;
    padding: 0;
    /* Enter only. Animating the exit means keeping the modal mounted past
           the state flip, which is real machinery for the less-noticed half of
           the gesture; dismissal is instant on purpose. */
    animation: _dialogUp_1czza_1 200ms ease-out;
  }
  ._content_1czza_46 {
    /* the sheet stays anchored and its content scrolls. Letting the
           backdrop scroll instead would let the sheet's top edge scroll away,
           at which point it stops reading as a sheet. */
    overflow-y: auto;
    min-height: 0;
    /* Without this the box refuses to shrink below its widest child's
           min-content, overflows the dialog on both sides, and the side padding
           silently stops existing. */
    min-width: 0;
    justify-content: flex-start;
    /* the safe-area inset is padding *inside* the sheet, so content clears
           the home indicator while the background still runs to the edge --
           which is the point of going flush */
    padding: 1.5rem 1.25rem calc(env(safe-area-inset-bottom) + 1.5rem);
  }
  /* A sheet that fills the screen isn't sitting on anything, so it drops the
       rounded top. Which modals reach this is content, not identity: Stats is
       446px mid-game and taller once a game-over adds its message and next-game
       block, so no per-modal rule could get it right. Measured in Modal.tsx. */
  ._fullHeight_1czza_123 {
    border-radius: 0;
  }
  /* Only at full height does the sheet reach the top of the screen, so only
       here does the top inset matter — ~0 in a Safari tab today, but ADR-0001
       keeps these so a PWA follow-up needs no relayout, and under one this is
       what stops the close X landing under the notch. */
  ._fullHeight_1czza_123 ._content_1czza_46 {
    padding-top: calc(env(safe-area-inset-top) + 1.5rem);
  }
  ._fullHeight_1czza_123 ._closeButton_1czza_63 {
    top: calc(env(safe-area-inset-top) + 0.5rem);
  }
  /* Stays top-right, where a close X is expected. Moving it to the bottom for
       thumb reach would diverge from desktop for reach alone, and cost more
       recognition than it buys. */
  ._closeButton_1czza_63 {
    top: 0.5rem;
    right: 0.5rem;
    min-width: 44px;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
  }
}

@keyframes _dialogUp_1czza_1 {
  from {
    transform: translateY(100%);
  }
  to {
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  ._dialog_1czza_3 {
    animation: none;
  }
}
._switch_ekcx2_1 {
  --base-size: 0.7rem;
  --width: calc(3 * var(--base-size));
  --height: calc(1.7 * var(--base-size));
  --radius: calc(1.3 * var(--base-size));
  position: relative;
  display: inline-block;
  width: var(--width);
  height: var(--height);
  vertical-align: bottom;
}

._switch_ekcx2_1 input {
  opacity: 0;
  width: 0;
  height: 0;
}

._slider_ekcx2_19 {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #aaaaaa;
  -webkit-transition: 0.4s;
  transition: 0.4s;
}

._slider_ekcx2_19:before {
  position: absolute;
  content: "";
  height: var(--radius);
  width: var(--radius);
  left: calc(0.2 * var(--base-size));
  bottom: calc(0.2 * var(--base-size));
  background-color: #fefefe;
  -webkit-transition: 0.4s;
  transition: 0.4s;
}

input:checked + ._slider_ekcx2_19 {
  background-color: var(--bingo);
}

input:focus + ._slider_ekcx2_19 {
  box-shadow: 0 0 1px var(--bingo);
}

input:checked + ._slider_ekcx2_19:before {
  -webkit-transform: translateX(var(--radius));
  -ms-transform: translateX(var(--radius));
  transform: translateX(var(--radius));
}

/* Rounded sliders */
._slider_ekcx2_19._round_ekcx2_58 {
  border-radius: var(--height);
}

._slider_ekcx2_19._round_ekcx2_58:before {
  border-radius: 50%;
}
/* Phone top bar (<=600px). Desktop keeps the inline-styled two-row header. */

._topBar_165b7_3 {
  box-sizing: border-box;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  /* pad under the notch when installed as a PWA; ~0 in a Safari tab */
  padding: calc(env(safe-area-inset-top) + 0.25rem) 0.5rem 0.25rem;
}

._titleGroup_165b7_14 {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  min-width: 0;
}

._title_165b7_14 {
  font-size: 1.4rem;
  font-weight: bold;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Tappable hard-mode pill: shows state (bright on / dimmed off), toggles on tap */
._hardPill_165b7_30 {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 0.25rem;
  border: none;
  border-radius: 999px;
  background: transparent;
  font-size: 1.35rem;
  line-height: 1;
  cursor: pointer;
  filter: grayscale(1) opacity(0.45);
  transition: filter 0.15s ease;
}

._hardPillOn_165b7_48 {
  filter: none;
}

._icons_165b7_52 {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

/* Wrap each icon in a >=44px touch target */
._iconButton_165b7_60 {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  border: none;
  background: transparent;
  color: inherit;
  cursor: pointer;
}
._banner_46v4v_1 {
  display: flex;
  gap: 1em;
  margin-bottom: 1em;
  width: 100%;
}

._statBlock_46v4v_8 {
  text-align: center;
  flex: 1;
}

._distributions_46v4v_13 {
  display: flex;
  gap: 2px;
}

/* ── Phone (<=600px) ────────────────────────────────────────────────────
   Six charts of ~66px side by side need ~405px, which overflows the dialog
   at either phone width — it was only ever masked by the old full-screen
   modal handing the row the whole viewport. Wrap to two rows of three
   rather than compressing six across, which would squeeze the bars past
   reading. Explicit columns, not flex-wrap: six charts do fit five-across
   at 390px, and 5 + 1 orphan is worse than 3 + 3. */
@media (max-width: 600px) {
  ._distributions_46v4v_13 {
    display: grid;
    grid-template-columns: repeat(3, auto);
    justify-content: center;
    gap: 0.5rem 2px;
  }
}

._chartBackground_46v4v_34 {
  padding: 0.3em 0.2em;
  borderradius: 0.25em;
  background-color: var(--background);
}
._container_ap96y_1 {
  display: flex;
  flex-direction: column;
}

._chartRow_ap96y_6 {
  display: flex;
  align-items: center;
}

._label_ap96y_11 {
  min-width: 1em;
  text-align: right;
  padding-right: 0.25em;
}

._barContainer_ap96y_17 {
  flex: 1;
  padding: 0.1em 0;
}

._bar_ap96y_17 {
  background-color: var(--bingo);
  text-align: right;
  padding: 0.1em 0;
}

._dead_ap96y_28 {
  font-size: 0.8em;
}
._button_yhgfb_1 {
  padding: 0.5em 0.75em;
  border: none;
  border-radius: 0.25em;
  background-color: var(--primary);
  cursor: pointer;
  font-size: 0.8em;
}
._button_yhgfb_1:hover {
  background-color: var(--primary-hover);
}
._button_yhgfb_1:active {
  background-color: var(--primary-active);
}
