/* Theme-independent layout rules. Theme stylesheets live in themes/ and are
   scoped to html[data-theme="<name>"] so they never affect each other. */

.character-portrait {
  max-height: 128px !important;
  width: auto !important;
}

#load-indicator {
  position: fixed;
  right: 40px;
  bottom: 40px;
}

/* Bulma takes the margin off titles in a .level-item, which squashes the
   Characteristics box's title against its grid */
.level-item .box > .section-title {
  margin-bottom: 0.75rem;
}

.characteristics-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.5rem;
}

.characteristic-button {
  justify-content: space-between;
  gap: 1rem;
}

/* Each characteristic's half and fifth are only shown by themes that lay
   them out like the printed sheet's boxes */
.characteristic-fractions {
  display: none;
}

/* Skills (components/skill-row.j2), laid out like the printed sheet: the
   name, then a column of levels with each one's half and fifth stacked
   beside it. Long names are cut short rather than widening the column. */
:root {
  --skill-name-weight: 400;
  --skill-value-weight: 700;
  --skill-divider: rgba(0, 0, 0, 0.15);
}

#skill-columns > .column,
.skill-row .control.is-expanded {
  min-width: 0;
}

.skill-roll {
  justify-content: space-between;
  gap: 0.75rem;
}

.skill-label {
  display: flex;
  align-items: center;
  gap: 0.4em;
  min-width: 0;
}

.skill-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-weight: var(--skill-name-weight);
}

.skill-emoji {
  flex-shrink: 0;
  font-size: 0.8em;
}

.skill-roll.is-medium {
  padding-left: 0.75em;
  padding-right: 0.75em;
}

.skill-values {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  align-self: stretch;
  gap: 0.35rem;
  padding-left: 0.65rem;
  border-left: 1px solid var(--skill-divider);
  font-variant-numeric: tabular-nums;
}

.skill-level {
  min-width: 2ch;
  text-align: right;
  font-weight: var(--skill-value-weight);
}

.skill-fractions {
  display: flex;
  flex-direction: column;
  min-width: 2ch;
  font-size: 0.65em;
  line-height: 1.1;
  text-align: right;
  opacity: 0.75;
}

/* "Show skill mastery" (templates/character.j2), kept small at the end
   of the Skills title. While it's ticked, a bar along the bottom of each
   skill shows its level, so the trained ones stand out down a column, and
   proficient (50%+) and expert (75%+) ones get a bold name and the accent
   colour. Themes recolour them with these tokens. */
:root {
  --skill-bar: #e8e8e8;
  --skill-bar-proficient: #7e8fd8;
  --skill-bar-expert: #485fc7;
  --skill-strong-weight: 700;
}

.skill-mastery-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-size: 0.8rem;
  font-weight: normal;
  line-height: 1.5;
  opacity: 0.8;
  cursor: pointer;
}

.skill-mastery-toggle input {
  accent-color: currentColor;
}

.skill-mastery-toggle:hover {
  opacity: 1;
}

.character-sheet:has(.skill-mastery-toggle :checked) .skill-roll {
  --skill-bar-color: var(--skill-bar);
  --skill-bar-height: 3px;
  background-image: linear-gradient(var(--skill-bar-color), var(--skill-bar-color));
  background-position: left bottom;
  background-repeat: no-repeat;
  background-size: min(var(--skill-level, 0%), 100%) var(--skill-bar-height);
}

.character-sheet:has(.skill-mastery-toggle :checked) .skill-roll:is(.is-proficient, .is-expert) {
  --skill-bar-color: var(--skill-bar-proficient);
  --skill-bar-height: 4px;
}

.character-sheet:has(.skill-mastery-toggle :checked) .skill-roll:is(.is-proficient, .is-expert) .skill-name {
  font-weight: var(--skill-strong-weight);
}

.character-sheet:has(.skill-mastery-toggle :checked) .skill-roll.is-expert {
  --skill-bar-color: var(--skill-bar-expert);
}

/* Campaign trackers: a centred row of identical square boxes. The boxes are
   plain <button>s (not Bulma .button) so filled and empty boxes can never
   differ in size; the X mark is drawn with pseudo-elements. */

/* The last tracker is its wrapper's last child, so Bulma leaves it no margin */
#trackers:not(:last-child) {
  margin-bottom: 1.5rem;
}

.tracker-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
}

.tracker-boxes {
  --tracker-box-size: 2.75rem;
  display: grid;
  grid-template-columns: repeat(var(--tracker-box-count), minmax(0, var(--tracker-box-size)));
  justify-content: center;
  gap: 0.6rem;
  width: 100%;
}

.tracker-box {
  position: relative;
  aspect-ratio: 1;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 2px solid #b5b5b5;
  border-radius: 4px;
  background-color: #fff;
  color: #363636;
  cursor: pointer;
  transition: background-color 0.1s, border-color 0.1s, transform 0.1s;
}

/* The X: two diagonal strokes */
.tracker-box::before,
.tracker-box::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 60%;
  height: 3px;
  border-radius: 2px;
  background-color: currentColor;
  opacity: 0;
  transform: translate(-50%, -50%) rotate(45deg);
}

.tracker-box::after {
  transform: translate(-50%, -50%) rotate(-45deg);
}

.tracker-box.is-filled::before,
.tracker-box.is-filled::after {
  opacity: 1;
}

.tracker-box.is-filled {
  border-color: #363636;
  background-color: #363636;
  color: #fff;
}

.tracker-box:focus-visible {
  outline: 3px solid #485fc7;
  outline-offset: 2px;
}

/* Hover preview: boxes up to the hovered one show as they'd be after clicking */
.tracker-boxes:has(.tracker-box:hover) .tracker-box:not(.is-filled) {
  border-color: #7a7a7a;
}

.tracker-boxes:has(.tracker-box:hover) .tracker-box:hover ~ .tracker-box:not(.is-filled) {
  border-color: #b5b5b5;
}

/* Hovering the last filled box previews clearing it */
.tracker-box.is-last-filled:hover::before,
.tracker-box.is-last-filled:hover::after {
  opacity: 0.35;
}

.tracker-box:active {
  transform: scale(0.94);
}

.tracker-count {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  opacity: 0.7;
}

@media screen and (max-width: 640px) {
  .tracker-boxes {
    grid-template-columns: repeat(var(--tracker-narrow-count), minmax(0, var(--tracker-box-size)));
  }
}

/* Weapons (components/weapons.j2): a table like the printed sheet's, in the
   box's colours. Each picture is an SVG used as a mask over the text colour,
   in a lightly tinted tile (themes set its corners) so pictures of different
   shapes, and the initials of weapons without one, line up evenly. */
:root {
  --weapon-tile-size: 2.6rem;
  --weapon-tile-radius: 6px;
  --weapon-divider: rgba(0, 0, 0, 0.15);
}

.weapons-table {
  background-color: transparent;
  color: inherit;
}

.weapons-table th,
.weapons-table td {
  color: inherit;
  vertical-align: middle;
  border-color: var(--weapon-divider);
}

.weapons-table thead th {
  font-size: 0.8em;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  opacity: 0.75;
}

.weapon-icon-cell {
  width: calc(var(--weapon-tile-size) + 1.5em);
}

.weapon-tile {
  display: grid;
  place-items: center;
  width: var(--weapon-tile-size);
  height: var(--weapon-tile-size);
  border-radius: var(--weapon-tile-radius);
  background-color: color-mix(in srgb, currentColor 9%, transparent);
}

.weapon-icon {
  width: 78%;
  height: 78%;
  background-color: currentColor;
  -webkit-mask: var(--weapon-icon) center / contain no-repeat;
  mask: var(--weapon-icon) center / contain no-repeat;
}

.weapon-initial {
  font-size: 1.1rem;
  font-weight: 700;
  opacity: 0.55;
}

.weapon-name-cell {
  min-width: 10rem;
}

.weapon-name {
  display: block;
  font-weight: 700;
}

.weapon-skill {
  display: block;
  font-size: 0.8em;
  font-weight: 400;
  opacity: 0.75;
}

.weapon-levels {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-variant-numeric: tabular-nums;
}

.weapon-detail {
  white-space: nowrap;
}

.weapon-damage {
  color: inherit;
}

.weapon-impales {
  font-size: 0.85em;
  opacity: 0.75;
}

.weapon-summary {
  display: none;
}

.weapon-icons-credit {
  margin-top: 0.75rem;
  font-size: 0.7rem;
  opacity: 0.6;
}

.weapon-icons-credit a {
  color: inherit;
  text-decoration: underline;
}

/* On a phone each weapon is a header (picture, name and skill, levels) over
   one line of text in place of the columns: damage, then the rest quieter */
