@charset "UTF-8";

/* ==========================================================================
   OnlineDice - design system
   No framework, no external fonts, no build step. Written with logical
   properties throughout so the Hebrew (RTL) build needs no separate sheet.
   ========================================================================== */

/* --------------------------------------------------------------- 1. Tokens */

:root {
  color-scheme: light;

  /* Brand */
  --brand: #6c4cf1;
  --brand-strong: #5735e0;
  --brand-soft: #ede9ff;
  --brand-contrast: #ffffff;
  --accent: #ff9f1c;
  --crit: #12a67a;
  --fumble: #e5484d;

  /* Surfaces */
  --bg: #f4f5fa;
  --bg-grad-a: #eceafd;
  --bg-grad-b: #f4f5fa;
  --surface: #ffffff;
  --surface-2: #f7f8fc;
  --surface-3: #eef0f7;
  --line: #e3e5ef;
  --line-strong: #cdd0e0;

  /* Ink */
  --ink: #14161f;
  --ink-2: #454a5c;
  --ink-3: #6d7387;

  /* Dice */
  --die-face: #ffffff;
  --die-face-2: #dde1ef;
  --die-edge: #b6bcd2;
  --die-pip: #1b1d27;
  --die-ink: #1b1d27;
  --die-shadow: rgba(23, 26, 45, .28);

  /* Shape + depth */
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 18px;
  --r-xl: 26px;
  --r-pill: 999px;
  --shadow-1: 0 1px 2px rgba(20, 22, 40, .06), 0 2px 8px rgba(20, 22, 40, .05);
  --shadow-2: 0 2px 6px rgba(20, 22, 40, .07), 0 12px 28px rgba(20, 22, 40, .09);
  --shadow-3: 0 8px 20px rgba(20, 22, 40, .1), 0 24px 60px rgba(20, 22, 40, .14);
  --ring: 0 0 0 3px color-mix(in srgb, var(--brand) 35%, transparent);

  /* Type */
  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
    "Noto Sans", "Liberation Sans", Arial, "Apple Color Emoji", "Segoe UI Emoji", sans-serif;
  --font-num: ui-rounded, "SF Pro Rounded", system-ui, var(--font);

  /* Rhythm */
  --wrap: 1120px;
  --gap: 16px;
  --pad-block: clamp(28px, 5vw, 56px);
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --brand: #8b74ff;
  --brand-strong: #7a5cff;
  --brand-soft: #241f47;
  --brand-contrast: #0d0f17;
  --accent: #ffb648;
  --crit: #2bd39a;
  --fumble: #ff6b70;

  --bg: #0c0e15;
  --bg-grad-a: #15132a;
  --bg-grad-b: #0c0e15;
  --surface: #161926;
  --surface-2: #1c2030;
  --surface-3: #232838;
  --line: #262b3b;
  --line-strong: #363c50;

  --ink: #eef0f7;
  --ink-2: #b6bccd;
  --ink-3: #868da3;

  --die-face: #f2f3f9;
  --die-face-2: #c9ccdd;
  --die-edge: #9ba0b8;
  --die-pip: #14161f;
  --die-ink: #14161f;
  --die-shadow: rgba(0, 0, 0, .55);

  --shadow-1: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-2: 0 2px 8px rgba(0, 0, 0, .45), 0 14px 30px rgba(0, 0, 0, .35);
  --shadow-3: 0 10px 24px rgba(0, 0, 0, .5), 0 30px 70px rgba(0, 0, 0, .45);
}

/* ----------------------------------------------------------- 2. Base reset */

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

* { margin: 0; }

/* Any author `display` rule beats the UA sheet's [hidden], so make it stick. */
[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  font-family: var(--font);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--ink);
  background: var(--bg);
  background-image:
    radial-gradient(1100px 620px at 78% -12%, color-mix(in srgb, var(--brand) 16%, transparent), transparent 62%),
    linear-gradient(180deg, var(--bg-grad-a) 0%, var(--bg-grad-b) 46%);
  background-repeat: no-repeat;
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, svg { display: block; max-width: 100%; }

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; }

h1, h2, h3, h4 {
  line-height: 1.18;
  font-weight: 700;
  letter-spacing: -.02em;
  text-wrap: balance;
  color: var(--ink);
}

h1 { font-size: clamp(1.6rem, 1.1rem + 2.2vw, 2.6rem); }
h2 { font-size: clamp(1.3rem, 1.05rem + 1.1vw, 1.75rem); }
h3 { font-size: clamp(1.08rem, 1rem + .45vw, 1.28rem); }

p { text-wrap: pretty; }

a { color: var(--brand); text-underline-offset: .18em; }
a:hover { color: var(--brand-strong); }

:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

::selection { background: color-mix(in srgb, var(--brand) 28%, transparent); }

/* --------------------------------------------------------- 3. Layout parts */

.wrap {
  width: min(100% - 2rem, var(--wrap));
  margin-inline: auto;
}

.skip-link {
  position: absolute;
  inset-inline-start: -9999px;
  top: 8px;
  z-index: 200;
  padding: 10px 16px;
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--shadow-2);
  text-decoration: none;
  font-weight: 600;
}
.skip-link:focus { inset-inline-start: 12px; }

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
}

.section { margin-block-start: clamp(32px, 5vw, 56px); }

.section__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-block-end: 16px;
}

.muted { color: var(--ink-3); }
.small { font-size: .875rem; }
.nums { font-variant-numeric: tabular-nums; }
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

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

