/* App styles on top of µCSS. No inline styles: the CSP forbids them. */

/* µCSS dark theme pairs white text on hovered/focused buttons with #018cd4 (3.68:1). Use ≈5:1 blue.
   Its focused fields get a border and ring in the button navy (#052940, ≈1.3:1 on the page): use
   the primary blue (≈4.5:1) so the focused field stands out. */
[data-theme='dark'] {
  --mu-primary-hover-background: #0172ad;
  --mu-primary-hover-border: #0172ad;
  --mu-form-element-active-border-color: var(--mu-primary);
  --mu-form-element-focus-color: var(--mu-primary);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --mu-primary-hover-background: #0172ad;
    --mu-primary-hover-border: #0172ad;
    --mu-form-element-active-border-color: var(--mu-primary);
    --mu-form-element-focus-color: var(--mu-primary);
  }
}

/* On a dialog's panel (#1a1f28) the dark theme's blue (#018cd4) is 4.48:1: links and outline buttons
   there take a lighter one (≈4.7:1). */
[data-theme='dark'] dialog > article {
  --mu-primary: #0a90d8;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) dialog > article {
    --mu-primary: #0a90d8;
  }
}

/* µCSS light theme pairs white button text with #b7d9fc (1.46:1). Use its darker blue (≈5:1). */
[data-theme='light'] {
  --mu-primary-background: #0172ad;
  --mu-primary-hover-background: #02659a;
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme]) {
    --mu-primary-background: #0172ad;
    --mu-primary-hover-background: #02659a;
  }
}

.skip-link {
  position: absolute;
  left: 1rem;
  top: -100%;
  z-index: 100;
  padding: 0.5rem 1rem;
  background: var(--mu-background-color, Canvas);
  color: var(--mu-color, CanvasText);
}

.skip-link:focus {
  top: 1rem;
}

main:focus {
  outline: none;
}

/* sticky header: one row of a fixed height at every width, so the card search bar can stick
   right below it. Narrow screens fold the links into a popover menu to stay on one row. */
:root {
  --header-h: 3.5rem;
  /* the page's text colour, resolved here: inside buttons µCSS redefines --mu-color (white on red) */
  --page-text-color: var(--mu-color);
}

/* keep the element that gets focus (keyboard, skip link) out from under the sticky bars */
html {
  scroll-padding-top: calc(var(--header-h) + 1rem);
}

.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--mu-background-color);
  border-bottom: 1px solid var(--mu-muted-border-color);
}

/* main navigation, then the language and theme switches at the end of the bar */
.header-bar {
  display: flex;
  align-items: center;
  gap: 1rem;
  height: var(--header-h);
  white-space: nowrap;
}

.header-bar > nav:first-child {
  flex: 1;
  min-width: 0;
}

/* µCSS pulls the edge lists of a nav outwards (nav ul:first-child/:last-child) */
.header-bar nav ul {
  margin: 0;
}

.site-header nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.brand {
  font-weight: 700;
  text-decoration: none;
}

.brand-group {
  display: flex;
  align-items: baseline;
  gap: 0.375rem;
  min-width: 0;
}

.app-version {
  color: var(--mu-muted-color);
  font-size: 0.75rem;
  white-space: nowrap;
}

/* below 512px the version would run into the menu button */
@media (max-width: 32rem) {
  .app-version {
    display: none;
  }
}

.lang-switch {
  display: flex;
  gap: 0.75rem;
  list-style: none;
  margin: 0;
  padding: 0 0 0 1rem;
  border-inline-start: 1px solid var(--mu-muted-border-color, currentColor);
}

.lang-switch li {
  list-style: none;
  margin: 0;
  padding: 0;
}

.lang-switch a[aria-current] {
  font-weight: 700;
  text-decoration: none;
}