@media screen and (max-width: 768px) {
  .weapons-table thead {
    display: none;
  }

  .weapons-table,
  .weapons-table tbody {
    display: block;
  }

  .weapons-table tr {
    display: grid;
    grid-template-columns: var(--weapon-tile-size) minmax(0, 1fr) auto;
    align-items: center;
    gap: 0.3rem 0.75rem;
    padding: 0.75rem 0;
  }

  .weapons-table tr + tr {
    border-top: 1px solid var(--weapon-divider);
  }

  .weapons-table th,
  .weapons-table td {
    display: block;
    width: auto;
    padding: 0;
    border: 0;
  }

  .weapons-table .weapon-detail {
    display: none;
  }

  .weapon-name-cell {
    min-width: 0;
  }

  .weapons-table .weapon-summary {
    display: block;
    grid-column: 2 / -1;
    font-size: 0.85rem;
    line-height: 1.45;
  }

  .weapon-summary .weapon-damage {
    font-size: 1rem;
  }

  /* Lines break between details, never inside one ("1 (3) attacks") */
  .weapon-summary-detail {
    white-space: nowrap;
    opacity: 0.75;
  }

  .weapon-summary .weapon-impales {
    font-size: inherit;
  }

  .weapon-sep {
    opacity: 0.4;
  }
}

/* HP / Sanity / Luck / MP cards (components/counter.j2) */

.counter-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1rem;
  margin-top: 1.5rem;
}

@media screen and (max-width: 1023px) {
  .counter-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media screen and (max-width: 480px) {
  .counter-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

.counter-grid > .counter-card {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin: 0;
}

.counter-card > .section-title {
  margin-bottom: 0;
}

.counter-stepper {
  display: grid;
  grid-template-columns: 2.75rem minmax(0, 1fr) 2.75rem;
  align-items: center;
  gap: 0.5rem;
}

.counter-step {
  aspect-ratio: 1;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 2px solid #dbdbdb;
  border-radius: 50%;
  background-color: #fff;
  color: #363636;
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  transition: background-color 0.1s, border-color 0.1s, transform 0.1s;
}

.counter-step:hover {
  border-color: #485fc7;
  color: #485fc7;
}

.counter-step:active {
  transform: scale(0.92);
}

.counter-step:focus-visible,
.counter-input:focus-visible {
  outline: 3px solid #485fc7;
  outline-offset: 2px;
}

/* "/ max" drops below the number when the card is too narrow for both */
.counter-readout {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: 0 0.35rem;
  min-width: 0;
}

/* The current value is an <input> styled as a big number; click it to type */
.counter-input {
  /* Sized to its digits (--digits, kept current by counters.js) so the
     number and "/ max" centre together. Themes whose numbers lean or cast a
     shadow past the right of the glyphs set --counter-ink-overhang, since
     inputs crop text at their edges; the room is added on the right only */
  width: calc(var(--digits, 2) * 1ch + 0.15em + var(--counter-ink-overhang, 0em));
  flex-shrink: 0; /* squeezing it would crop the number */
  padding: 0;
  border: 0;
  border-bottom: 2px dashed transparent;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 2.5rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  text-align: left;
}

/* Typing "+5" or "-3" changes the value by that much (counters.js); the
   number takes these colours meanwhile so it's clear which way it's going.
   So do the encounter panel's HP and order fields, marked on their form.
   Themes override the tokens */
:root {
  --counter-increase: #257953;
  --counter-decrease: #cc0f35;
}

.counter-card.is-increasing .counter-input,
.is-increasing > .encounter-number-input {
  color: var(--counter-increase);
}

.counter-card.is-decreasing .counter-input,
.is-decreasing > .encounter-number-input {
  color: var(--counter-decrease);
}

/* "+10 / 99" would misread, and the sign needs the room */
.counter-card.is-increasing .counter-max,
.counter-card.is-decreasing .counter-max {
  display: none;
}

/* On the encounter panel the field keeps its width, so its row doesn't
   shift as the Keeper types */
.encounter-hp-value:is(.is-increasing, .is-decreasing) .encounter-of {
  visibility: hidden;
}

.counter-input:hover,
.counter-input:focus {
  border-bottom-color: currentColor;
}

.counter-max {
  font-size: 1.1rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  opacity: 0.6;
  white-space: nowrap;
}

.counter-meter {
  height: 0.6rem;
  overflow: hidden;
  border-radius: 999px;
  background-color: #ededed;
}

.counter-meter-fill {
  height: 100%;
  border-radius: inherit;
  background-color: #48c78e;
  transition: width 0.2s ease-out, background-color 0.2s;
}

.counter-card.is-low .counter-meter-fill {
  background-color: #ffb70f;
}

.counter-card.is-empty .counter-input {
  color: #f14668;
}

.counter-footer {
  display: flex;
  justify-content: space-between;
  gap: 0.5rem;
  min-height: 1.25rem;
  font-size: 0.8rem;
}

.counter-hint {
  opacity: 0.7;
}

.counter-status {
  margin-left: auto;
  font-weight: 600;
  opacity: 0.7;
}

.counter-card.is-error .counter-status {
  color: #f14668;
  opacity: 1;
}

/* The printed sheet's boxes beside the current value (maximum or starting,
   Insane, Max Sanity), for themes laid out like it */
.counter-ref,
.counter-limit {
  display: none;
}

.counter-unset {
  font-size: 0.875rem;
  opacity: 0.8;
}

/* Bonus/penalty dice picker (components/roll-modifier.j2): a pill floating
   at the bottom of the screen, so it's in reach wherever you roll from */

/* Themes restyle the picker and modified roll buttons by overriding these
   tokens; the states themselves (tint at rest, solid fill on hover) live
   here so every theme behaves the same way */
:root {
  --roll-penalty: #f14668;
  --roll-penalty-tint: #feecf0;
  --roll-on-penalty: #fff;
  --roll-bonus: #48c78e;
  --roll-bonus-tint: #effaf5;
  --roll-on-bonus: #0a3d27;
  --roll-edge-width: 2px;
}

[data-roll-modifier="penalty"] {
  --roll-color: var(--roll-penalty);
  --roll-edge: var(--roll-penalty-edge, var(--roll-penalty));
  --roll-tint: var(--roll-penalty-tint);
  --roll-on-color: var(--roll-on-penalty);
}

[data-roll-modifier="bonus"] {
  --roll-color: var(--roll-bonus);
  --roll-edge: var(--roll-bonus-edge, var(--roll-bonus));
  --roll-tint: var(--roll-bonus-tint);
  --roll-on-color: var(--roll-on-bonus);
}

#content:has(#roll-modifier) {
  padding-bottom: 5.5rem; /* keep the end of the page clear of the pill */
}

.roll-modifier {
  position: fixed;
  left: 50%;
  bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.35rem 0.6rem;
  transform: translateX(-50%);
  border: 1px solid #dbdbdb;
  border-radius: 999px;
  background-color: #fff;
  box-shadow: 0 6px 20px rgba(10, 10, 10, 0.18);
  white-space: nowrap;
}

.roll-modifier-side {
  padding: 0 0.25rem;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.roll-modifier-side.is-penalty {
  color: var(--roll-penalty);
}

.roll-modifier-side.is-bonus {
  color: var(--roll-bonus);
}

.roll-modifier-option {
  position: relative;
  cursor: pointer;
}

/* The radio stays in the page for keyboard and screen reader use */
.roll-modifier-option input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.roll-modifier-face {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.2rem;
  min-width: 2.4rem;
  height: 2.2rem;
  padding: 0 0.6rem;
  border-radius: 999px;
  color: #4a4a4a;
  font-size: 0.85rem;
  font-weight: 600;
  transition: background-color 0.1s, color 0.1s;
}

.roll-modifier-option.is-penalty .roll-modifier-face {
  color: var(--roll-penalty);
}

.roll-modifier-option.is-bonus .roll-modifier-face {
  color: var(--roll-bonus);
}

.roll-modifier-option:hover .roll-modifier-face {
  background-color: rgba(10, 10, 10, 0.06);
}

.roll-modifier-option.is-normal input:checked + .roll-modifier-face {
  background-color: #363636;
  color: #fff;
}

.roll-modifier-option.is-penalty input:checked + .roll-modifier-face {
  background-color: var(--roll-penalty);
  color: var(--roll-on-penalty);
}

.roll-modifier-option.is-bonus input:checked + .roll-modifier-face {
  background-color: var(--roll-bonus);
  color: var(--roll-on-bonus);
}

.roll-modifier-option input:focus-visible + .roll-modifier-face {
  outline: 3px solid #485fc7;
  outline-offset: 2px;
}

/* A die: rounded square with a centre pip */
.roll-modifier-die {
  width: 0.8rem;
  height: 0.8rem;
  border: 2px solid currentColor;
  border-radius: 3px;
  background: radial-gradient(circle, currentColor 0 1.5px, transparent 2px);
}

.roll-modifier-status {
  position: absolute;
  bottom: calc(100% + 0.4rem);
  left: 50%;
  padding: 0.15rem 0.7rem;
  transform: translateX(-50%);
  border-radius: 999px;
  background-color: #363636;
  color: #fff;
  font-size: 0.8rem;
  font-weight: 600;
}

.roll-modifier-status:empty {
  display: none;
}

[data-roll-modifier] .roll-modifier-status {
  background-color: var(--roll-color);
  color: var(--roll-on-color);
}

/* While a modifier is set, every roll button shows it: tinted at rest, and
   filled solid on hover/focus, i.e. "this is the roll you're about to make".
   These outrank the themes' own .button:hover rules on purpose. */
[data-roll-modifier] [data-roll-form] button[type="submit"] {
  background-color: var(--roll-tint);
  box-shadow: inset 0 0 0 var(--roll-edge-width) var(--roll-edge);
}

[data-roll-modifier] [data-roll-form] button[type="submit"]:hover,
[data-roll-modifier] [data-roll-form] button[type="submit"]:focus-visible {
  background-color: var(--roll-color);
  color: var(--roll-on-color);
}

@media screen and (max-width: 480px) {
  .roll-modifier-side {
    display: none;
  }

  .roll-modifier-face {
    min-width: 2.2rem;
    padding: 0 0.45rem;
  }
}

/* Right-click menu on roll buttons (components/roll-menu.j2). The highlighted
   item is the focused one, so pointer and keyboard look the same; it fills
   with the modifier's colour like a hovered roll button does. */

.roll-menu {
  position: fixed;
  z-index: 40;
  min-width: 13rem;
  max-width: calc(100vw - 16px);
  padding: 0.3rem;
  border: 1px solid #dbdbdb;
  border-radius: 10px;
  background-color: #fff;
  color: #363636;
  box-shadow: 0 12px 32px rgba(10, 10, 10, 0.22);
  animation: roll-menu-in 0.12s ease-out;
}

@keyframes roll-menu-in {
  from {
    opacity: 0;
    transform: translateY(-4px) scale(0.98);
  }
}

@media (prefers-reduced-motion: reduce) {
  .roll-menu {
    animation: none;
  }
}

.roll-menu-title {
  margin-bottom: 0.25rem;
  padding: 0.3rem 0.6rem 0.45rem;
  overflow: hidden;
  border-bottom: 1px solid rgba(10, 10, 10, 0.08);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  opacity: 0.65;
  text-overflow: ellipsis;
  text-transform: uppercase;
  white-space: nowrap;
}

.roll-menu-item {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  width: 100%;
  margin: 0;
  padding: 0.45rem 0.6rem;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.roll-menu-item:focus {
  outline: none;
}

.roll-menu-dice {
  display: flex;
  justify-content: center;
  gap: 0.2rem;
  width: 1.9rem; /* room for two dice, so labels line up */
}

.roll-menu-item.is-penalty .roll-menu-dice {
  color: var(--roll-penalty);
}

.roll-menu-item.is-bonus .roll-menu-dice {
  color: var(--roll-bonus);
}

.roll-menu-item.is-normal:focus {
  background-color: rgba(10, 10, 10, 0.07);
}

.roll-menu-item.is-penalty:focus {
  background-color: var(--roll-penalty);
  color: var(--roll-on-penalty);
}

.roll-menu-item.is-bonus:focus {
  background-color: var(--roll-bonus);
  color: var(--roll-on-bonus);
}

.roll-menu-item:focus .roll-menu-dice {
  color: inherit;
}

/* --- Campaigns ---------------------------------------------------------- */

/* The navbar stays one wrapping row at every width: brand, then the
   campaign nav (templates/components/campaign-nav.j2), then the theme
   picker on the right */
#header .navbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}

#header .navbar-start,
#header .navbar-end {
  display: flex;
  align-items: center;
}

/* Wraps too, so its links never run off a phone's screen */
#header .navbar-start {
  flex-wrap: wrap;
  margin-right: 0;
}

@media screen and (max-width: 768px) {
  #header .navbar-item {
    padding-left: 0.6rem;
    padding-right: 0.6rem;
  }
}