.btn {
  --btn-bg: var(--surface-2);
  --btn-ink: var(--ink);
  --btn-line: var(--line);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 16px;
  border: 1px solid var(--btn-line);
  border-radius: var(--r-md);
  background: var(--btn-bg);
  color: var(--btn-ink);
  font-weight: 600;
  font-size: .94rem;
  text-decoration: none;
  white-space: nowrap;
  transition: transform .12s ease, background-color .15s ease, border-color .15s ease, box-shadow .15s ease;
}
.btn:hover { background: var(--surface-3); color: var(--btn-ink); }
.btn:active { transform: translateY(1px); }

.btn--primary {
  --btn-bg: var(--brand);
  --btn-ink: var(--brand-contrast);
  --btn-line: transparent;
  box-shadow: var(--shadow-1);
}
.btn--primary:hover { --btn-bg: var(--brand-strong); color: var(--brand-contrast); }

.btn--ghost { --btn-bg: transparent; --btn-line: var(--line); }
.btn--danger { --btn-ink: var(--fumble); }
.btn--sm { padding: 7px 12px; font-size: .85rem; }

.icon-btn {
  display: inline-grid;
  place-items: center;
  inline-size: 42px;
  block-size: 42px;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-2);
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.icon-btn:hover { background: var(--surface-3); color: var(--ink); }
.icon-btn svg { inline-size: 20px; block-size: 20px; }
.icon-btn[aria-pressed="false"] { color: var(--ink-3); }

.field { display: grid; gap: 6px; }
.field > label { font-size: .82rem; font-weight: 600; color: var(--ink-3); letter-spacing: .01em; }

.input,
.select {
  inline-size: 100%;
  padding: 11px 13px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.input:focus, .select:focus { outline: none; border-color: var(--brand); box-shadow: var(--ring); }
.input::placeholder { color: var(--ink-3); }

.select {
  appearance: none;
  padding-inline-end: 36px;
  background-image: linear-gradient(45deg, transparent 49%, currentColor 50%, currentColor 56%, transparent 57%),
                    linear-gradient(-45deg, transparent 49%, currentColor 50%, currentColor 56%, transparent 57%);
  background-size: 9px 9px, 9px 9px;
  background-repeat: no-repeat;
  background-position: right 16px center, right 10px center;
}
[dir="rtl"] .select { background-position: left 10px center, left 16px center; }

/* Number stepper: - [ n ] + */
.stepper {
  display: grid;
  grid-template-columns: 42px 1fr 42px;
  align-items: stretch;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface);
  overflow: hidden;
}
.stepper:focus-within { border-color: var(--brand); box-shadow: var(--ring); }
.stepper input {
  border: 0;
  text-align: center;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  background: transparent;
  padding: 11px 4px;
  min-inline-size: 0;
}
.stepper input:focus { outline: none; }
.stepper input::-webkit-outer-spin-button,
.stepper input::-webkit-inner-spin-button { appearance: none; margin: 0; }
.stepper input[type=number] { -moz-appearance: textfield; }
.stepper button {
  display: grid;
  place-items: center;
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--ink-3);
  background: var(--surface-2);
  transition: background-color .15s ease, color .15s ease;
}
.stepper button:hover { background: var(--surface-3); color: var(--ink); }

.select--sm { padding: 7px 30px 7px 10px; font-size: .88rem; font-weight: 700; }
[dir="rtl"] .select--sm { padding: 7px 10px 7px 30px; }

.stepper--sm { grid-template-columns: 32px 1fr 32px; }
.stepper--sm input { padding: 7px 2px; font-size: .92rem; }
.stepper--sm button { font-size: 1rem; }

/* Chip / toggle pills */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink-2);
  font-size: .875rem;
  font-weight: 600;
  text-decoration: none;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.chip:hover { color: var(--ink); border-color: var(--line-strong); }
.chip[aria-pressed="true"],
.chip.is-active {
  background: var(--brand);
  border-color: transparent;
  color: var(--brand-contrast);
}
.chip__hint { font-weight: 500; opacity: .72; font-size: .8em; }

.chip-row { display: flex; flex-wrap: wrap; gap: 8px; }

/* --------------------------------------------------------------- 5. Header */

.site-header {
  position: sticky;
  top: 0;
  z-index: 60;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: saturate(1.6) blur(14px);
  border-block-end: 1px solid var(--line);
}

.header-inner {
  display: flex;
  align-items: center;
  gap: 12px;
  min-block-size: 66px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-weight: 800;
  font-size: 1.05rem;
  letter-spacing: -.02em;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}
.brand:hover { color: var(--ink); }
.brand__mark {
  inline-size: 34px;
  block-size: 34px;
  border-radius: 10px;
  display: grid;
  place-items: center;
  background: linear-gradient(145deg, var(--brand), color-mix(in srgb, var(--brand) 55%, var(--accent)));
  color: #fff;
  box-shadow: var(--shadow-1);
  flex: 0 0 auto;
}
.brand__mark svg { inline-size: 21px; block-size: 21px; }

/* The page heading sits in the bar, so the tool starts at the top of the page. */
.site-title {
  flex: 1 1 auto;
  min-inline-size: 0;
  font-size: clamp(1.02rem, .82rem + .85vw, 1.4rem);
  font-weight: 800;
  letter-spacing: -.025em;
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}