.header-tools {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

/* theme switch, notifications and feedback: icon buttons, the same frame as the menu button
   (.header-bar: outranks µCSS's button styles on the feedback button) */
.theme-switch a,
.notifications-link,
.header-bar .feedback-button {
  position: relative; /* holds the visually hidden name */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  margin: 0;
  padding: 0;
  color: inherit;
  background: transparent;
  border: 1px solid var(--mu-muted-border-color);
  border-radius: var(--mu-border-radius);
  text-decoration: none;
}

.theme-switch a:hover,
.notifications-link:hover,
.header-bar .feedback-button:hover {
  color: inherit;
  background: var(--mu-muted-border-color);
  border-color: var(--mu-muted-border-color);
}

.theme-switch a:focus-visible,
.notifications-link:focus-visible,
.header-bar .feedback-button:focus-visible {
  outline: 2px solid var(--page-text-color);
  outline-offset: 2px;
}

/* header navigation: a menu button and a popover list on narrow screens */

/* .header-bar: outranks µCSS's button colours */
.header-bar .menu-button {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  width: auto;
  margin: 0;
  padding: 0.375rem 0.75rem;
  color: inherit; /* µCSS redefines --mu-color on buttons */
  background: transparent;
  border: 1px solid var(--mu-muted-border-color);
}

.header-bar .menu-button:hover,
.header-bar .menu-button:focus-visible {
  color: inherit;
  background: var(--mu-muted-border-color);
  border-color: var(--mu-muted-border-color);
}

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

.nav-links li {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* µCSS gives nav lists a display, which would override the browser hiding a closed popover */
.nav-links:not(:popover-open) {
  display: none;
}

/* the open menu: a panel under the bar, ending at its right edge (µCSS's .container width, 1rem
   gutter on phones). The height and row alignment keep it as tall as its links even if a browser
   sets both top and bottom (iOS Safari 26 stretched it to the bottom of the screen) */
.nav-links {
  --container-w: 100%;
}

@media (min-width: 576px) {
  .nav-links {
    --container-w: 510px;
  }
}

@media (min-width: 768px) {
  .nav-links {
    --container-w: 700px;
  }
}

@media (min-width: 1024px) {
  .nav-links {
    --container-w: 950px;
  }
}

@media (min-width: 1280px) {
  .nav-links {
    --container-w: 1200px;
  }
}

.nav-links:popover-open {
  display: grid;
  align-content: start;
  inset: var(--header-h) max(1rem, (100% - var(--container-w)) / 2) auto auto;
  height: max-content;
  min-width: 12rem;
  max-width: min(16rem, 100% - 2rem); /* fits under the button at every width; long names get an ellipsis */
  margin: 0.25rem 0 0;
  padding: 0.5rem 0;
  color: var(--mu-color);
  background: var(--mu-background-color);
  border: 1px solid var(--mu-muted-border-color);
  border-radius: var(--mu-border-radius);
  box-shadow: 0 0.5rem 1.5rem rgb(0 0 0 / 0.2);
}

/* from 30rem (the labelled menu button) the panel fits under the button, starting at its left
   edge. No position-try fallbacks: phones keep the placement above, and iOS Safari 26 stretched
   the panel when it had fallbacks */
.header-bar .menu-button {
  anchor-name: --site-menu;
}

@media (min-width: 30.0625rem) {
  @supports (anchor-name: --a) {
    .nav-links:popover-open {
      position-anchor: --site-menu;
      left: anchor(left);
      right: auto;
    }
  }
}

/* full-width rows */
.header-bar .nav-links:popover-open :is(li, .inline-form) {
  display: grid;
}

.header-bar .nav-links:popover-open :is(a, .link-button, .nav-user) {
  margin: 0;
  padding: 0.625rem 1.25rem;
}

.header-bar .nav-links:popover-open .nav-user {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* phones: an icon-only menu button (it keeps its name for screen readers) and tighter gaps keep
   the bar on one row, with the language switch, the theme switch and (logged in) the bell */
@media (max-width: 30rem) {
  .header-bar .menu-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  .header-bar .menu-button {
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
  }

  .header-bar,
  .site-header nav {
    gap: 0.75rem;
  }

  .header-tools {
    gap: 0.5rem;
  }

  .lang-switch {
    gap: 0.5rem;
    padding-left: 0.5rem;
  }
}

/* feedback in the menu: narrow phones only (below) */
.nav-links .nav-feedback {
  display: none;
}

/* the smallest phones (320px): smaller icon buttons (still over 24px, WCAG 2.5.8) and brand */
@media (max-width: 22.5rem) {
  .header-bar,
  .site-header nav {
    gap: 0.5rem;
  }

  .header-tools {
    gap: 0.375rem;
  }

  .brand {
    font-size: 0.9375rem;
  }

  .header-bar .menu-button,
  .theme-switch a,
  .notifications-link {
    width: 2rem;
    height: 2rem;
  }
}

/* below 378px the feedback icon would squeeze the menu button: feedback moves into the menu */
@media (max-width: 23.625rem) {
  .header-bar .feedback-button {
    display: none;
  }

  .nav-links .nav-feedback {
    display: block;
  }
}

/* wide screens: no menu button, the links sit inline in the bar (app.js closes a menu left
   open when the window grows past this width). From 96rem (where µCSS widens the container) it is
   wide enough for every link, Invites included, in Polish with the longest username; below it, the menu */
@media (min-width: 96rem) {
  .header-bar .menu-button {
    display: none;
  }

  .nav-links[popover] {
    position: static;
    display: flex;
    align-items: center;
    gap: 1rem;
    inset: auto;
    width: auto;
    height: auto;
    overflow: visible;
    color: inherit;
    background: none;
    border: 0;
  }

  /* a long display name must not push the bar onto a second row */
  .nav-user {
    display: inline-block;
    max-width: 12rem;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: bottom;
  }
}

/* theme switch: offer only the theme that isn't active */
[data-theme='dark'] .theme-to-dark,
[data-theme='light'] .theme-to-light {
  display: none;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) .theme-to-dark {
    display: none;
  }
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme]) .theme-to-light {
    display: none;
  }
}

.nav-user {
  color: var(--mu-muted-color);
}

.inline-form {
  display: inline;
  margin: 0;
}

/* a <button> that looks like a link (e.g. logout, which must be a POST) */
.link-button {
  all: unset;
  box-sizing: border-box; /* all: unset resets it; padded menu rows would overflow the panel */
  cursor: pointer;
  color: var(--mu-primary);
  text-decoration: underline;
}

.link-button:focus-visible {
  outline: 2px solid var(--mu-primary-focus, currentColor);
  outline-offset: 2px;
}

/* page layout: main fills the space below the header */
.page {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
}

/* µCSS spaces only body > main; .page sits in between */
.page > main {
  padding-block: var(--mu-block-spacing-vertical);
}

main {
  flex: 1;
}

/* a page built around one form (<section class="form-page">): a narrow column centered
   below the header; taller than the screen, it scrolls normally */