#header .navbar-end {
  margin-left: auto;
}

.campaign-nav-current,
.campaign-switcher {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.campaign-nav-label {
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.75;
}

.campaign-nav-name {
  font-weight: 600;
}

.campaign-nav a.navbar-item:hover,
.campaign-nav a.navbar-item:focus {
  background-color: transparent;
  text-decoration: underline;
}

/* Theme switch (templates/base.j2): a quiet palette-and-label toggle that
   drops down a menu like the roll menu's */
.theme-switch {
  position: relative;
}

.theme-switch-toggle {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.2rem 0.4rem;
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  list-style: none;
  opacity: 0.6;
  cursor: pointer;
  user-select: none;
}

.theme-switch-toggle::-webkit-details-marker {
  display: none;
}

.theme-switch-toggle:hover,
.theme-switch-toggle:focus-visible,
.theme-switch[open] .theme-switch-toggle {
  opacity: 1;
}

.theme-switch-menu {
  position: absolute;
  top: 100%;
  right: 0.5rem;
  z-index: 40;
  min-width: 13rem;
  max-width: calc(100vw - 16px);
  padding: 0.3rem;
  border: 1px solid #dbdbdb;
  border-radius: 10px;
  background-color: #fff;
  color: #363636;
  box-shadow: 0 12px 32px rgba(10, 10, 10, 0.22);
  animation: roll-menu-in 0.12s ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .theme-switch-menu {
    animation: none;
  }
}

.theme-switch-title {
  margin-bottom: 0.25rem;
  padding: 0.3rem 0.6rem 0.45rem;
  border-bottom: 1px solid rgba(10, 10, 10, 0.08);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  opacity: 0.65;
  text-transform: uppercase;
}

.theme-switch-item {
  display: flex;
  align-items: baseline;
  gap: 0.35rem;
  /* Padding inside the width, or the items stick out past the menu */
  box-sizing: border-box;
  width: 100%;
  margin: 0;
  padding: 0.45rem 0.6rem;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}

/* A tick beside the theme in use; the space is kept so names line up */
.theme-switch-item::before {
  content: "";
  width: 1em;
  flex: none;
}

.theme-switch-item[aria-current="true"] {
  font-weight: 700;
}

.theme-switch-item[aria-current="true"]::before {
  content: "✓";
}

.theme-switch-item:hover,
.theme-switch-item:focus-visible {
  outline: none;
  background-color: rgba(10, 10, 10, 0.07);
}

.theme-switch-note {
  font-weight: 400;
  opacity: 0.65;
}

.content .title + .sheet-status {
  margin-top: -0.75rem;
}

.sheet-status .status-tag {
  margin-right: 0.35rem;
}

/* Small outlined labels ("Playing", "Archived"), in the surrounding text
   colour so they suit every theme */
.status-tag {
  display: inline-block;
  padding: 0.1em 0.5em;
  border: 1px solid currentColor;
  border-radius: 3px;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  line-height: 1.5;
  text-transform: uppercase;
  vertical-align: middle;
}

.status-tag.is-muted {
  opacity: 0.65;
}

.campaign-choices {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
  gap: 1rem;
}

.campaign-choices form {
  display: contents;
}

.campaign-choice {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.25rem;
  width: 100%;
  margin: 0;
  border: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.campaign-choice:hover,
.campaign-choice:focus-visible {
  box-shadow: 0 0 0 2px currentColor;
}

.campaign-choice-name {
  font-size: 1.25rem;
  font-weight: 600;
}

.campaign-choice-character {
  opacity: 0.75;
}

.investigator-group-title {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.investigator-list li + li {
  margin-top: 0.35rem;
}

.investigator-link {
  margin-right: 0.5rem;
  font-size: 1.1rem;
}

.investigator-link.is-retired {
  text-decoration: line-through;
}

.investigator-empty {
  opacity: 0.75;
}

/* An investigator who isn't being played: the sheet's controls are
   disabled (templates/character.j2) but should read as content, not as
   greyed-out buttons */
fieldset.character-sheet {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

fieldset.character-sheet[disabled] .button,
fieldset.character-sheet[disabled] .tracker-box,
fieldset.character-sheet[disabled] .counter-input {
  opacity: 1;
  cursor: default;
  pointer-events: none;
}

fieldset.character-sheet[disabled] .counter-step {
  visibility: hidden;
}

/* --- Party and Keeper's screen ------------------------------------------ */

/* A page title with a button at its end (e.g. the party page's view
   switch). Themes with centred titles keep the title centred. */
.section-title.has-action {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
}

.title-action {
  flex-shrink: 0;
  letter-spacing: normal;
  text-shadow: none;
  text-transform: none;
}

/* In the theme's box colours rather than Bulma's white */
.party-table {
  background-color: transparent;
  color: inherit;
}

.party-table th,
.party-table td {
  color: inherit;
  white-space: nowrap;
}

/* Investigator portraits (templates/components/portrait.j2): the image
   covers a placeholder of their initials, which shows when there's no
   image or it fails to load. Colours follow the surrounding text. */
.portrait {
  --portrait-size: 3.25rem;
  position: relative;
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: var(--portrait-size);
  height: var(--portrait-size);
  overflow: hidden;
  border: 2px solid currentColor;
  border-radius: 50%;
  background-color: rgba(128, 128, 128, 0.15);
}

.portrait.is-small {
  --portrait-size: 2rem;
  border-width: 1px;
}

.portrait-initials {
  font-size: calc(var(--portrait-size) * 0.38);
  font-weight: 700;
  letter-spacing: 0.04em;
  line-height: 1;
  opacity: 0.7;
}

.portrait-image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The character sheet's placeholder, the size of its portrait */
.sheet-portrait-placeholder {
  --portrait-size: 128px;
  display: none;
  align-items: center;
  justify-content: center;
  width: var(--portrait-size);
  height: var(--portrait-size);
  border: 2px solid currentColor;
  background-color: rgba(128, 128, 128, 0.15);
}

.sheet-portrait.is-missing .sheet-portrait-placeholder {
  display: flex;
}

.party-investigator {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
}

.party-table th,
.party-table td {
  vertical-align: middle;
}

/* The Keeper's screen (components/party.j2): a grid with a row per
   investigator and a column per value. On a phone or tablet, too narrow
   for the columns, it turns on its side, a column per investigator, so the
   whole party fits across. Each row is a subgrid, so its cells line up with
   the headings either way. */
.keeper-screen {
  --keeper-rule: rgba(128, 128, 128, 0.3);
  display: grid;
  /* No wider than the page: a grid that doesn't fit scrolls in its box */
  grid-template-columns: minmax(0, 1fr);
  gap: 1.5rem;
  margin-bottom: 1.5rem;
}

.keeper-screen > .box {
  margin-bottom: 0;
}

/* Only an unusually big party scrolls sideways, in its box. (Nothing stays
   put while it does: a sticky grid item can't leave its grid area.) */
.keeper-scroll {
  overflow-x: auto;
}

.keeper-grid {
  display: grid;
  grid-template-columns:
    minmax(11rem, 1.6fr)
    repeat(var(--keeper-columns), minmax(min-content, 1fr));
  font-variant-numeric: tabular-nums;
}

.keeper-row {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
}

.keeper-cell {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  padding: 0.5em 0.6em;
  border-bottom: 1px solid var(--keeper-rule);
  white-space: nowrap;
}

.keeper-cell.is-group-start {
  padding-left: 1.25em;
  border-left: 1px solid var(--keeper-rule);
}

.keeper-investigator {
  position: relative;
  align-items: flex-start;
}

.keeper-head .keeper-cell {
  justify-content: flex-end;
  border-bottom-width: 2px;
  font-weight: 700;
}

/* The heading of a group of columns, over its first and running on over
   the rest, so it doesn't widen the first */
.keeper-group {
  align-self: flex-start;
  width: 0;
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  opacity: 0.65;
  text-transform: uppercase;
}

/* Who needs attention: a counter low or out */
.needs-attention > .keeper-investigator {
  box-shadow: inset 4px 0 0 var(--roll-penalty);
}

.keeper-who {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  max-width: 100%;
}

/* A long name wraps rather than running into the next column; a word too
   long for a line of its own breaks */
.keeper-names {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.2;
  white-space: normal;
  overflow-wrap: break-word;
}

.keeper-name {
  font-weight: 700;
}

.keeper-name:hover {
  text-decoration: underline;
}

.keeper-player {
  font-size: 0.8rem;
  opacity: 0.7;
}

.keeper-value {
  font-size: 1.1rem;
  font-weight: 700;
}

.keeper-of {
  font-size: 0.8em;
  font-weight: 400;
  opacity: 0.55;
}

.keeper-value.is-low {
  color: var(--roll-penalty);
}

.keeper-value.is-out {
  display: inline-block;
  padding: 0 0.35em;
  border-radius: 3px;
  background-color: var(--roll-penalty);
  color: #fff;
}

.keeper-value.is-out .keeper-of {
  opacity: 0.85;
}

.keeper-none {
  opacity: 0.4;
}

.keeper-characteristics > summary {
  cursor: pointer;
  font-weight: 700;
}

.keeper-characteristics[open] > summary {
  margin-bottom: 0.75rem;
}

@media screen and (max-width: 1023px) {
  .keeper-screen > .box {
    padding: 0.75rem 0.5rem;
  }

  .keeper-characteristics > summary {
    padding-left: 0.5rem;
  }

  .keeper-grid {
    grid-template-rows: auto repeat(var(--keeper-columns), auto);
    grid-template-columns: max-content;
    /* As narrow as a name's longest word, so a party of five fits */
    grid-auto-columns: minmax(auto, 1fr);
    grid-auto-flow: column;
  }

  .keeper-row {
    grid-row: 1 / -1;
    grid-column: auto;
    grid-template-rows: subgrid;
    grid-template-columns: none;
  }

  .keeper-cell {
    align-items: center;
    justify-content: flex-end;
    padding: 0.35em 0.25em;
  }

  .keeper-head .keeper-cell {
    align-items: flex-start;
    padding-right: 0.6em;
    border-bottom-width: 1px;
    font-weight: 400;
  }

  .keeper-cell.is-group-start {
    padding-top: 1.1em;
    padding-left: 0.25em;
    border-left: 0;
  }

  .keeper-head .keeper-group {
    width: auto;
    font-weight: 700;
    opacity: 0.8;
  }

  /* Each investigator heads their column, portraits in a line; the
     headings are the column down the left */
  .keeper-investigator {
    align-items: center;
    justify-content: flex-start;
  }

  .keeper-head .keeper-investigator .keeper-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }

  /* Short of the column's edges, so neighbours' don't run together */
  .needs-attention > .keeper-investigator {
    box-shadow: none;
  }

  .needs-attention > .keeper-investigator::before {
    content: "";
    position: absolute;
    top: 0;
    right: 15%;
    left: 15%;
    height: 4px;
    border-radius: 2px;
    background-color: var(--roll-penalty);
  }

  .keeper-who {
    flex-direction: column;
    gap: 0.3rem;
    text-align: center;
  }

  .keeper-who .portrait {
    --portrait-size: 1.6rem;
  }

  .keeper-name {
    font-size: 0.75rem;
  }

  .keeper-player {
    font-size: 0.7rem;
  }

  .keeper-value {
    font-size: 0.95rem;
  }

  /* Out of what, under it, so five investigators fit across */
  .keeper-of {
    display: block;
    font-size: 0.7rem;
    line-height: 1;
  }
}

/* The Keeper's encounter panel (components/encounter.j2), above the party:
   whose turn it is, the one bold thing, then the order with HP meters side
   by side. Themes set --encounter-accent for the turn's marks. */
.encounter-panel {
  --encounter-rule: rgba(128, 128, 128, 0.3);
  --encounter-turn-tint: rgba(128, 128, 128, 0.1);
  --encounter-meter: rgba(128, 128, 128, 0.25);
}

.encounter-panel.is-idle {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
}

/* Sentences, unlike the Keeper's screen's missing values, so as quiet as
   its other hints but no fainter */
.encounter-idle-text,
.encounter-panel .keeper-none {
  opacity: 0.7;
}

.encounter-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.25rem 1rem;
}

.encounter-title {
  font-size: 1.25rem;
  font-weight: 700;
}

.encounter-round,
.encounter-turn-label {
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.75;
}

.encounter-round > span {
  font-size: 1.1rem;
  font-weight: 700;
  letter-spacing: normal;
}

.encounter-turn {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1.5rem;
  margin: 0.75rem 0 1rem;
  padding: 0.75rem 1rem;
  border-left: 4px solid var(--encounter-accent, currentColor);
  background-color: var(--encounter-turn-tint);
}

.encounter-turn-who {
  display: flex;
  flex-direction: column;
  line-height: 1.2;
}

.encounter-turn-who > strong {
  color: inherit;
  font-size: 1.6rem;
}

.encounter-next {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
}

.encounter-then {
  font-size: 0.85rem;
  opacity: 0.75;
}

.encounter-order {
  margin: 0;
  padding: 0;
  list-style: none;
  font-variant-numeric: tabular-nums;
}

.encounter-row {
  display: grid;
  grid-template-areas: "number who hp state actions";
  grid-template-columns: 2.75rem minmax(0, 16rem) minmax(8rem, 22rem) minmax(6rem, 1fr) auto;
  align-items: center;
  gap: 0 1rem;
  padding: 0.45rem 0.5rem;
  border-bottom: 1px solid var(--encounter-rule);
}

.encounter-row.is-current {
  box-shadow: inset 4px 0 0 var(--encounter-accent, currentColor);
}

.encounter-order-number {
  grid-area: number;
}

/* The order and HP are fields, looking like the numbers they are until
   pointed at or typed in */
.encounter-order-input,
.encounter-hp-input {
  width: 100%;
  padding: 0.05em 0.2em;
  border: 1px solid transparent;
  border-bottom-color: var(--encounter-rule);
  border-radius: 2px;
  background: transparent;
  color: inherit;
  font: inherit;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.encounter-order-input:hover,
.encounter-hp-input:hover {
  border-color: var(--encounter-rule);
}

.encounter-order-input:focus,
.encounter-hp-input:focus {
  border-color: var(--encounter-accent, currentColor);
  outline: none;
  background-color: var(--encounter-turn-tint);
}

.encounter-order-input {
  opacity: 0.75;
}

.encounter-order-input:focus {
  opacity: 1;
}

.encounter-who {
  display: flex;
  grid-area: who;
  flex-direction: column;
  min-width: 0;
  line-height: 1.2;
  overflow-wrap: break-word;
}

.encounter-name {
  font-weight: 700;
}

.encounter-detail {
  font-size: 0.8rem;
  opacity: 0.7;
}

.encounter-hp {
  display: flex;
  grid-area: hp;
  align-items: center;
  gap: 0.6rem;
}

.encounter-hp-bar {
  flex: 1;
  height: 0.5rem;
  overflow: hidden;
  border-radius: 999px;
  background-color: var(--encounter-meter);
}

.encounter-hp-bar > span {
  display: block;
  height: 100%;
  border-radius: inherit;
  background-color: currentColor;
  opacity: 0.7;
}

.encounter-hp.is-low .encounter-hp-bar > span {
  background-color: var(--roll-penalty);
  opacity: 1;
}

.encounter-hp-value {
  display: flex;
  align-items: baseline;
  font-weight: 700;
  white-space: nowrap;
}

.encounter-hp-input {
  width: 2.6em;
}

/* Hide, Reveal and Remove: quiet, since every row has them */
.encounter-row-actions {
  display: flex;
  grid-area: actions;
  justify-content: flex-end;
  gap: 0.25rem;
}

.encounter-action {
  padding: 0.2em 0.45em;
  border: 0;
  border-radius: 2px;
  background: none;
  color: inherit;
  font: inherit;
  font-size: 0.8rem;
  text-decoration: underline;
  text-decoration-color: var(--encounter-rule);
  text-underline-offset: 0.2em;
  cursor: pointer;
  opacity: 0.7;
}

.encounter-action:hover,
.encounter-action:focus-visible {
  background-color: var(--encounter-turn-tint);
  text-decoration-color: currentColor;
  opacity: 1;
}

.encounter-add {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.encounter-add > .label {
  margin: 0;
}

.encounter-of {
  font-size: 0.8em;
  font-weight: 400;
  opacity: 0.55;
}

.encounter-hp.is-low .encounter-hp-value,
.encounter-hp.is-out .encounter-hp-value {
  color: var(--roll-penalty);
}

.encounter-state {
  grid-area: state;
  font-size: 0.85rem;
  font-style: italic;
}

.encounter-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem 1rem;
  margin-top: 1rem;
}

.encounter-help > summary {
  cursor: pointer;
  font-weight: 700;
}

.encounter-help > ul {
  max-width: 65ch;
  margin: 0.5rem 0 0 1.25rem;
  list-style: disc;
}

.encounter-help > ul > li + li {
  margin-top: 0.3rem;
}

.encounter-start .encounter-help {
  margin-top: 1rem;
}

.encounter-start .input {
  max-width: 24rem;
}

.encounter-start-who {
  display: flex;
  flex-wrap: wrap;
  gap: 0 3rem;
}

.encounter-start-who fieldset {
  min-width: 12rem;
}

.encounter-start-who .checkbox {
  display: block;
  margin: 0.3rem 0;
}

/* A named NPC, with whether it starts hidden beside it */
.encounter-start-npc {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 1rem;
}

.encounter-start-npc > .checkbox:first-child {
  flex: 1;
}

/* Hidden: quieter than who's there, a choice about them */
.encounter-hidden-choice {
  font-size: 0.85rem;
}

.encounter-start-who .encounter-hidden-choice {
  opacity: 0.8;
}

/* Quick NPCs: a name and a statblock, then what was read of it, set off
   as the turn is, in a row of short fields to check */
.encounter-quick {
  max-width: 40rem;
  margin-bottom: 1rem;
}

.encounter-start-who + .encounter-quick {
  margin-top: 0.75rem;
}

.encounter-quick-read {
  margin-top: 0.75rem;
  padding: 0.75rem;
  border-left: 4px solid var(--encounter-accent, currentColor);
  background-color: var(--encounter-turn-tint);
}

.encounter-quick-makes {
  margin-bottom: 0.5rem;
}

.encounter-quick-problem {
  color: var(--roll-penalty);
}

.encounter-quick-stats {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(4.25rem, 1fr));
  gap: 0.5rem 0.75rem;
  margin-bottom: 0.75rem;
}

.encounter-quick-stats > .field {
  margin: 0;
}

.encounter-quick-stats .label {
  margin-bottom: 0.2rem;
  white-space: nowrap;
}

.encounter-quick-read > .field:last-child {
  margin-bottom: 0;
}

/* The encounter's log: a quiet fold under the panel, newest first, with
   Undo beside the latest that can be undone */
.encounter-log.box {
  padding: 0.6rem 1.25rem;
}

.encounter-log-summary {
  cursor: pointer;
  font-weight: 700;
}

.encounter-log-entries {
  max-height: 20rem;
  margin-top: 0.5rem;
  overflow-y: auto;
  list-style: none;
}

.encounter-log-entry {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.25rem 0.75rem;
  padding: 0.25rem 0;
  border-top: 1px solid rgba(128, 128, 128, 0.25);
  font-variant-numeric: tabular-nums;
}

.encounter-log-entry.is-undone {
  opacity: 0.6;
}

.encounter-log-error {
  color: var(--roll-penalty);
}

.encounter-log-error:not(:empty) {
  margin-top: 0.5rem;
}

.encounter-error {
  color: var(--roll-penalty);
}

.encounter-error:not(:empty) {
  margin-bottom: 0.75rem;
}

@media screen and (max-width: 600px) {
  .encounter-panel.box,
  .encounter-log.box {
    padding: 0.75rem;
  }

  .encounter-turn {
    padding: 0.6rem 0.75rem;
  }

  .encounter-turn-who > strong {
    font-size: 1.3rem;
  }

  /* The state goes under the name, and Hide and Remove under HP */
  .encounter-row {
    grid-template-areas:
      "number who hp"
      "number state actions";
    grid-template-columns: 2.25rem minmax(0, 1fr) 7.5rem;
    gap: 0 0.6rem;
    padding: 0.4rem 0.25rem;
  }

  .encounter-hp {
    flex-direction: column-reverse;
    align-items: stretch;
    gap: 0.2rem;
  }

  .encounter-hp-bar {
    flex: none;
  }
}

/* The encounter strip at the top of the sheet (components/encounter-strip.j2):
   "Your turn" is the one bold thing, then the order on a line or two, the
   player's own place and whose turn it is marked. Themes set
   --encounter-accent (the turn's marks) and --encounter-on-accent (text on
   it), as for the Keeper's panel. */
.encounter-strip {
  --encounter-rule: rgba(128, 128, 128, 0.35);
  --encounter-turn-tint: rgba(128, 128, 128, 0.12);
  margin-bottom: 1.5rem;
  border-left: 4px solid var(--encounter-accent, currentColor);
}

.encounter-strip-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.25rem 1rem;
}

.encounter-strip-title {
  font-size: 1.15rem;
  font-weight: 700;
  overflow-wrap: anywhere;
}

.encounter-strip-turn {
  margin-top: 0.5rem;
  line-height: 1.2;
}

.encounter-strip-turn > strong {
  color: inherit;
  font-size: 1.25rem;
}

.encounter-strip-turn.is-yours {
  display: inline-block;
  padding: 0.3rem 0.9rem;
  background-color: var(--encounter-accent, currentColor);
}

.encounter-strip-turn.is-yours > strong {
  color: var(--encounter-on-accent, #fff);
  font-size: 1.4rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.encounter-strip-order {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.75rem 0 0;
  padding: 0;
  list-style: none;
}

.encounter-strip-who {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.4rem;
  min-width: 0;
  padding: 0.2rem 0.65rem;
  border: 1px solid var(--encounter-rule);
  border-radius: 999px;
  line-height: 1.3;
  overflow-wrap: anywhere;
}

.encounter-strip-who.is-current {
  border-color: var(--encounter-accent, currentColor);
  box-shadow: inset 0 0 0 1px var(--encounter-accent, currentColor);
  background-color: var(--encounter-turn-tint);
}

.encounter-strip-who.is-own > .encounter-strip-name {
  font-weight: 700;
}

.encounter-strip-you {
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.7;
}

.encounter-strip-state {
  color: var(--roll-penalty);
  font-size: 0.8rem;
  font-style: italic;
}

/* The chase strip at the top of the sheet (components/chase-strip.j2), in
   place of the encounter strip while a vehicle chase runs, edged in the
   party's colour: the round and whose turn on top ("Your turn" the one bold
   thing), the party's vehicles on the left and the other vehicles on the
   right; on a phone, one under the other, the party's first. Its badges
   and colours are the chase panel's (--chase-party, --chase-other). */
.chase-strip {
  margin-bottom: 1.5rem;
  border-left: 6px solid var(--chase-party);
}

.chase-strip-turn {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.9rem;
  line-height: 1.2;
}

.chase-strip-round {
  font-weight: 700;
}

.chase-strip-whose {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
  overflow-wrap: anywhere;
}

.chase-strip-whose > strong {
  color: inherit;
}

.chase-strip-turn .chase-badge {
  width: 1.35rem;
  height: 1.35rem;
  font-size: 0.75rem;
}

.chase-strip-turn.is-yours .chase-strip-whose {
  padding: 0.3rem 0.9rem;
  background-color: var(--chase-party);
  color: var(--chase-on-party);
}

.chase-strip-turn.is-yours .chase-strip-whose > strong {
  font-size: 1.4rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.chase-strip-turn.is-yours .chase-badge {
  outline: 2px solid var(--chase-on-party);
}

.chase-strip-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.25rem 2.5rem;
  margin-top: 0.75rem;
}

@media screen and (min-width: 769px) {
  .chase-strip-body {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  }
}

.chase-strip-party + .chase-strip-party {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--chase-rule);
}

.chase-strip-vehicle {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.chase-strip-vehicle .chase-badge {
  width: 2.75rem;
  height: 2.75rem;
  font-size: 1.2rem;
}

.chase-strip-title {
  font-size: 1.35rem;
  font-weight: 700;
  line-height: 1.15;
  overflow-wrap: anywhere;
}

.chase-strip-numbers strong {
  color: inherit;
  font-size: 1.25rem;
}

.chase-strip-you-do {
  margin-top: 0.75rem;
}

.chase-strip-aboard {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 0.1rem 1rem;
  margin: 0.6rem 0 0;
  padding: 0;
  list-style: none;
  font-size: 0.9rem;
}

.chase-strip-person {
  display: contents;
}

.chase-strip-person > .chase-strip-name {
  overflow-wrap: anywhere;
}

.chase-strip-person.is-own > .chase-strip-name {
  font-weight: 700;
}

.chase-strip-notes {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.5rem;
}

.chase-strip-you {
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.7;
}

.chase-strip-note {
  opacity: 0.75;
}

.chase-strip-note.is-wound {
  color: var(--roll-penalty);
  font-style: italic;
  opacity: 1;
}

.chase-strip-next {
  margin-top: 0.75rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--chase-rule);
}

.chase-strip-hazard {
  font-weight: 700;
}

.chase-strip-hazard .chase-obstacle {
  font-size: inherit;
}

.chase-strip-heading {
  font-size: 1.1rem;
  font-weight: 700;
}

.chase-strip-list {
  margin: 0.4rem 0 0;
  padding: 0;
  list-style: none;
}

.chase-strip-other {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 0 0.75rem;
  padding: 0.5rem 0;
  border-top: 1px solid var(--chase-rule);
}

.chase-strip-other-name {
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow-wrap: anywhere;
}

.chase-strip-other-name > .chase-strip-name {
  font-weight: 700;
}

.chase-strip-gap {
  font-weight: 700;
  text-align: right;
}

.chase-strip-gap.is-out {
  font-weight: 400;
  opacity: 0.75;
}

.party-roll-fields {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1rem;
}

.party-roll-fields .field {
  margin-bottom: 0.75rem;
}

.party-roll .buttons {
  margin-bottom: 0;
}

.party-roll-error:empty {
  display: none;
}

.party-roll-error {
  margin-top: 0.5rem;
  color: var(--roll-penalty);
}

.party-roll-log {
  margin-bottom: 1.5rem;
}

.party-roll-result-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  margin-bottom: 0.5rem;
}

.party-roll-result-header .title {
  margin-bottom: 0;
}

/* New results slide in; clearing one is animated by static/js/party-roll.js */
.party-roll-result {
  animation: party-roll-in 180ms ease-out;
}

@keyframes party-roll-in {
  from {
    opacity: 0;
    transform: translateY(-0.5rem);
  }
}

@media (prefers-reduced-motion: reduce) {
  .party-roll-result {
    animation: none;
  }
}

/* A server's custom emoji, sized like Discord shows them inline */
.discord-emoji {
  height: 1.375em;
  width: auto;
  vertical-align: -0.3em;
}

.party-roll-modifier {
  font-weight: 400;
  opacity: 0.75;
}

/* Success/failure as a coloured edge, from the bonus/penalty tokens so
   every theme gets its own green and red */
.party-roll-table tr.is-success th {
  box-shadow: inset 4px 0 0 var(--roll-bonus);
}

.party-roll-table tr.is-failure th {
  box-shadow: inset 4px 0 0 var(--roll-penalty);
}

.party-roll-numbers {
  font-variant-numeric: tabular-nums;
}

/* The result text takes the spare width and wraps, so a phone needn't
   scroll sideways */
.party-roll-table td:last-child {
  width: 100%;
  white-space: normal;
}

.party-roll-target,
.party-roll-dice,
.party-roll-none {
  opacity: 0.7;
}

/* --- Live sheet (static/js/live.js) ------------------------------- */

:root {
  /* The glow round a part of the sheet that changed elsewhere, and the
     colour its changed numbers flash */
  --live-highlight: #485fc7;
  --live-number: #485fc7;
  /* A soft halo close in, and a wider fainter one, in --live-highlight
     (themes set their own: stronger where the page is about as light as
     the highlight). Three shadows always, as in --live-no-glow, and colours
     in rgb() (not color-mix(), which Chromium won't fade from), so one
     fades smoothly into the other. */
  --live-glow: drop-shadow(0 0 2px rgb(72 95 199 / 0.7))
    drop-shadow(0 0 12px rgb(72 95 199 / 0.55)) drop-shadow(0 0 0 transparent);
  --live-no-glow: drop-shadow(0 0 0 transparent) drop-shadow(0 0 0 transparent)
    drop-shadow(0 0 0 transparent);
  /* A table row's mark: the highlight, faint (rgb() too) */
  --live-wash: rgb(72 95 199 / 0.22);
}

/* A glow in the shape of what's drawn (rounded corners, a skill row's
   controls), taking no room, so nothing moves, and leaving the part's own
   borders and shadows alone. It comes up quickly, then fades. Nothing
   fixed in place may go in a part: a filter becomes its frame. */
[data-live-mark] {
  animation: live-mark 2s ease-in-out;
}

@keyframes live-mark {
  0%,
  100% {
    filter: var(--live-no-glow);
  }

  10%,
  40% {
    filter: var(--live-glow);
  }
}

/* A table row has no shape of its own to glow round (its text would glow
   instead), so it's washed with the colour */
tr[data-live-mark],
.keeper-row[data-live-mark] {
  animation-name: live-mark-row;
}

@keyframes live-mark-row {
  10%,
  40% {
    background-color: var(--live-wash);
  }
}

[data-live-mark-number] {
  animation: live-mark-number 2s ease-out;
}

@keyframes live-mark-number {
  from {
    color: var(--live-number);
  }
}

/* Something turning on (a skill's check): a wiggle, then a pop, with a ring
   bursting out of it. The ring is in the number colour, which reads on the
   paper the check sits on. */
[data-live-mark-cheer] {
  position: relative;
  animation: live-cheer 0.5s ease-out;
}

[data-live-mark-cheer]::after {
  content: "";
  position: absolute;
  inset: -0.3em;
  border: 2px solid var(--live-number);
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
  animation: live-cheer-ring 0.55s ease-out 0.05s;
}

/* The ring bursts out over its neighbours: the button next to it and the
   rows around it, even hovered or focused ones (Bulma raises those to 4).
   Its part needs raising too: the glow is a filter, which stacks the part
   on its own. */
[data-live-region]:has([data-live-mark-cheer]) {
  position: relative;
  z-index: 5;
}

:has(> [data-live-mark-cheer]) {
  z-index: 5;
}

@keyframes live-cheer {
  0% {
    transform: scale(1) rotate(0);
  }

  12% {
    transform: scale(0.85) rotate(-14deg);
  }

  26% {
    transform: scale(1.05) rotate(12deg);
  }

  40% {
    transform: scale(1) rotate(-8deg);
  }

  58% {
    transform: scale(1.5) rotate(0);
  }

  78% {
    transform: scale(0.92);
  }

  100% {
    transform: scale(1);
  }
}

@keyframes live-cheer-ring {
  from {
    opacity: 0.9;
    transform: scale(0.5);
  }

  to {
    opacity: 0;
    transform: scale(1.7);
  }
}

/* No fade: marked, then not. (Important, as the animation would be: themes
   colour numbers more specifically.) No wiggle either: the check turning
   on is enough. */
@media (prefers-reduced-motion: reduce) {
  [data-live-mark-cheer],
  [data-live-mark-cheer]::after {
    animation: none;
  }

  [data-live-mark] {
    animation: none;
    filter: var(--live-glow);
  }

  tr[data-live-mark],
  .keeper-row[data-live-mark] {
    filter: none;
    background-color: var(--live-wash);
  }

  [data-live-mark-number] {
    animation: none;
    color: var(--live-number) !important;
  }
}

.live-stale-note {
  margin-top: 0.5rem;
  font-size: 0.85em;
  opacity: 0.75;
}

/* Wraps rather than pushing the theme menu off a phone's screen (why the
   page will reload is a sentence) */
.live-status {
  flex: 0 1 auto;
  min-width: 0;
  white-space: normal;
  font-size: 0.85em;
  opacity: 0.7;
}

.live-status[hidden] {
  display: none;
}

/* A dice expression ("1D3−1", "1D4+DB"), marked by the `dice` filter
   wherever text can hold one: a quiet chip in even figures, kept on one
   line. Themes tune its face, tint and colour. */
:root {
  --dice-font: inherit;
  --dice-weight: 600;
  --dice-color: inherit;
  --dice-tint: rgba(128, 128, 128, 0.14);
}

.dice {
  padding: 0 0.15em;
  border-radius: 3px;
  background-color: var(--dice-tint);
  color: var(--dice-color);
  font-family: var(--dice-font);
  font-weight: var(--dice-weight);
  font-variant-numeric: lining-nums tabular-nums;
  white-space: nowrap;
}

/* A vehicle's movement actions left out of a round's ("1/2 actions left"):
   red once none are left, or some are owed */
:root {
  --actions-out: #cc0f35;
}

.actions-left.is-out,
.actions-left.is-out > strong {
  color: var(--actions-out);
}

/* The Keeper's chase setup (components/chase-setup.j2), below "Call for a
   roll": the vehicles, one block each, then how the chase starts. A vehicle
   is the same badge everywhere (docs/plans/chase.md, "The web"): a square
   P for the party's, a circle with its letter for any other, in colours
   each theme sets (--chase-party, --chase-other, and what's written on
   them), for the setup and the chase panel alike. */
.chase-setup,
.chase-panel,
.chase-strip {
  --chase-party: #3d6b73;
  --chase-on-party: #ffffff;
  --chase-other: #8b1e1e;
  --chase-on-other: #ffffff;
  --chase-impaired: #a06a00;
  --chase-rule: rgba(128, 128, 128, 0.3);
  --chase-tint: rgba(128, 128, 128, 0.1);
}

.chase-setup.is-idle {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
}

.chase-setup-idle-text,
.chase-setup .keeper-none,
.chase-note,
.chase-setup-saved {
  opacity: 0.7;
}

.chase-badge {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 4px;
  background-color: var(--chase-party);
  color: var(--chase-on-party);
  font-size: 0.85rem;
  font-weight: 700;
  line-height: 1;
}

.chase-badge.is-other {
  border-radius: 50%;
  background-color: var(--chase-other);
  color: var(--chase-on-other);
}

.chase-setup-help {
  margin-bottom: 1rem;
}

.chase-setup-help > summary {
  cursor: pointer;
  font-weight: 700;
}

.chase-setup-help > ol {
  max-width: 65ch;
  margin: 0.5rem 0 0 1.5rem;
  list-style: decimal;
}

.chase-setup-help ul {
  margin: 0.25rem 0 0 1.25rem;
  list-style: disc;
}

.chase-setup-help li + li {
  margin-top: 0.3rem;
}

/* Each vehicle: its name with its badge, what it is, who's in it, its
   speed roll, then the book's proposal for it. Edged in its badge's
   colour. */
.chase-vehicle {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  grid-template-areas:
    "head head"
    "fields who"
    "roll who"
    "proposal proposal";
  gap: 0.5rem 1.5rem;
  padding: 0.75rem 0 0.75rem 0.75rem;
  border-top: 1px solid var(--chase-rule);
  border-left: 4px solid var(--chase-party);
}

.chase-vehicle.is-other {
  border-left-color: var(--chase-other);
}

.chase-vehicle-head {
  grid-area: head;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.chase-vehicle-head .chase-badge {
  width: 2rem;
  height: 2rem;
  font-size: 1rem;
}

.chase-vehicle-name.input {
  flex: 1 1 10rem;
  max-width: 20rem;
  font-size: 1.15rem;
  font-weight: 700;
}

.chase-vehicle-fields {
  grid-area: fields;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem;
}

.chase-vehicle-fields .field {
  margin: 0;
}

.chase-vehicle-fields .label {
  margin-bottom: 0.15rem;
}

.chase-number .input {
  width: 3.75rem;
}

.chase-skill .input {
  width: 10rem;
}

.chase-vehicle-who {
  grid-area: who;
}

/* One person to a line, their notes and actions in columns */
.chase-occupants {
  display: grid;
  grid-template-columns: minmax(0, max-content) repeat(3, auto);
  justify-content: start;
  align-items: baseline;
  gap: 0.2rem 0.6rem;
  margin-bottom: 0.4rem;
}

.chase-occupant {
  display: contents;
}

.chase-vehicles,
.chase-occupants,
.chase-track,
.chase-actions,
.chase-order {
  list-style: none;
}

.chase-occupants-none {
  display: block;
  grid-column: 1 / -1;
}

.chase-note {
  font-size: 0.85rem;
}

strong.chase-note {
  opacity: 1;
}

/* A quiet action, as on the encounter panel: underlined text */
.chase-action {
  padding: 0 0.2rem;
  border: none;
  background: none;
  color: inherit;
  font: inherit;
  font-size: 0.85rem;
  text-decoration: underline;
  text-decoration-color: var(--chase-rule);
  text-underline-offset: 0.2em;
  cursor: pointer;
  opacity: 0.7;
}

.chase-action:hover,
.chase-action:focus-visible {
  background-color: var(--chase-tint);
  text-decoration-color: currentColor;
  opacity: 1;
}

.chase-vehicle-head .chase-action {
  margin-left: auto;
}

.chase-speed-roll {
  grid-area: roll;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}

.chase-speed-roll > .label {
  width: 100%;
  margin: 0;
}

.chase-speed-result {
  width: 100%;
  font-size: 0.9rem;
}

.chase-proposal {
  grid-area: proposal;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem 1rem;
  padding: 0.4rem 0.6rem;
  background-color: var(--chase-tint);
}

.chase-setup-buttons {
  margin-top: 0.75rem;
}

/* How the chase starts: the track, movement actions and the order side by
   side, one under another on a phone */
.chase-result {
  margin-top: 0.5rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--chase-rule);
}

.chase-result-away {
  margin-bottom: 0.75rem;
  padding: 0.4rem 0.6rem;
  background-color: var(--chase-tint);
}

.chase-result-parts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 1rem 2rem;
}