/* Language menu - a plain <details> so it works before JS loads */
.menu { position: relative; }
.menu > summary {
  list-style: none;
  display: inline-grid;
  place-items: center;
  inline-size: 42px;
  block-size: 42px;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-2);
  cursor: pointer;
}
.menu > summary::-webkit-details-marker { display: none; }
.menu > summary:hover { background: var(--surface-3); color: var(--ink); }
.menu > summary svg { inline-size: 20px; block-size: 20px; }

.menu__panel {
  position: absolute;
  inset-inline-end: 0;
  top: calc(100% + 8px);
  z-index: 70;
  min-inline-size: 208px;
  max-block-size: min(58vh, 420px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--shadow-3);
  animation: pop .16s ease;
}
.menu__panel a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-radius: var(--r-md);
  color: var(--ink-2);
  text-decoration: none;
  font-size: .92rem;
}
.menu__panel a:hover { background: var(--surface-3); color: var(--ink); }
.menu__panel a[aria-current="true"] { color: var(--brand); font-weight: 700; background: var(--brand-soft); }
.menu__code {
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-3);
  min-inline-size: 22px;
}

@keyframes pop {
  from { opacity: 0; transform: translateY(-6px) scale(.98); }
  to { opacity: 1; transform: none; }
}

/* Mobile drawer */
.drawer {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  grid-template-columns: min(84vw, 320px) 1fr;
}
[dir="rtl"] .drawer { grid-template-columns: 1fr min(84vw, 320px); }
.drawer[hidden] { display: none; }
.drawer__scrim {
  grid-area: 1 / 1 / 2 / 3;
  background: rgba(10, 12, 20, .5);
  backdrop-filter: blur(2px);
  animation: fade .2s ease;
}
.drawer__panel {
  grid-area: 1 / 1 / 2 / 2;
  position: relative;
  padding: 18px;
  overflow-y: auto;
  background: var(--surface);
  border-inline-end: 1px solid var(--line);
  box-shadow: var(--shadow-3);
  animation: slide-in .24s cubic-bezier(.22, .9, .3, 1);
}
[dir="rtl"] .drawer__panel {
  grid-area: 1 / 2 / 2 / 3;
  border-inline-end: 0;
  border-inline-start: 1px solid var(--line);
}
.drawer__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-block-end: 18px;
}
.drawer__label {
  margin-block: 20px 8px;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.drawer__head + .drawer__label { margin-block-start: 4px; }

.drawer__list { list-style: none; padding: 0; display: grid; gap: 4px; }
.drawer__list--plain a { font-weight: 500; color: var(--ink-3); }
.drawer__list--plain a:hover { color: var(--ink); }
.drawer__list a {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 12px;
  border-radius: var(--r-md);
  color: var(--ink-2);
  text-decoration: none;
  font-weight: 600;
}
.drawer__list a:hover { background: var(--surface-3); color: var(--ink); }
.drawer__list a[aria-current="page"] { background: var(--brand-soft); color: var(--brand); }
.drawer__glyph {
  inline-size: 30px;
  block-size: 30px;
  display: grid;
  place-items: center;
  border-radius: 9px;
  background: var(--surface-3);
  font-size: .72rem;
  font-weight: 800;
  letter-spacing: -.03em;
}
.drawer__list a[aria-current="page"] .drawer__glyph { background: var(--brand); color: var(--brand-contrast); }

@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes slide-in {
  from { transform: translateX(-100%); }
  to { transform: none; }
}
[dir="rtl"] .drawer__panel { animation-name: slide-in-rtl; }
@keyframes slide-in-rtl {
  from { transform: translateX(100%); }
  to { transform: none; }
}

/* --------------------------------------------------------------- 6. Footer */

.site-footer {
  margin-block-start: clamp(48px, 8vw, 96px);
  padding-block: 32px;
  border-block-start: 1px solid var(--line);
  background: color-mix(in srgb, var(--surface) 55%, transparent);
}
.footer-grid {
  display: grid;
  gap: 28px;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.footer-grid h2 {
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--ink-3);
  margin-block-end: 12px;
}
.footer-links { list-style: none; padding: 0; display: grid; gap: 8px; }
.footer-links a { color: var(--ink-2); text-decoration: none; font-size: .92rem; }
.footer-links a:hover { color: var(--brand); }
.footer-bottom {
  margin-block-start: 28px;
  padding-block-start: 20px;
  border-block-start: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: 10px 20px;
  align-items: center;
  justify-content: space-between;
  color: var(--ink-3);
  font-size: .87rem;
}

/* ------------------------------------------------------------- 7. Page top */

/* No hero: the roller is the first thing under the header. */
.page { padding-block-start: clamp(18px, 3vw, 28px); }
.page > .section:first-child { margin-block-start: 0; }

.lede {
  max-inline-size: 62ch;
  font-size: 1.05rem;
  color: var(--ink-2);
}

.prose__lede {
  font-size: 1.06rem;
  color: var(--ink-2);
  margin-block-end: 18px;
}

/* --------------------------------------------------------------- 8. Roller */

.roller {
  margin-block-start: 22px;
  border-radius: var(--r-xl);
  border: 1px solid var(--line);
  background: var(--surface);
  box-shadow: var(--shadow-2);
  overflow: hidden;
}

/* --- the tray the dice land in --- */
.tray {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  align-content: center;
  gap: clamp(10px, 2vw, 20px);
  min-block-size: clamp(210px, 30vw, 290px);
  padding: clamp(20px, 4vw, 34px);
  background:
    radial-gradient(120% 100% at 50% 0%, color-mix(in srgb, var(--brand) 12%, transparent), transparent 68%),
    repeating-linear-gradient(135deg, color-mix(in srgb, var(--ink) 3%, transparent) 0 2px, transparent 2px 9px),
    var(--surface-2);
  border-block-end: 1px solid var(--line);
}
.tray.is-shaking { animation: tray-shake .34s ease-in-out; }
@keyframes tray-shake {
  0%, 100% { transform: none; }
  20% { transform: translate3d(-5px, 2px, 0) rotate(-.5deg); }
  45% { transform: translate3d(5px, -2px, 0) rotate(.5deg); }
  70% { transform: translate3d(-3px, 1px, 0) rotate(-.25deg); }
}

.tray__empty {
  display: grid;
  gap: 10px;
  justify-items: center;
  color: var(--ink-3);
  text-align: center;
  font-size: .95rem;
}
.tray__empty svg { inline-size: 46px; block-size: 46px; opacity: .35; }

/* --- a single die --- */
.die {
  --size: clamp(52px, 9vw, 78px);
  position: relative;
  inline-size: var(--size);
  block-size: var(--size);
  flex: 0 0 auto;
  /* Each die is projected around its own centre. A single perspective on the
     tray would push dice near the edges towards the vanishing point, making
     them drift out of the flex row and overlap. */
  perspective: 620px;
}
.die__body {
  position: relative;
  inline-size: 100%;
  block-size: 100%;
  transform-style: preserve-3d;
  transform: rotateX(var(--fx, 0deg)) rotateY(var(--fy, 0deg));
  will-change: transform;
}
.die__shadow {
  position: absolute;
  inset-block-end: -13%;
  inset-inline: 8%;
  block-size: 16%;
  border-radius: 50%;
  background: radial-gradient(closest-side, var(--die-shadow), transparent 78%);
  filter: blur(1px);
  z-index: -1;
}

.tray[data-density="mid"] .die { --size: clamp(40px, 6vw, 56px); }
.tray[data-density="lots"] .die { --size: clamp(30px, 4.4vw, 42px); }
.tray[data-density="swarm"] .die { --size: clamp(24px, 3.4vw, 32px); }

/* Flat polyhedral dice (d4, d8, d10, d12, d20, d100, coin) */
.die--poly .die__shape {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  filter: drop-shadow(0 3px 5px rgba(15, 18, 35, .18));
}
.die--poly .die__value {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding-block-start: 6%;
  font-family: var(--font-num);
  font-weight: 800;
  font-size: calc(var(--size) * .36);
  letter-spacing: -.04em;
  color: var(--die-ink);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}
.die--poly[data-shape="tetra"] .die__value { padding-block-start: 20%; font-size: calc(var(--size) * .3); }
.die--poly[data-shape="coin"] .die__value { padding-block-start: 0; }
.die--poly[data-digits="3"] .die__value { font-size: calc(var(--size) * .27); }

.die__shape .facet-a { fill: var(--die-face); }
.die__shape .facet-b { fill: var(--die-face-2); }
.die__shape .facet-c { fill: color-mix(in srgb, var(--die-face) 72%, var(--die-face-2)); }
.die__shape .edge { fill: none; stroke: var(--die-edge); stroke-width: 1.6; stroke-linejoin: round; }

/* True 3D cube for the d6 */
/* The cube is centred on the die's own origin: pushing it back along z here
   would be applied after the parent's rotation, sliding the die sideways
   whenever it lands on a left, right, top or bottom face. */
.cube {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}
.cube__face {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template: repeat(3, 1fr) / repeat(3, 1fr);
  gap: 6%;
  padding: 15%;
  border-radius: 18%;
  background: linear-gradient(150deg, var(--die-face), var(--die-face-2));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--die-edge) 70%, transparent);
  backface-visibility: hidden;
}
.cube__face--f { transform: translateZ(calc(var(--size) / 2)); }
.cube__face--b { transform: rotateY(180deg) translateZ(calc(var(--size) / 2)); }
.cube__face--r { transform: rotateY(90deg) translateZ(calc(var(--size) / 2)); }
.cube__face--l { transform: rotateY(-90deg) translateZ(calc(var(--size) / 2)); }
.cube__face--u { transform: rotateX(90deg) translateZ(calc(var(--size) / 2)); }
.cube__face--d { transform: rotateX(-90deg) translateZ(calc(var(--size) / 2)); }