main:has(> .form-page) {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.form-page {
  width: 100%;
  max-width: 28rem;
  margin-inline: auto;
}

/* forms */

.field {
  margin-bottom: var(--mu-block-spacing-vertical, 1rem);
}

.field :is(input, select, textarea) {
  margin-bottom: 0.25rem;
}

/* µCSS pulls a <small> after a control up into the control's (here smaller) bottom margin */
.field :is(input, select, textarea) + .field-error {
  margin-top: 0;
  margin-bottom: 0;
}

.field-hint {
  display: block;
  margin-bottom: 0.25rem;
  color: var(--mu-muted-color);
}

.field-error,
.form-error {
  display: block;
  color: var(--mu-error);
  font-weight: 600;
}

.form-notice {
  font-weight: 600;
}

/* card search */

/* µCSS lays out [role=search] as one inline row; here the card name (its label above the
   input + button group, role=group, which µCSS joins into one control) and the city sit side by side,
   stacked on phones. It sticks right below the sticky header while the results scroll under it. */
.search-form[role='search'] {
  position: sticky;
  top: var(--header-h);
  z-index: 5;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  margin-bottom: 0.5rem;
  padding-block: 0.75rem;
  background: var(--mu-background-color);
  border-radius: 0;
  box-shadow: none;
}

/* the focused element must also clear the search bar on the card search page */
html:has(.search-form) {
  scroll-padding-top: calc(var(--header-h) + 7.5rem);
}

/* phones: the city goes below the card name (.search-name and .search-city no longer fit side by side) */
@media (max-width: 33rem) {
  html:has(.search-form) {
    scroll-padding-top: calc(var(--header-h) + 12.5rem);
  }
}

/* side by side, the labels and the controls each share a line and a height: the controls fill what
   the labels leave */
.search-name,
.search-city {
  display: flex;
  flex-direction: column;
}

.search-name {
  flex: 3 1 18rem;
}

.search-city {
  flex: 1 1 12rem;
}

.search-row,
.search-form .search-city select {
  flex: 1 1 auto;
}

.search-form label {
  display: block;
  margin-bottom: 0.25rem;
}

/* µCSS joins every select in [role=search] to the control before it: this one stands alone, a pill
   like the name field */
.search-form .search-city select {
  margin: 0;
  border-radius: var(--mu-border-radius);
}

.search-row {
  margin-bottom: 0;
}

.card-count {
  color: var(--mu-muted-color);
}

/* tiles: 2 columns on phones, as many ~11rem columns as fit on wider screens (room for the controls
   on your own binder) */
.card-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(11rem, calc(50% - 0.5rem)), 1fr));
  /* every row as tall as the tallest, so all tiles have the same height */
  grid-auto-rows: 1fr;
  gap: 1.5rem 1rem;
}

.card-grid li {
  list-style: none;
  margin: 0;
}

/* a panel holding the art and its info. The art fills its width, so it is as large as without the
   panel; the edge is an inset outline like the art's, taking no room, and the text is padded */
.card-tile {
  display: grid;
  align-content: start;
  gap: 0.5rem;
  min-width: 0;
  padding-bottom: 0.5rem;
  background: var(--mu-card-background-color);
  border-radius: 0.5rem;
  outline: 1px solid var(--mu-muted-border-color);
  outline-offset: -1px;
  /* the art is never wider than the panel, even when the controls below don't fit */
  grid-template-columns: minmax(0, 1fr);
}

/* nothing below the art (card search, the home page): no strip of panel under it */
.card-tile:has(> .card-link:last-child, > .card-art:last-child) {
  padding-bottom: 0;
}

.card-tile > :not(.card-link, .card-art) {
  padding-inline: 0.5rem;
}

/* the bordered buttons need no inset of their own: more room for them on a phone */
.card-tile > .binder-actions {
  padding-inline: 0.25rem;
}

/* the art links to the printing's page; the solid ring follows the card's corners */
.card-link {
  display: block;
  border-radius: 4.5%/3.2%;
}

.card-link:focus-visible {
  outline: 2px solid var(--mu-primary);
  outline-offset: 2px;
}

/* portrait card shape; art of another shape is letterboxed, never cropped. The 1px border is an
   inset outline: it follows the rounded corners, draws over the art's edge and leaves the size
   alone. */
.card-art {
  position: relative;
  display: block;
  border-radius: 4.5%/3.2%;
  overflow: hidden;
  outline: 1px solid var(--mu-muted-border-color);
  outline-offset: -1px;
}

.card-art img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 744 / 1039;
  object-fit: contain;
}

/* battlefields: landscape art turned a quarter clockwise into the same portrait tile. The box keeps
   the card shape itself (the image is taken out of the flow), and the image is sized to the box
   swapped (its width is the box's height, and the other way round) before turning about its
   centre, so the art's left edge ends up at the top. */
.card-art--landscape {
  aspect-ratio: 744 / 1039;
}

.card-art--landscape img {
  position: absolute;
  top: 50%;
  left: 50%;
  width: calc(100% * 1039 / 744);
  max-width: none;
  height: calc(100% * 744 / 1039);
  aspect-ratio: auto;
  transform: translate(-50%, -50%) rotate(90deg);
}

/* With JS (app.js adds .img-fade to <html>): a card-shaped placeholder while the image loads,
   then the image fades in and the placeholder fades out. Without JS images show as they load. */
.img-fade .card-art {
  background-color: var(--mu-muted-border-color);
  transition: background-color 0.4s ease-out;
}

.img-fade .card-art img {
  opacity: 0;
  transition: opacity 0.25s ease-out;
}

.img-fade .card-art:has(img.is-loaded) {
  background-color: transparent;
}

.img-fade .card-art img.is-loaded {
  opacity: 1;
}

/* already loaded or from the browser cache (app.js): no animation */
.img-fade .card-art.no-fade,
.img-fade .card-art.no-fade img {
  transition: none;
}

@media (prefers-reduced-motion: reduce) {
  .img-fade .card-art,
  .img-fade .card-art img {
    transition: none;
  }
}

/* Foil and metal printings: a soft-light sheen over the art (lights a little lighter, darks a
   little darker, so the card is no brighter overall), and a softer band that keeps sweeping
   across. Decorative only: the finish is also named in a pill (.card-pill), or implied by the rarity
   (rares and above are foil). The band sits in the middle of a 300%-wide layer (see card-sheen for
   how far it travels). */
.card-art--foil::after,
.card-art--metal::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background-repeat: no-repeat;
  background-size:
    300% 100%,
    100% 100%;
  background-position:
    100% 0,
    0 0;
  mix-blend-mode: soft-light;
  opacity: 0.4;
}

.card-art--foil::after {
  background-image:
    linear-gradient(115deg, transparent 30%, hsl(200 100% 75% / 0.8) 45%, hsl(320 100% 75% / 0.8) 55%, transparent 70%),
    linear-gradient(
      125deg,
      hsl(0 100% 60%),
      hsl(55 100% 55%),
      hsl(130 90% 55%),
      hsl(190 100% 55%),
      hsl(250 100% 65%),
      hsl(310 100% 60%)
    );
}