.chase-result-title {
  margin-bottom: 0.4rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.75;
}

.chase-location {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 2rem;
  border-bottom: 1px dashed var(--chase-rule);
}

.chase-location-number {
  width: 1.5rem;
  text-align: right;
  opacity: 0.6;
}

.chase-location-vehicles {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem 0.4rem;
}

.chase-location-name {
  margin-right: 0.4rem;
  font-size: 0.9rem;
}

.chase-off-track {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.4rem;
  font-size: 0.9rem;
}

/* Off the track: dashed, as a stopped vehicle's badge is */
.chase-off-track .chase-badge {
  border: 2px dashed var(--chase-other);
  background: none;
  color: inherit;
}

.chase-off-track .chase-badge.is-party {
  border-color: var(--chase-party);
}

.chase-gap {
  margin-top: 0.75rem;
}

.chase-gap .label {
  font-weight: 400;
}

.chase-actions > li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 0.4rem;
  padding: 0.15rem 0;
}

.chase-actions .chase-badge,
.chase-order .chase-badge,
.chase-off-track .chase-badge,
.chase-location .chase-badge {
  width: 1.35rem;
  height: 1.35rem;
  font-size: 0.75rem;
}

/* DEX, name, vehicle and notes in columns */
.chase-order {
  display: grid;
  grid-template-columns: auto minmax(0, max-content) auto minmax(0, 1fr);
  align-items: center;
  gap: 0.3rem 0.5rem;
}