.pip {
  border-radius: 50%;
  background: radial-gradient(circle at 34% 30%, color-mix(in srgb, var(--die-pip) 62%, #fff), var(--die-pip));
  box-shadow: inset 0 -1px 1px rgba(255, 255, 255, .25);
}
.pip--tl { grid-area: 1 / 1; }
.pip--tc { grid-area: 1 / 2; }
.pip--tr { grid-area: 1 / 3; }
.pip--ml { grid-area: 2 / 1; }
.pip--mc { grid-area: 2 / 2; }
.pip--mr { grid-area: 2 / 3; }
.pip--bl { grid-area: 3 / 1; }
.pip--bc { grid-area: 3 / 2; }
.pip--br { grid-area: 3 / 3; }

/* --- the roll choreography --- */
.die.is-rolling .die__body {
  animation: tumble var(--dur, 900ms) cubic-bezier(.28, .72, .3, 1) var(--delay, 0ms) both;
}
.die.is-rolling .die__shadow {
  animation: shadow-drop var(--dur, 900ms) cubic-bezier(.28, .72, .3, 1) var(--delay, 0ms) both;
}

@keyframes tumble {
  0% {
    transform: translate3d(var(--dx, 0px), -220%, 0)
               rotateX(var(--sx, 0deg)) rotateY(var(--sy, 0deg)) rotateZ(var(--sz, 0deg))
               scale(.62);
  }
  52% {
    transform: translate3d(0, 4%, 0)
               rotateX(calc(var(--fx, 0deg) + 180deg)) rotateY(calc(var(--fy, 0deg) + 180deg)) rotateZ(0deg)
               scale(1.06);
  }
  63% {
    transform: translate3d(0, -26%, 0)
               rotateX(calc(var(--fx, 0deg) + 62deg)) rotateY(calc(var(--fy, 0deg) + 74deg)) rotateZ(0deg)
               scale(1);
  }
  78% {
    transform: translate3d(0, 3%, 0)
               rotateX(calc(var(--fx, 0deg) + 8deg)) rotateY(calc(var(--fy, 0deg) + 12deg)) rotateZ(0deg)
               scale(1.03, .95);
  }
  88% { transform: translate3d(0, -8%, 0) rotateX(var(--fx, 0deg)) rotateY(var(--fy, 0deg)) scale(1); }
  100% { transform: translate3d(0, 0, 0) rotateX(var(--fx, 0deg)) rotateY(var(--fy, 0deg)) scale(1); }
}

@keyframes shadow-drop {
  0% { opacity: 0; transform: scale(.3); }
  52% { opacity: .95; transform: scale(1.12); }
  63% { opacity: .45; transform: scale(.78); }
  100% { opacity: 1; transform: scale(1); }
}

.die.is-landed .die__body { animation: land .34s cubic-bezier(.3, 1.5, .5, 1) both; }
@keyframes land {
  0% { transform: rotateX(var(--fx, 0deg)) rotateY(var(--fy, 0deg)) scale3d(1.14, .86, 1); }
  100% { transform: rotateX(var(--fx, 0deg)) rotateY(var(--fy, 0deg)) scale3d(1, 1, 1); }
}

/* Critical success / failure flourishes */
.die.is-crit::after,
.die.is-fumble::after {
  content: "";
  position: absolute;
  inset: -14%;
  border-radius: 30%;
  pointer-events: none;
  animation: halo 1.5s ease-out forwards;
}
.die.is-crit::after { box-shadow: 0 0 0 2px var(--crit), 0 0 26px 4px color-mix(in srgb, var(--crit) 55%, transparent); }
.die.is-fumble::after { box-shadow: 0 0 0 2px var(--fumble), 0 0 26px 4px color-mix(in srgb, var(--fumble) 55%, transparent); }
@keyframes halo {
  0% { opacity: 0; transform: scale(.85); }
  22% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.14); }
}
.die.is-crit .die__value { color: var(--crit); }
.die.is-fumble .die__value { color: var(--fumble); }