.card-art--metal::after {
  background-image:
    linear-gradient(115deg, transparent 30%, rgb(255 255 255 / 0.6) 50%, transparent 70%),
    linear-gradient(125deg, #6b6b6b, #e0e0e0 25%, #8c8c8c 45%, #d6d6d6 70%, #707070);
}

.card-art--foil::after,
.card-art--metal::after {
  animation: card-sheen 3s ease-in-out infinite;
}

/* out of step, so neighbouring foils don't flash together */
.card-tile:nth-child(3n + 2) .card-art::after {
  animation-delay: -1s;
}

.card-tile:nth-child(3n + 3) .card-art::after {
  animation-delay: -2s;
}

/* The band is tilted, so its corners reach past the layer's 0 and 100% positions: it must travel
   beyond them (at least 128% and -28% for a portrait card) to be fully off the card at both ends.
   Then the first and last frames are the same and the loop has no jump. */
@keyframes card-sheen {
  from {
    background-position:
      130% 0,
      0 0;
  }
  to {
    background-position:
      -30% 0,
      0 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .card-art--foil::after,
  .card-art--metal::after {
    animation: none;
  }
}

/* with JS, the sheen waits for the image (see .img-fade above), then shows at full strength at once */
.img-fade .card-art:not(:has(img.is-loaded))::after {
  opacity: 0;
}

/* the card's name in the middle of a card back standing in for missing art; on a dark plate, like
   the pills, so it reads at AA contrast over any card back. It wraps, never wider than the card. */
.card-art-name {
  position: absolute;
  z-index: 1;
  top: 50%;
  left: 50%;
  translate: -50% -50%;
  width: max-content;
  max-width: calc(100% - 1.5rem);
  padding: 0.25rem 0.625rem;
  border-radius: 0.5rem;
  background: rgb(0 0 0 / 0.7);
  box-shadow: 0 0 0 1px rgb(255 255 255 / 0.25);
  color: #fff;
  font-weight: 700;
  line-height: 1.3;
  text-align: center;
  overflow-wrap: anywhere;
  pointer-events: none;
}

/* the traits (Foil, Alt art, Promo...), then on grid tiles the price and who has and wants the printing,
   as pills over the art's bottom-right corner, one per line, clear
   of the rounded corner and above the sheen. Dark in both themes: they sit on the art, not on the page,
   and the near-opaque fill keeps the white text at AA contrast over any art. Never wider than the art:
   a long name wraps rather than gets cut off by the art's overflow. */
.card-pills {
  position: absolute;
  z-index: 1;
  inset: auto 0.375rem 0.375rem;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.25rem;
  pointer-events: none;
}

.card-pill {
  max-width: 100%;
  padding: 0.0625rem 0.5rem;
  border-radius: 0.75rem;
  background: rgb(0 0 0 / 0.8);
  /* a faint ring sets the pill apart from dark art */
  box-shadow: 0 0 0 1px rgb(255 255 255 / 0.25);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.4;
  overflow-wrap: anywhere;
}

.card-text {
  display: grid;
  gap: 0.125rem;
  min-width: 0;
}

/* at most 2 lines, then an ellipsis (the full name stays in the DOM for screen readers). The clamp
   clips to the line boxes, so the line height must be taller than the font's own ascent plus descent
   (about 1.33em for Segoe UI, 1.36em for Noto Sans) or accents and descenders get cut off. */
.card-name {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  font-weight: 600;
  line-height: 1.45;
  overflow-wrap: anywhere;
}

.card-meta {
  color: var(--mu-muted-color);
  font-size: 0.8125rem;
  line-height: 1.35;
}

/* the collector number and the rarity always on two lines (grid items), never one in some tiles
   and two in others; a long number may still break, at any character, rather than overflow */
.card-code {
  display: grid;
  overflow-wrap: anywhere;
}

/* binder */

/* the tabs are a plain row, not a µCSS navbar: µCSS pads every `nav li` (20px above and below)
   and pulls the first and last `nav ul` out by 10px, which beats a single class */
nav ul.binder-sides,
nav ul.binder-overlap {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.5rem;
  margin: 0 0 1rem;
  padding: 0;
  list-style: none;
}

.binder-sides li,
.binder-overlap li {
  margin: 0;
  padding: 0;
  list-style: none;
}

.binder-sides a[aria-current],
.binder-overlap a[aria-current] {
  font-weight: 700;
  text-decoration: none;
}

/* Every part of a tile lines up across a row of tiles: each tile spans one grid row per part
   (art, with its price and who has and wants it as pills over it, then the quantity on a public binder
   or in matches, "players who want it" and the controls on your own binder, or the "Add" button in the
   add dialog's results) and shares those rows through subgrid, so a part that wraps in one tile moves
   the next part down in all of them. The "+" slot sits in the art row. */
.card-grid--aligned {
  grid-auto-rows: auto;
  /* the rows are shared, so their gap would also split a tile's parts: tiles keep their gap with
     padding below them instead, and their own row-gap spaces their parts */
  row-gap: 0;
  --tile-rows: 2;
}

.binder-grid--own {
  --tile-rows: 4;
}

/* a row more for a trade button under others' haves, one for held copies (views/binder.ejs) */
.binder-grid--trade,
.binder-grid--held {
  --tile-rows: 3;
}

.binder-grid--trade.binder-grid--held {
  --tile-rows: 4;
}

.binder-grid--own.binder-grid--held {
  --tile-rows: 5;
}

.card-grid--aligned > li {
  display: grid;
  grid-row: span var(--tile-rows);
  grid-template-rows: subgrid;
  row-gap: 0.125rem;
  margin-bottom: 1rem;
}

/* the parts below the art are spaced a little further apart than the tile's tight row-gap */
.card-grid--aligned .card-tile > :not(.card-link, .card-art) {
  margin-top: 0.375rem;
}

.binder-status {
  min-height: 1.5em;
  color: var(--mu-muted-color);
}

/* the status under the tabs keeps its line even when empty, so a message never pushes the tiles
   (and the button just pressed) down; it sits in the tabs' bottom spacing instead of adding a
   paragraph margin of its own */
#binder-sides + .binder-status {
  margin: -0.5rem 0 0.5rem;
}

.binder-others,
.card-tile p.binder-qty {
  margin: 0;
  font-size: 0.875rem;
  color: var(--mu-muted-color);
}

/* a logged-in visitor on someone else's binder: how many cards meet their own binder, each count
   showing only those cards (a row like the tabs, see above, in a box) */
nav ul.binder-overlap {
  padding: 0.75rem 1rem;
  border: 1px solid var(--mu-muted-border-color);
  border-radius: var(--mu-border-radius);
}

/* − quantity + and the bin on one row, even in a two-column grid on a 360px phone (tiles ~9.5rem):
   2.25rem (36px) square icon buttons; the bin sits apart at the end against mis-taps */
.binder-actions {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  margin: 0;
}

.binder-actions button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  min-width: 2.25rem;
  min-height: 2.25rem;
  margin: 0;
  padding: 0.25rem;
}

