/*
 * The Cartel primitives. Every value here comes from tokens.css; a raw colour
 * or font stack below is a defect. /styleguide renders each one in every state.
 */

/* ── Base ──────────────────────────────────────────────────────────────── */

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

html {
  text-size-adjust: 100%;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  margin: 0;
  background-color: var(--ink);
  color: var(--texto);
  font: 400 var(--text-body) / var(--leading-body) var(--font-body);
  text-wrap: pretty;
}

body::before {
  content: "";
  position: fixed;
  z-index: -1;
  inset: 0;
  background-image: var(--poster);
  background-repeat: no-repeat;
  pointer-events: none;
}

/* Keeps the footer at the bottom of a short page instead of mid-viewport. */
main {
  flex: 1;
}

/* Everything in this system stacks with a flex gap, never with a margin. */
h1,
h2,
h3,
h4,
p,
figure,
blockquote,
dl,
dd {
  margin: 0;
}

img {
  max-width: 100%;
}

/* Every component here sets its own display, which would outrank [hidden]. */
[hidden] {
  display: none !important;
}

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

::selection {
  background: var(--amarillo);
  color: var(--ink);
}

/* The replay animation must have a still path. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}

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

.shell {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  max-width: var(--shell);
  margin-inline: auto;
  padding: var(--space-4) var(--space-3) var(--space-7);
}

.masthead {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding-block: var(--space-2);
}

.masthead > * {
  min-width: 0;
}

.section {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}


/* ── Type roles ────────────────────────────────────────────────────────── */

.wordmark {
  font-family: var(--font-display);
  font-size: var(--text-body);
  font-weight: 400;
  letter-spacing: var(--track-wordmark);
  text-transform: uppercase;
  color: var(--amarillo);
}

.wordmark__tld {
  color: var(--rosa);
}

.display {
  font-family: var(--font-display);
  font-size: var(--text-display);
  font-weight: 400;
  line-height: var(--leading-tight);
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  text-wrap: balance;
  overflow-wrap: anywhere;
}

.display--hero {
  font-size: var(--text-hero);
}

.title {
  font-size: var(--text-title);
  font-weight: 800;
  line-height: var(--leading-tight);
  text-wrap: balance;
}

.eyebrow {
  font-variant-numeric: tabular-nums;
  font-family: var(--font-data);
  font-size: var(--text-micro);
  font-weight: 700;
  letter-spacing: var(--track-micro);
  text-transform: uppercase;
  color: var(--dim);
}

/*
 * Every HP value, token count, level, price and table column — and the
 * addresses and slugs that read as data too. Bungee and Archivo both set
 * proportional figures by default, so numbers that have to line up wear this
 * role rather than the display or body face. Monospace breaks at neither a dot
 * nor an at-sign, so the role wraps anywhere or an email pushes a 320px card
 * off the screen.
 */
.data {
  font-family: var(--font-data);
  font-size: var(--text-data);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.muted {
  color: var(--dim);
}

/* What a postura, a piece of equipment or a level gap moves. The sign carries
   the meaning; colour only doubles it. */
.delta {
  font-family: var(--font-data);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.delta--up {
  color: var(--menta);
}

.delta--down {
  color: var(--rosa);
}

/* ── Card ──────────────────────────────────────────────────────────────── */

.card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-3);
  background: var(--card);
  border: var(--border) solid var(--line);
  border-radius: var(--radius);
}

/* The marquee border bills what it holds the way a printed cartel does: the
   landing's fixture fight, the arena's Reto del Día, the billing above a
   scouting sheet, and a jauría's week once it is won. */
.card--marquee {
  border-color: var(--amarillo);
}

/*
 * The sticker treatment, kept from the rejected Álbum direction for the pet
 * card alone: it makes a photo feel like an object you own, which is the
 * identity mechanic immutable stats depend on (ADR 0010).
 */
.pet-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-2);
  background: var(--card);
  border: var(--sticker-border) solid var(--texto);
  border-radius: var(--radius-xs);
  box-shadow: var(--shadow-sticker);
}

.pet-card__photo {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1;
  overflow: hidden;
  background: var(--well);
  border-radius: var(--radius-xs);
  font-size: 3rem;
  line-height: 1;
}

.pet-card__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The jauría a pet runs with, worn on the sticker itself: a chip is inline and
   every other child of the card is not. */
.pet-card__pack {
  align-self: center;
  max-width: 100%;
}

