/* Atlas / home — page-specific layer.
   Loads after atlas-core.css, which supplies the tokens, the card, the grid
   and the search primitives.

   The idea: a mod site's front page should show a mod. This page leads with one
   piece of real work at size, takes its colour from that work, and then lays
   the catalogue out as one shelf per game rather than one mixed feed — almost
   every visitor plays exactly one game, so a mixed feed is mostly noise to all
   of them. The shelf for the game the visitor last browsed comes first. */

/* Repeated from core on purpose; see the note there. Guarded per file by
   tests/smoke/design-system-hidden-guard.test.mjs. */
[hidden],
.hidden { display: none !important; }

/* Reaches screen readers and search engines, never the layout. Carries the
   page's h1, which must not depend on a fetch resolving. */
.am-vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  white-space: nowrap;
  clip-path: inset(50%);
}

/* --------------------------------------------------------------- ambient */
/* Sampled from the featured mod, so the front door is coloured by the work it
   is leading with rather than by a fixed brand tint. */
.am-ambient { height: 72vh; }

/* Quieter than a creator page: the shelf panels already carry their own tints
   below the fold, so the floor is only here to keep the gaps between them and
   the footer from going flat. */
body.am { --am-floor: .65; }

.am-ambient__img {
  background-position: center 28%;
  filter: blur(100px) saturate(1.9) brightness(.52);
}

.am-ambient__veil {
  background:
    radial-gradient(110% 65% at 50% 18%, transparent 0%, rgba(6, 8, 11, .52) 66%, rgba(6, 8, 11, .86) 100%),
    linear-gradient(180deg,
      rgba(6, 8, 11, .68) 0%,
      rgba(6, 8, 11, .42) 24%,
      rgba(6, 8, 11, .62) 64%,
      var(--am-void) 96%);
}

/* -------------------------------------------------------------- featured */
.am-feat { padding-block: .6rem 0; }

.am-feat__card {
  position: relative;
  display: grid;
  overflow: hidden;
  border: 1px solid var(--am-line);
  border-radius: var(--am-r);
  background: rgba(9, 12, 17, .5);
  text-decoration: none;
  transition: border-color .22s var(--am-ease);
}
.am-feat__card:hover { border-color: rgba(var(--am-glow), .45); }

/* Side by side once there is room; stacked on a phone, artwork first. */
@media (min-width: 56rem) {
  .am-feat__card { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); }
}

.am-feat__media {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: #0b0f14;
}
.am-feat__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .6s var(--am-ease);
}
.am-feat__card:hover .am-feat__media img { transform: scale(1.03); }

/* Fades the artwork into the panel beside it rather than butting two
   rectangles together. */
.am-feat__media::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(180deg, transparent 55%, rgba(9, 12, 17, .75) 100%);
}
@media (min-width: 56rem) {
  .am-feat__media::after {
    background: linear-gradient(90deg, transparent 60%, rgba(9, 12, 17, .8) 100%);
  }
}

.am-feat__body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: .5rem;
  padding: 1.3rem 1.4rem 1.5rem;
}
@media (min-width: 56rem) { .am-feat__body { padding: 2rem 2.2rem; } }

.am-feat__eyebrow {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .5rem;
  font-family: var(--am-mono);
  font-size: .5625rem;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--am-ink-3);
}

/* Names why this mod is here — an owner's pick reads differently from
   "most liked this month", and the page should not pretend otherwise. */
.am-feat__tag {
  padding: .18rem .45rem;
  border-radius: var(--am-r);
  background: rgba(var(--am-glow), .16);
  color: var(--am-accent);
}

.am-feat__name {
  margin: .2rem 0 0;
  font-family: var(--am-display);
  font-size: clamp(1.6rem, 3.6vw, 2.5rem);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -.03em;
  color: var(--am-ink);
}

.am-feat__by { font-size: .8125rem; color: var(--am-ink-2); }
.am-feat__by:empty { display: none; }