.chase-order-row {
  display: contents;
}

.chase-order-none {
  display: block;
  grid-column: 1 / -1;
}

.chase-order-dex {
  font-weight: 700;
  text-align: right;
}

.chase-order-row.is-out > * {
  opacity: 0.5;
}

.chase-setup-note {
  margin-top: 0.75rem;
}

.chase-setup-error {
  color: var(--roll-penalty);
}

.chase-setup-error:empty {
  display: none;
}

.chase-setup-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  margin-top: 1rem;
}

@media screen and (max-width: 768px) {
  .chase-vehicle {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "head"
      "fields"
      "who"
      "roll"
      "proposal";
  }

  .chase-occupants {
    column-gap: 0.4rem;
  }
}

/* The Keeper's chase panel (components/chase.j2), above the encounter
   panel: the turn band (the one bold element), then the vehicles front
   first beside the road, then the help and End the chase. */
.chase-panel[hidden] {
  display: none;
}

/* Its last box has no margin of its own (Bulma's .box:not(:last-child)),
   so the panel keeps a box's space from the encounter panel after it */
.chase-panel:not(:last-child) {
  margin-bottom: 1.5rem;
}

.chase-panel .chase-note,
.chase-panel .keeper-none,
.chase-then,
.chase-panel-later,
.chase-of {
  opacity: 0.7;
}