/* -------------------------------------------------------------- 9. Readout */

.readout {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 10px 22px;
  padding: 18px clamp(16px, 3vw, 26px);
  border-block-end: 1px solid var(--line);
  background: var(--surface);
  text-align: center;
}
.readout__total {
  font-family: var(--font-num);
  font-size: clamp(2.1rem, 1.3rem + 3.6vw, 3.4rem);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.04em;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  transition: color .2s ease;
}
.readout__total.is-empty { color: var(--ink-3); opacity: .5; }
.readout.is-crit .readout__total { color: var(--crit); }
.readout.is-fumble .readout__total { color: var(--fumble); }
.readout__meta { display: grid; gap: 3px; text-align: start; }
[dir="rtl"] .readout__meta { text-align: start; }
.readout__label {
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.readout__formula {
  font-size: .95rem;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.readout__badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px;
  border-radius: var(--r-pill);
  font-size: .78rem;
  font-weight: 800;
  letter-spacing: .04em;
  text-transform: uppercase;
  animation: pop .3s ease;
}
.readout__badge--crit { background: color-mix(in srgb, var(--crit) 16%, transparent); color: var(--crit); }
.readout__badge--fumble { background: color-mix(in srgb, var(--fumble) 16%, transparent); color: var(--fumble); }

/* Per-die breakdown pills under the total */
.breakdown {
  --pill-height: 26px;
  display: flex;
  flex-wrap: wrap;
  align-content: center;
  gap: 6px;
  justify-content: center;
  padding: 16px clamp(16px, 3vw, 26px) 16px;
  /* Reserve one row up front. Without it the strip is 0px tall until the
     first roll, and appearing pushes the whole console - including the
     button that was just clicked - down the page. Three rows is the ceiling;
     a hundred-dice roll scrolls rather than shoving the console down. */
  /* one pill + 16px padding top and bottom + the 1px bottom border, which
     border-box sizing counts towards the height. */
  min-block-size: calc(var(--pill-height) + 33px);
  max-block-size: calc(var(--pill-height) * 3 + 12px + 33px);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--surface);
  border-block-end: 1px solid var(--line);
}
.breakdown__item {
  block-size: var(--pill-height);
  display: inline-flex;
  align-items: center;
  padding: 0 9px;
  border-radius: var(--r-sm);
  background: var(--surface-3);
  font-size: .8rem;
  font-weight: 700;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.breakdown__item--max { background: color-mix(in srgb, var(--crit) 18%, transparent); color: var(--crit); }
.breakdown__item--min { background: color-mix(in srgb, var(--fumble) 18%, transparent); color: var(--fumble); }
.breakdown__item--dropped { opacity: .45; text-decoration: line-through; }

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

.console { padding: clamp(16px, 3vw, 24px); display: grid; gap: 18px; }

.dice-bar { display: flex; flex-wrap: wrap; gap: 8px; }
.die-key {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 14px 7px 8px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface-2);
  font-weight: 700;
  font-size: .9rem;
  color: var(--ink-2);
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.die-key:hover { border-color: var(--line-strong); color: var(--ink); }
.die-key svg { inline-size: 22px; block-size: 22px; }
.die-key[aria-pressed="true"] {
  background: var(--brand);
  border-color: transparent;
  color: var(--brand-contrast);
}

.console__row {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  align-items: end;
}

.roll-btn {
  inline-size: 100%;
  padding: 17px 24px;
  border: 0;
  border-radius: var(--r-lg);
  background: linear-gradient(140deg, var(--brand), color-mix(in srgb, var(--brand) 62%, var(--accent)));
  color: #fff;
  font-size: 1.06rem;
  font-weight: 800;
  letter-spacing: .05em;
  text-transform: uppercase;
  box-shadow: 0 6px 0 color-mix(in srgb, var(--brand-strong) 82%, #000), var(--shadow-2);
  transition: transform .1s ease, box-shadow .1s ease, filter .15s ease;
}
.roll-btn:hover { filter: brightness(1.06); }
.roll-btn:active,
.roll-btn.is-busy {
  transform: translateY(4px);
  box-shadow: 0 2px 0 color-mix(in srgb, var(--brand-strong) 82%, #000), var(--shadow-1);
}
.roll-btn.is-busy { opacity: .78; }
.roll-btn__hint {
  display: block;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .1em;
  opacity: .75;
  text-transform: none;
  margin-block-start: 2px;
}

.console__actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }

/* Dice-notation input */
.notation {
  display: grid;
  gap: 10px;
  padding: 16px;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface-2);
}
.notation__row { display: flex; gap: 8px; flex-wrap: wrap; }
.notation__row .input {
  flex: 1 1 220px;
  font-family: var(--font-num);
  font-weight: 700;
  letter-spacing: .02em;
}
.notation__error { color: var(--fumble); font-size: .86rem; font-weight: 600; }
.notation__error:empty { display: none; }
.notation__help { font-size: .84rem; color: var(--ink-3); }
.notation__help code {
  padding: 1px 6px;
  border-radius: 5px;
  background: var(--surface-3);
  color: var(--ink-2);
  font-size: .92em;
  font-weight: 700;
}

/* Game presets */
.presets__grid {
  display: grid;
  gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
}
.preset {
  display: grid;
  gap: 2px;
  padding: 11px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  text-align: start;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.preset:hover { border-color: var(--brand); box-shadow: var(--shadow-1); }
.preset__name { font-weight: 700; font-size: .92rem; color: var(--ink); }
.preset__dice {
  font-family: var(--font-num);
  font-size: .8rem;
  font-weight: 700;
  color: var(--brand);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------- 11. Gamification */

.progress-card { display: grid; gap: 16px; padding: clamp(16px, 3vw, 22px); }
.progress-top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
}
.level-badge {
  position: relative;
  display: grid;
  place-items: center;
  inline-size: 56px;
  block-size: 56px;
  flex: 0 0 auto;
  border-radius: 16px;
  background: linear-gradient(145deg, var(--brand), color-mix(in srgb, var(--brand) 58%, var(--accent)));
  color: #fff;
  box-shadow: var(--shadow-1);
}
.level-badge__num { font-family: var(--font-num); font-size: 1.45rem; font-weight: 800; line-height: 1; }
.level-badge__cap {
  position: absolute;
  inset-block-end: 5px;
  font-size: .53rem;
  font-weight: 800;
  letter-spacing: .13em;
  text-transform: uppercase;
  opacity: .8;
}
.progress-titles { flex: 1 1 180px; display: grid; gap: 2px; }
.progress-titles strong { font-size: 1.02rem; }

.xp-bar {
  block-size: 10px;
  border-radius: var(--r-pill);
  background: var(--surface-3);
  overflow: hidden;
}
.xp-bar__fill {
  block-size: 100%;
  inline-size: 0;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--brand), var(--accent));
  transition: inline-size .6s cubic-bezier(.2, .8, .3, 1);
}
[dir="rtl"] .xp-bar__fill { background: linear-gradient(-90deg, var(--brand), var(--accent)); }