/* Every podio a pet has finished on (COMBAT-31), worn beside the jauría's chip.
   A pet can collect one a season, so they wrap rather than push the sticker
   wide. */
.pet-card__badges {
  justify-content: center;
  max-width: 100%;
}

.pet-card__name {
  font-family: var(--font-display);
  font-size: var(--text-data);
  line-height: var(--leading-tight);
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  overflow-wrap: anywhere;
}

/* ── Shelf ─────────────────────────────────────────────────────────────── */

/*
 * One slot of the shop, opened and closed by its own header. A native
 * <details> rather than a controller: the toggle, its keyboard handling and
 * what a screen reader announces all come with the element.
 */
.shelf {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

/* A closed block still lays out its content box, so the row gap outlives what
   it was spacing and a collapsed header carries 12px of nothing. */
.shelf:not([open]) {
  gap: 0;
}

.shelf__head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--tap);
  padding-block: var(--space-2);
  border-bottom: var(--border) solid var(--line);
  list-style: none;
  cursor: pointer;
}

/* Safari draws its own triangle unless this pseudo-element is dismissed too. */
.shelf__head::-webkit-details-marker {
  display: none;
}

.shelf__name {
  flex: 1;
  min-width: 0;
}

.shelf__mark {
  color: var(--amarillo);
  transition: transform var(--motion) var(--ease);
}

.shelf[open] .shelf__mark {
  transform: rotate(90deg);
}

/* ── Billing ───────────────────────────────────────────────────────────── */

/* Two fighters abreast with the mark between them: the landing's intro, the
   arena's, and the replay. Promoted out of the landing when the replay became
   its second caller. The corners stretch to a shared height rather than
   centring, so whatever a 20-character name does to one of them, the two cards
   stay billed on the same line. */
.vs {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: var(--space-2);
}

.vs > * {
  min-width: 0;
}

/* Two cards abreast leave a name 80px at 320px, and the pet-card specimen is
   drawn at 120px; at the card's own size an 8-character name breaks mid-word.
   Billing type is smaller than the card type it is borrowed from. */
.vs .pet-card__name {
  font-size: var(--text-micro);
}

.vs__mark {
  font-family: var(--font-display);
  font-size: var(--text-display);
  letter-spacing: var(--track-display);
  color: var(--rosa);
}

/* ── Button ────────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--tap);
  padding: var(--space-2) var(--space-4);
  border: var(--border) solid transparent;
  border-radius: var(--radius-sm);
  max-width: 100%;
  font: 800 var(--text-body) / var(--leading-tight) var(--font-body);
  text-align: center;
  text-decoration: none;

  /* A button label can carry a name a player authored: a pet's, a jauría's. */
  overflow-wrap: anywhere;
  cursor: pointer;
  transition: transform var(--motion-fast) var(--ease),
    filter var(--motion) var(--ease);
}

.btn:active {
  transform: translateY(1px);
}

.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none;
}

.btn--primary {
  background: var(--amarillo);
  color: var(--ink);
}

.btn--ghost {
  background: var(--card);
  border-color: var(--dim);
  color: var(--texto);
}

/* Consequence, in the damage colour — the reading .flash--alert and
   .chip--alert already establish. It never outranks the primary: on the one
   page that offers an irreversible action, the safe way out keeps the amarillo
   weight and this one only has to stop reading like a nav link. */
.btn--danger {
  background: var(--card);
  border-color: var(--rosa);
  color: var(--rosa);
}

/* An amarillo ring on the amarillo button reads as a halo, not a focus state. */
.btn--primary:focus-visible {
  outline-color: var(--texto);
}

/* Patchy signal is the median session; every action can be in flight. */
.btn[aria-busy="true"] {
  cursor: progress;
  pointer-events: none;
}

.btn[aria-busy="true"]::before {
  content: "";
  width: 1em;
  height: 1em;
  border: var(--border) solid currentcolor;
  border-block-start-color: transparent;
  border-radius: var(--radius-pill);
  animation: btn-spin 600ms linear infinite;
}

@keyframes btn-spin {
  to {
    transform: rotate(1turn);
  }
}

.btn--block {
  width: 100%;
}

@media (hover: hover) {
  .btn--primary:hover:not(:disabled) {
    filter: brightness(1.08);
  }

  .btn--ghost:hover:not(:disabled) {
    border-color: var(--dim);
  }
}

/* ── HP bar ────────────────────────────────────────────────────────────── */

.bar {
  height: 11px;
  overflow: hidden;
  background: var(--well);
  border: var(--border-hair) solid var(--line);
  border-radius: var(--radius-pill);
}

