/*
  Familiar.

  Built phone first, because that is where it gets used. A few deliberate choices
  for readability rather than decoration:

  - Warm off white rather than pure white. Less glare, easier on a long read.
  - Line height 1.65 and a hard cap on line length. Long lines are where a reader
    loses their place.
  - Never justified. Ragged right keeps word spacing even.
  - Every spell leads with one plain line and a row of numbers. The book's own
    wording is there but it is behind a tap, not the first thing you meet.
*/

:root {
  --bg: #faf7f2;
  --surface: #ffffff;
  --surface-2: #f3eee6;
  --text: #2b2620;
  --muted: #6d6558;
  --border: #e4dcd1;
  --accent: #8f6118;
  --accent-bg: #f7ecd9;
  --danger: #8a3324;
  --shadow: 0 1px 2px rgba(43, 38, 32, .06), 0 4px 12px rgba(43, 38, 32, .05);

  --abjuration: #4a6fa5;
  --conjuration: #7a5aa3;
  --divination: #4f8a8b;
  --enchantment: #a85a8c;
  --evocation: #b4632a;
  --illusion: #6a5acd;
  --necromancy: #5b6b52;
  --transmutation: #a08327;

  color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #15140f;
    --surface: #1e1c16;
    --surface-2: #26231b;
    --text: #ece7dd;
    --muted: #a49a89;
    --border: #34302a;
    --accent: #d9a441;
    --accent-bg: #2e2617;
    --danger: #d4796a;
    --shadow: none;

    --abjuration: #7fa3d6;
    --conjuration: #b295db;
    --divination: #79c2c3;
    --enchantment: #dc93bf;
    --evocation: #e0955c;
    --illusion: #9d92ea;
    --necromancy: #93a888;
    --transmutation: #d6b95c;
  }
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: "Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system, sans-serif;
  font-size: 16px;
  line-height: 1.65;
  text-align: left;
  -webkit-text-size-adjust: 100%;
}

h1, h2, h3 { line-height: 1.25; margin: 0; font-weight: 650; }
h1 { font-size: 1.6rem; letter-spacing: -.01em; }
h2 { font-size: 1.15rem; }
h3 { font-size: 1rem; }
p { margin: 0 0 .85em; max-width: 34rem; }
p:last-child { margin-bottom: 0; }

/* ---- shell ---------------------------------------------------------------- */

.app {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  max-width: 46rem;
  margin: 0 auto;
  background: var(--bg);
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
  padding: .9rem 1.1rem .75rem;
}

.topbar .wordmark {
  display: flex;
  align-items: baseline;
  gap: .55rem;
}

.topbar .wordmark small {
  color: var(--muted);
  font-size: .78rem;
  letter-spacing: .04em;
  text-transform: uppercase;
}

.content {
  flex: 1;
  padding: 1.1rem 1.1rem 6rem;
}

.tabbar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 20;
  display: flex;
  background: color-mix(in srgb, var(--surface) 94%, transparent);
  backdrop-filter: blur(14px);
  border-top: 1px solid var(--border);
  padding-bottom: env(safe-area-inset-bottom);
}

.tabbar > * {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .15rem;
  padding: .6rem 0 .7rem;
  color: var(--muted);
  text-decoration: none;
  font-size: .72rem;
  letter-spacing: .02em;
  border: 0;
  background: none;
  cursor: pointer;
  font-family: inherit;
}

.tabbar > *.active { color: var(--accent); }
.tabbar .glyph { font-size: 1.15rem; line-height: 1; }

/* ---- search --------------------------------------------------------------- */

.search {
  display: flex;
  align-items: center;
  gap: .6rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: .7rem;
  padding: .55rem .8rem;
  box-shadow: var(--shadow);
}

.search input {
  flex: 1;
  border: 0;
  outline: 0;
  background: none;
  color: var(--text);
  font: inherit;
  min-width: 0;
}

.search input::placeholder { color: var(--muted); }

.filters {
  display: flex;
  gap: .4rem;
  overflow-x: auto;
  padding: .8rem 0 .2rem;
  scrollbar-width: none;
}

.filters::-webkit-scrollbar { display: none; }

.filter {
  flex: none;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--muted);
  border-radius: 999px;
  padding: .3rem .75rem;
  font: inherit;
  font-size: .82rem;
  cursor: pointer;
  white-space: nowrap;
}

.filter.on {
  background: var(--accent-bg);
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 600;
}

.resultcount {
  color: var(--muted);
  font-size: .82rem;
  padding: .7rem .1rem .4rem;
}

/* ---- cards ---------------------------------------------------------------- */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: .7rem;
  margin-bottom: .6rem;
  box-shadow: var(--shadow);
  overflow: hidden;
}

.card > button.head {
  display: block;
  width: 100%;
  text-align: left;
  border: 0;
  background: none;
  /* Explicit, not inherited. A button's colour is set by the user agent and by anything
     else on the page, and a spell name that quietly renders dark on dark is exactly the
     kind of thing nobody notices until it is in someone's hand at a table. */
  color: var(--text);
  font: inherit;
  padding: .8rem .95rem;
  cursor: pointer;
}

.card .title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .7rem;
}

.card .title .name { font-weight: 650; font-size: 1.02rem; color: var(--text); }
.card .title .lvl { color: var(--muted); font-size: .8rem; white-space: nowrap; }

/* The always visible plain English line. This is the whole point of the app. */
.summary {
  margin-top: .3rem;
  color: var(--text);
  max-width: 34rem;
}

.meta {
  margin-top: .45rem;
  display: flex;
  flex-wrap: wrap;
  gap: .35rem .4rem;
  align-items: center;
}

.chip {
  font-size: .74rem;
  line-height: 1.5;
  padding: .1rem .5rem;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--muted);
  white-space: nowrap;
}