.stat-grid {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(112px, 1fr));
}
.stat {
  padding: 12px 14px;
  border-radius: var(--r-md);
  background: var(--surface-2);
  border: 1px solid var(--line);
}
.stat__value {
  font-family: var(--font-num);
  font-size: 1.4rem;
  font-weight: 800;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.stat__label {
  font-size: .74rem;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.stat--streak .stat__value { color: var(--accent); }

.badges {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
}
.badge {
  display: grid;
  gap: 6px;
  justify-items: center;
  padding: 14px 10px;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface-2);
  text-align: center;
  transition: border-color .15s ease;
}
.badge.is-locked { opacity: .45; filter: grayscale(1); }
.badge:not(.is-locked):hover { border-color: var(--brand); }
.badge__icon {
  display: grid;
  place-items: center;
  inline-size: 42px;
  block-size: 42px;
  border-radius: 13px;
  background: var(--brand-soft);
  color: var(--brand);
  font-size: 1.25rem;
}
.badge:not(.is-locked) .badge__icon {
  background: linear-gradient(145deg, var(--brand), color-mix(in srgb, var(--brand) 55%, var(--accent)));
  color: #fff;
}
.badge__name { font-size: .82rem; font-weight: 700; line-height: 1.25; }
.badge__desc { font-size: .72rem; color: var(--ink-3); line-height: 1.35; }

/* Unlock toasts */
.toasts {
  position: fixed;
  inset-block-end: 18px;
  inset-inline-end: 18px;
  z-index: 150;
  display: grid;
  gap: 10px;
  max-inline-size: min(92vw, 340px);
  pointer-events: none;
}
.toast {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface);
  box-shadow: var(--shadow-3);
  animation: toast-in .34s cubic-bezier(.2, .9, .3, 1);
}
.toast.is-leaving { animation: toast-out .3s ease forwards; }
.toast__icon {
  display: grid;
  place-items: center;
  inline-size: 36px;
  block-size: 36px;
  flex: 0 0 auto;
  border-radius: 11px;
  background: linear-gradient(145deg, var(--brand), color-mix(in srgb, var(--brand) 55%, var(--accent)));
  color: #fff;
  font-size: 1.05rem;
}
.toast__text { display: grid; gap: 2px; min-inline-size: 0; }
.toast__title { font-weight: 700; font-size: .92rem; line-height: 1.3; }
.toast__body { font-size: .8rem; color: var(--ink-3); line-height: 1.35; }
@keyframes toast-in { from { opacity: 0; transform: translateY(14px) scale(.96); } to { opacity: 1; transform: none; } }
@keyframes toast-out { to { opacity: 0; transform: translateY(8px) scale(.97); } }

