/*
 * Propshaft makes all the assets from all the paths it's been configured
 * available for serving and will copy all of them into public/assets when
 * precompiling. This is unlike Sprockets, which did not copy over assets
 * that hadn't been explicitly included in one of the bundled assets.
 *
 * Propshaft will automatically convert asset references in CSS to use the
 * digested file names. So, for example, a background url pointing to
 * "/bg/pattern.svg" will be converted to "/assets/bg/pattern-2169cbef.svg"
 * before the stylesheet is served.
 *
 * You're free to add application-wide styles to this file and they'll appear
 * at the bottom of the file order and take precedence over styles defined in
 * any other CSS files in this directory. It is generally better to create a
 * new file per style scope (and @import it here, apparently).
 */

/**
  * A fix for viewport units on mobile.
  * @see  https://stackoverflow.com/a/75648985
  */
.svh-100 {
  height: 100vh; /* Fallback for browsers that don't support "svh" units. */
  height: 100svh;
}

/**
  * An icon beside a block of text is centered on the whole block by default,
  * which reads as off once the block runs to more than one line: the icon
  * drifts away from the sentence it marks. Font Awesome sets line-height: 1
  * on its icons, so give the icon the line height of the small text beside
  * it, and a flex row that starts its items will center it on the first line.
  *
  * The selector names the element on purpose. Font Awesome's kit injects its
  * stylesheet at runtime, after this one, so a bare class would lose the tie
  * with .fa-solid on source order.
  */
i.lh-small-text {
  line-height: calc(0.875rem * 1.5); /* .small's size at the body's line height. */
}

/**
  * Font Awesome's fa-lg collapses an icon's line height to .05em and nudges
  * its baseline down, which drops the icon to the bottom of a button instead
  * of centering it there. Restore the button's own line height and baseline,
  * so an icon button lines up with its neighbors.
  *
  * The selector names the element for the same reason as above.
  */
i.lh-button-icon {
  line-height: 1.5;
  vertical-align: baseline;
}

/**
  * A card's art is a fixed square flush down its left edge, which sets the
  * card's height and shows the whole image. A card whose text runs longer
  * crops the art's sides around its center.
  */
.card-art {
  align-self: stretch;
  aspect-ratio: 1;
  border-bottom-left-radius: var(--bs-card-inner-border-radius);
  border-top-left-radius: var(--bs-card-inner-border-radius);
  flex-shrink: 0;
  height: auto;
  object-fit: cover;
  object-position: center;
  width: 10rem;
}

/**
  * Art across the top of a card, square and full width.
  */
.card-art-top {
  aspect-ratio: 1;
  object-fit: cover;
}

/**
  * Cuts text off with an ellipsis after three lines, so a long description
  * can't grow its card past the art.
  */
.line-clamp-3 {
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  display: -webkit-box;
  line-clamp: 3;
  overflow: hidden;
}

/**
  * A missing cursor option.
  */
.cursor-help {
  cursor: help;
}

/**
  * Invisible borders still take up space but are not visible. This can
  * be helpful for vertically centering components by adding borders in
  * pairs (e.g., a visible border-top and a border-bottom-invisible).
  */
.border-top-invisible {
  padding-top: 1px;
}

.border-bottom-invisible {
  padding-top: 1px;
}

/**
  * A stat pill (a player's approval, money, economy, or forests count) can
  * render as either an inert span or an actionable button, and its value can
  * be one or two digits. Without a fixed minimum width, those differences
  * shift every pill after it, making the values hard to scan down a column.
  */
.stat-pill {
  --bs-btn-padding-x: 0.25rem;
  min-width: 3.25rem;
}

/**
  * These styles help create radio-button list-groups.
  * @see https://getbootstrap.com/docs/5.3/examples/list-groups/
  * @see https://getbootstrap.com/docs/5.3/examples/list-groups/list-groups.css
  */
.form-check-input:checked + .form-checked-content {
  opacity: 0.5;
}

.form-check-input-placeholder {
  border-style: dashed;
}
[contenteditable]:focus {
  outline: 0;
}

.list-group-checkable .list-group-item {
  cursor: pointer;
}

.list-group-item-check {
  position: absolute;
  clip: rect(0, 0, 0, 0);
}

.list-group-item-check:hover + .list-group-item {
  background-color: var(--bs-secondary-bg);
}

.list-group-item-check:checked + .list-group-item,
.list-group-item-check:checked + .list-group-item .card,
label.list-group-item:has(input[type="checkbox"]:checked) .card,
label.list-group-item:has(input[type="radio"]:checked) .card {
  border-color: var(--bs-primary);
  background-color: var(--bs-primary-bg-subtle) !important;
}

.list-group-item-check[disabled] + .list-group-item,
.list-group-item-check:disabled + .list-group-item {
  pointer-events: none;
  filter: none;
  opacity: 0.5;
}

.list-group-radio .list-group-item {
  cursor: pointer;
  border-radius: 0.5rem;
}
.list-group-radio .form-check-input {
  z-index: 2;
  margin-top: -0.5em;
}
.list-group-radio .list-group-item:hover,
.list-group-radio .list-group-item:focus {
  background-color: var(--bs-secondary-bg);
}

.list-group-radio .form-check-input:checked + .list-group-item {
  background-color: var(--bs-body);
  border-color: var(--bs-primary);
  box-shadow: 0 0 0 2px var(--bs-primary);
}
.list-group-radio .form-check-input[disabled] + .list-group-item,
.list-group-radio .form-check-input:disabled + .list-group-item {
  pointer-events: none;
  filter: none;
  opacity: 0.5;
}