/* A stopped vehicle's badge is dashed; the acting one is ringed on the
   road */
.chase-badge.is-stopped {
  border: 2px dashed var(--chase-party);
  background-color: transparent;
  color: inherit;
}

.chase-badge.is-other.is-stopped {
  border-color: var(--chase-other);
}

.chase-badge.is-acting {
  outline: 2px solid var(--chase-party);
  outline-offset: 2px;
}

.chase-badge.is-other.is-acting {
  outline-color: var(--chase-other);
}

.chase-panel .chase-band.box {
  border-left: 8px solid var(--chase-party);
}

.chase-panel .chase-band.box.is-other {
  border-left-color: var(--chase-other);
}

.chase-band-round {
  margin-bottom: 0.5rem;
  font-size: 0.9rem;
  font-weight: 700;
}

.chase-band-head {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.chase-band-head .chase-badge {
  width: 3.25rem;
  height: 3.25rem;
  font-size: 1.6rem;
}

.chase-band-title {
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.15;
}

.chase-band-next {
  max-width: 65ch;
  margin-top: 1rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--chase-rule);
}

.chase-band-next > p + p {
  margin-top: 0.25rem;
}

/* The driver's move, suggested: quieter than what's next */
.chase-band-next > .chase-band-hint {
  margin-top: 0.5rem;
  font-size: 0.9rem;
  opacity: 0.85;
}