.chip.key { background: var(--accent-bg); color: var(--accent); font-weight: 600; }
.chip.warn { background: color-mix(in srgb, var(--danger) 14%, transparent); color: var(--danger); }
.chip.book { border: 1px dashed var(--border); background: none; }
.chip.expert { background: var(--accent-bg); color: var(--accent); font-weight: 600; }

/* The control for a feature you can actually do something with. Sits on the feature card,
   above the fold, because a button you have to open a panel to find is a button nobody uses
   mid fight. */
.actionrow {
  padding: .5rem .7rem .6rem;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: .4rem;
}

/* Point buy: a stepper rather than a box, because it is a budget and typing into a budget is
   how you go over it. */
.buy { display: flex; align-items: center; gap: .35rem; }
.buy .bought {
  min-width: 2ch;
  text-align: center;
  font-variant-numeric: tabular-nums;
  font-weight: 650;
}

.buy .cost { color: var(--muted); font-size: .7rem; min-width: 4ch; }

/* The roleplay boxes. Generous line height and a comfortable measure, because this is the
   part of the sheet somebody actually reads back rather than glances at. */
.roleplay { padding: .5rem .2rem; }
.roleplay label {
  display: block;
  font-size: .78rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: .3rem;
}

.roleplay textarea {
  width: 100%;
  box-sizing: border-box;
  padding: .5rem .6rem;
  border: 1px solid var(--border);
  border-radius: .4rem;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  line-height: 1.6;
  resize: vertical;
}

.roleplay textarea:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

.actionrow .meta { display: flex; flex-wrap: wrap; gap: .3rem; }
.actionrow .options { margin: 0; }
.actionrow .hint { margin: 0; }

.body {
  border-top: 1px solid var(--border);
  padding: .85rem .95rem 1rem;
  background: color-mix(in srgb, var(--surface-2) 55%, transparent);
}

.body h3 {
  font-size: .74rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--muted);
  margin-bottom: .5rem;
}

.body .prose { white-space: pre-wrap; }

.statgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
  gap: .5rem;
  margin-bottom: .9rem;
}

.stat {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: .5rem;
  padding: .45rem .6rem;
}

.stat .k {
  display: block;
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
}

.stat .v { font-weight: 650; font-variant-numeric: tabular-nums; }

.notice {
  border-left: 3px solid var(--danger);
  background: color-mix(in srgb, var(--danger) 8%, transparent);
  padding: .5rem .7rem;
  border-radius: .35rem;
  font-size: .88rem;
  margin-bottom: .9rem;
}

.missing {
  color: var(--muted);
  font-size: .88rem;
  font-style: italic;
}

/* School accents, so a list is scannable without reading every word. */
.s-abjuration { border-left-color: var(--abjuration); }
.s-conjuration { border-left-color: var(--conjuration); }
.s-divination { border-left-color: var(--divination); }
.s-enchantment { border-left-color: var(--enchantment); }
.s-evocation { border-left-color: var(--evocation); }
.s-illusion { border-left-color: var(--illusion); }
.s-necromancy { border-left-color: var(--necromancy); }
.s-transmutation { border-left-color: var(--transmutation); }

/* ---- tables --------------------------------------------------------------- */

.tablewrap { overflow-x: auto; margin: 0 -.95rem; padding: 0 .95rem; }

table { border-collapse: collapse; font-size: .86rem; width: 100%; }
th, td { padding: .35rem .5rem; text-align: left; white-space: nowrap; }
th { color: var(--muted); font-weight: 600; font-size: .7rem; text-transform: uppercase; letter-spacing: .05em; }
tbody tr:nth-child(odd) { background: color-mix(in srgb, var(--surface-2) 60%, transparent); }
td.num { text-align: center; font-variant-numeric: tabular-nums; }
td.dim { color: var(--muted); }

.loading { color: var(--muted); padding: 2rem 0; }

::selection { background: var(--accent-bg); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: .35rem;
}

/* ---- character sheet ------------------------------------------------------- */

.identity { margin-bottom: 1rem; }
.identity h2 { font-size: 1.35rem; }
.identity .sub { color: var(--muted); margin: .15rem 0 0; }

.section {
  font-size: .74rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--muted);
  margin: 1.6rem 0 .6rem;
}

.vitals { display: grid; gap: .6rem; }

.hp {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: .7rem;
  padding: .75rem .9rem;
  box-shadow: var(--shadow);
}

.hp .k {
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
}