/* ---------------------------------------------------------- 12. History */

/* Capped and scrollable: the table gains a row on every roll, and without a
   ceiling each roll would push everything below it further down the page.
   The header is sticky, so the columns stay readable while scrolling. */
/* The history is a fixed-height window rather than a growing list: it gains a
   row on every roll, and any change in its height would shove the rest of the
   page around each time you throw the dice. The header stays sticky while the
   rows scroll underneath, and the empty state matches the same height. */
.table-scroll {
  --history-height: min(46vh, 232px);
  block-size: var(--history-height);
  overflow: auto;
  overscroll-behavior: contain;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
}
[data-history] .empty-state { block-size: min(46vh, 232px); }
table.data {
  inline-size: 100%;
  border-collapse: collapse;
  background: var(--surface);
  font-size: .92rem;
}
table.data th,
table.data td {
  padding: 11px 14px;
  text-align: start;
  border-block-end: 1px solid var(--line);
  white-space: nowrap;
}
table.data th {
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-3);
  background: var(--surface-2);
  position: sticky;
  top: 0;
}
table.data tbody tr:last-child td { border-block-end: 0; }
table.data tbody tr:hover td { background: var(--surface-2); }
table.data .num { font-variant-numeric: tabular-nums; font-weight: 700; }
table.data .rolls { color: var(--ink-3); white-space: normal; min-inline-size: 180px; }

.empty-state {
  display: grid;
  gap: 6px;
  justify-items: center;
  align-content: center;
  padding: 34px 20px;
  border-radius: var(--r-lg);
  border: 1px dashed var(--line-strong);
  color: var(--ink-3);
  text-align: center;
  font-size: .93rem;
}

/* ------------------------------------------------------------ 13. Prose */

.prose { max-inline-size: 74ch; }
.prose h2 { margin-block: 32px 12px; }
.prose h3 { margin-block: 24px 8px; }
.prose p, .prose ul, .prose ol { margin-block-end: 14px; color: var(--ink-2); }
.prose ul, .prose ol { padding-inline-start: 1.35rem; }
.prose li { margin-block-end: 6px; }
.prose strong { color: var(--ink); }

.faq { display: grid; gap: 8px; max-inline-size: 74ch; }
.faq details {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  overflow: hidden;
}
.faq summary {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px;
  font-weight: 600;
  cursor: pointer;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "";
  inline-size: 9px;
  block-size: 9px;
  flex: 0 0 auto;
  border-inline-end: 2px solid var(--ink-3);
  border-block-end: 2px solid var(--ink-3);
  transform: rotate(45deg);
  transition: transform .2s ease;
}
.faq details[open] summary::after { transform: rotate(-135deg); }
.faq summary:hover { background: var(--surface-2); }
.faq p { padding: 0 16px 15px; color: var(--ink-2); margin: 0; }

/* Cross-links to the other dice */
.dice-links {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(126px, 1fr));
}
.dice-link {
  display: grid;
  gap: 8px;
  justify-items: center;
  padding: 16px 10px;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-2);
  text-decoration: none;
  font-weight: 700;
  font-size: .88rem;
  text-align: center;
  transition: border-color .15s ease, box-shadow .15s ease, color .15s ease;
}
.dice-link:hover { border-color: var(--brand); color: var(--brand); box-shadow: var(--shadow-2); }
.dice-link svg { inline-size: 40px; block-size: 40px; }
.dice-link[aria-current="page"] { border-color: var(--brand); background: var(--brand-soft); color: var(--brand); }

/* Share row */
.share-row { display: flex; flex-wrap: wrap; gap: 8px; }
.share-btn {
  display: inline-grid;
  place-items: center;
  inline-size: 42px;
  block-size: 42px;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-2);
  transition: color .15s ease, border-color .15s ease;
}
.share-btn:hover { color: var(--ink); border-color: var(--line-strong); }
.share-btn svg { inline-size: 19px; block-size: 19px; }