/* This turn's moves, then the quiet corrections, then Pass at the end */
.chase-band-buttons {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1rem;
  margin-top: 1rem;
}

.chase-band-moves,
.chase-band-fixes {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.chase-band-pass {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.5rem 1rem;
  margin-left: auto;
}

.chase-then {
  font-size: 0.85rem;
}

.chase-panel-body {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
  align-items: start;
  gap: 1.5rem;
  margin-bottom: 1.5rem;
}

.chase-panel-body > .box {
  margin-bottom: 0;
}

.chase-panel-title {
  margin-bottom: 0.5rem;
  font-size: 1.1rem;
  font-weight: 700;
}

/* A vehicle, everything aligned to the top of its row, which opens (the
   toggle at its top right) to show its corrections */
.chase-mover {
  position: relative;
  list-style: none;
  border-top: 1px solid var(--chase-rule);
  border-left: 3px solid transparent;
}

.chase-mover.is-acting {
  border-left-color: var(--chase-party);
}

.chase-mover.is-acting.is-other {
  border-left-color: var(--chase-other);
}

.chase-mover:has(> .chase-fix[open]) > .chase-row {
  background-color: var(--chase-tint);
}

.chase-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) 5.5rem 7rem 6rem;
  grid-template-areas: "badge who build actions gap";
  align-items: start;
  gap: 0.25rem 1rem;
  padding: 0.6rem 2rem 0.6rem 0.5rem;
}