.am-feat__copy {
  margin: .3rem 0 0;
  font-size: .8125rem;
  line-height: 1.7;
  color: var(--am-ink-3);
}
.am-feat__copy:empty { display: none; }

.am-feat__meta {
  display: flex;
  align-items: center;
  gap: .8rem;
  margin-top: .6rem;
  font-family: var(--am-mono);
  font-size: .625rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--am-ink-3);
}
.am-feat__card.is-paid #featuredPrice { color: var(--am-paid); }

/* The search box and the counted game chips that used to sit between the
   featured card and the shelves are both gone. Searching belongs to the hubs,
   which own filtering and paging; and each game's panel below is a bigger door
   than a chip, already carrying that game's banner, count and arrow — so the
   chips were a second index of the same games, one screen above the first. */

/* ------------------------------------------------------------- sections */
.am-section { padding-block: 1.8rem 0; }
/* On `main` rather than a `:last-child` section, because the last section in
   the markup is Collections and it is usually hidden — a structural selector
   would hand the padding to an element that is not displayed. */
main { padding-bottom: 2.5rem; }

/* ------------------------------------------------------------- skeletons */
/* Same vocabulary as the game hub's own skeletons in atlas-game.css, kept
   local because these sheets are deliberately self-contained.

   These exist to give the first paint a shape. The page cannot paint content
   before JavaScript has fetched it, so without them the visitor gets an empty
   canvas for half a second — which is what reads as a stall. */
.sk-row {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: clamp(9.5rem, 42vw, 13.5rem);
  gap: 14px;
  overflow: hidden;
  padding-bottom: .4rem;
}

.sk-card {
  overflow: hidden;
  border: 1px solid var(--am-line-soft);
  border-radius: var(--am-r);
  background: var(--am-panel);
  padding-bottom: .7rem;
}

.sk-img {
  display: block;
  aspect-ratio: 4 / 3;
  background: rgba(255, 255, 255, .035);
  margin-bottom: .65rem;
}

.sk-bar {
  display: block;
  height: 8px;
  border-radius: 2px;
  background: rgba(255, 255, 255, .05);
  margin-inline: .65rem;
}

.sk-banner {
  position: relative;
  display: block;
  flex: 0 1 clamp(28rem, 52vw, 52rem);
  aspect-ratio: 4 / 1;
  overflow: hidden;
  border: 1px solid var(--am-line-soft);
  border-radius: var(--am-r);
  background: rgba(255, 255, 255, .03);
}

/* Featured silhouette: the same body rhythm as the real card. */
#featuredSkeleton .am-feat__media { position: relative; }
#featuredSkeleton .am-feat__body { gap: .65rem; }
.sk-bar--eyebrow { width: 8rem; height: 7px; margin-inline: 0; }
.sk-bar--title { width: min(100%, 20rem); height: 20px; margin-inline: 0; }
.sk-bar--line { width: min(100%, 26rem); margin-inline: 0; }
.sk-bar--short { width: min(100%, 15rem); }

.shimmer {
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .045), transparent);
  transform: translateX(-100%);
  animation: am-shimmer 1.4s infinite;
}
@keyframes am-shimmer { to { transform: translateX(100%); } }

/* --------------------------------------------------------- artwork fade */
/* Artwork arrives transparent and fades once it has actually decoded. The
   snap from empty box to full-bleed image is what registers as slowness on a
   page carrying this much art. Images already in the browser cache are marked
   ready before their first paint, so a returning visitor sees no fade at all
   — a warm load must not be made to look like a slow one. */
.am-art { opacity: 0; transition: opacity .45s var(--am-ease); }
.am-art.is-ready { opacity: 1; }

/* --------------------------------------------------------------- shelves */
/* One shelf per game: header, then a single row of that game's newest work
   that scrolls sideways and ends in a link to the hub. A shelf is a trailer
   for a hub, never a second catalogue — if this page ever grows sort or
   filter controls beyond the game itself, it has become the hub. */