/* ------------------------------------------------------- 13b. Roll dock */

/*
 * A floating bar with the roll button and the settings that matter most.
 * It slides up the moment the console's own roll button leaves the viewport,
 * so the dice stay one tap away however far down the page you have read.
 */
.dock {
  position: fixed;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: 90;
  padding-block: 10px;
  padding-block-end: max(10px, env(safe-area-inset-bottom, 0px));
  background: color-mix(in srgb, var(--surface) 86%, transparent);
  backdrop-filter: saturate(1.6) blur(16px);
  border-block-start: 1px solid var(--line);
  box-shadow: 0 -6px 24px rgba(20, 22, 40, .1);
  transform: translateY(115%);
  transition: transform .3s cubic-bezier(.22, .9, .3, 1);
}
.dock.is-visible { transform: none; }

.dock__inner {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 18px;
}

.dock__result {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-inline-end: auto;
}
.dock__result-label {
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.dock__result-value {
  font-family: var(--font-num);
  font-size: 1.5rem;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.03em;
}
.dock.is-crit .dock__result-value { color: var(--crit); }
.dock.is-fumble .dock__result-value { color: var(--fumble); }

.roll-btn--dock {
  inline-size: auto;
  flex: 0 0 auto;
  min-inline-size: 172px;
  padding: 13px 26px;
  font-size: .95rem;
  border-radius: var(--r-md);
  box-shadow: 0 4px 0 color-mix(in srgb, var(--brand-strong) 82%, #000), var(--shadow-1);
}
.roll-btn--dock:active,
.roll-btn--dock.is-busy {
  transform: translateY(3px);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--brand-strong) 82%, #000);
}

/* Leave room so the dock never covers the end of the page. */
body.has-dock { padding-block-end: 84px; }

@media (max-width: 560px) {
  .dock__inner { gap: 12px; }
  .roll-btn--dock { flex: 1 1 auto; min-inline-size: 0; }
}

/* ------------------------------------------------- 14. Distribution chart */

.chart {
  display: grid;
  gap: 12px;
  padding: clamp(16px, 3vw, 22px);
}
.chart__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px 16px;
}
.chart__title { font-size: .95rem; font-weight: 700; }
.chart__note { font-size: .82rem; color: var(--ink-3); }
.chart__plot { position: relative; min-block-size: 190px; }
.chart__plot:empty { min-block-size: 0; }

/* Empty states that stand in for a fixed-height element match its height,
   so swapping one for the other does not resize the page. */
.chart .empty-state { min-block-size: 190px; align-content: center; }
[data-chart-tabs] { min-block-size: 35px; }
/* The plot is a numeric axis, so it stays left-to-right in every locale.
   Without this, `text-anchor="end"` flips under dir="rtl" and pushes the
   reference label off the side of the chart. */
.chart__svg { inline-size: 100%; block-size: auto; overflow: visible; direction: ltr; }

/* Recessive scaffolding: axis and the "expected" reference line */
.chart .axis { stroke: var(--line-strong); stroke-width: 1; }
.chart .expected { stroke: var(--ink-3); stroke-width: 1; stroke-dasharray: 3 4; opacity: .55; }
.chart .expected-label {
  fill: var(--ink-3);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .04em;
  paint-order: stroke;
  stroke: var(--surface);
  stroke-width: 3px;
  stroke-linejoin: round;
}

/* One series, one hue. Data-ends rounded, anchored to the baseline. */
.chart .bar { fill: var(--brand); transition: fill .15s ease; }
.chart .bar-hit { fill: transparent; }
.chart__plot g:hover .bar { fill: var(--brand-strong); }
.chart .tick {
  fill: var(--ink-3);
  font-size: 10px;
  font-weight: 600;
  text-anchor: middle;
  font-variant-numeric: tabular-nums;
}
/* Selective direct labels - the extremes only, never every bar */
.chart .bar-label {
  fill: var(--ink-2);
  font-size: 10px;
  font-weight: 800;
  text-anchor: middle;
  font-variant-numeric: tabular-nums;
}

.chart__tip {
  position: absolute;
  z-index: 5;
  padding: 7px 11px;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface);
  box-shadow: var(--shadow-2);
  font-size: .8rem;
  line-height: 1.4;
  white-space: nowrap;
  pointer-events: none;
  transform: translate(-50%, -112%);
  opacity: 0;
  transition: opacity .12s ease;
}
.chart__tip.is-visible { opacity: 1; }
.chart__tip b { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------- 15. Preferences */

@media (max-width: 640px) {
  .readout { flex-direction: column; gap: 6px; }
  .readout__meta { text-align: center; }
  .console__row { grid-template-columns: 1fr 1fr; }
  .console__row .roll-btn { grid-column: 1 / -1; }
  .toasts { inset-inline: 12px; inset-block-end: 12px; max-inline-size: none; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .die.is-rolling .die__body,
  .die.is-rolling .die__shadow { animation: none; }
  .die__body { transform: rotateX(var(--fx, 0deg)) rotateY(var(--fy, 0deg)); }
}

@media print {
  .site-header, .site-footer, .console, .share-row, .toasts, .roll-btn, .dock { display: none !important; }
  body.has-dock { padding-block-end: 0; }
  body { background: #fff; }
  .card, .roller { box-shadow: none; }
}