.chase-row > .chase-badge {
  grid-area: badge;
}

.chase-fix-toggle {
  position: absolute;
  top: 0.45rem;
  right: 0.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 4px;
  cursor: pointer;
  list-style: none;
}

.chase-fix-toggle::-webkit-details-marker {
  display: none;
}

.chase-fix-toggle::before {
  content: "›";
  font-size: 1.25rem;
  line-height: 1;
  opacity: 0.7;
  transition: transform 0.15s ease;
}

.chase-fix[open] > .chase-fix-toggle::before {
  transform: rotate(90deg);
}

.chase-fix-toggle:hover,
.chase-fix-toggle:focus-visible {
  background-color: var(--chase-tint);
}

/* Under the name, lined up with it: the badge's width and the gap */
.chase-fix-fields {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr));
  align-items: start;
  gap: 0.75rem 1.5rem;
  padding: 0.75rem 1rem 1rem calc(0.5rem + 2rem + 1rem);
}

.chase-fix-fields .field {
  min-width: 0;
  margin-bottom: 0;
}

.chase-fix-fields .label {
  margin-bottom: 0.25rem;
  font-size: 0.85rem;
}

.chase-fix-fields .help {
  opacity: 0.7;
}

.chase-fix-fields .input {
  max-width: 6rem;
}

/* Over the themes' colour for a Bulma input */
.chase-fix-fields > .is-increasing > .encounter-number-input {
  color: var(--counter-increase);
}

.chase-fix-fields > .is-decreasing > .encounter-number-input {
  color: var(--counter-decrease);
}

.chase-fix-pair {
  display: flex;
  gap: 0.25rem;
}

.chase-fix-fields .select,
.chase-fix-fields select {
  box-sizing: border-box;
  max-width: 100%;
}

.chase-row-who {
  grid-area: who;
}

.chase-row-name {
  font-weight: 700;
}

.chase-aboard {
  font-size: 0.9rem;
}

/* One to a line: the name, then its notes, each kept whole */
.chase-aboard > li {
  display: flex;
  flex-wrap: wrap;
  column-gap: 0.5rem;
}

.chase-aboard-name {
  min-width: 7.5rem;
}

.chase-aboard .chase-note {
  white-space: nowrap;
}

.chase-row-build {
  display: flex;
  flex-direction: column;
  grid-area: build;
}

.chase-row-actions {
  grid-area: actions;
}

.chase-row-build strong,
.chase-row-actions strong {
  font-size: 1.25rem;
}

.chase-of {
  font-size: 0.8rem;
}

.chase-state {
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--chase-other);
}

.chase-state.is-impaired {
  color: var(--chase-impaired);
}

.chase-row-gap {
  grid-area: gap;
  font-weight: 700;
  text-align: right;
}

.is-off-track > .chase-row {
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas: "badge who bring";
  align-items: center;
}

.chase-bring-in {
  grid-area: bring;
}

/* The road, front first: planned locations and placeholders dashed */
.chase-stop {
  display: grid;
  grid-template-columns: 1.5rem minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.5rem;
  min-height: 2.75rem;
  padding: 0.35rem 0;
  border-top: 1px solid var(--chase-rule);
}

.chase-stop.is-unseen,
.chase-stop.is-placeholder {
  border-top-style: dashed;
}

.chase-stop-number {
  opacity: 0.7;
  text-align: right;
}

.chase-stop-what {
  display: flex;
  flex-direction: column;
}

.chase-stop.is-unseen .chase-stop-what {
  font-style: italic;
}

.chase-obstacle,
.chase-stop .chase-note {
  font-size: 0.85rem;
}

.chase-stop-vehicles {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.4rem;
  padding: 3px;
}

.chase-panel-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
}

.chase-help {
  flex: 1 1 100%;
}

.chase-help > summary {
  cursor: pointer;
  font-weight: 700;
}

.chase-help > p {
  max-width: 70ch;
  margin-top: 0.5rem;
}

.chase-panel-later {
  flex: 1 1 20rem;
  font-size: 0.85rem;
}

.chase-panel-error {
  flex: 1 1 100%;
  color: var(--roll-penalty);
}

.chase-panel-error:empty {
  display: none;
}

/* Whose investigator someone in the band is, as the Keeper's screen has
   it (.keeper-player) */
.chase-player {
  font-size: 0.8em;
  font-weight: 400;
  opacity: 0.7;
}

/* A button lays its text out as flex items, which drop the space before */
.button > .chase-player {
  margin-left: 0.3em;
}

/* Whether the fight has started, after the round, quietly */
.chase-band-fight {
  margin-left: 0.75rem;
  font-weight: 400;
  opacity: 0.8;
}

/* A road preset or clear road in a click: Add ahead at the top of the
   road, and the band's "What's at…?" */
.chase-road-choice {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin: 0.5rem 0;
}

.chase-road-choice .select,
.chase-road-choice select {
  max-width: 100%;
}

/* A location, which opens (the toggle at its right) to its edit */
.chase-stop-item {
  position: relative;
  list-style: none;
}

.chase-stop-item > .chase-stop {
  padding-right: 2rem;
}

.chase-stop-item:has(> .chase-fix[open]) > .chase-stop {
  background-color: var(--chase-tint);
}

.chase-stop-item > .chase-fix > .chase-fix-toggle {
  top: 0.5rem;
}

.chase-fix-fields.chase-road-fields {
  grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
  padding-left: 2rem;
}

.chase-road-fields .input,
.chase-add-fields .input {
  box-sizing: border-box;
  width: 100%;
  max-width: 100%;
}

.chase-fix-save {
  align-self: end;
}

/* Add a vehicle, below the last row */
.chase-add-vehicle {
  padding-top: 0.75rem;
  border-top: 1px solid var(--chase-rule);
}

.chase-add-vehicle > summary {
  list-style: none;
}

.chase-add-vehicle > summary::-webkit-details-marker {
  display: none;
}

.chase-add-fields {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
  align-items: start;
  gap: 0.75rem 1.25rem;
  margin-top: 0.75rem;
}

.chase-add-fields .field {
  min-width: 0;
  margin-bottom: 0;
}

.chase-add-fields .label {
  margin-bottom: 0.25rem;
  font-size: 0.85rem;
}

.chase-add-fields .select,
.chase-add-fields select {
  box-sizing: border-box;
  max-width: 100%;
}

.chase-add-number .input {
  max-width: 6rem;
}

.chase-add-aboard,
.chase-add-help,
.chase-add-submit {
  grid-column: 1 / -1;
}

/* One to a line, in as many columns as fit: a long list grows rather than
   scrolls */
.chase-add-aboard {
  min-width: 0;
}

.chase-add-choices {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: 0.15rem 1.25rem;
}

.chase-add-choices > .checkbox {
  font-size: 0.9rem;
}

.chase-add-help {
  max-width: 70ch;
  opacity: 0.7;
}

/* Start the fight and End the chase, side by side at the end */
.chase-panel-fight {
  margin-left: auto;
}

/* The encounter panel while a chase passes the turns on */
.encounter-chase-turns {
  margin: 0.75rem 0 1rem;
  font-size: 0.9rem;
  opacity: 0.8;
}

@media screen and (max-width: 768px) {
  .chase-panel-body {
    grid-template-columns: minmax(0, 1fr);
  }

  .chase-band-title {
    font-size: 1.4rem;
  }

  .chase-band-pass {
    justify-content: flex-start;
    margin-left: 0;
  }

  .chase-fix-fields {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 0.75rem;
    padding-left: 0.5rem;
    padding-right: 0.5rem;
  }

  .chase-fix-fields .input {
    min-width: 0;
  }

  .chase-add-fields,
  .chase-fix-fields.chase-road-fields {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 0.75rem;
  }

  .chase-fix-fields.chase-road-fields {
    padding-left: 0.5rem;
  }

  .chase-add-fields .select,
  .chase-add-fields select {
    width: 100%;
  }

  .chase-fix-fields .select,
  .chase-fix-fields select {
    width: 100%;
  }

  .chase-row {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "badge who gap"
      ". build actions";
  }

  .chase-row-actions {
    text-align: right;
  }

  .chase-aboard-name {
    min-width: 0;
  }
}