.hpvalue { display: flex; align-items: baseline; gap: .5rem; margin: .1rem 0 .5rem; }
.hpvalue .now { font-size: 2rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.hpvalue .max { color: var(--muted); }

.step {
  margin-left: auto;
  width: 2.2rem;
  height: 2.2rem;
  border-radius: .5rem;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
}

.step + .step { margin-left: .4rem; }
.hpvalue .step:first-of-type { margin-left: auto; }

.hpbar {
  height: .4rem;
  border-radius: 999px;
  background: var(--surface-2);
  overflow: hidden;
  margin-bottom: .6rem;
}

.hpbar span { display: block; height: 100%; background: var(--accent); transition: width .18s ease; }

.hprow { display: flex; align-items: end; gap: .4rem; flex-wrap: wrap; }
.hprow label { font-size: .7rem; color: var(--muted); display: grid; gap: .2rem; }
.hprow input { width: 4.5rem; }

input[type="number"], input[type="text"] {
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  border-radius: .45rem;
  padding: .35rem .5rem;
  font: inherit;
  min-width: 0;
}

.btn {
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  border-radius: .5rem;
  padding: .4rem .8rem;
  font: inherit;
  font-size: .88rem;
  cursor: pointer;
}

.btn.primary { background: var(--accent-bg); border-color: var(--accent); color: var(--accent); font-weight: 600; }
.btn.small { padding: .2rem .55rem; font-size: .8rem; }
.btn:disabled { opacity: .4; cursor: not-allowed; }

.restrow { display: flex; gap: .5rem; margin-top: .8rem; }
.restrow .btn { flex: 1; }

.stat .big { font-size: 1.35rem; }
.stat .how { display: block; font-size: .68rem; color: var(--muted); margin-top: .1rem; }
.stat .v small { font-size: .75rem; color: var(--muted); }

.abilities { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem; }

.ability {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: .6rem;
  padding: .5rem .3rem;
  text-align: center;
}

.ability .k { display: block; font-size: .66rem; letter-spacing: .08em; color: var(--muted); }
.ability .mod { display: block; font-size: 1.45rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.ability .score { font-size: .78rem; color: var(--muted); }

.rolls { list-style: none; margin: 0; padding: 0; }

.rolls li {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .42rem .6rem;
  border-bottom: 1px solid var(--border);
}

.rolls li:last-child { border-bottom: 0; }
.rolls .dot { width: .55rem; height: .55rem; border-radius: 50%; border: 1.5px solid var(--muted); flex: none; }
.rolls li.prof .dot { background: var(--accent); border-color: var(--accent); }

/* A doubled bonus gets a ring as well as a fill, so the two are told apart at a glance
   rather than by reading the number and doing the arithmetic. */
.rolls li.expert .dot {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 3.5px var(--accent);
}
.rolls .label { flex: 1; }
.rolls .label small { color: var(--muted); font-size: .7rem; margin-left: .25rem; }
.rolls .mod { font-variant-numeric: tabular-nums; font-weight: 650; min-width: 2.2rem; text-align: right; }

.resource {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: .6rem;
  padding: .6rem .8rem;
  margin-bottom: .5rem;
}

.resource .title { display: flex; justify-content: space-between; align-items: baseline; gap: .6rem; }
.resource .name { font-weight: 650; }
.resource .lvl { color: var(--muted); font-size: .74rem; }

.pips { display: flex; align-items: center; gap: .3rem; margin-top: .45rem; flex-wrap: wrap; }
.pip { width: .8rem; height: .8rem; border-radius: 50%; border: 1.5px solid var(--accent); }
.pip.used { background: var(--surface-2); border-color: var(--border); }
.pips .count { color: var(--muted); font-size: .76rem; margin: 0 .3rem 0 .4rem; }
.pips .btn { margin-left: auto; }

.pool { display: flex; gap: .4rem; margin-top: .45rem; flex-wrap: wrap; align-items: center; }

.die {
  min-width: 2.4rem;
  height: 2.4rem;
  border-radius: .5rem;
  border: 1px solid var(--accent);
  background: var(--accent-bg);
  color: var(--accent);
  font: inherit;
  font-weight: 700;
  font-size: 1.05rem;
  cursor: pointer;
}

.prompt {
  border: 1px solid var(--accent);
  background: var(--accent-bg);
  border-radius: .7rem;
  padding: .8rem .9rem;
  margin-bottom: .8rem;
}

.prompt h3 { color: var(--accent); margin-bottom: .3rem; }
.prompt p { margin-bottom: .5rem; }
.rollrow { display: flex; gap: .4rem; flex-wrap: wrap; align-items: center; }
.rollrow input { width: 3.2rem; text-align: center; }

.notice.info { border-left-color: var(--accent); background: var(--accent-bg); color: var(--text); }

/* ---- roll tray ------------------------------------------------------------- */

/* Sits above the tab bar so a result stays on screen while the table talks over you. */
.tray {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(3.4rem + env(safe-area-inset-bottom));
  z-index: 19;
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .45rem .8rem;
  background: color-mix(in srgb, var(--surface) 96%, transparent);
  backdrop-filter: blur(14px);
  border-top: 1px solid var(--border);
  max-width: 46rem;
  margin: 0 auto;
  min-height: 3rem;
}

.tray.asking { border-top-color: var(--accent); background: var(--accent-bg); align-items: start; }

.modes { display: flex; flex: none; border: 1px solid var(--border); border-radius: .45rem; overflow: hidden; }

/* Sized for a thumb, not a mouse. These were about 20px tall against the 44px that a finger
   actually needs, and they sit in the one place you reach for mid fight, so a missed tap here
   means rolling with advantage when you meant disadvantage and not noticing. */
.modes button {
  border: 0;
  background: var(--surface-2);
  color: var(--muted);
  font: inherit;
  font-size: .85rem;
  min-height: 2.75rem;
  min-width: 3.4rem;
  padding: .5rem .7rem;
  cursor: pointer;

  /* Stops a fast double tap selecting the label instead of pressing the button. */
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
}

.modes button + button { border-left: 1px solid var(--border); }
.modes button.on { background: var(--accent); color: var(--bg); font-weight: 650; }

.tray .idle { color: var(--muted); font-size: .82rem; }

.tray .result {
  flex: 1;
  display: flex;
  align-items: center;
  gap: .55rem;
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  min-width: 0;
}

.tray .result .what {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: .84rem;
  color: var(--muted);
}

.tray .result .total {
  font-size: 1.5rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.tray .result .total.crit { color: var(--accent); }
.tray .result .total.fumble { color: var(--danger); }

.tray .how { display: flex; gap: .25rem; align-items: center; flex: none; }

.tray .face {
  font-size: .72rem;
  font-variant-numeric: tabular-nums;
  background: var(--surface-2);
  border-radius: .3rem;
  padding: 0 .3rem;
  color: var(--muted);
}

.tray .face.dropped { text-decoration: line-through; opacity: .5; }
.tray .plus { font-size: .72rem; color: var(--muted); }

.asking-for { flex: 1; display: grid; gap: .3rem; min-width: 0; }
.asking-for .what { font-size: .8rem; color: var(--accent); font-weight: 600; }
.asking-for .hint { font-size: .72rem; color: var(--muted); }

/* Room for the tray as well as the tab bar. */
.content { padding-bottom: 9.5rem; }

/* ---- tappable rows --------------------------------------------------------- */

.rolls li { padding: 0; }

.rollable {
  flex: 1;
  display: flex;
  align-items: center;
  gap: .55rem;
  width: 100%;
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  padding: .42rem .6rem;
  cursor: pointer;
  border-radius: .4rem;
  min-width: 0;
}

.rollable:active { background: var(--surface-2); }

.chip.tappable {
  border: 1px solid var(--accent);
  cursor: pointer;
  font-family: inherit;
  margin-right: .6rem;
}

.hint { font-size: .82rem; color: var(--muted); }

.choice { border-top: 1px solid color-mix(in srgb, var(--accent) 30%, transparent); padding-top: .55rem; margin-top: .55rem; }
.choice:first-of-type { border-top: 0; padding-top: 0; margin-top: 0; }
.choice p { margin-bottom: .45rem; }
.choice .hint { display: block; font-size: .74rem; }
.options { display: flex; flex-wrap: wrap; gap: .35rem; }
.options .btn:disabled { opacity: .35; }

.roster { display: flex; flex-wrap: wrap; gap: .35rem; margin-bottom: 1rem; align-items: center; }
.roster a.btn { text-decoration: none; display: inline-block; }
.btn.danger { border-color: var(--danger); color: var(--danger); }
.ability input {
  width: 100%;
  text-align: center;
  font-size: 1.25rem;
  font-weight: 700;
  margin: .1rem 0;
  background: var(--surface-2);
}

textarea {
  width: 100%;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  border-radius: .45rem;
  padding: .5rem .6rem;
  font: inherit;
  font-size: .85rem;
  margin: .5rem 0;
  resize: vertical;
}

label.btn { cursor: pointer; }
.resource .options { margin-top: .5rem; }

/* ---- welcome --------------------------------------------------------------- */

/* No tab bar and no roll tray here, so the content does not need to dodge them. */
.app.bare .content { padding: 2.5rem 1.1rem 3rem; }

.welcome { display: grid; gap: 1.6rem; }

.welcome-mark h1 { font-size: 2.4rem; letter-spacing: -.02em; }
.welcome-mark .sub { color: var(--muted); margin: .3rem 0 0; }

.welcome-actions { display: grid; gap: .6rem; }

.tile {
  display: grid;
  grid-template-columns: 2.4rem 1fr;
  grid-template-rows: auto auto;
  column-gap: .8rem;
  align-items: center;
  padding: .9rem 1rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: .7rem;
  box-shadow: var(--shadow);
  text-decoration: none;
  color: var(--text);
}

.tile .glyph {
  grid-row: 1 / span 2;
  font-size: 1.5rem;
  text-align: center;
  color: var(--accent);
  line-height: 1;
}

.tile .what { font-weight: 650; font-size: 1.05rem; }
.tile .why { color: var(--muted); font-size: .84rem; }
.tile:active { border-color: var(--accent); }
.tile.disabled { opacity: .45; }
.tile.disabled .glyph { color: var(--muted); }

.welcome-browse .options { margin-top: .4rem; }
.welcome-browse a.btn { text-decoration: none; }

.linky {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  color: var(--accent);
  text-decoration: underline;
  cursor: pointer;
}

.topbar .wordmark { text-decoration: none; color: inherit; }
.restrow a.btn { text-decoration: none; text-align: center; }

/* ---- collapsible sections --------------------------------------------------- */

/*
  The whole header is the target, and it is deliberately big. A thumb is about 45px across
  and people are tapping these on a phone, in a pub, holding a drink. 56px tall with a real
  background so it reads as a button rather than a heading you might or might not be able
  to press.
*/
button.section.toggle {
  display: flex;
  align-items: center;
  gap: .7rem;
  width: 100%;
  min-height: 3.5rem;
  margin: .8rem 0 0;
  padding: .9rem 1rem;
  border: 1px solid var(--border);
  border-radius: .7rem;
  background: var(--surface);
  box-shadow: var(--shadow);
  font: inherit;
  color: var(--text);
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

button.section.toggle .caret {
  color: var(--accent);
  font-size: 1.1rem;
  width: 1rem;
  flex: none;
  line-height: 1;
}

button.section.toggle .label {
  font-size: .9rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  font-weight: 700;
}

button.section.toggle .tally {
  margin-left: auto;
  font-size: .84rem;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

button.section.toggle.open {
  background: var(--accent-bg);
  border-color: var(--accent);
  color: var(--accent);
}

button.section.toggle.open .tally { color: var(--accent); }
button.section.toggle:active { transform: scale(.99); }

.section-body { padding-top: .7rem; }

/* The one heading that is not a toggle keeps the old look. */
.section.plain { margin-top: 1.6rem; }

/*
  Everything else a thumb has to hit at a table. Same reasoning as the section headers:
  these get pressed mid-combat by someone who is not looking carefully.
*/
.rolls li { min-height: 3rem; }

.rollable {
  min-height: 3rem;
  padding: .6rem .7rem;
}

.rolls .label { font-size: 1rem; }
.rolls .mod { font-size: 1.05rem; min-width: 2.6rem; }
.rolls .dot { width: .7rem; height: .7rem; }

.btn { min-height: 2.75rem; padding: .55rem 1rem; }
.btn.small { min-height: 2.4rem; padding: .45rem .85rem; font-size: .86rem; }
.step { width: 2.75rem; height: 2.75rem; font-size: 1.35rem; }
.die { min-width: 2.9rem; height: 2.9rem; }
.pip { width: 1rem; height: 1rem; }
.filter { min-height: 2.5rem; padding: .45rem 1rem; }
.tabbar > * { padding: .7rem 0 .8rem; }
.chip.tappable { min-height: 2.2rem; display: inline-flex; align-items: center; }

/* The card headers on spells, classes, races and features are tapped constantly too. */
.card > button.head { padding: 1rem .95rem; }

/* ---- innate racial magic ---------------------------------------------------- */

/* One row per spell rather than a run of chips, because the recharge matters as much
   as the name and a wrapped chip list buries it. */
.innate {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  padding: .4rem 0;
  border-top: 1px solid color-mix(in srgb, var(--border) 60%, transparent);
}

.innate:first-of-type { border-top: 0; }
.innate small { color: var(--muted); font-size: .74rem; }

/* ---- conditions ------------------------------------------------------------- */

.conditionnotice p { margin: 0 0 .35rem; }
.conditionnotice p:last-child { margin-bottom: 0; }

/* One per row rather than a grid of chips. These get tapped mid fight with one thumb,
   so the target is the whole row and the effect is readable without opening anything. */
.conditions { display: flex; flex-direction: column; gap: .4rem; margin-bottom: 1rem; }

.condition {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: .15rem .5rem;
  width: 100%;
  min-height: 3.25rem;
  padding: .6rem .75rem;
  text-align: left;
  font-family: inherit;
  font-size: .9rem;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: .5rem;
  cursor: pointer;
}

.condition .name { font-weight: 650; }
.condition .what { grid-column: 1 / -1; font-size: .78rem; color: var(--muted); }
.condition .tag { font-size: .7rem; color: var(--muted); align-self: center; }

.condition.on {
  border-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 12%, transparent);
}

.condition.on .name { color: var(--danger); }

/* Dragged in by another condition rather than chosen. Shown as on, but clearly not the
   thing the player ticked, so turning it off separately is obviously not the move. */
.condition.implied {
  border-style: dashed;
  border-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 5%, transparent);
}

.exhaustion { border-top: 1px solid var(--border); padding-top: .8rem; }
.exhaustion .title { display: flex; justify-content: space-between; align-items: baseline; }
.exhaustion .name { font-weight: 650; }
.exhaustion .lvl { color: var(--muted); font-size: .78rem; }

.exhaustion .levels {
  margin: .7rem 0 0;
  padding-left: 1.1rem;
  font-size: .8rem;
  color: var(--muted);
}

.exhaustion .levels li { padding: .12rem 0; }
.exhaustion .levels li.on { color: var(--danger); font-weight: 600; }

.pagehint { margin: 0 0 .9rem; }

/* ---- the crash bar ---------------------------------------------------------- */

/* Blazor puts this in index.html and shows it by setting display to block. Without a rule
   hiding it, it sits on every screen announcing an error that has not happened, which is
   exactly the thing that makes someone stop trusting an app. */
#blazor-error-ui {
  display: none;
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 1000;
  padding: .8rem 1.1rem;
  background: var(--danger);
  color: #fff;
  font-size: .88rem;
  box-shadow: 0 -2px 12px rgb(0 0 0 / .25);
}

#blazor-error-ui .reload { color: #fff; text-decoration: underline; margin-left: .5rem; }
#blazor-error-ui .dismiss { float: right; cursor: pointer; padding: 0 .3rem; }

/* A condition marker sitting inside a roll label needs to breathe, or it reads as one word:
   "Strengthfails automatically". */
.rollable .label .chip { margin-left: .45rem; }

/* ---- weapon customisation --------------------------------------------------- */

.customise {
  margin-top: .6rem;
  padding: .7rem .75rem .75rem;
  border: 1px dashed var(--border);
  border-radius: .5rem;
  background: color-mix(in srgb, var(--surface-2) 60%, transparent);
}

.customise .hint { margin: 0 0 .6rem; }
.customise .rollrow { margin-bottom: .5rem; }
.customise select {
  font-family: inherit;
  font-size: .9rem;
  padding: .4rem .5rem;
  min-height: 2.5rem;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: .35rem;
}

/* ---- spells on the sheet ---------------------------------------------------- */

.spellgroup { padding: .7rem 0; border-top: 1px solid var(--border); }
.spellgroup:first-of-type { border-top: 0; padding-top: 0; }
.spellgroup > .title { display: flex; justify-content: space-between; align-items: baseline; }
.spellgroup .name { font-weight: 650; }
.spellgroup > .title .lvl { color: var(--muted); font-size: .78rem; }
.spellgroup .hint { margin: .3rem 0 .6rem; }

.spellrow { display: flex; align-items: center; gap: .4rem; }
.spellrow + .spellrow { border-top: 1px solid color-mix(in srgb, var(--border) 55%, transparent); }

/* A levelled spell stacks its cast buttons under the name, because one button per slot
   level does not fit beside it on a phone. */
.spellrow.levelled { flex-direction: column; align-items: stretch; padding: .5rem 0; }
.spellrow.levelled > .label { font-size: .92rem; }
.spellrow.levelled > .label small { color: var(--muted); font-size: .76rem; margin-left: .35rem; }

.casts { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin-top: .45rem; }
.casts .btn.small.danger { margin-left: auto; }

/* ---- death saves ------------------------------------------------------------ */

/* At zero hit points this is the whole screen, so it is allowed to be loud. */
.deathsaves {
  border: 2px solid var(--danger);
  border-radius: .6rem;
  padding: 1rem;
  margin-bottom: 1rem;
  background: color-mix(in srgb, var(--danger) 10%, transparent);
}

.deathsaves.dead { border-style: double; border-width: 4px; }

.deathsaves h3 {
  margin: 0 0 .3rem;
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--danger);
}

.deathsaves .headline { margin: 0 0 .9rem; font-size: 1rem; font-weight: 600; }
.deathsaves .hint { margin: .8rem 0; }
.deathsaves .options { margin-top: .9rem; }
.deathsaves .notice { margin: .9rem 0 0; }

.deathsaves .tally .row {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .3rem 0;
}

.deathsaves .tally .k { min-width: 5.5rem; font-size: .84rem; color: var(--muted); }
.deathsaves .tally .pips { display: flex; gap: .45rem; }

.deathsaves .pip {
  width: 1.15rem;
  height: 1.15rem;
  border-radius: 50%;
  border: 2px solid var(--border);
}

.deathsaves .pip.good.on { background: var(--accent); border-color: var(--accent); }
.deathsaves .pip.bad.on { background: var(--danger); border-color: var(--danger); }

.btn.wide { width: 100%; }

/* ---- defences, senses, proficiencies ---------------------------------------- */

.listrow {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .7rem;
  padding: .5rem 0;
  border-top: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
}

.listrow:first-of-type { border-top: 0; }
.listrow .name { font-weight: 650; font-size: .9rem; white-space: nowrap; }
.listrow .lvl { color: var(--muted); font-size: .82rem; }
.listrow .options { justify-content: flex-end; margin: 0; }

/* Languages and weapon lists get long, so they wrap under their label instead. */
.listrow.stacked { flex-direction: column; align-items: stretch; }
.listrow.stacked .options { justify-content: flex-start; margin-top: .4rem; }

/* Temporary hit points sit beside the real ones without being added into them. */
.hpvalue .temp {
  margin-left: .5rem;
  padding: .05rem .45rem;
  border-radius: 999px;
  font-size: .8rem;
  font-weight: 650;
  color: var(--accent);
  background: var(--accent-bg);
}

/* The line under a spell's name: cost, reach, components, what it asks of the target. */
.spellrow .detail {
  font-size: .74rem;
  color: var(--muted);
  margin-top: .2rem;
}

.spellrow.levelled > .label .chip { margin-left: .4rem; }

/* ---- roll history ----------------------------------------------------------- */

.rollgroup { margin-bottom: 1rem; }

.rollgroup .when {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
  padding: .3rem 0 .35rem;
}

.rollentry {
  padding: .6rem .75rem;
  margin-bottom: .4rem;
  border-radius: .5rem;
  border: 1px solid var(--border);
  background: var(--surface-2);
}

.rollentry .top { display: flex; justify-content: space-between; align-items: baseline; gap: .7rem; }
.rollentry .what { font-weight: 650; font-size: .92rem; }
.rollentry .total { font-size: 1.35rem; font-weight: 700; font-variant-numeric: tabular-nums; }

.rollentry .how {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .35rem;
  margin-top: .4rem;
}

.rollentry .faces { display: flex; flex-wrap: wrap; gap: .3rem; }

/* Each face as it landed, so a total can always be checked back to the dice. */
.rollentry .face {
  min-width: 1.5rem;
  padding: .05rem .3rem;
  text-align: center;
  font-size: .78rem;
  font-variant-numeric: tabular-nums;
  border-radius: .3rem;
  background: var(--surface);
  border: 1px solid var(--border);
}

.rollentry .plus { color: var(--muted); font-size: .8rem; }

.rollentry.great { border-color: var(--accent); background: var(--accent-bg); }
.rollentry.great .total { color: var(--accent); }
.rollentry.grim { border-color: var(--danger); background: color-mix(in srgb, var(--danger) 10%, transparent); }
.rollentry.grim .total { color: var(--danger); }

/* ---- finishing a character -------------------------------------------------- */

/* The one action the page exists for should never need finding. It rides at the bottom
   of the screen, above the roll tray and the tab bar, however far down the form goes. */
.restrow.finish {
  position: sticky;
  bottom: 9.7rem;
  z-index: 15;
  padding: .6rem;
  margin: .8rem -.4rem 0;
  border-radius: .6rem;
  background: color-mix(in srgb, var(--surface) 94%, transparent);
  backdrop-filter: blur(14px);
  border: 1px solid var(--border);
}

/* Sticks with it, so the reason the button is dead is never off screen either. */
.notice.stillneeds {
  position: sticky;
  bottom: 13.2rem;
  z-index: 15;
  margin-bottom: 0;
  backdrop-filter: blur(14px);
  background: color-mix(in srgb, var(--danger) 14%, var(--surface));
}

/* ---- picking spells --------------------------------------------------------- */

.picker {
  margin-top: .7rem;
  padding: .8rem .75rem;
  border: 1px dashed var(--border);
  border-radius: .5rem;
  background: color-mix(in srgb, var(--surface-2) 60%, transparent);
}

.picker .hint { margin: 0 0 .7rem; }
.picker .filters { margin-bottom: .7rem; }
.picker .search { margin-bottom: .5rem; }
.picker .resultcount { margin-bottom: .5rem; }

/* One row per spell with its plain English line under the name, because picking a spell off
   a name alone is guesswork if you have not memorised the book. */
.pickable { display: flex; flex-direction: column; gap: .4rem; max-height: 26rem; overflow-y: auto; }

.pick {
  display: flex;
  flex-direction: column;
  gap: .15rem;
  width: 100%;

  /* A flex item shrinks by default, and this one lives in a column with a max-height, so the
     rows were being squeezed below the height of their own text and the summary was cut off
     mid sentence. The whole point of the summary is that you can read it before choosing, so
     the row takes the height its text needs and the list scrolls instead. */
  flex-shrink: 0;
  min-height: 3.25rem;
  padding: .55rem .7rem;
  text-align: left;
  font-family: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: .45rem;
  cursor: pointer;
}

.pick .top { display: flex; justify-content: space-between; align-items: baseline; gap: .6rem; }
.pick .name { font-weight: 650; font-size: .9rem; }
.pick .lvl { color: var(--muted); font-size: .74rem; white-space: nowrap; }
.pick .what { font-size: .76rem; color: var(--muted); }

.pick.on { border-color: var(--accent); background: var(--accent-bg); }
.pick.on .name { color: var(--accent); }
.pick.on .name::after { content: " ✓"; }

/* ---- metamagic --------------------------------------------------------------- */

/* Sits under the spell it will shape, so the cost and the effect are read together. */
.shaping {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .4rem;
  margin-top: .45rem;
  padding-top: .45rem;
  border-top: 1px dashed color-mix(in srgb, var(--border) 70%, transparent);
}

.shaping .chip small { margin-left: .3rem; opacity: .75; }
.shaping .cost { margin-left: auto; font-size: .76rem; color: var(--muted); white-space: nowrap; }
.shaping .cost.short { color: var(--danger); font-weight: 650; }

/* A cantrip row plus whatever metamagic is being applied to it. */
.cantrip { border-top: 1px solid color-mix(in srgb, var(--border) 55%, transparent); padding: .1rem 0 .4rem; }
.cantrip:first-of-type { border-top: 0; }
.cantrip .spellrow + .shaping { margin-top: .2rem; }

/* A stat tile that rolls when tapped. Looks like the others until you touch it. */
.stat.tappable {
  font: inherit;
  text-align: left;
  cursor: pointer;
  border: 1px solid var(--accent);
  background: var(--accent-bg);
}

.stat.tappable .how { color: var(--accent); font-size: .68rem; }

/* ---- feats ------------------------------------------------------------------- */

.featdetail {
  padding: .7rem .75rem;
  margin: -.2rem 0 .4rem;
  border: 1px solid var(--accent);
  border-top: 0;
  border-radius: 0 0 .45rem .45rem;
  background: var(--accent-bg);
}

.featdetail .hint { margin: 0 0 .5rem; }
.featdetail .options { margin-bottom: .7rem; }
.featdetail .notice { margin-bottom: .7rem; }

/* A prerequisite is reported, never enforced, so it reads as information not a barrier. */
.pick .what.needs { margin-top: .2rem; font-style: italic; opacity: .8; }

.listrow.stacked .what { font-size: .8rem; color: var(--muted); margin-top: .25rem; }
.listrow.stacked .name small { color: var(--muted); font-weight: 400; margin-left: .4rem; }

/* ---- switchable features ------------------------------------------------------ */

.toggles { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: .9rem; }

.toggle {
  flex: 1 1 10rem;
  display: flex;
  flex-direction: column;
  gap: .15rem;
  min-height: 3rem;
  padding: .55rem .7rem;
  text-align: left;
  font-family: inherit;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: .5rem;
  cursor: pointer;
}

.toggle .top { display: flex; justify-content: space-between; align-items: baseline; gap: .6rem; }
.toggle .name { font-weight: 650; font-size: .9rem; }
.toggle .lvl { font-size: .72rem; color: var(--muted); white-space: nowrap; }
.toggle .what { font-size: .74rem; color: var(--accent); }

/* On is loud on purpose. Forgetting a stance is switched on is the whole problem. */
.toggle.on { border-color: var(--accent); border-width: 2px; background: var(--accent-bg); }
.toggle.on .name { color: var(--accent); }
.toggle.on .lvl { color: var(--accent); font-weight: 650; text-transform: uppercase; }

/* ---- writing your own spell ------------------------------------------------- */

/* A form long enough that it has to read as a shape before it reads as fields, which is why
   it lives in folding sections and why every label sits above its input rather than beside it:
   on a phone, a label to the left of a box costs the box half its width. */
.forge { display: grid; gap: .7rem; }

.forge label { display: grid; gap: .25rem; font-size: .8rem; color: var(--muted); }

.forge label > span { font-size: .72rem; letter-spacing: .02em; }

.forge input[type="text"],
.forge input[type="number"],
.forge select,
.forge textarea {
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  border-radius: .45rem;
  padding: .4rem .5rem;
  font: inherit;
  font-size: .92rem;
  width: 100%;
  min-width: 0;
}

.forge textarea { resize: vertical; line-height: 1.45; }

.forge input:focus, .forge select:focus, .forge textarea:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.forge .row { display: flex; gap: .5rem; align-items: end; flex-wrap: wrap; }
.forge .row > label { flex: 1 1 8rem; }
.forge .row > label.narrow { flex: 0 1 7rem; }

.forge .fieldlabel { font-size: .72rem; color: var(--muted); }

.forge .hint { font-size: .74rem; color: var(--muted); margin: 0; }

/* A checkbox reads as a checkbox, so the label wraps it rather than sitting above it. */
.forge label.tick {
  display: flex;
  align-items: center;
  gap: .45rem;
  color: var(--text);
  font-size: .88rem;
}

.forge label.tick > span { font-size: .88rem; }
.forge label.tick input { width: auto; }

.forge .ticks { display: flex; flex-wrap: wrap; gap: .4rem; }

/* The class list is the field that decides whether the spell is ever seen again, so it is
   shaped like the filter chips elsewhere rather than like a column of tickboxes. */
.forge .chip-tick {
  border: 1px solid var(--border);
  background: var(--surface-2);
  border-radius: 999px;
  padding: .28rem .7rem;
}

.forge .chip-tick.on { border-color: var(--accent); background: var(--accent-bg); color: var(--accent); }

.forge .effect {
  border: 1px solid var(--border);
  border-radius: .6rem;
  padding: .6rem;
  display: grid;
  gap: .55rem;
  background: var(--surface);
}

.forge .effecthead { display: flex; justify-content: space-between; align-items: center; }
.forge .effecthead .k { font-size: .72rem; letter-spacing: .06em; color: var(--muted); }

.forgehead { font-size: .74rem; letter-spacing: .06em; color: var(--muted); margin: 1rem 0 .4rem; }

.problems { margin: .4rem 0 0; padding-left: 1.1rem; display: grid; gap: .3rem; }
.problems li { font-size: .85rem; }

/* The button that starts a new spell, sat under the search where the eye already is. */
.writerow { display: flex; gap: .5rem; margin-bottom: .7rem; }
.writerow .btn { flex: 1; }

/* ---- your own copy of the book text ------------------------------------------ */

/* Tall by default, because what goes in here is a whole spell rather than a line. */
.booktext {
  width: 100%;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  border-radius: .45rem;
  padding: .5rem .6rem;
  font: inherit;
  font-size: .9rem;
  line-height: 1.5;
  resize: vertical;
  min-height: 8rem;
}

.booktext:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

/* The row under the text, holding the chip that says it is yours and the buttons. */
.body .options { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; margin-top: .5rem; }

/* ---- typed damage parts ------------------------------------------------------- */

/* A spell dealing fire and force is one roll whose total is unusable on its own, since
   resistance applies to one and not the other. The parts sit under the total in both the
   tray and the history. */
.parts { display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .25rem; }

.part {
  display: inline-flex;
  align-items: baseline;
  gap: .22rem;
  padding: .1rem .4rem;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: .72rem;
  color: var(--muted);
}

.part b { color: var(--text); font-variant-numeric: tabular-nums; }
.part .faces { display: inline-flex; gap: .18rem; margin-left: .1rem; opacity: .7; }

.tray .parts { margin-top: .15rem; }

/* ---- roll balance ------------------------------------------------------------- */

.balance { margin-bottom: .8rem; }

.balancehead { display: flex; justify-content: space-between; align-items: baseline; gap: .6rem; margin-bottom: .6rem; }
.balancehead .name { font-weight: 650; font-size: 1.05rem; }
.balancehead .lvl { color: var(--muted); font-size: .78rem; }

/* A row per face. The bar is relative to the tallest, so the shape of the spread reads at a
   glance rather than needing the numbers to be compared one by one. */
.faces-chart { display: grid; gap: .18rem; margin-top: .7rem; }

.facerow { display: grid; grid-template-columns: 2.2rem 1fr 2.6rem; align-items: center; gap: .5rem; }

.facelabel { font-size: .74rem; color: var(--muted); text-align: right; font-variant-numeric: tabular-nums; }

.facebar {
  position: relative;
  height: .72rem;
  background: var(--surface-2);
  border-radius: 999px;
  overflow: hidden;
}

.facebar .fill { display: block; height: 100%; background: var(--accent); border-radius: 999px; }

/* Where the bar would end if every face came up equally often. The single most useful mark on
   the chart, because it turns a row of bars into a comparison. */
.facebar .even {
  position: absolute;
  top: -2px;
  bottom: -2px;
  width: 0;
  border-left: 1px dashed var(--muted);
  opacity: .8;
}

.facecount { font-size: .74rem; color: var(--muted); font-variant-numeric: tabular-nums; }

.warnhint { color: var(--danger); }

/* ---- natural 1 ---------------------------------------------------------------- */

/* A fumble is a moment at the table rather than a number in a log, so the screen dims and
   everybody looks up. It stays until dismissed, so nobody misses it mid conversation. */
.fumble {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  background: color-mix(in srgb, #000 72%, transparent);
  backdrop-filter: blur(3px);
  animation: fumble-in .18s ease-out;
}

@keyframes fumble-in { from { opacity: 0; } to { opacity: 1; } }

.fumble-card {
  width: 100%;
  max-width: 20rem;
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--danger);
  border-radius: .9rem;
  padding: 1.4rem 1.2rem 1.2rem;
  box-shadow: 0 12px 40px rgba(0, 0, 0, .45);
}

.fumble-what {
  margin: 0 0 .9rem;
  color: var(--danger);
  font-weight: 700;
  font-size: .82rem;
  letter-spacing: .14em;
  text-transform: uppercase;
}

/* The die. Tumbling while it rolls, then it stops square and grows slightly as it lands, so
   the settle is visible without anyone having to read anything. */
.fumble-die {
  width: 7.5rem;
  height: 7.5rem;
  margin: 0 auto 1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 1.1rem;
  border: 2px solid var(--danger);
  background: color-mix(in srgb, var(--danger) 12%, var(--surface-2));
}

.fumble-die.rolling { animation: fumble-tumble .28s linear infinite; }
.fumble-die.settled { animation: fumble-land .32s cubic-bezier(.2, 1.5, .4, 1); }

@keyframes fumble-tumble {
  0%   { transform: rotate(0deg)   scale(1); }
  50%  { transform: rotate(8deg)   scale(1.04); }
  100% { transform: rotate(-8deg)  scale(1); }
}

@keyframes fumble-land {
  0%   { transform: scale(.82); }
  100% { transform: scale(1); }
}

.fumble-number {
  font-size: 3rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  line-height: 1;
}

.fumble-hint { margin: 0 0 1rem; color: var(--muted); font-size: .84rem; }

/* Full width and finger sized, for the same reason as the advantage buttons. */
.fumble-back { width: 100%; min-height: 2.75rem; }

/* Nobody should be watching a die tumble if they have asked the system to stop moving things. */
@media (prefers-reduced-motion: reduce) {
  .fumble { animation: none; }
  .fumble-die.rolling, .fumble-die.settled { animation: none; }
}

/* An optional rider on an attack, such as Sneak Attack. Off by default and lit when armed,
   because the app cannot see whether an ally is beside the target or whether this is the
   first one this turn, so the player decides and the chip shows the decision. */
.chip.extra {
  border: 1px dashed var(--border);
  background: none;
  color: var(--muted);
  cursor: pointer;
  font: inherit;
  font-size: .74rem;
  padding: .1rem .5rem;
  min-height: 1.9rem;
}

.chip.extra.on {
  border-style: solid;
  border-color: var(--accent);
  background: var(--accent-bg);
  color: var(--accent);
  font-weight: 650;
}