.bar__fill {
  display: block;
  width: 100%;
  height: 100%;
  background: var(--menta);
  transform: scaleX(var(--hp, 1));
  transform-origin: left center;
  transition: transform var(--motion) var(--ease);
}

.bar__fill--hurt {
  background: var(--amarillo);
}

.bar__fill--critical {
  background: var(--rosa);
}

/* A jauría's weekly goal borrows the track and fills toward a target instead
   of draining from one, so it carries its own fraction and the marquee yellow
   that bills a win everywhere else. */
.bar__fill--goal {
  background: var(--amarillo);
  transform: scaleX(var(--progress, 0));
}

/* The same track carrying the walk to the next level. It reads --xp rather than
   --hp so a replay can never scale a progress bar by accident. */
.bar__fill--xp {
  background: var(--amarillo);
  transform: scaleX(var(--xp, 0));
}

/* ── Fight log ─────────────────────────────────────────────────────────── */

/*
 * One modifier per resolver event type (CONTEXT.md): exchange, hit, dodge,
 * counter, snack, trait, end. A critical is a flagged hit, not its own event.
 * The emoji markers are game content, not chrome.
 */
.log {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font: 400 var(--text-log) / var(--leading-log) var(--font-data);
  font-variant-numeric: tabular-nums;
}

.log-line {
  overflow-wrap: anywhere;
}

.log-line--exchange {
  font-size: var(--text-micro);
  color: var(--dim);
}

.log-line--hit {
  color: var(--texto);
}

.log-line--hit.is-crit {
  font-weight: 700;
  color: var(--rosa);
}

.log-line--dodge {
  color: var(--menta);
}

.log-line--counter {
  font-weight: 700;
  color: var(--azul);
}

.log-line--snack {
  font-weight: 700;
  color: var(--naranja);
}

.log-line--trait {
  font-weight: 700;
  color: var(--lila);
}

.log-line--end {
  font-weight: 700;
  color: var(--amarillo);
}

/* ── Verdict ───────────────────────────────────────────────────────────── */

/*
 * The card a fight ends on: what happened, in the biggest type the system has,
 * over the pet it happened to. Amarillo for a win and rosa for a loss are the
 * two colours the fight log already spends on those same two meanings, so the
 * border carries the result before the word is read. A win therefore wears the
 * marquee's colour without being a billing, and it is the only amarillo border
 * its page is allowed.
 */
.verdict {
  align-items: center;
  text-align: center;
}

.verdict--won {
  border-color: var(--amarillo);
}

.verdict--lost {
  border-color: var(--rosa);
}

.verdict__call {
  color: var(--amarillo);
}

.verdict--lost .verdict__call {
  color: var(--rosa);
}

/* The photo is the art (.impeccable.md), and the only thing on this card
   competing with the call above it, so it is billed wider than the arena's
   list thumbnail and narrower than the card the pet page gives it. */
.verdict__pet {
  width: 9.5rem;
  max-width: 100%;
}

/* ── Payout ────────────────────────────────────────────────────────────── */

/* What a fight paid, one line per payout. The numbers are set at display size
   because this is the screen the daily ritual ends on and they have to read at
   arm's length — but in the data face, which is the only one of the three that
   sets tabular figures (ADR 0010). The label beside them stays quiet. */
.payout {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.payout__line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}

.payout__value {
  font-family: var(--font-data);
  font-size: var(--text-display);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--amarillo);
}

.payout__value--xp {
  color: var(--menta);
}

/* ── Form field ────────────────────────────────────────────────────────── */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.field__label {
  font-size: var(--text-data);
  font-weight: 600;
}

.field__input {
  width: 100%;
  min-height: var(--tap);
  padding: 0 var(--space-3);
  background: var(--well);
  border: var(--border) solid var(--dim);
  border-radius: var(--radius-sm);
  color: var(--texto);
  font: 400 var(--text-body) / 1 var(--font-body);
}

.field__input::placeholder {
  color: var(--dim);
}

.field__hint {
  font-size: var(--text-data);
  color: var(--dim);
}

.field__error {
  font-size: var(--text-data);
  font-weight: 600;
  color: var(--rosa);
}

/* A field under a cooldown. The hint beside it carries the date it opens again
   (ADR 0013); the dash is the half of that signal colour does not carry. A
   readonly field still holds the pet's real name and stays in the tab order, so
   it keeps body contrast and its 3:1 boundary — only the genuinely inactive
   file input dims. Both sit above .field--invalid, which has the same
   specificity and has to win when a locked field comes back with an error. */