.binder-actions svg {
  flex: none;
}

/* µCSS's focus ring is a faint translucent shadow: a solid outline is visible on both themes */
.binder-actions button:focus-visible {
  outline: 2px solid var(--mu-primary);
  outline-offset: 2px;
}

.binder-actions button[aria-disabled='true'] {
  opacity: 0.5;
  cursor: not-allowed;
}

.binder-actions .binder-qty {
  min-width: 1.5rem;
  text-align: center;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.binder-actions .binder-remove {
  margin-inline-start: auto;
}

.binder-actions .binder-add-result {
  padding-inline: 0.75rem 1rem;
}

/* "Also take" on your wants: a row of its own under the language, a dropdown like it (.binder-language)
   of the other printings the want can take; the box in each gets a tick when on (the state isn't the
   colour alone), and the border the link colour */
.binder-grid--own-want {
  --tile-rows: 5;
}

.binder-language .binder-alt-toggle {
  display: flex;
  align-items: center;
  gap: 0.375rem;
}

.binder-alt-toggle svg {
  flex: none;
}

.binder-language .binder-alt-toggle[aria-pressed='true'] {
  border-color: var(--mu-primary);
}

/* "Also takes: Foil" or "This printing only" on someone's want, on its own line under the quantity */
.binder-any,
.binder-exact {
  display: block;
  font-weight: 600;
}

/* the language of someone's entry, on its own line under the quantity */
.binder-lang {
  display: block;
}

/* the language of your entry: a full-width row of its own under − quantity + and the bin, a dropdown
   (µCSS) of the other languages that opens over the tiles below */
.card-tile > .binder-language {
  display: block;
  margin-bottom: 0;
  padding-inline: 0.25rem;
}

details.dropdown.binder-language > summary:not([role]) {
  display: flex;
  align-items: center;
  height: auto;
  min-height: 2.25rem;
  padding: 0.25rem 0.5rem;
  font-size: 0.875rem;
  color: inherit;
}

details.dropdown.binder-language > summary::after {
  margin-inline-start: auto;
}

.binder-language > summary:focus-visible {
  outline: 2px solid var(--mu-primary);
  outline-offset: 2px;
}

.binder-language > summary + ul li {
  padding: 0.125rem 0.25rem;
}

.binder-language form,
.binder-language button {
  width: 100%;
  margin: 0;
}

.binder-language button {
  min-height: 2.25rem;
  padding: 0.25rem 0.5rem;
  font-size: 0.875rem;
  text-align: start;
  white-space: normal;
}

.binder-language button:focus-visible {
  outline: 2px solid var(--mu-primary);
  outline-offset: 2px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* the empty slot at the end: card-shaped, dashed */
.binder-add-button {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  width: 100%;
  aspect-ratio: 744 / 1039;
  margin: 0;
  border-style: dashed;
  border-radius: 4.5%/3.2%;
}

.binder-add-button span {
  font-size: 2.5rem;
  line-height: 1;
}

/* wider than µCSS's default panel: room for a few columns of results. Only the results scroll,
   so the title, Close and the search stay in view and nothing (not even a focused tile) can
   slide under them. */
.add-dialog > article {
  display: flex;
  flex-direction: column;
  max-width: min(56rem, calc(100vw - 2rem));
  max-height: calc(100dvh - 2rem);
  padding-bottom: 0;
  overflow: hidden;
}

.add-dialog > article > :not(#add-results, .dialog-results) {
  flex: none;
}

/* reaches the panel's edges, so the scrollbar sits there and focus rings aren't clipped */
#add-results,
.dialog-results {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  margin-inline: calc(var(--mu-block-spacing-horizontal) * -1);
  padding: 0.25rem var(--mu-block-spacing-horizontal) var(--mu-block-spacing-vertical);
}

/* too short for fixed parts (phones in landscape): the whole panel scrolls */
@media (max-height: 30rem) {
  .add-dialog > article {
    display: block;
    overflow: auto;
    padding-bottom: var(--mu-block-spacing-vertical);
  }

  #add-results,
  .dialog-results {
    overflow: visible;
    margin-inline: 0;
    padding: 0.25rem 0 0;
  }
}

/* as on the card search page: the label above the input + button group, not inline */
.add-search[role='search'] {
  display: block;
  margin-bottom: 0.5rem;
  border-radius: 0;
  box-shadow: none;
}

.add-search > label {
  display: block;
  margin-bottom: 0.25rem;
}

/* "Also take foil and promo versions" (wants): clear of the language select above and the card name label below */
.add-search > .add-any {
  margin-block: 0.5rem 0.75rem;
}

.add-dialog .card-count,
.add-dialog .binder-status {
  margin-bottom: 0.25rem;
}

.add-dialog-head,
.dialog-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.add-dialog-head h2,
.dialog-head h2 {
  margin: 0;
}

.add-dialog-head button,
.dialog-head button {
  margin: 0;
}

/* feedback (views/partials/feedback.ejs), opened from the header */
.feedback-dialog > article {
  width: min(36rem, calc(100vw - 2rem));
  max-height: calc(100dvh - 2rem);
  overflow: auto;
}

.feedback-form textarea {
  resize: vertical;
}

/* focused after a swap (app.js) only so the result is read out: no ring around the whole form */
#feedback-body:focus {
  outline: none;
}

.account-details dd {
  margin: 0 0 0.75rem;
}

/* destructive actions (account deletion): µCSS's .btn-error, but the same reds in both themes, so
   the white text keeps ≥4.5:1 (µCSS's dark red is 3.9:1, its dark hover 2.4:1), and a solid focus
   ring in the page's text colour instead of the translucent blue one: near black or near white,
   it stands out on any background */
.btn-error {
  background-color: #c52f21; /* 5.5:1 with white */
  border-color: #c52f21;
}

.btn-error:is(:hover, :active) {
  background-color: #9e2519; /* 7.6:1 with white */
  border-color: #9e2519;
}

button.btn-error:focus {
  --mu-box-shadow: none;
}

.btn-error:focus-visible {
  outline: var(--mu-outline-width) solid var(--page-text-color);
  outline-offset: 2px;
}

/* binder freshness: "still current" and stale binders */

.binder-fresh {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  margin-bottom: 1rem;
  padding: 0.75rem 1rem;
  border: 1px solid var(--mu-muted-border-color);
  border-radius: var(--mu-border-radius);
}

.binder-fresh p {
  flex: 1 1 20rem;
  margin: 0;
}

.binder-fresh button {
  width: auto;
  margin: 0;
}

.binder-fresh--stale {
  border-color: var(--mu-error, currentColor);
  border-width: 2px;
}

.binder-stale {
  font-weight: 600;
}

/* prices */

/* the price below the art on the printing's page (elsewhere a pill over the art) */
.card-stats {
  display: grid;
  margin: 0;
  font-variant-numeric: tabular-nums;
}

/* the amount never breaks */
.card-price [aria-hidden] {
  white-space: nowrap;
}

/* the link to Cardmarket: a 24px tall target (WCAG 2.2) */
.card-price a {
  display: inline-block;
  padding-block: 0.25rem;
}

/* the price, then the button explaining it */
.card-price {
  display: flex;
  align-items: center;
  gap: 0.125rem;
}

/* .card-price: outranks µCSS's button styles. A 24px target (WCAG 2.2), muted like the price */
.card-price .price-info-button {
  display: inline-grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  margin: 0;
  padding: 0;
  color: inherit;
  background: transparent;
  border: 0;
  border-radius: 50%;
}

.card-price .price-info-button:hover,
.card-price .price-info-button:focus-visible,
.card-price .price-info-button:has(+ :popover-open) {
  color: var(--mu-color);
  background: var(--mu-muted-border-color);
}

/* the explanation, a popover; without anchor positioning, in the middle of the screen */
.price-info:popover-open {
  max-width: min(18rem, 100vw - 2rem);
  padding: 0.5rem 0.75rem;
  color: var(--mu-color);
  background: var(--mu-background-color);
  border: 1px solid var(--mu-muted-border-color);
  border-radius: var(--mu-border-radius);
  box-shadow: 0 0.5rem 1.5rem rgb(0 0 0 / 0.2);
  font-size: 0.875rem;
  white-space: normal;
}

/* with anchor positioning: under its button (the popover's anchor), starting at the button's left
   edge; where it doesn't fit there, ending at its right edge, then above, then centred under it */
@supports (position-area: bottom) {
  .price-info:popover-open {
    position-area: bottom span-right;
    position-try-fallbacks:
      flip-inline,
      flip-block,
      flip-block flip-inline,
      bottom;
    min-width: min(14rem, 100vw - 2rem);
    margin: 0.25rem;
  }
}

/* contact details on a binder */

.binder-contact p {
  white-space: pre-line;
  overflow-wrap: anywhere;
}

.binder-contact h2 {
  font-size: 1.125rem;
  margin-bottom: 0.25rem;
}

/* "Show contact details": a button its own width under the heading */
.binder-contact button {
  width: auto;
  margin: 0.25rem 0 1rem;
}

/* lists of binders, with filters (binders, matches) */

/* filters above lists (binders, matches): one row on wide screens, stacked on phones */
.filter-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem 1rem;
  margin-bottom: 1.5rem;
}