/* A row of radio buttons whose labels are stars: outlined until lit, solid
 * after. A star is lit if it's the checked (or hovered) one, or if the checked
 * (or hovered) one comes after it. */
.star-rating {
  display: inline-flex;
  font-size: 2rem;
}
.star-rating label {
  color: var(--bs-secondary-color);
  cursor: pointer;
  padding: 0 0.2rem 0 0;
}
.star-rating .star-on {
  display: none;
}
.star-rating input:checked + label,
.star-rating label:has(~ input:checked),
.star-rating label:hover,
.star-rating label:has(~ label:hover) {
  color: var(--bs-warning);
}
.star-rating input:checked + label .star-off,
.star-rating label:has(~ input:checked) .star-off,
.star-rating label:hover .star-off,
.star-rating label:has(~ label:hover) .star-off {
  display: none;
}
.star-rating input:checked + label .star-on,
.star-rating label:has(~ input:checked) .star-on,
.star-rating label:hover .star-on,
.star-rating label:has(~ label:hover) .star-on {
  display: inline-block;
}
.star-rating input:focus-visible + label {
  outline: 2px solid var(--bs-primary);
  outline-offset: 2px;
  border-radius: 0.25rem;
}

/* Bootstraps spinner has no chill. */
.spinner-slow {
  --bs-spinner-animation-speed: 2.5s;
}

/* Without this, a <turbo-frame> wrapping several <div class="col-*">s
 * becomes the flex item itself and breaks the grid. */
turbo-frame {
  display: contents;
}

/**
 * On medium and larger devices, we want the game to function as three
 * columns that scroll.
 */
@media (min-width: 768px) {
  .overflow-md-hidden {
    overflow: hidden;
  }

  .h-md-screen {
    height: 100%;
    overflow: hidden;
    overflow-y: scroll;
  }

  .h-md-100 {
    height: 100%;
  }

  .svh-md-100 {
    height: 100vh; /* Fallback for browsers that don't support "svh" units. */
    height: 100svh;
  }
}

/**
 * Reserve space for Font Awesome icons before the kit's webfont arrives.
 *
 * The kit is loaded from a CDN, and an `i.fa-*` has no content of its own.
 * Until the font lands, every icon is a 0x0 box. The navbar, whose only
 * content is the brand icon, collapses from 57px to 27px, and everything
 * below it sits 30px too high.
 *
 * That's a layout shift for real users; and, in system tests, it's a race.
 * Capybara measures an element, then clicks its coordinates. If the font
 * lands in between, the click lands 30px above the target, and the test
 * fails somewhere far away from the cause.
 */
i[class*="fa-"] {
  display: inline-block;
  min-width: 1em;
  min-height: 1em;
}

/**
  * On extra large devices, the hero's text and cards sit side by side and fill
  * the first screen below the navbar, so they center in what a visitor sees.
  * Below that, the cards stack under the text.
  */
@media (min-width: 1200px) {
  .hero {
    max-width: 90rem;
    min-height: calc(100svh - 3.5625rem);
  }
}

/**
  * A table of cards strewn across the hero. Each card sits at the table's
  * center, then is moved, turned, and sprayed out to its own pose, which the
  * card sets with --x, --y, --r, and --i (its order). The table's --spread
  * pulls the poses in on narrow screens, so the fan fits the screen.
  */
.hero-cards {
  --spread: 0.25;

  height: 28rem;
  position: relative;
  scale: 0.85;
}

@media (min-width: 576px) {
  .hero-cards {
    --spread: 0.6;
  }
}

@media (min-width: 768px) {
  .hero-cards {
    --spread: 1;
  }
}

@media (min-width: 1200px) {
  .hero-cards {
    height: 34rem;
  }
}

@media (min-width: 1400px) {
  .hero-cards {
    scale: 1;
  }
}

.hero-card {
  animation: hero-card-spray 800ms cubic-bezier(0.22, 1, 0.36, 1) calc(var(--i) * 120ms) backwards;
  aspect-ratio: 5 / 7;
  left: 50%;
  position: absolute;
  rotate: var(--r);
  top: 50%;
  transition: rotate 200ms ease-out, scale 200ms ease-out;
  translate: calc(-50% + var(--x) * var(--spread)) calc(-50% + var(--y));
  width: 17rem;
}

.hero-card:hover,
.hero-card:focus {
  rotate: 0deg;
  scale: 1.1;
  z-index: 10;
}

@keyframes hero-card-spray {
  from {
    opacity: 0;
    rotate: 0deg;
    scale: 0.5;
    translate: -50% -50%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero-card {
    animation: none;
    transition: none;
  }
}

/**
  * A scroller that shades the edge where more content is hiding. The "local"
  * layers scroll with the content and mask the "scroll" shadows beneath them,
  * so a shadow shows only on an edge the list can still scroll toward.
  */
.scroll-shadows {
  background:
    linear-gradient(var(--bs-light) 30%, transparent) top / 100% 2rem local,
    linear-gradient(transparent, var(--bs-light) 70%) bottom / 100% 2rem local,
    linear-gradient(rgba(0, 0, 0, 0.15), transparent) top / 100% 0.75rem scroll,
    linear-gradient(transparent, rgba(0, 0, 0, 0.15)) bottom / 100% 0.75rem scroll;
  background-repeat: no-repeat;
}