.field__input[readonly] {
  border-style: dashed;
  cursor: not-allowed;
}

.field__input:disabled {
  border-color: var(--line);
  border-style: dashed;
  color: var(--dim);

  /* iOS Safari paints its own colour on a disabled control and ignores `color`. */
  -webkit-text-fill-color: var(--dim);
  cursor: not-allowed;
}

.field--invalid .field__input {
  border-color: var(--rosa);
}

/* The shorthand above sets a leading of 1, which clips a file input's button. */
.field__input[type="file"] {
  padding-block: var(--space-2);
  line-height: var(--leading-body);
}

/* Same shorthand, same problem from the other side: a leading of 1 stacks the
   lines of a multi-line field on top of each other. Qualified by element the
   way the file input is, so no paragraph field can be added without it. */
textarea.field__input {
  padding-block: var(--space-2);
  line-height: var(--leading-body);
  resize: vertical;
}

/* The six digits copied out of a sign-in mail. It wears the data role because
   that is what it is, and it is set large and tracked out because it is read
   off one screen and typed into another — on a phone, one handed, usually with
   the mail app still half covering the field. */
.field__input--code {
  font-family: var(--font-data);
  font-size: var(--text-display);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--track-display);
  text-align: center;
}

.fieldset {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

/* A legend is not a flex item — it sits above the anonymous content box — so
   the fieldset's row-gap never reaches it and the space has to be its own. */
.fieldset > legend {
  padding: 0;
  margin-block-end: var(--space-3);
}

/* Reparto libre reveals its own fields with no JavaScript, so they never paint
   before a controller can hide them, and the screen still works without one.
   `:has()` is already a requirement (allow_browser versions: :modern). */
.fieldset--spread {
  display: none;
}

form:has(.choice__input--free:checked) .fieldset--spread {
  display: flex;
}

/* ── Choice ────────────────────────────────────────────────────────────── */

/*
 * A radio stretched over its own panel: the whole card is the tap target, the
 * control stays a real radio for the keyboard and the screen reader, and the
 * check mark means colour is never the only signal of what is chosen.
 */
.choice {
  position: relative;
  display: block;
}

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

.choice__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  background: var(--card);
  border: var(--border) solid var(--line);
  border-radius: var(--radius);
  transition: border-color var(--motion) var(--ease);
}

.choice__input:checked + .choice__body {
  border-color: var(--amarillo);
}

.choice__input:focus-visible + .choice__body {
  outline: var(--border) solid var(--amarillo);
  outline-offset: 2px;
}

/* An amarillo ring on the amarillo border reads as a halo, not a focus state,
   and the checked card is the first one a keyboard lands on. */
.choice__input:checked:focus-visible + .choice__body {
  outline-color: var(--texto);
}

.choice__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

.choice__name {
  font-family: var(--font-display);
  font-size: var(--text-body);
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  overflow-wrap: anywhere;
}

.choice__check {
  color: var(--amarillo);
  opacity: 0;
}

.choice__input:checked + .choice__body .choice__check {
  opacity: 1;
}

/* ── Point spread ──────────────────────────────────────────────────────── */

.spread {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.spread__value {
  width: 5rem;
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  text-align: center;
}

.spread__left {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
}

/* Overspent is the only state the number cannot explain on its own. */
.spread__remaining.is-over {
  font-weight: 700;
  color: var(--rosa);
}

/* ── Flash ─────────────────────────────────────────────────────────────── */

/* One line of consequence after a redirect: signed out, link expired. The
   border carries the meaning, so the message stays readable at --texto. */
.flash-region {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-width: var(--shell);
  margin-inline: auto;
  padding: var(--space-4) var(--space-3) 0;
}

.flash {
  padding: var(--space-3);
  background: var(--card);
  border: var(--border) solid var(--line);
  border-radius: var(--radius);
  font-weight: 600;
}

.flash--notice {
  border-color: var(--menta);
}

.flash--alert {
  border-color: var(--rosa);
}

/* ── Chip ──────────────────────────────────────────────────────────────── */

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  background: var(--well);
  border: var(--border-hair) solid var(--line);
  border-radius: var(--radius-pill);
  font: 700 var(--text-micro) / 1 var(--font-data);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--track-micro);
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--dim);
}

/* A state to find on a scrolling page, not a decoration: the moderation queue
   is scanned before it is read. The label says the same thing without it. */