.filter-form > div {
  flex: 1 1 12rem;
}

.filter-form :is(input, select, button) {
  margin-bottom: 0;
}

/* µCSS makes search inputs pill-shaped: keep them the same shape as the selects and buttons */
.filter-form [type='search'] {
  --mu-border-radius: inherit;
}

.filter-form button {
  width: auto;
}

/* binders as rows: name, city, counts, date; wrapping on phones */
.binder-list {
  padding: 0;
  list-style: none;
}

.binder-list li {
  display: grid;
  grid-template-columns: minmax(8rem, 2fr) minmax(6rem, 1fr) minmax(10rem, 2fr) minmax(10rem, 2fr);
  gap: 0.25rem 1rem;
  margin: 0;
  padding: 0.625rem 0;
  list-style: none;
  border-bottom: 1px solid var(--mu-muted-border-color);
}

@media (max-width: 40rem) {
  .binder-list li {
    grid-template-columns: 1fr 1fr;
  }
}

.binder-list-name {
  font-weight: 600;
  overflow-wrap: anywhere;
}

.binder-list-date {
  color: var(--mu-muted-color);
}

.pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  margin-top: 1rem;
}

/* notifications */

/* the unread count on the bell's top right corner: white on the darker primary blue (≈5:1), the
   same in both themes */