/* `minmax(0, 1fr)`, never a bare `auto` column: an auto track sizes to its
   item's max-content, and a horizontally scrolling row still reports the full
   width of its cards as max-content. That propagates back up and the whole
   page scrolls sideways instead of the row. */
.am-shelves {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  /* Each game is its own place, so the gap between panels is wide enough that
     two hubs never read as one long list. */
  gap: 2.25rem;
}

/* Each game reads as its own panel rather than a loose header over a row.
   The surface is dark and translucent, like the featured card — the mod cards
   are a *light* translucent, so a light panel behind them would swallow them
   and the ambient artwork would still show through both. */
.am-shelf {
  /* Replaced per panel by home-page-app.js with a colour sampled from that
     game's banner. The default is the panel's own base, so before sampling —
     or when a game has no banner at all — the gradient is invisible rather
     than a grey smear. */
  --am-shelf-tint: 9, 12, 17;

  /* Cards inside a panel take that panel's colour rather than the page's.
     Without this a shelf tinted from the HS1 banner would hold cards tinted
     from whatever the featured mod happened to be — an orange box full of
     pink plates. */
  --am-tint-rgb: var(--am-shelf-tint);

  padding: 1rem 1.1rem 1.1rem;
  border: 1px solid var(--am-line);
  border-radius: calc(var(--am-r) * 2);
  /* The tint pools in the top-left corner, under the banner it came from, and
     falls away before it reaches the mods. A background layer rather than an
     overlay: backgrounds always paint beneath content, so the cards can never
     end up behind a wash. */
  background:
    /* The glow, pooling under the banner it was sampled from. */
    radial-gradient(120% 155% at 2% 0%,
      rgba(var(--am-shelf-tint), .26) 0%,
      rgba(var(--am-shelf-tint), .07) 45%,
      rgba(var(--am-shelf-tint), 0) 78%),
    /* A flat wash under all of it, so the box reads as having its own colour
       rather than a bright corner on a grey card. */
    linear-gradient(0deg, rgba(var(--am-shelf-tint), .055), rgba(var(--am-shelf-tint), .055)),
    rgba(9, 12, 17, .46);
  transition: border-color .25s var(--am-ease);
}
.am-shelf:hover {
  border-color: rgba(var(--am-shelf-tint), .32);
  background:
    radial-gradient(120% 155% at 2% 0%,
      rgba(var(--am-shelf-tint), .32) 0%,
      rgba(var(--am-shelf-tint), .09) 45%,
      rgba(var(--am-shelf-tint), 0) 78%),
    linear-gradient(0deg, rgba(var(--am-shelf-tint), .075), rgba(var(--am-shelf-tint), .075)),
    rgba(9, 12, 17, .52);
}

/* Header: the game's own banner on the left, then a hairline, the count, and
   the arrow into the hub. The banner is the fastest way to say which game this
   shelf is, and most visitors are here to leave for their hub — so the art and
   the arrow are both doors, and the old "Open hub" button is gone. */
.am-shelf__head { align-items: center; gap: 1rem; }

.am-shelf__banner {
  display: block;
  /* Grows with the window so the game's name stays readable on a large
     monitor, and stops before the art crowds out the mods underneath it.
     The source is 4:1, so width alone decides the height. */
  flex: 0 1 clamp(28rem, 52vw, 52rem);
  min-width: 0;
  overflow: hidden;
  border: 1px solid var(--am-line-soft);
  border-radius: var(--am-r);
  background: #0b0f14;
  line-height: 0;
  transition: border-color .2s var(--am-ease);
}
.am-shelf__banner:hover { border-color: rgba(var(--am-glow), .45); }