.chip--alert {
  border-color: var(--rosa);
  color: var(--rosa);
}

/* A podio a closed season left on a pet (COMBAT-31), and the one chip that is a
   reward rather than a reading. Menta rather than amarillo, the victory colour,
   because amarillo on this same card is already the padrino's. A season is named
   in `config/seasons.yml`, so the label is as long as somebody authored it. */
.chip--temporada {
  max-width: 100%;
  border-color: var(--menta);
  color: var(--menta);
}

/* ── Rank ──────────────────────────────────────────────────────────────── */

/* Rango is the one thing on a pet that is purely earned and purely cosmetic
   (CONTEXT.md), so it gets the marquee treatment the numbers never do. One
   treatment for all five: the name is the reward, and a colour per rank would
   spend the palette's meanings on decoration. */
.rank {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--well);
  border: var(--border) solid var(--amarillo);
  border-radius: var(--radius-pill);
  font: var(--text-body) / var(--leading-tight) var(--font-display);
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  color: var(--amarillo);
}

/* ── Table ─────────────────────────────────────────────────────────────── */

/* Dense surfaces scroll inside their own box; the page never does. */
.table-scroll {
  overflow-x: auto;
}

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-data);
}

.table th,
.table td {
  padding: var(--space-2);
  border-block-end: var(--border-hair) solid var(--line);
  font-variant-numeric: tabular-nums;
  text-align: left;
}

.table th {
  font-family: var(--font-data);
  font-size: var(--text-micro);
  font-weight: 700;
  letter-spacing: var(--track-micro);
  text-transform: uppercase;
  color: var(--dim);
}

.table .num {
  font-family: var(--font-data);
  text-align: right;
  white-space: nowrap;
}

/* Four columns of tracked mono caps and a row header as long as "Inteligencia"
   do not fit 320px at the padding above. A comparison the screen exists for
   may not be the thing that scrolls sideways. */
.table--dense th,
.table--dense td {
  padding-inline: var(--space-1);
}

/* A button that lives in a row rather than under a card. `.btn` breaks a label
   anywhere so a pet's or a jauría's name can wrap inside one; an action column
   is about 90px on a 320px phone, where that turns "Comprar" into two lines and
   the row into 54px. These labels are ours and each is one short word, so here
   the word stays whole and the row keeps a 44px tap target. */
.table .btn {
  padding-inline: var(--space-2);
  overflow-wrap: normal;
}

/* ── Stat boost ────────────────────────────────────────────────────────── */

/* What a pet's equipment adds to a stat, kept beside the number instead of
   folded into it: the 20 points are permanent and this half is not. It carries
   its own figures, so it stays aligned outside a table cell too. */
.boost {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--menta);
}

/* ── Padrino ───────────────────────────────────────────────────────────── */

/*
 * What a one-time supporter tier buys, and the whole of what it buys: nothing
 * below moves a number anywhere (ADR 0011). Tier 1 gilds the name on the
 * sticker, tier 2 swaps the sticker's white border for the holographic sweep
 * .impeccable.md reserves for it. Both ride on the pet card, so every surface
 * that bills a pet wears them from the same rule.
 */
.pet-card--padrino .pet-card__name {
  color: var(--amarillo);
}

.pet-card--holo {
  background:
    linear-gradient(var(--card), var(--card)) padding-box,
    var(--holo) border-box;
  border-color: transparent;
}

/* The badge, on the two pages a pet is the subject of. Marquee yellow, which is
   what a victory already wears — but a chip, never `.rank`, because the rango
   is earned and this was bought (CONTEXT.md). It centres itself the way the
   jauría tag does: the card is a stretching column, so an inline pill left to
   itself goes full-bleed. */
.chip--padrino {
  align-self: center;
  max-width: 100%;
  border-color: var(--amarillo);
  color: var(--amarillo);
}

/* What a tier includes, read before a price is paid, with the tick outside the
   text column. `list-style: none` costs a list its semantics in VoiceOver, so
   the markup carries `role="list"` to put them back. */
.includes {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);

  /* The UA indent is 40px, which is 15% of the content column at 320px and
     leaves every line hanging off the label above it. */
  margin: 0;
  padding: 0;
  list-style: none;
}

.includes__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
}

/*
 * The lema de entrada a tier-2 padrino wrote, announced before the bell the way
 * a cartel bills a luchador. Quoted rather than shouted: the log is what the
 * page exists for, and sixty characters of somebody else's words must not
 * out-bill it.
 */