.notifications-link .nav-count {
  position: absolute;
  top: -0.5rem;
  right: -0.5rem;
  min-width: 1.25rem;
  padding: 0 0.3125rem;
  border-radius: 1em;
  background: #0172ad;
  color: #fff;
  font-size: 0.75rem;
  font-weight: 700;
  line-height: 1.25rem;
  text-align: center;
}

.notifications-link[aria-current] {
  background: var(--mu-muted-border-color);
}

/* the notifications page: a list of messages, the unread ones marked with a bar */
.notifications-page {
  max-width: 44rem;
}

.notification-list {
  margin: 1.5rem 0;
  padding: 0;
  list-style: none;
}

.notification {
  margin: 0 0 1rem;
  padding: 0.875rem 1rem;
  list-style: none;
  border: 1px solid var(--mu-muted-border-color);
  border-radius: var(--mu-border-radius);
}

.notification--unread {
  /* a shadow, not a border: the text lines up with the read ones */
  box-shadow: inset 0.25rem 0 0 #0172ad;
}

.notification-title {
  margin: 0;
  font-size: 1.125rem;
}

.notification-meta {
  margin: 0.25rem 0 0.5rem;
  color: var(--mu-muted-color);
  font-size: 0.875rem;
}

.notification-new {
  margin-right: 0.5rem;
  color: var(--page-text-color);
}

/* the description's line breaks are kept (e.g. one card per line) */
.notification-description {
  margin: 0;
  white-space: pre-line;
}

/* matches */

.match-list {
  margin-bottom: 2.5rem;
}

.match {
  margin: 0 0 1.5rem;
  padding: 1rem;
}

.match h3 {
  margin: 0;
}

.match-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.5rem;
  margin: 0.25rem 0 0.75rem;
  color: var(--mu-muted-color);
}

/* who has and wants a printing */

/* one printing: its tile beside who has and wants it */
.printing-layout {
  display: grid;
  gap: 1.5rem;
}

@media (min-width: 40rem) {
  .printing-layout {
    grid-template-columns: 14rem 1fr;
    align-items: start;
  }
}

.card-grid.printing-tile {
  grid-template-columns: 1fr;
  max-width: 14rem;
}

/* text import */

.binder-sides .binder-import-link {
  margin-inline-start: auto;
}

.import-lines {
  padding: 0;
  list-style: none;
}

.import-lines li {
  list-style: none;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--mu-muted-border-color);
}

.import-lines li > span {
  display: block;
}

.import-line-text,
.import-lines label {
  font-family: var(--mu-font-family-monospace, monospace);
  overflow-wrap: anywhere;
}

.import-form fieldset label {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  margin-inline-end: 1.5rem;
}

.import-edit {
  margin: 2rem 0 1rem;
}

/* sharing your binder */

.binder-share {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  margin-bottom: 1rem;
}

.binder-share p {
  margin: 0;
}

.binder-share .binder-status {
  flex-basis: 100%;
  min-height: 0;
}

.binder-share a {
  overflow-wrap: anywhere;
}

/* home page */

/* the heading, lead and calls to action beside the playmat on wide screens; the playmat below them
   on phones */
.home-hero {
  display: grid;
  gap: 1.5rem 3rem;
  align-items: center;
  margin-bottom: 2.5rem;
}

@media (min-width: 48rem) {
  .home-hero {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
}

.home-intro > :last-child {
  margin-bottom: 0;
}

.home-lead {
  font-size: 1.125rem;
  color: var(--mu-muted-color);
}

.home-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.home-actions a {
  margin: 0;
}

/* white on blue that passes in both themes: µCSS fills .btn-primary with the link colour (3.68:1 in
   the dark theme), and its light --mu-primary-background (1.46:1) outranks the override at the top */
.home-hero,
.home-steps {
  --home-fill: #0172ad;
  --home-fill-hover: #02659a;
}

.home-actions .btn-primary:not(.btn-outline) {
  background-color: var(--home-fill);
  border-color: var(--home-fill);
}

.home-actions .btn-primary:not(.btn-outline):hover {
  background-color: var(--home-fill-hover);
  border-color: var(--home-fill-hover);
}

/* its own dark mat in both themes; the light theme adds a thin edge so it sits on the page. The radius
   is the SVG's (24 of 600x420) */
.home-art {
  display: block;
  width: 100%;
  max-width: 36rem;
  height: auto;
  justify-self: center;
  border-radius: 4% / 5.714%;
}

[data-theme='light'] .home-art {
  outline: 1px solid var(--mu-muted-border-color);
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme]) .home-art {
    outline: 1px solid var(--mu-muted-border-color);
  }
}

/* three numbered steps: stacked on phones, side by side from tablets up */
.home-steps {
  margin-bottom: 2.5rem;
}

.home-steps ol {
  display: grid;
  gap: 0.75rem 1rem;
  margin: 0;
  padding: 0;
  counter-reset: step;
}

.home-steps li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.75rem;
  align-items: start;
  margin: 0;
  padding: 1rem;
  list-style: none;
  counter-increment: step;
  border: 1px solid var(--mu-muted-border-color);
  border-radius: var(--mu-border-radius);
}