.am-shelf__banner img {
  display: block;
  width: 100%;
  /* The source art is 4:1 with the game's sign in the left third. */
  aspect-ratio: 4 / 1;
  object-fit: cover;
  transition: transform .5s var(--am-ease);
}
.am-shelf__banner:hover img { transform: scale(1.02); }

.am-shelf__count {
  flex: 0 0 auto;
  font-family: var(--am-mono);
  font-size: .625rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--am-ink-3);
}

.am-shelf__go {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  height: 2.4rem;
  width: 2.4rem;
  border: 1px solid var(--am-line);
  border-radius: 999px;
  background: var(--am-panel);
  color: var(--am-ink-2);
  text-decoration: none;
  transition: color .18s var(--am-ease), border-color .18s var(--am-ease),
    background .18s var(--am-ease), transform .18s var(--am-ease);
}
.am-shelf__go:hover {
  color: var(--am-accent);
  border-color: rgba(var(--am-glow), .55);
  background: var(--am-panel-2);
  transform: translateX(2px);
}
.am-shelf__go svg { width: 15px; height: 15px; }

/* On a phone the banner competing with the count and the arrow for one line
   left it 176px wide, which is too small to read the game's name off — the
   one thing it exists to do. It takes the whole line instead, and the count
   and arrow drop beneath it. */
@media (max-width: 40rem) {
  .am-shelf { padding: .75rem .8rem .85rem; }
  .am-shelf__head { flex-wrap: wrap; row-gap: .55rem; }
  .am-shelf__banner { flex: 1 1 100%; }
}

.am-shelf__row {
  display: grid;
  grid-auto-flow: column;
  /* Sized so the row always ends mid-card: the part-visible card is the only
     affordance that says the row scrolls. The viewport term is what keeps that
     true on a phone — a fixed minimum here happened to fit exactly two cards
     at 375px, which reads as a row that ends. */
  grid-auto-columns: clamp(9.5rem, 42vw, 13.5rem);
  gap: 14px;
  align-items: stretch;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  /* Keeps a card tabbed into view off the container's own edge. */
  scroll-padding-inline: .25rem;
  padding-bottom: .4rem;
  scrollbar-width: thin;
  scrollbar-color: var(--am-line) transparent;
}
.am-shelf__row > * { scroll-snap-align: start; }

.am-shelf__row::-webkit-scrollbar { height: 6px; }
.am-shelf__row::-webkit-scrollbar-track { background: transparent; }
.am-shelf__row::-webkit-scrollbar-thumb {
  border-radius: 999px;
  background: var(--am-line);
}
.am-shelf__row:hover::-webkit-scrollbar-thumb { background: var(--am-line-soft); }

/* The end of the row is the way out of it: "View all 1,113" as a card, so it
   sits in the scroll rather than below it. */
.am-shelf__more {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .3rem;
  padding: 1rem .8rem;
  border: 1px dashed var(--am-line);
  border-radius: var(--am-r);
  text-align: center;
  text-decoration: none;
  font-family: var(--am-mono);
  font-size: .625rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--am-ink-3);
  transition: color .18s var(--am-ease), border-color .18s var(--am-ease);
}
.am-shelf__more:hover { color: var(--am-accent); border-color: rgba(var(--am-glow), .45); }
.am-shelf__more__count {
  font-size: .875rem;
  font-family: var(--am-display);
  letter-spacing: -.01em;
  text-transform: none;
  color: var(--am-ink-2);
}

/* A live game with nothing published yet — HS2 on launch day. An invitation,
   not an apology. */
.am-shelf__empty { margin-top: .2rem; }
.am-shelf__empty a { color: var(--am-accent); text-decoration: none; }
.am-shelf__empty a:hover { text-decoration: underline; }

/* Games that are not places you can go yet: the header alone, dimmed, at the
   end of the same column — so this column reads as the full list of games on
   Mod Atlas rather than a catalogue with an announcement stapled beneath it. */