.lema {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  font-size: var(--text-data);
  line-height: var(--leading-body);
  color: var(--dim);
  overflow-wrap: anywhere;
}

.lema__who {
  font-family: var(--font-display);
  font-size: var(--text-micro);
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  color: var(--amarillo);
}

/* ── The case against a verdict ────────────────────────────────────────── */

/*
 * What a hidden player wrote to the one human who hid them, read on the
 * moderation card and nowhere else. Prose rather than a table row: it is the
 * thing on that card which has to be read in full, at whatever length its
 * author chose, and nothing stops five hundred characters arriving without a
 * space in them.
 */
.case {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  line-height: var(--leading-body);
  overflow-wrap: anywhere;
}

.case__when {
  font-family: var(--font-data);
  font-size: var(--text-micro);
  color: var(--dim);
}

/* ── Empty state ───────────────────────────────────────────────────────── */

/* Empty states teach the next action; they never just say "nothing here". */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-6) var(--space-4);
  text-align: center;
}

.empty__body {
  color: var(--dim);
}

/* ── Segmented control ─────────────────────────────────────────────────── */

/* One choice out of a few, all of them worth showing at once: a board's week
   against its season, the globe against a country. How many options there are
   is data rather than layout — a country earns its place by having players —
   so the track scrolls inside its own box and never wraps. Wrapped pills stop
   reading as one choice, and three rows of them push the thing the page is for
   below the fold. The options are links, so focus scrolls the track and it
   needs no tabindex of its own. */
.segmented {
  display: flex;
  gap: var(--space-1);
  padding: var(--space-1);
  overflow-x: auto;
  background: var(--well);
  border: var(--border) solid var(--dim);
  border-radius: var(--radius-pill);
}

.segmented__option {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  padding-inline: var(--space-4);
  border-radius: var(--radius-pill);
  font: 700 var(--text-micro) / 1 var(--font-data);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--track-micro);
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  color: var(--dim);
  transition: color var(--motion) var(--ease);
}

.segmented__option[aria-current="page"] {
  background: var(--amarillo);
  color: var(--ink);
}

/* An amarillo ring on the amarillo fill reads as a halo, not a focus state. */
.segmented__option[aria-current="page"]:focus-visible {
  outline-color: var(--texto);
}

@media (hover: hover) {
  .segmented__option:not([aria-current="page"]):hover {
    color: var(--texto);
  }
}

/* ── Locale switch ─────────────────────────────────────────────────────── */

.site-footer {
  display: flex;
  justify-content: center;
  padding: var(--space-4) var(--space-3) var(--space-6);
}

/* The hairline is decoration elsewhere; here it is the whole affordance, so
   the boundary takes --dim and clears the 3:1 non-text floor. */
.locale-switch {
  display: flex;
  gap: var(--space-1);
  padding: var(--space-2);
  background: var(--well);
  border: var(--border) solid var(--dim);
  border-radius: var(--radius-pill);
}

.locale-switch__option {
  min-height: var(--tap);
  padding-inline: var(--space-4);
  background: none;
  border: 0;
  border-radius: var(--radius-pill);
  color: var(--dim);
  font: 700 var(--text-micro) / 1 var(--font-data);
  letter-spacing: var(--track-micro);
  text-transform: uppercase;
  cursor: pointer;
  transition: color var(--motion) var(--ease);
}

.locale-switch__option[aria-current="true"] {
  background: var(--amarillo);
  color: var(--ink);
}

/* An amarillo ring on the amarillo fill reads as a halo, not a focus state. */
.locale-switch__option[aria-current="true"]:focus-visible {
  outline-color: var(--texto);
}

@media (hover: hover) {
  .locale-switch__option:not([aria-current="true"]):hover {
    color: var(--texto);
  }
}

/* ── Install prompt ────────────────────────────────────────────────────── */

.install-prompt {
  position: fixed;
  z-index: 1;
  inset-inline: var(--space-3);
  inset-block-end: var(--space-3);
  max-width: var(--shell);
  margin-inline: auto;
  border-color: var(--amarillo);
}

/* Fixed, so the page has to grow past the banner's tallest state or it buries
   the last log line of the fight it is congratulating. */
body:has(.install-prompt:not([hidden])) {
  padding-block-end: 15rem;
}

/* ── Icon ──────────────────────────────────────────────────────────────── */

/* IconHelper#icon is the only sanctioned glyph; shapes carry currentColor. */
.ic {
  flex: none;
  fill: none;
  vertical-align: -0.15em;
}