@media (min-width: 48rem) {
  .home-steps ol {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.home-steps li::before {
  content: counter(step);
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  font-weight: 700;
  color: #fff;
  background: var(--home-fill);
}

.home-latest {
  margin-bottom: 2rem;
}

/* six tiles fill whole rows: 2 columns on phones, 3 on tablets and laptops, 6 where each stays about
   11rem wide (the width card-tile.ejs sizes its images for) */
@media (min-width: 40rem) {
  .home-latest .card-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (min-width: 75rem) {
  .home-latest .card-grid {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
}

/* a trade: the cards each side gives (two columns from 60rem), cash and place, the actions, the chat */
.trade {
  max-width: 60rem;
}

.trade-back {
  margin-bottom: 0.5rem;
}

.trade-status {
  font-weight: 600;
}

.trade-held,
.trade-hint,
.trade-none {
  color: var(--mu-muted-color);
}

.trade-sides {
  display: grid;
  gap: 0 2rem;
  margin-bottom: 1rem;
}

@media (min-width: 60rem) {
  .trade-sides {
    grid-template-columns: 1fr 1fr;
  }
}

.trade-side h2,
.trade-terms h2 {
  font-size: 1.25rem;
  margin-bottom: 0.75rem;
}

/* a card as a row: small art, the text, and the controls at the end (below on narrow screens) */
.trade-items {
  margin: 0 0 1rem;
  padding: 0;
  list-style: none;
}

.trade-item {
  display: grid;
  grid-template-columns: 3rem minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.5rem 0.75rem;
  margin: 0;
  padding: 0.5rem 0;
  list-style: none;
  border-bottom: 1px solid var(--mu-muted-border-color);
}

.trade-item-art {
  width: 3rem;
  height: auto;
  border-radius: 0.25rem;
}

.trade-item-text {
  display: grid;
  min-width: 0;
  overflow-wrap: anywhere;
}

.trade-item-name {
  font-weight: 600;
}

/* the offer form: "No cards." until a card is added (from a picker, without a page load) */
.trade-side:has(.trade-item) .trade-none {
  display: none;
}

/* "Add" in a picker: a plain button, the same in a form of its own (a trade) or not (the offer form) */
.trade-item-pick,
.trade-item-pick button,
.trade-item > button {
  margin: 0;
}

/* "Add cards from …", opening a picker: as wide as its text */
.trade-side button {
  width: auto;
}

/* the pickers: a heading as the sides', so a long name fits beside "Done" on phones */
.trade-pick-dialog .add-dialog-head h2 {
  font-size: 1.25rem;
}

.trade-terms-list {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 0.25rem 1rem;
}

.trade-terms-list dd {
  margin: 0;
  overflow-wrap: anywhere;
}

/* the summary is the way to the form: in the link colour (µCSS mutes it, below 4.5:1 in dark mode) */
.trade-terms-edit > summary:not([role]) {
  color: var(--mu-primary);
  font-weight: 600;
}

.trade-terms-edit fieldset label {
  display: block;
}

.trade-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  margin: 1.5rem 0;
}

.trade-actions form,
.trade-actions p {
  margin: 0;
}

/* as wide as its text, like the buttons in the forms beside it (the offer form's send) */
.trade-actions > button {
  width: auto;
  margin: 0;
}

/* the unread count after a menu link's text (Trades), like the bell's */
.nav-badge {
  display: inline-block;
  min-width: 1.25rem;
  margin-inline-start: 0.375rem;
  padding: 0 0.3125rem;
  border-radius: 1em;
  background: #0172ad;
  color: #fff;
  font-size: 0.75rem;
  font-weight: 700;
  line-height: 1.25rem;
  text-align: center;
  vertical-align: 0.125em;
}

/* the chat: the other user's messages on the left, yours on the right, system lines in between */
.trade-chat {
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: 1px solid var(--mu-muted-border-color);
}

.chat-list {
  display: grid;
  gap: 0.75rem;
  margin: 0 0 1rem;
  padding: 0;
  list-style: none;
}

.chat-msg {
  margin: 0;
  list-style: none;
}

.chat-msg p {
  margin: 0;
}

.chat-msg--mine,
.chat-msg--theirs {
  max-width: min(36rem, 85%);
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--mu-muted-border-color);
  border-radius: var(--mu-border-radius);
}

.chat-msg--mine {
  justify-self: end;
  background: var(--mu-card-background-color);
}

.chat-meta {
  color: var(--mu-muted-color);
  font-size: 0.8125rem;
}

.chat-meta strong {
  margin-right: 0.375rem;
  color: var(--page-text-color);
}

/* line breaks kept; long words and links break rather than widen the page */
.chat-body {
  white-space: pre-line;
  overflow-wrap: anywhere;
}

.chat-msg--event {
  color: var(--mu-muted-color);
  font-size: 0.875rem;
  text-align: center;
}

.chat-msg--event time {
  white-space: nowrap;
}

.chat-form textarea {
  resize: vertical;
}

/* "Start a trade": a button on its own line (binder header, card page rows, matches) */
.start-trade {
  margin: 0.5rem 0;
}

/* as wide as its text (µCSS stretches buttons in some containers), but on a tile: the tile's width */
.start-trade button {
  width: auto;
}

.card-tile > .start-trade button {
  width: 100%;
  margin: 0;
  padding: 0.375rem 0.5rem;
  font-size: 0.875rem;
}

/* your haves: every copy held for a trade, the art dimmed (the badge below says why) */
/* the art dimmed, not its pills (they keep their contrast) */
.card-tile--held .card-art img,
.card-tile--held .card-art::after {
  filter: opacity(0.45);
}

.binder-held {
  margin: 0;
  font-size: 0.875rem;
  font-weight: 600;
}

.binder-held-total {
  color: var(--mu-muted-color);
}

/* your invite links (/invites): aligned with the text, each under a heading with its number and status */
.invite-list {
  margin: 1.5rem 0;
  padding: 0;
  list-style: none;
}

.invite-list > li {
  margin-bottom: 1.5rem;
  list-style: none;
}

.invite-list h2 {
  margin-bottom: 0.5rem;
  font-size: 1.125rem;
}

/* share and revoke side by side, wrapping on narrow screens */
.invite-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
}

.invite-actions :is(button, form) {
  flex: 1 1 12rem;
  margin: 0;
}

/* the revoke button as tall as the share button beside it, should either wrap */
.invite-actions form {
  display: flex;
}

.invite-actions form button {
  width: 100%;
}

.invite-list .share-status {
  margin: 0.5rem 0 0;
}

.invite-list .share-status:empty {
  display: none;
}

/* the merge dialog (trade's merge-dialog.ejs): the cards scroll, the buttons below them stay */
.merge-dialog > article {
  padding-bottom: var(--mu-block-spacing-vertical);
}

.merge-dialog .trade-actions {
  margin: 0;
}
