/* Layout and components. Every colour, font and size comes from the tokens in themes.css. */

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

[hidden] {
  display: none !important;
}

/* Set by boot.js while a non-English page is being translated, so English never flashes */
:root[data-i18n-pending] body {
  visibility: hidden;
}

html {
  color-scheme: var(--scheme);
  scrollbar-color: var(--border) var(--bg);
  background-color: var(--bg);
  -webkit-text-size-adjust: 100%;
  font-synthesis: none;
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  background-color: var(--bg);
  background-image: var(--bg-image);
  background-size: var(--bg-size);
  background-attachment: fixed;
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.35;
  text-shadow: var(--glow);
}

/* CRT scanlines in the terminal themes; nothing elsewhere */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 100;
  pointer-events: none;
  background: var(--overlay);
}

h1,
h2,
h3,
p {
  margin: 0;
}

a {
  color: var(--accent);
}

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* Headings focused when a dialog opens (openDialog in ui.js) aren't controls, so no focus ring */
h2[tabindex="-1"]:focus {
  outline: none;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ── Layout ────────────────────────────────────────────────────── */

.app {
  display: grid;
  gap: 12px;
  width: 100%;
  max-width: 30rem;
  margin: 0 auto;
  padding: 8px 16px 32px;
}

.roller {
  display: grid;
  gap: 12px;
  min-width: 0;
}

/* Grid children default to never shrinking below their content, so one long unbreakable line
   (a saved attack's summary) would widen the whole column past the screen. Let them shrink;
   long lines inside are cut with an ellipsis or wrap instead. */
.roller > *,
.tab-panel > *,
.panel > * {
  min-width: 0;
}

@media (min-width: 60rem) {
  .app {
    grid-template-columns: minmax(0, 30rem) minmax(0, 1fr);
    align-items: start;
    column-gap: 24px;
    max-width: 66rem;
    padding-top: 16px;
  }

  .topbar {
    grid-column: 1 / -1;
  }

  /* History matches the left column's height instead of growing with every roll: height 0 keeps
     it out of the row's sizing, min-height 100% then stretches it to that row, and its list scrolls */
  .history {
    align-self: stretch;
    height: 0;
    min-height: 100%;
    overflow: hidden;
  }


  .history-list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
  }

}

/* ── Tabs ──────────────────────────────────────────────────────── */

.tabs {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 4px;
}