/* Not a place you can go yet, so it gets the outline of a panel without the
   substance of one: dashed, unfilled, and not interactive on hover. */
.am-shelf--soon {
  padding: .7rem 1.1rem;
  border-style: dashed;
  background: none;
  opacity: .5;
}
.am-shelf--soon:hover { border-color: var(--am-line); background: none; }
.am-shelf--soon .am-work__head { padding-bottom: 0; }

/* -------------------------------------------------------------- creators */
/* The same scrolling row the game shelves use, so "there is more of this than
   fits" is expressed one way on this page rather than two. */
.am-creators {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: clamp(11.5rem, 26vw, 14rem);
  gap: .5rem;
  align-items: stretch;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  scroll-padding-inline: .25rem;
  padding-bottom: .4rem;
  scrollbar-width: thin;
  scrollbar-color: var(--am-line) transparent;
}
.am-creators > * { scroll-snap-align: start; }

.am-creators::-webkit-scrollbar { height: 6px; }
.am-creators::-webkit-scrollbar-track { background: transparent; }
.am-creators::-webkit-scrollbar-thumb { border-radius: 999px; background: var(--am-line); }

/* Closes the row by naming what is not in it. Not a link, because there is no
   page listing every creator yet — a dashed card that led nowhere would be
   worse than a plain statement of the remainder. */
.am-creators__more {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .2rem;
  padding: .7rem;
  border: 1px dashed var(--am-line-soft);
  border-radius: var(--am-r);
  text-align: center;
  font-family: var(--am-mono);
  font-size: .5625rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--am-ink-3);
}
.am-creators__more strong {
  font-family: var(--am-display);
  font-size: .95rem;
  font-weight: 600;
  letter-spacing: -.01em;
  color: var(--am-ink-2);
}

.am-creator {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: .7rem;
  border: 1px solid var(--am-line-soft);
  border-radius: var(--am-r);
  background: var(--am-panel);
  padding: .7rem .8rem;
  text-decoration: none;
  transition: border-color .18s var(--am-ease), background .18s var(--am-ease);
}
.am-creator:hover { border-color: rgba(var(--am-glow), .4); background: var(--am-panel-2); }

.am-creator__avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 2.4rem;
  width: 2.4rem;
  flex: 0 0 auto;
  overflow: hidden;
  border: 1px solid var(--am-line);
  border-radius: 999px;
  background: rgba(255, 255, 255, .05);
  font-family: var(--am-display);
  font-size: .75rem;
  font-weight: 600;
  color: var(--am-ink-2);
}
.am-creator__avatar img { width: 100%; height: 100%; object-fit: cover; }

.am-creator__body { min-width: 0; }

.am-creator__name {
  font-size: .8125rem;
  font-weight: 600;
  color: var(--am-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.am-creator__meta {
  margin-top: .1rem;
  font-family: var(--am-mono);
  font-size: .5625rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--am-ink-3);
}

.am-creator__tagline {
  margin-top: .25rem;
  font-size: .6875rem;
  line-height: 1.45;
  color: var(--am-ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ----------------------------------------------------------- collections */
.am-collections {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
  gap: .5rem;
}

.am-collection {
  border: 1px solid var(--am-line-soft);
  border-radius: var(--am-r);
  background: var(--am-panel);
  padding: .85rem .95rem;
  text-decoration: none;
  transition: border-color .18s var(--am-ease), background .18s var(--am-ease);
}
.am-collection:hover { border-color: rgba(var(--am-glow), .4); background: var(--am-panel-2); }

.am-collection__title { font-size: .875rem; font-weight: 600; color: var(--am-ink); }
.am-collection__sub { margin-top: .2rem; font-size: .75rem; color: var(--am-ink-3); }

/* The `.am-soon` banner tiles that used to sit in a separate "On the way"
   section at the foot of the page are gone: unreleased games are now a dimmed
   header at the end of the shelves column (`.am-shelf--soon` above). */