.tab {
  min-width: 0;
  min-height: 44px;
  margin: 0;
  padding: 0 4px;
  overflow: hidden;
  color: var(--btn-text);
  background: var(--btn-bg);
  border: var(--bw) solid var(--btn-border);
  border-radius: var(--radius-sm);
  font-family: var(--font-ui);
  font-size: var(--fs-small);
  text-overflow: ellipsis;
  text-shadow: inherit;
  white-space: nowrap;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

.tab[aria-selected="true"] {
  color: var(--accent-text);
  background: var(--accent);
  border-color: var(--accent);
}

.tab-panel {
  display: grid;
  align-content: start;
  gap: 12px;
  min-width: 0;
}

.tab-panel.is-inactive {
  display: none;
}

/* Wide screens (same breakpoint as the two-column layout above). These come after the base tab
   rules so they win without extra specificity. */
@media (min-width: 60rem) {
  /* History is its own column, never a hidden tab */
  .history.is-inactive {
    display: flex;
  }

  .tabs {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .tab-history {
    display: none;
  }

  /* Panels share one cell, so switching tabs never changes the column height */
  .tab-panels {
    display: grid;
  }

  .tab-panels > .tab-panel {
    grid-area: 1 / 1;
  }

  .tab-panels > .tab-panel.is-inactive {
    display: grid;
    visibility: hidden;
  }
}

.panel {
  padding: 12px;
  background: var(--surface);
  border: var(--bw) solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--panel-shadow);
}

/* ── Top bar ───────────────────────────────────────────────────── */

.topbar {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 52px;
}

.title {
  margin-right: auto;
  color: var(--accent);
  font-family: var(--font-display);
  font-size: var(--fs-title);
  font-weight: var(--fw-strong);
  letter-spacing: var(--title-spacing);
  text-transform: var(--title-case);
}

:root:is([data-theme="terminal"], [data-theme="amber"]) .title::after {
  content: "_";
  animation: blink 1.1s steps(1) infinite;
}

/* ── Buttons ───────────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 44px;
  min-height: 44px;
  margin: 0;
  padding: 0 14px;
  color: var(--btn-text);
  background: var(--btn-bg);
  border: var(--bw) solid var(--btn-border);
  border-radius: var(--radius-sm);
  box-shadow: var(--btn-shadow);
  font-family: var(--font-ui);
  font-size: var(--fs-ui);
  line-height: 1;
  text-shadow: inherit;
  cursor: pointer;
  appearance: none;
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition: transform 60ms ease-out, box-shadow 60ms ease-out;
}

.btn:active,
.btn.is-pressed {
  color: var(--btn-active-text, var(--btn-text));
  background: var(--btn-active-bg, var(--btn-bg));
  box-shadow: var(--btn-shadow-pressed);
  transform: translate(var(--press-x), var(--press-y));
}

.btn[aria-pressed="true"] {
  color: var(--accent-text);
  background: var(--accent);
  border-color: var(--accent);
}

.btn-small {
  min-height: 40px;
  padding: 0 10px;
  font-size: var(--fs-small);
}

.btn-icon {
  width: 44px;
  padding: 0;
}

.btn-icon svg {
  width: 20px;
  height: 20px;
  fill: currentColor;
}

.lang-btn {
  font-size: var(--fs-small);
  letter-spacing: 0.04em;
}

.btn-quiet {
  color: var(--text-dim);
  background: transparent;
  border-color: transparent;
  box-shadow: none;
}

.btn-quiet:active,
.btn-quiet.is-pressed {
  background: var(--surface-2);
  box-shadow: none;
  transform: none;
}

.btn-danger {
  color: var(--danger);
  border-color: var(--danger);
}

/* ── Result ────────────────────────────────────────────────────── */

.result {
  display: grid;
  align-content: start;
  gap: 4px;
  min-height: 12.5rem;
  scroll-margin-top: calc(12px + env(safe-area-inset-top));
}

.result-head {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
}

.result-notation {
  margin-right: auto;
  min-width: 0;
  color: var(--text-dim);
  font-family: var(--font-ui);
  font-size: var(--fs-ui);
  overflow-wrap: anywhere;
}

.result-notation.is-error {
  color: var(--danger);
}

.result-actions {
  display: flex;
  flex: none;
  gap: 6px;
}

.result-total {
  font-family: var(--font-numbers);
  font-size: var(--fs-total);
  font-weight: var(--fw-strong);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  text-align: center;
}

.result-total.is-max {
  color: var(--crit-max);
}

.result-total.is-min {
  color: var(--crit-min);
}

.result-total.pop {
  animation: total-pop var(--roll-ms) var(--roll-ease) both;
}

.result-badge {
  font-family: var(--font-display);
  font-size: var(--fs-small);
  letter-spacing: 0.08em;
  text-align: center;
  text-transform: uppercase;
}

.result-badge.is-max {
  color: var(--crit-max);
}

.result-badge.is-min {
  color: var(--crit-min);
}

.result-badge.is-note {
  color: var(--accent);
}

/* Six ability scores, each with its modifier and dice */
.result-parts {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
  margin: 4px 0 0;
  padding: 0;
  list-style: none;
}

.part {
  --i: 0;
  display: grid;
  justify-items: center;
  gap: 2px;
  min-width: 0;
  padding: 8px 4px;
  color: var(--die-text);
  background: var(--die-bg);
  border: var(--bw) solid var(--die-border);
  border-radius: var(--radius-sm);
  animation: die-in var(--roll-ms) var(--roll-ease) both;
  animation-delay: calc(var(--i) * 40ms);
}

.part-label {
  color: var(--text-dim);
  font-family: var(--font-ui);
  font-size: var(--fs-label);
  letter-spacing: var(--label-spacing);
}

.part-total {
  font-family: var(--font-numbers);
  font-size: var(--fs-die-btn);
  font-weight: var(--fw-strong);
  line-height: 1.1;
}

.part-note {
  color: var(--accent);
  font-family: var(--font-ui);
  font-size: var(--fs-ui);
}

.part-dice {
  max-width: 100%;
  overflow: hidden;
  color: var(--text-dim);
  font-family: var(--font-ui);
  font-size: var(--fs-small);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Attack results: each attack is a card of up to three lines (name, to hit, damage). The list
   owns three columns (label, details, total) and every card uses them through subgrid, so
   labels, details and totals line up from one attack to the next. */
.result-attacks {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  column-gap: 12px;
  row-gap: 6px;
  margin: 4px 0 0;
  padding: 0;
  list-style: none;
}

.attack-row {
  --i: 0;
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  align-items: first baseline;
  row-gap: 2px;
  padding: 8px 10px;
  color: var(--die-text);
  background: var(--die-bg);
  border: var(--bw) solid var(--die-border);
  border-radius: var(--radius-sm);
  animation: die-in var(--roll-ms) var(--roll-ease) both;
  animation-delay: calc(var(--i) * 60ms);
}

/* Browsers without subgrid: fixed label and total columns still line up */
@supports not (grid-template-columns: subgrid) {
  .attack-row {
    grid-template-columns: 6rem minmax(0, 1fr) auto;
    column-gap: 12px;
  }
}

.attack-label {
  grid-column: 1 / -1;
  font-family: var(--font-ui);
  font-size: var(--fs-ui);
  overflow-wrap: break-word;
}

.attack-kind {
  color: var(--text-dim);
  font-family: var(--font-ui);
  font-size: var(--fs-small);
}

.attack-detail {
  display: grid;
  font-family: var(--font-ui);
  font-size: var(--fs-small);
}

.attack-value {
  font-family: var(--font-numbers);
  font-size: var(--fs-die);
  font-weight: var(--fw-strong);
  line-height: 1.2;
  text-align: right;
}

.attack-row.is-max {
  border-color: var(--crit-max);
}

.attack-row.is-max .attack-value.attack-hit {
  color: var(--crit-max);
}

.attack-row.is-min {
  border-color: var(--crit-min);
}

.attack-row.is-min .attack-value.attack-hit {
  color: var(--crit-min);
}

/* Small phones: tighter attack columns and tabs, so details and tab labels keep their room */
@media (max-width: 24rem) {
  .result-attacks {
    column-gap: 8px;
  }

  .tabs {
    gap: 3px;
  }

  .tab {
    padding: 0 1px;
  }
}

.result-dice {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
  max-height: calc(3 * (var(--die-size) + 18px));
  margin: 8px 0 0;
  padding: 4px;
  overflow-y: auto;
  list-style: none;
}

.die {
  --i: 0;
  position: relative;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-width: var(--die-size);
  min-height: var(--die-size);
  padding: 2px 6px;
  color: var(--die-text);
  background: var(--die-bg);
  border: var(--bw) solid var(--die-border);
  border-radius: var(--radius-sm);
  font-family: var(--font-numbers);
  font-size: var(--fs-die);
  font-weight: var(--fw-strong);
  line-height: 1;
  animation: die-in var(--roll-ms) var(--roll-ease) both;
  animation-delay: calc(min(var(--i), 15) * 30ms);
}

.die-sub {
  margin-top: 2px;
  font-family: var(--font-ui);
  font-size: var(--fs-die-sub);
  font-weight: 400;
  opacity: 0.85;
}

.die.is-max {
  color: var(--crit-max-fg);
  background: var(--crit-max-bg);
  border-color: var(--crit-max-fg);
}

.die.is-min {
  color: var(--crit-min-fg);
  background: var(--crit-min-bg);
  border-color: var(--crit-min-fg);
}

.die.has-mark .die-value::after,
.die.is-exploded .die-value::after {
  content: "!";
}

.die.is-extra::before {
  content: "+";
  position: absolute;
  left: calc(-6px - var(--bw));
  color: var(--text-dim);
  font-size: 0.6em;
  transform: translateX(-50%);
}

/* Die-shaped tiles: an SVG outline behind the number replaces the box.
   Padding is in em so wide pixel digits widen the tile, and the outline stretches with it. */
.die.has-shape {
  --shape-size: calc(var(--die-size) * 1.15);
  min-width: var(--shape-size);
  min-height: var(--shape-size);
  padding: 4px 0.6em;
  isolation: isolate;
}

/* Pointed shapes are narrow away from their middle, so their numbers need more room */
.die.shape-8,
.die.shape-10,
.die.shape-100 {
  padding-inline: 0.95em;
}

.die.shape-4 {
  padding-inline: 1.1em;
}

.die.has-shape,
.die.has-shape.is-max,
.die.has-shape.is-min {
  background: transparent;
  border-color: transparent;
}

.die-shape {
  position: absolute;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.die-shape > * {
  fill: var(--die-bg);
  stroke: var(--die-border);
  stroke-width: var(--bw);
  stroke-linejoin: var(--stroke-join);
  vector-effect: non-scaling-stroke;
  shape-rendering: var(--shape-rendering);
}

.die.is-max .die-shape > * {
  fill: var(--crit-max-bg);
  stroke: var(--crit-max-fg);
}

.die.is-min .die-shape > * {
  fill: var(--crit-min-bg);
  stroke: var(--crit-min-fg);
}

/* A triangle's middle sits low, so the d4's number does too */
.die.shape-4 {
  justify-content: flex-end;
  padding-bottom: calc(var(--shape-size) * 0.12);
}

.die.is-dropped {
  opacity: 0.45;
}

.die.is-dropped .die-value {
  text-decoration: line-through;
}

.result-dice.is-many {
  gap: 4px;
}

.result-dice.is-many .die {
  min-width: calc(var(--die-size) * 0.8);
  min-height: calc(var(--die-size) * 0.8);
  padding: 1px 4px;
}

.result-dice.is-many .die.has-shape {
  --shape-size: calc(var(--die-size) * 0.9);
}

/* Redrawn after a language change: no replayed roll animation */
.result.is-static .die,
.result.is-static .part,
.result.is-static .attack-row {
  animation: none;
}

/* ── Controls ──────────────────────────────────────────────────── */

.controls {
  display: grid;
  gap: 12px;
}

.steppers {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.field {
  display: grid;
  gap: 4px;
  min-width: 0;
}

.field-label,
.panel-head h2,
.setting legend {
  color: var(--text-dim);
  font-family: var(--font-ui);
  font-size: var(--fs-label);
  font-weight: 400;
  letter-spacing: var(--label-spacing);
  text-transform: var(--label-case);
}

.stepper {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) 44px;
  gap: 4px;
}

.step {
  padding: 0;
  font-family: var(--font-numbers);
  font-size: var(--fs-die);
}

.step-input,
.text-input,
select {
  width: 100%;
  min-width: 0;
  min-height: 44px;
  color: var(--text);
  background: var(--die-bg);
  border: var(--bw) solid var(--border);
  border-radius: var(--radius-sm);
  font-family: var(--font-ui);
  /* 16px or more stops iOS zooming in on focus */
  font-size: max(16px, var(--fs-ui));
  text-shadow: inherit;
}

.step-input {
  padding: 0;
  font-family: var(--font-numbers);
  font-size: max(16px, var(--fs-die));
  font-weight: var(--fw-strong);
  text-align: center;
  -moz-appearance: textfield;
  appearance: textfield;
}

.step-input::-webkit-inner-spin-button,
.step-input::-webkit-outer-spin-button {
  margin: 0;
  -webkit-appearance: none;
}

.chips {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 4px;
}

.chip {
  min-width: 0;
  min-height: 40px;
  padding: 0;
  font-size: var(--fs-small);
}

.controls-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

/* Switch built on a real checkbox, so labels, focus and keyboard all work natively */
.toggle {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  font-family: var(--font-ui);
  font-size: var(--fs-ui);
  cursor: pointer;
}

.toggle input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.toggle-box {
  position: relative;
  flex: none;
  width: 44px;
  height: 24px;
  background: var(--surface-2);
  border: var(--bw) solid var(--border);
  border-radius: var(--radius-sm);
}

.toggle-box::after {
  content: "";
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: 2px;
  aspect-ratio: 1;
  background: var(--text-dim);
  border-radius: calc(var(--radius-sm) / 2);
  transition: transform 120ms ease-out;
}

.toggle input:checked + .toggle-box {
  background: var(--accent);
  border-color: var(--accent);
}

.toggle input:checked + .toggle-box::after {
  background: var(--accent-text);
  transform: translateX(20px);
}

.toggle input:focus-visible + .toggle-box {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.toggle input:disabled ~ * {
  opacity: 0.5;
}

.toggle small {
  color: var(--text-dim);
  font-size: var(--fs-small);
}

.segmented {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.segmented label {
  position: relative;
  display: grid;
}

.segmented input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.segmented label > span {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  padding: 0 6px;
  color: var(--btn-text);
  background: var(--btn-bg);
  border: var(--bw) solid var(--btn-border);
  border-radius: var(--radius-sm);
  font-family: var(--font-ui);
  font-size: var(--fs-small);
  text-align: center;
}

.segmented input:checked + span {
  color: var(--accent-text);
  background: var(--accent);
  border-color: var(--accent);
}

.segmented input:focus-visible + span {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.segmented .short {
  display: none;
}

@media (max-width: 26rem) {
  .segmented .long {
    display: none;
  }

  .segmented .short {
    display: inline;
  }
}

.dice-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}

.die-btn {
  gap: 8px;
  min-height: 56px;
  font-family: var(--font-display);
  font-size: var(--fs-die-btn);
  font-weight: var(--fw-strong);
}

.die-icon {
  flex: none;
  width: 22px;
  height: 22px;
  overflow: visible;
  fill: none;
  stroke: currentColor;
}

.die-icon > * {
  stroke-width: var(--icon-stroke);
  stroke-linejoin: var(--stroke-join);
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  shape-rendering: var(--shape-rendering);
}

.die-btn-d20 {
  color: var(--d20-text);
  background: var(--d20-bg);
  border-color: var(--d20-border);
}

.die-btn-d20:active,
.die-btn-d20.is-pressed {
  color: var(--btn-active-text, var(--d20-text));
  background: var(--btn-active-bg, var(--d20-bg));
}

/* ── Saved rolls and quick rolls ───────────────────────────────── */

.saved,
.presets {
  display: grid;
  gap: 8px;
}

.saved-empty {
  color: var(--text-dim);
  font-size: var(--fs-small);
}

.saved-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.saved-roll,
.preset-btn {
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  min-height: 52px;
  padding: 6px 12px;
  text-align: left;
}

.saved-roll {
  min-width: 0;
  max-width: 100%;
}

.saved-list li {
  min-width: 0;
  max-width: 100%;
}

.saved-name,
.preset-name {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.saved-notation,
.preset-hint {
  max-width: 100%;
  overflow: hidden;
  color: var(--text-dim);
  font-size: var(--fs-small);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.panel-actions {
  display: flex;
  gap: 6px;
}

.saved-name .die-icon {
  width: 1em;
  height: 1em;
  margin-right: 6px;
  vertical-align: -0.15em;
  fill: none;
  stroke: currentColor;
}

/* Edit mode: dashed outlines say "tap to change" rather than "tap to roll" */
.saved-list.is-editing .saved-roll {
  border-style: dashed;
  box-shadow: none;
}

.preset-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.preset-btn {
  min-width: 0;
}

/* ── Custom roll ───────────────────────────────────────────────── */

.custom {
  display: grid;
  gap: 6px;
}

.custom-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 8px;
}

.text-input {
  padding: 0 12px;
}

.text-input::placeholder {
  color: var(--text-dim);
  opacity: 0.8;
}

/* ── History ───────────────────────────────────────────────────── */

.history {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 40px;
}

.history-empty {
  color: var(--text-dim);
  font-size: var(--fs-small);
}

.history-list {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.history-item {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr) auto;
  align-items: center;
  gap: 2px 10px;
  width: 100%;
  min-height: 52px;
  padding: 6px 10px 6px 6px;
  color: var(--text);
  background: var(--surface-2);
  border: var(--bw) solid transparent;
  border-radius: var(--radius-sm);
  font-family: var(--font-ui);
  font-size: var(--fs-ui);
  text-align: left;
  text-shadow: inherit;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

.history-item:hover {
  border-color: var(--border);
}

.history-item:active {
  border-color: var(--accent);
}

.history-total {
  grid-row: span 2;
  font-family: var(--font-numbers);
  font-size: var(--fs-die);
  font-weight: var(--fw-strong);
  text-align: center;
}

.history-total.is-max {
  color: var(--crit-max);
}

.history-total.is-min {
  color: var(--crit-min);
}

.history-notation {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.history-time,
.history-dice {
  color: var(--text-dim);
  font-size: var(--fs-small);
}

.history-dice {
  grid-column: 2 / -1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Toast ─────────────────────────────────────────────────────── */

.toast {
  position: fixed;
  bottom: calc(16px + env(safe-area-inset-bottom));
  left: 50%;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 12px;
  width: max-content;
  max-width: calc(100vw - 32px);
  padding: 8px 8px 8px 16px;
  color: var(--text);
  background: var(--surface-2);
  border: var(--bw) solid var(--accent);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgb(0 0 0 / 0.45);
  transform: translateX(-50%);
}

/* ── Dialogs ───────────────────────────────────────────────────── */

dialog,
.result-dice,
.history {
  scrollbar-color: var(--border) transparent;
  scrollbar-width: thin;
}

dialog {
  width: min(32rem, calc(100vw - 24px));
  max-height: calc(100dvh - 24px);
  padding: 0;
  overflow-y: auto;
  color: var(--text);
  background: var(--surface);
  border: var(--bw) solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--panel-shadow);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  text-shadow: var(--glow);
}

/* ::backdrop doesn't inherit custom properties in every browser, so no tokens here */
dialog::backdrop {
  background: rgb(0 0 0 / 0.65);
}

.dialog-body {
  display: grid;
  gap: 16px;
  padding: 16px;
}

dialog h2 {
  color: var(--accent);
  font-family: var(--font-display);
  font-size: var(--fs-title);
  letter-spacing: var(--title-spacing);
  text-transform: var(--title-case);
}

.dialog-foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
}

.dialog-foot .btn-danger {
  margin-right: auto;
}

.form-error {
  color: var(--danger);
  font-size: var(--fs-small);
}

/* Attack builder */
.attack-lines {
  display: grid;
  gap: 12px;
}

.attack-line {
  display: grid;
  gap: 8px;
  min-width: 0;
  margin: 0;
  padding: 10px;
  background: var(--surface-2);
  border: var(--bw) solid var(--border);
  border-radius: var(--radius-sm);
}

.attack-line-head {
  display: flex;
  gap: 6px;
}

.attack-line-head .text-input {
  flex: 1;
}

.step-value {
  display: grid;
  place-items: center;
  min-width: 0;
  min-height: 44px;
  color: var(--text);
  background: var(--die-bg);
  border: var(--bw) solid var(--border);
  border-radius: var(--radius-sm);
  font-family: var(--font-numbers);
  font-size: max(16px, var(--fs-die));
  font-weight: var(--fw-strong);
}

.die-chips {
  display: grid;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  gap: 4px;
}

.die-chips .chip {
  padding: 0;
}

@media (max-width: 22rem) {
  .die-chips {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.attack-preview {
  color: var(--text-dim);
  font-size: var(--fs-small);
}

/* Each damage part (1d8+3 slashing, 2d6 fire) sits in its own inset box */
.damage-parts {
  display: grid;
  gap: 8px;
}

.damage-part {
  display: grid;
  gap: 8px;
  min-width: 0;
  margin: 0;
  padding: 8px;
  border: 1px dashed var(--border);
  border-radius: var(--radius-sm);
}

/* Damage-only rows (spells) keep the damage in the same column as rows with a to-hit */


.attack-add {
  justify-self: start;
}

.setting-hint {
  color: var(--text-dim);
  font-size: var(--fs-small);
}

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

.setting {
  display: grid;
  gap: 8px;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.setting legend {
  margin-bottom: 8px;
  padding: 0;
}

.toggles {
  gap: 2px;
}

select {
  padding: 0 10px;
}

.font-preview {
  font-family: var(--font-numbers);
  font-size: var(--fs-die);
  text-align: center;
}

/* Each card carries its own data-theme, so it renders with that theme's tokens */
.theme-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

@media (max-width: 22rem) {
  .theme-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

.theme-card {
  position: relative;
  display: grid;
  gap: 8px;
  min-width: 0;
  padding: 8px;
  color: var(--text);
  background-color: var(--bg);
  background-image: var(--bg-image);
  background-size: var(--bg-size);
  border: var(--bw) solid var(--border);
  border-radius: var(--radius);
  font-family: var(--font-body);
  text-shadow: var(--glow);
  cursor: pointer;
}

.theme-card input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.theme-card:has(input:checked) {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.theme-card:has(input:focus-visible) {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.theme-name {
  color: var(--accent);
  font-family: var(--font-display);
  font-size: var(--fs-card);
  letter-spacing: var(--title-spacing);
  text-transform: var(--title-case);
}

.theme-sample {
  display: flex;
  gap: 4px;
}

/* Thinner borders than real tiles so three samples fit a narrow card in every theme */
.theme-sample span {
  display: inline-grid;
  flex: 1 1 0;
  place-items: center;
  min-width: 0;
  max-width: 3rem;
  height: 2.25rem;
  color: var(--die-text);
  background: var(--die-bg);
  border: min(var(--bw), 2px) solid var(--die-border);
  border-radius: var(--radius-sm);
  font-family: var(--font-numbers);
  font-size: min(var(--fs-die), 1rem);
  font-weight: var(--fw-strong);
}

.theme-sample .is-max {
  color: var(--crit-max-fg);
  background: var(--crit-max-bg);
  border-color: var(--crit-max-fg);
}

.theme-sample .is-min {
  color: var(--crit-min-fg);
  background: var(--crit-min-bg);
  border-color: var(--crit-min-fg);
}

.prose {
  line-height: 1.45;
}

.prose-block {
  display: grid;
  gap: 12px;
}

.prose h3 {
  margin-top: 4px;
  color: var(--accent);
  font-family: var(--font-ui);
  font-size: var(--fs-label);
  font-weight: 400;
  letter-spacing: var(--label-spacing);
  text-transform: var(--label-case);
}

.prose ul {
  display: grid;
  gap: 4px;
  margin: 0;
  padding-left: 1.2em;
}

code,
kbd {
  padding: 0 4px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-family: var(--mono);
  font-size: 0.85em;
  text-shadow: none;
}

.mark-max {
  color: var(--crit-max);
  font-weight: 700;
}

.mark-min {
  color: var(--crit-min);
  font-weight: 700;
}

.credits {
  color: var(--text-dim);
  font-size: var(--fs-small);
}

/* ── Motion ────────────────────────────────────────────────────── */

@keyframes die-in {
  from {
    opacity: 0;
    transform: translateY(-10px) rotate(-14deg) scale(0.7);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes total-pop {
  from {
    opacity: 0.2;
    transform: scale(0.8);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes blink {
  50% {
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
}
