/* ---- LOBBY ----
   Motion tokens (--dur-*, --ease-*, --lift-*, --shadow-tile-hover, --field-*)
   are always read with a fallback: the shared scale lives in frame.css and the
   lobby must look right with or without it. */
.lobby {
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: 20px;
  padding: 16px 0 0;
  background: var(--bg-primary);
}
/* Breathing room on desktop: the lobby never touches the sidebar or the window
   edge (e.g. at 1441-1552px). The 1280px content width is kept on wide screens. */
@media (min-width: 769px) {
  .lobby {
    --lobby-gutter: clamp(16px, 2.2vw, 32px);
    max-width: calc(1280px + 2 * var(--lobby-gutter));
    padding-left: var(--lobby-gutter);
    padding-right: var(--lobby-gutter);
  }
}

/* ===== BANNERS ===== */
.banners-wrapper {
  display: flex;
  flex-direction: column;
  gap: 13px;
  margin-left: -20px;
  margin-right: -20px;
}
.banners {
  display: flex;
  gap: 16px;
  flex-wrap: nowrap;
  margin-top: -20px;
  margin-bottom: -20px;
  padding: 20px;
  overflow-x: auto;
  /* sideways only (owner 2026-10-15: "on mobile you can lift the banners up by pressing on them and moving finger up"):
     the castle look's lights reach past each card (theme-castle.css .banner-promo__clouds), which made the row
     scrollable up / down too; they are cut at the row's edge either way, so nothing looks different */
  overflow-y: hidden;
  scrollbar-width: none;
  -ms-overflow-style: none;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: 20px;
  touch-action: manipulation;
}
.banners::-webkit-scrollbar { display: none; }
.banner-card {
  flex: none;
  width: 416px;
  min-width: 398px;
  height: 180px;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  /* Card colour behind banners with a transparent background (opaque art covers it). */
  background: var(--bg-secondary, #213545);
  position: relative;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  cursor: pointer;
  transition:
    transform var(--dur-hover-out, 0.22s) var(--ease-hover, cubic-bezier(0.33, 1, 0.68, 1)),
    box-shadow var(--dur-hover-out, 0.22s) var(--ease-hover, cubic-bezier(0.33, 1, 0.68, 1)),
    filter var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1));
}
@media (hover: hover) and (pointer: fine) {
  .banner-card:hover {
    transform: translateY(var(--lift-card, -4px));
    z-index: 1;
    box-shadow: var(--shadow-tile-hover, 0 14px 28px -10px rgba(0, 0, 0, 0.6));
    transition-duration: var(--dur-hover-in, 0.38s);
  }
  .banner-card:hover:active {
    transform: translateY(var(--lift-card, -4px)) scale(0.98);
    transition-duration: var(--dur-press, 0.08s);
  }
}
.banner-card--clickable { cursor: pointer; }
/* Brand glow behind transparent "headline only" banner art (BannersSection):
   dark navy on the left, blue glow behind the character on the right.
   The base glow is static; two blurred layers make it slowly swirl:
   ::before — a soft conic "beam" turning around the glow centre,
   ::after  — two light blobs drifting in a slow loop.
   Transform-only animations (composited); off with prefers-reduced-motion. */
.banner-card--glow {
  overflow: hidden;
  isolation: isolate;
  background:
    radial-gradient(ellipse 55% 55% at 72% 68%, rgba(29, 154, 248, 0.7) 0%, rgba(9, 89, 184, 0.45) 40%, rgba(9, 89, 184, 0) 100%),
    linear-gradient(100deg, #041b2e 0%, #06223b 45%, #0a3a6e 100%);
}
.banner-card--glow img { position: relative; z-index: 1; }
.banner-card--glow::before,
.banner-card--glow::after {
  content: '';
  position: absolute;
  z-index: 0;
  pointer-events: none;
  left: 72%;
  top: 68%;
  aspect-ratio: 1;
  will-change: transform;
}
.banner-card--glow::before {
  width: 85%;
  /* Blue beams with one warm gold band (site gold #ffd54a) that sweeps through. */
  background: conic-gradient(
    from 0deg,
    rgba(29, 154, 248, 0) 0deg,
    rgba(29, 154, 248, 0.75) 60deg,
    rgba(9, 89, 184, 0.15) 120deg,
    rgba(255, 213, 74, 0.5) 165deg,
    rgba(255, 180, 60, 0.12) 200deg,
    rgba(120, 205, 255, 0.6) 250deg,
    rgba(9, 89, 184, 0.1) 310deg,
    rgba(29, 154, 248, 0) 360deg
  );
  border-radius: 50%;
  filter: blur(30px);
  opacity: 0.45;
  transform: translate(-50%, -50%) rotate(0deg);
  /* Slow turn + an independent, longer "breathing" fade: the two periods don't
     line up, so the combined motion takes many minutes to repeat. */
  animation:
    banner-glow-swirl 67s linear infinite,
    banner-glow-breathe 23s ease-in-out infinite alternate;
}
.banner-card--glow::after {
  width: 70%;
  background:
    radial-gradient(circle at 35% 40%, rgba(120, 205, 255, 0.4) 0%, rgba(120, 205, 255, 0) 38%),
    radial-gradient(circle at 68% 62%, rgba(29, 154, 248, 0.45) 0%, rgba(29, 154, 248, 0) 42%),
    radial-gradient(circle at 62% 24%, rgba(255, 213, 74, 0.22) 0%, rgba(255, 213, 74, 0) 30%);
  filter: blur(16px);
  opacity: 0.8;
  transform: translate(-50%, -50%) rotate(0deg) scale(1);
  animation: banner-glow-drift 41s ease-in-out infinite alternate;
}
/* Each banner gets its own periods and start point (not just a delay), so the
   three never look like the same loop side by side. */
.banner-card--glow:nth-child(2)::before {
  animation-duration: 79s, 29s;
  animation-delay: -31s, -7s;
  animation-direction: reverse, alternate;
}
.banner-card--glow:nth-child(2)::after { animation-duration: 53s; animation-delay: -19s; }
.banner-card--glow:nth-child(3)::before {
  animation-duration: 59s, 19s;
  animation-delay: -12s, -11s;
}
.banner-card--glow:nth-child(3)::after { animation-duration: 47s; animation-delay: -33s; }
@keyframes banner-glow-swirl {
  to { transform: translate(-50%, -50%) rotate(360deg); }
}
@keyframes banner-glow-breathe {
  0%   { opacity: 0.3; }
  45%  { opacity: 0.55; }
  100% { opacity: 0.38; }
}
/* Uneven steps so the drift wanders instead of swinging back and forth evenly. */
@keyframes banner-glow-drift {
  0%   { transform: translate(-50%, -50%) rotate(0deg) scale(1); }
  23%  { transform: translate(-47%, -53%) rotate(48deg) scale(1.04); }
  51%  { transform: translate(-52%, -55%) rotate(97deg) scale(0.98); }
  78%  { transform: translate(-55%, -48%) rotate(151deg) scale(1.05); }
  100% { transform: translate(-51%, -46%) rotate(190deg) scale(0.97); }
}
@media (prefers-reduced-motion: reduce) {
  .banner-card--glow::before,
  .banner-card--glow::after { animation: none; }
}
.banner-card--clickable:focus-visible { outline: 2px solid var(--focus-ring, #8fd6ff); outline-offset: 2px; }
.banner-card:active {
  filter: brightness(1.15);
}
.banner-card img {
  width: 100%; height: 100%; min-width: 100%; min-height: 100%;
  object-fit: cover; object-position: center; display: block;
  border-radius: var(--radius-lg);
}
/* Desktop: the three banners share the row as three equal columns (no
   cut-off third banner). Equal flex columns rather than display:grid, so a
   width set on .banner-card elsewhere (desktop-density.css) can't shrink a
   banner inside its grid cell. Phones and small tablets keep the swipe. */
@media (min-width: 769px) {
  .banners {
    overflow: visible;
    scroll-snap-type: none;
  }
  .banner-card {
    flex: 1 1 0;
    width: auto;
    min-width: 0;
    height: auto;
    aspect-ratio: 416 / 180;
  }
}

/* ===== CATEGORY TABS ===== */
.category-nav {
  display: flex;
  gap: 6px;
  padding-top: 0;
  padding-bottom: 0;
  margin-top: -4px;    /* 20px lobby gap - 4 = 16px below Recent Wins */
  margin-bottom: 0;    /* full 20px lobby gap above the first section */
  align-items: center;
}
.category-tabs-scroll {
  flex: 0 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
}
/* Stake-style segmented control: ONE dark track holding the tabs, with a single
   grey pill that glides under the selected tab (CategoryNav positions it). */
.category-tabs {
  position: relative;   /* anchors the sliding selector pill */
  display: flex;
  gap: 2px;
  overflow-x: auto;
  flex-wrap: nowrap;
  scrollbar-width: none;
  -ms-overflow-style: none;
  padding: 4px;
  border-radius: var(--radius-lg);
  background: var(--bg-sidebar);
}
.category-tabs::-webkit-scrollbar { display: none; }
/* The search box sits next to the track, so it takes the track's height and corners. */
.category-nav { gap: 8px; }
.category-nav > .search-tab,
.category-nav__tools > .search-tab { height: 48px; box-sizing: border-box; border-radius: var(--radius-lg); }
/* Lobby bar (CategoryNav): the search box, Providers and Sort by are one group
   after the tabs. When the bar is too narrow for the tabs and the group side by
   side, the group wraps onto a second line and takes the full width, so the
   tabs are never squeezed out of sight (tablets, narrow windows, the laptop
   zoom). The group's flex-basis is its smallest comfortable width: the search
   box (240px), plus Providers (160px) and Sort by (about 200px) when shown. */
.category-nav--wraps { flex-wrap: wrap; row-gap: 8px; }
.category-nav__tools {
  display: flex;
  flex-wrap: wrap;      /* last resort, narrower than the three controls */
  align-items: center;
  gap: 8px;
  flex: 1 1 240px;
  min-width: 0;
}
.category-nav__tools.has-providers { flex-basis: 408px; }
.category-nav__tools.has-providers.has-sort { flex-basis: 616px; }
/* On its own line the search box may give up some width, so the three
   controls still fit side by side in a 600px-wide window. */
.category-nav__tools > .search-tab { min-width: 150px; }

.lobby-tab {
  flex: 0 0 auto;
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: flex-start;
  padding: 9px 14px;
  border-radius: var(--radius-md);
  background-color: var(--bg-chip);
  text-decoration: none;
  color: var(--text-muted);
  font-size: var(--fs-md);
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.15px;
  cursor: pointer;
  white-space: nowrap;
  border: none;
  transition:
    background-color var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1)),
    color var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1)),
    transform var(--dur-base, 0.22s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1));
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
@media (hover: hover) {
  .lobby-tab:hover { background-color: var(--bg-chip-hover); color: #fff; }
}
.category-tabs > .lobby-tab {
  background-color: transparent;
  transition:
    color var(--dur-base, 0.22s) var(--ease-out, cubic-bezier(.33, 1, .68, 1)),
    transform var(--dur-base, 0.22s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1));
}
@media (hover: hover) {
  .category-tabs > .lobby-tab:hover { background-color: transparent; color: #fff; }
}
/* Press feedback while the tab is held (the selected tab and the search box don't dip). */
.lobby-tab:not(.search-tab):not(.active):active {
  transform: scale(0.96);
  transition-duration: var(--dur-fast, 0.16s), var(--dur-fast, 0.16s), var(--dur-press, 0.08s);
}
@media (hover: hover) and (pointer: fine) {
  .lobby-tab:not(.search-tab):not(.active):active { transform: scale(0.97); }
}
/* Selected: grey with white text (blue stays reserved for main buttons). In
   CategoryNav the grey is drawn by the sliding pill below; the tab's own
   background is the fallback for rows without a pill. */
.lobby-tab.active {
  background-color: var(--bg-elevated);
  color: #fff;
}
/* The tab just picked snaps out of its press instead of easing back: while a
   transform is still on it, its chip background paints above the pill and
   would hide the pill sliding in underneath. */
.category-tabs.has-pill > .lobby-tab.active {
  background-color: transparent;
  transition-property: color;
}

/* Sliding selector: one pill per tab row, positioned from the active tab by
   CategoryNav (--pill-x/--pill-y/--pill-w/--pill-h). It lives inside the
   scrolling row, so it scrolls with the tabs. It paints above the chips'
   backgrounds and below their content (the tab spans are positioned). */
.category-tabs__pill {
  position: absolute;
  top: var(--pill-y, 0px);
  left: 0;
  width: var(--pill-w, 0px);
  height: var(--pill-h, 100%);
  transform: translateX(var(--pill-x, 0px));
  border-radius: var(--radius-md);
  background-color: var(--bg-elevated);
  box-shadow: var(--shadow-sm);
  pointer-events: none;
  opacity: 0;
}
.category-tabs.has-pill > .category-tabs__pill { opacity: 1; }
.category-tabs__pill.is-ready {
  transition:
    transform var(--dur-base, 0.22s) var(--ease-out, cubic-bezier(.33, 1, .68, 1)),
    width var(--dur-base, 0.22s) var(--ease-out, cubic-bezier(.33, 1, .68, 1));
}
.category-tabs > .lobby-tab > span { position: relative; }
@media (prefers-reduced-motion: reduce) {
  .category-tabs__pill.is-ready { transition: none; }
}

/* Tab icons are masks filled with the text colour, so they follow the
   muted / hover / selected text colour. */
.lobby-tab .tab-icon {
  display: block; flex: 0 0 auto;
  width: 22px; height: 22px;
  background-color: currentColor;
  -webkit-mask: var(--tab-icon) center / contain no-repeat;
          mask: var(--tab-icon) center / contain no-repeat;
}
@media (min-width: 769px) {
  .lobby-tab:not(.search-tab) > span:not(.tab-icon):not(.search-icon-tab) { transform: translateY(1px); }
}
.tab-icon.icon-lobby { --tab-icon: url("/sidebarpc/img/vector-35.svg"); }
.tab-icon.icon-slots { --tab-icon: url("/lobby/slots.svg"); }
.tab-icon.icon-originals { --tab-icon: url("/sidebarpc/img/vector-36.svg"); }
.tab-icon.icon-live { --tab-icon: url("/lobby/live.svg"); }
.tab-icon.icon-shows { --tab-icon: url("/lobby/game-shows.svg"); }
.tab-icon.icon-new { --tab-icon: url("/lobby/new.svg"); }

/* One magnifier everywhere: the header's search icon, drawn as a mask so each
   field can tint it. */
.search-tab .search-icon-tab,
.search-btn-mobile .search-icon-tab,
.catnav-search-icon,
.catnav-dd-search-icon {
  display: block;
  flex: 0 0 auto;
  background-color: currentColor;
  -webkit-mask: url("/header/search.svg") center / contain no-repeat;
          mask: url("/header/search.svg") center / contain no-repeat;
}
/* the Providers list's search icon is inline SVG (SiteIcon, 2026-10-16: no masks in panels that scroll on iPhones) */
svg:is(.catnav-search-icon, .catnav-dd-search-icon) { background: none; -webkit-mask: none; mask: none; fill: currentColor; }

/* Lobby search bar — Stake-style: dark inset field, blue-grey icon + placeholder
   (#a1bfd6), "Ctrl + K" keycap on the right. Uses the shared field border. */
.search-tab {
  flex: 1;
  min-width: 240px;
  justify-content: flex-start;
  gap: 10px;
  background: var(--bg-input);
  border: 1px solid var(--field-border, var(--border-color));
  padding: 7px 8px 7px 14px;
  cursor: pointer;
  color: var(--sb-icon, #a1bfd6);
  font-family: inherit;
  font-size: 20px;          /* cap-to-baseline ≈ 14.6px = the magnifier glyph height */
  font-weight: 600;
  transition:
    border-color 0.18s var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1)),
    box-shadow 0.18s var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1));
}
.search-tab .search-icon-tab { width: 18px; height: 18px; }
@media (hover: hover) {
  .search-tab:hover {
    background: var(--bg-input);
    color: var(--sb-icon, #a1bfd6);
    border-color: var(--field-border-hover, var(--border-strong));
  }
}
.search-tab:focus-within {
  border-color: var(--field-border-focus, var(--bg-elevated-hover));
  box-shadow: var(--field-focus-shadow, 0 0 0 3px rgba(var(--accent-rgb), 0.16));
}
/* The field box above shows focus (border + ring), so the bare input inside it
   draws no second outline. */
.search-tab__input {
  flex: 1; min-width: 0; background: none; border: none; outline: none;
  color: #fff;
  font-family: "RM Neue", Helvetica, Arial, sans-serif;
  font-size: 20px; font-weight: 600;
  letter-spacing: 0.15px; line-height: 1;
  padding: 0; margin: 0; height: auto;
  /* the field fills the whole height of its box, so a tap anywhere in the box (not only on the
     22px text line) starts typing (mobile QA 2026-10-08); the text stays centred where it was */
  align-self: stretch;
}
/* (only where the box has its fixed 48px height — see .category-nav__tools > .search-tab above) */
.category-nav > .search-tab:has(> .search-tab__input),
.category-nav__tools > .search-tab:has(> .search-tab__input) { padding-top: 0; padding-bottom: 0; }
.search-tab__input::placeholder {
  color: var(--sb-icon, #a1bfd6);
  font-family: "RM Neue", Helvetica, Arial, sans-serif;
  font-size: 20px; font-weight: 600;
  letter-spacing: 0.15px;
  opacity: 1;
}
/* "Let fate decide" (owner 2026-10-17; it was the "Ctrl + K" keycap): a small block at the box's right end that opens a
   random house game (CategoryNav.tsx letFateDecide). Phones have no search box here (it is hidden up to 768 px). */
.search-tab__fate {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  flex-shrink: 0;
  height: 28px;
  padding: 0 10px;
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--bg-elevated);
  color: #fff;
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
}
.search-tab__fate svg.search-tab__fate-icon.is-px { width: 18px !important; height: 18px !important; color: var(--gold, #f2c440); }

/* ===== CATEGORY NAV INLINE SEARCH ===== */
.catnav-search {
  display: flex; align-items: center; gap: 8px;
  flex: 1; min-width: 240px; padding: 8px 13px;
  background: var(--bg-input);
  border: 1px solid var(--field-border, var(--border-color));
  border-radius: var(--radius-md);
  box-sizing: border-box;
  transition:
    border-color 0.18s var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1)),
    box-shadow 0.18s var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1));
}
@media (hover: hover) {
  .catnav-search:hover { border-color: var(--field-border-hover, var(--border-strong)); }
}
.catnav-search:focus-within {
  border-color: var(--field-border-focus, var(--bg-elevated-hover));
  box-shadow: var(--field-focus-shadow, 0 0 0 3px rgba(var(--accent-rgb), 0.16));
}
.catnav-search-icon {
  width: 20px; height: 20px;
  color: var(--text-muted);
}
.catnav-search input {
  flex: 1; min-width: 0; background: none; border: none;
  color: #fff; font-family: inherit; font-size: var(--fs-md); font-weight: 700;
  letter-spacing: 0.15px; line-height: 1; outline: none;
}
.catnav-search input::placeholder { color: var(--text-muted); font-weight: 700; opacity: 1; }
.catnav-search-popup { cursor: pointer; }
.catnav-search-placeholder { color: var(--text-muted); font-size: var(--fs-md); }

/* ===== CATEGORY NAV PROVIDER DROPDOWN ===== */
.catnav-provider-dd { position: relative; flex-shrink: 0; }
.catnav-dd-btn {
  display: flex; align-items: center; gap: 10px;
  height: 40px; width: 160px; padding: 0 16px;
  background-color: var(--bg-chip); border: none; border-radius: var(--radius-md);
  color: var(--text-muted); font-family: inherit; font-size: var(--fs-sm); font-weight: 700;
  cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition:
    background-color var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1)),
    color var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1));
  user-select: none;
}
@media (hover: hover) {
  .catnav-dd-btn:hover { background-color: var(--bg-chip-hover); color: #fff; }
}
.catnav-dd-btn.open { background-color: var(--bg-chip-hover); color: #fff; }
.catnav-dd-chevron {
  width: 16px; height: 16px; flex-shrink: 0; margin-left: auto;
  background-color: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") center / contain no-repeat;
  transition: transform 0.24s var(--ease-premium, cubic-bezier(0.22, 1, 0.36, 1));
}
.catnav-dd-btn.open .catnav-dd-chevron { transform: rotate(180deg); }

/* Panel: opens from just above, slightly small, and settles into place.
   A panel that is mounted on open (e.g. the search popup) plays the entry
   animation; CategoryNav keeps its panel mounted (.is-managed) and toggles
   .is-open, so closing animates too. */
.catnav-dd-panel {
  position: absolute; top: calc(100% + 6px); right: 0; width: 200px;
  background: var(--bg-chip); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); z-index: 200; overflow: hidden;
  padding-bottom: 6px;
  transform-origin: top right;
  animation: lobby-dd-in var(--dur-base, 0.22s) var(--ease-premium, cubic-bezier(0.22, 1, 0.36, 1)) both;
}
.catnav-dd-panel.is-managed {
  animation: none;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateY(-6px) scale(0.98);
  transition:
    opacity 0.14s var(--ease-in, cubic-bezier(0.4, 0, 1, 1)),
    transform 0.14s var(--ease-in, cubic-bezier(0.4, 0, 1, 1)),
    visibility 0s linear 0.14s;
}
.catnav-dd-panel.is-managed.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: none;
  transition:
    opacity var(--dur-base, 0.22s) var(--ease-premium, cubic-bezier(0.22, 1, 0.36, 1)),
    transform var(--dur-base, 0.22s) var(--ease-premium, cubic-bezier(0.22, 1, 0.36, 1)),
    visibility 0s linear 0s;
}
@keyframes lobby-dd-in {
  from { opacity: 0; transform: translateY(-6px) scale(0.98); }
}
.catnav-dd-search {
  display: flex; align-items: center; gap: 8px;
  margin: 8px 8px 6px; padding: 6px 10px;
  background: var(--bg-chip-hover); border-radius: var(--radius-md);
  transition: box-shadow 0.18s var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1));
}
.catnav-dd-search:focus-within {
  box-shadow: var(--field-focus-shadow, 0 0 0 3px rgba(var(--accent-rgb), 0.16));
}
.catnav-dd-search-icon {
  width: 16px; height: 16px;
  color: var(--text-dim);
}
.catnav-dd-search input {
  flex: 1; min-width: 0; background: none; border: none;
  color: #fff; font-family: inherit; font-size: var(--fs-sm); outline: none;
}
.catnav-dd-search input::placeholder { color: var(--text-muted); opacity: 1; }
.catnav-dd-list {
  max-height: 260px; overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--scrollbar-thumb, var(--bg-elevated)) transparent;
}
.catnav-dd-list::-webkit-scrollbar { width: var(--scrollbar-size, 6px); }
.catnav-dd-list::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb, var(--bg-elevated)); border-radius: var(--radius-sm); }
.catnav-dd-list::-webkit-scrollbar-thumb:hover { background: var(--scrollbar-thumb-hover, var(--bg-elevated-hover)); }
/* external audit T4: the options are buttons now — same look as the old divs */
:where(button.catnav-dd-item, button.slots-provider-panel-item) {
  width: 100%; border: 0; background: none; font-family: inherit; line-height: inherit; text-align: left; margin: 0;
}
.catnav-dd-item:focus-visible, .slots-provider-panel-item:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
.catnav-dd-item {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 14px; cursor: pointer;
  transition:
    background-color var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1)),
    color var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1));
  color: var(--text-muted); font-size: var(--fs-sm); font-weight: 500;
}
.catnav-dd-item:hover { background-color: var(--bg-chip-hover); color: #fff; }
.catnav-dd-item .catnav-dd-check {
  width: 14px; height: 14px; flex-shrink: 0; border-radius: var(--radius-sm);
  border: 1.5px solid var(--border-strong); background-color: transparent;
  transition:
    border-color var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1)),
    background-color var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1));
}
.catnav-dd-item.selected { color: #fff; }
.catnav-dd-item.selected .catnav-dd-check {
  background-color: var(--accent); border-color: var(--accent);
}

/* ===== "SORT BY" MENU (Slots tab; src/components/SortMenu.tsx) =====
   Desktop: the provider dropdown's look, sized to its text ("Sort by" in the
   dim colour, the choice after it). Phones: slots.css. */
.catnav-sort-btn { width: auto; min-width: 160px; }
.sort-menu__label { color: var(--text-dim); font-weight: 600; }
.sort-menu__value { overflow: hidden; text-overflow: ellipsis; }
.catnav-sort-btn:hover .sort-menu__label,
.catnav-sort-btn.open .sort-menu__label { color: var(--text-muted); }
.catnav-sort-panel { width: 100%; min-width: 180px; padding-top: 6px; }
/* Menu entries are buttons: drop the browser's button look. */
.sort-menu__item {
  width: 100%; margin: 0; border: 0; background: none; text-align: left;
  font-family: inherit; line-height: inherit; cursor: pointer;
}
.catnav-dd-item.sort-menu__item:focus-visible { outline-offset: -2px; }

/* Mobile search icon button (inside category tabs, hidden on desktop) */
.search-btn-mobile {
  display: none;
  border: none;
  font-family: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.search-btn-mobile .search-icon-tab { width: 20px; height: 20px; }

/* ===== GAME SECTION ===== */
.game-section {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding-top: 0;
  overflow: visible;
}
.section-header {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
.section-title {
  display: flex; gap: 10px; align-items: center;
}
.section-title h2 {
  font-family: inherit; font-size: var(--fs-lg); font-weight: 700;
  line-height: 1.25; letter-spacing: 0; color: var(--text-primary);
  margin: 0; opacity: 1;
}
/* Section icons: 24px (the pixel set's box, 2 screen px a block) and static, so the titles stay calm; the loading
   placeholder is the same size, so the words don't move when the row arrives. */
.section-icon {
  width: 24px; height: 24px; flex-shrink: 0;
  background-size: contain; background-position: center; background-repeat: no-repeat;
  opacity: 1;
}
/* Every heading icon's picture is the pixel set's (24 px): src/styles/pixel-icons.css (since 2026-10-21 for all of them). */

.section-controls {
  display: flex; gap: 6px; align-items: center; height: 33px;
}
/* the same fill as the row arrows beside it (owner 2026-10-16: "make view all lighter like the next button"; it was
   transparent, so it showed the dark page). Undo ../removed-features-backup/view-all-lighter-2026-10-16/README.txt */
.btn-view-all {
  flex: 0 0 auto; height: 100%; padding: 0 10px;
  background-color: var(--bg-chip); border: none; border-radius: var(--radius-md);
  color: var(--text-muted); font-family: inherit; font-size: var(--fs-sm); font-weight: 600;
  line-height: 1.5; cursor: pointer; white-space: nowrap;
  text-decoration: none; display: flex; align-items: center; justify-content: center;
  transition:
    background-color var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1)),
    color var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1));
}
@media (hover: hover) {
  .btn-view-all:hover { background-color: var(--bg-chip-hover); color: #fff; }
}
/* Row arrows: the glyph is a mask filled with the text colour. */
.btn-arrow {
  width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
  background-color: var(--bg-chip); border: none; border-radius: var(--radius-md);
  color: var(--text-muted);
  cursor: pointer; flex-shrink: 0;
  transition:
    background-color var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1)),
    color var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1)),
    opacity var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1));
}
.btn-arrow::before {
  content: '';
  display: block;
  width: 20px; height: 20px;
  background-color: currentColor;
  -webkit-mask: var(--arrow-icon) center / contain no-repeat;
          mask: var(--arrow-icon) center / contain no-repeat;
}
@media (hover: hover) {
  .btn-arrow:hover { background-color: var(--bg-chip-hover); color: #fff; }
}
.btn-prev { --arrow-icon: url("/lobby/left-arrow.svg"); }
.btn-next { --arrow-icon: url("/lobby/right-arrow.svg"); }
/* Nothing more to scroll that way (classes set by GameSection.updateState). */
.game-section.at-start .btn-prev,
.game-section.at-end .btn-next { opacity: 0.35; pointer-events: none; }
.btn-arrow:disabled { opacity: var(--disabled-opacity, 0.5); cursor: not-allowed; }

/* ===== GAME GRID ===== */
.game-grid-wrapper {
  position: relative; overflow: visible;
}
.game-grid-wrapper::before,
.game-grid-wrapper::after {
  content: ''; position: absolute; top: -12px; bottom: -20px;   /* = the grid's shadow room */
  width: 56px;
  pointer-events: none; z-index: 2;
  transition: opacity var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1));
}
.game-grid-wrapper::after {
  right: 0;
  background: linear-gradient(to left, var(--bg-primary) 0%, var(--bg-primary) 18%, rgba(var(--bg-primary-rgb), 0) 100%);
}
.game-grid-wrapper::before {
  left: 0; width: 56px;
  background: linear-gradient(to right, var(--bg-primary) 0%, var(--bg-primary) 18%, rgba(var(--bg-primary-rgb), 0) 100%);
  opacity: 0;
}
.game-grid-wrapper.at-end::after { opacity: 0; }
.game-section:not(.at-start) .game-grid-wrapper::before { opacity: 1; }

/* Desktop: nudge fades slightly toward outer edges */
@media (min-width: 769px) {
  .game-grid-wrapper::after {
    width: 56px;
    right: 0;
    transform: translateX(10px);
    background: linear-gradient(to left, var(--bg-primary) 0%, var(--bg-primary) 18%, rgba(var(--bg-primary-rgb), 0) 100%);
  }
  .game-grid-wrapper::before {
    width: 56px;
    left: 0;
    transform: translateX(-10px);
    background: linear-gradient(to right, var(--bg-primary) 0%, var(--bg-primary) 18%, rgba(var(--bg-primary-rgb), 0) 100%);
  }
}

.game-grid {
  display: flex; gap: 12px;
  overflow-x: auto; scrollbar-width: none; -ms-overflow-style: none;
  padding-top: 12px; margin-top: -12px;
  /* Room below the tiles for a hovered tile's drop shadow and glow, which the
     scroll box would otherwise cut off; the negative margin keeps the layout. */
  padding-bottom: 20px; margin-bottom: -20px;
  transform: translateZ(0);
  will-change: scroll-position;
  touch-action: manipulation;
}
.game-grid::-webkit-scrollbar { display: none; }

.game-card {
  flex: none;
  width: 160px; aspect-ratio: 3 / 4;
  background: transparent; border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  overflow: hidden; position: relative; z-index: 1;
  text-decoration: none;
}
.game-card img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}

/* ===== GAME TILE MOTION =====
   One recipe for every lobby tile: the lift glides in over the "in" timing and
   settles back over the shorter "out" timing; holding the button down shows
   the press; a click opens the game at once. Wide cards (providers, banners)
   lift less. The glow/outline/sweep layer is in game-shine.css. */
.game-card,
.original-card,
.originals-index-card {
  transition:
    transform var(--dur-hover-out, 0.22s) var(--ease-hover, cubic-bezier(0.33, 1, 0.68, 1)),
    box-shadow var(--dur-hover-out, 0.22s) var(--ease-hover, cubic-bezier(0.33, 1, 0.68, 1));
}
@media (hover: hover) and (pointer: fine) {
  .game-card:hover,
  .original-card:hover,
  .originals-index-card:hover {
    transform: translateY(var(--lift-tile, -5px));
    transition-duration: var(--dur-hover-in, 0.38s);
  }
  .game-card:active,
  .original-card:active,
  .originals-index-card:active {
    transform: translateY(var(--lift-tile, -5px)) scale(0.97);
    transition-duration: var(--dur-press, 0.08s);
  }
}
@media (hover: none) {
  .game-card:active,
  .original-card:active,
  .originals-index-card:active {
    transform: scale(0.96);
    transition-duration: var(--dur-press, 0.08s);
  }
}

/* ===== LOBBY TILE ART: LOADING / LOADED / BROKEN =====
   .lobby-tile marks the tiles Lobby.tsx renders (rails, slots grid, originals
   grid); the image handlers there set .is-loaded / .is-broken on the tile and
   its <img>. Until the art has decoded, the tile is a dark block with a soft
   shimmer; the art then fades in. Already-cached art is marked loaded before
   the first paint, so it shows instantly. A broken image keeps its card
   (nothing after it shifts) and shows the logo on dark instead. */
.lobby-tile { background-color: var(--bg-secondary); }
/* Visual-only tile (e.g. the retired Crash thumbnail): looks like the others but isn't a link.
   Two classes so it outranks the later `.originals-index-card { cursor: pointer }`.
   No lift, shine or outline on hover: see the end of game-shine.css. */
.lobby-tile.lobby-tile--display { cursor: default; }
/* "Soon" tag on a game we don't carry yet (Live Casino, Game Shows): a small
   dark-glass pill, readable on every art colour. 12px is about 9px at the
   desktop zoom of 0.75 and 7.8px at 0.65. It is a label, never a target. */
.lobby-tile__soon {
  position: absolute;
  top: 6px;
  right: 6px;
  z-index: 2;
  padding: 3px 7px;
  border-radius: 999px;
  background: rgba(var(--bg-sidebar-rgb), 0.78);
  color: #fff;
  font: inherit;
  font-size: var(--fs-xs);
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  pointer-events: none;
}
.lobby-tile:not(.is-loaded):not(.is-broken) {
  background-color: var(--bg-secondary);   /* also on tiles whose own rule sets a gradient background (originals index) */
  background-image: linear-gradient(90deg, rgba(var(--bg-card-rgb), 0) 25%, var(--bg-card) 50%, rgba(var(--bg-card-rgb), 0) 75%);
  background-size: 200% 100%;
  background-repeat: no-repeat;
  animation: lobby-tile-shimmer 1.4s ease-in-out infinite;
}
@keyframes lobby-tile-shimmer {
  from { background-position: 150% 0; }
  to   { background-position: -50% 0; }
}
.lobby-tile.is-broken {
  background:
    linear-gradient(rgba(var(--bg-secondary-rgb), 0.5), rgba(var(--bg-secondary-rgb), 0.5)),
    var(--bg-secondary) url("/mobile-header/icons/logo.png") center / 64% auto no-repeat;
}
.lobby-tile.is-broken img { visibility: hidden; }

.card-img-fade {
  opacity: 0;
  transition:
    opacity 0.35s var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1)),
    filter var(--dur-hover-out, 0.22s) var(--ease-hover, cubic-bezier(0.33, 1, 0.68, 1));
}
.card-img-fade.is-loaded { opacity: 1; }
/* A hovered tile's art brightens a touch (never zoomed: thumbnails go soft). */
@media (hover: hover) and (pointer: fine) {
  .lobby-tile:hover .card-img-fade {
    filter: brightness(1.06);
    transition-duration: 0.35s, var(--dur-hover-in, 0.38s);
  }
}

/* Skeleton placeholders (lazy rails before they load, the slots grid while the
   catalogue loads). Same shimmer as the Recent Wins skeleton (rw-shimmer). */
@keyframes lobby-shimmer {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}
.lobby-skel {
  display: block;
  position: relative;
  overflow: hidden;
  flex-shrink: 0;
  background: var(--bg-secondary);
  border-radius: var(--radius-sm);
}
.lobby-skel::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent 25%, var(--bg-card) 50%, transparent 75%);
  animation: lobby-shimmer 1.4s ease-in-out infinite;
  will-change: transform;
  pointer-events: none;
}
.lobby-skel--title { width: 128px; height: 16px; }
.lobby-skel--view-all { width: 84px; height: 100%; border-radius: var(--radius-md); }
.lobby-skel--arrow { width: 32px; height: 32px; border-radius: var(--radius-md); }
.lobby-skel-tile {
  width: var(--gz-tile-w, 160px);   /* same width as .game-card (desktop-density.css may narrow it) */
  aspect-ratio: 3 / 4;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
}
.lobby-skel-row { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .card-img-fade { transition: none; }
  .lobby-tile:not(.is-loaded):not(.is-broken) { animation: none; background-image: none; }
  .lobby-skel::after { animation: none; display: none; }
}

/* ===== PROVIDERS GRID ===== */

.providers-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 8px;
}

.provider-card {
  height: 76px;
  background-color: var(--bg-secondary); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  text-decoration: none;
  padding: 12px;
  transition:
    background-color var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1)),
    transform var(--dur-hover-out, 0.22s) var(--ease-hover, cubic-bezier(0.33, 1, 0.68, 1)),
    box-shadow var(--dur-hover-out, 0.22s) var(--ease-hover, cubic-bezier(0.33, 1, 0.68, 1));
}
@media (hover: hover) and (pointer: fine) {
  .provider-card:hover {
    background-color: var(--bg-card);
    transform: translateY(var(--lift-card, -4px));
    box-shadow: var(--shadow-tile-hover, 0 14px 28px -10px rgba(0, 0, 0, 0.6));
    transition-duration: var(--dur-fast, 0.16s), var(--dur-hover-in, 0.38s), var(--dur-hover-in, 0.38s);
  }
  .provider-card:hover .provider-logo-img { opacity: 1; }
  .provider-card:active {
    transform: translateY(var(--lift-card, -4px)) scale(0.97);
    transition-duration: var(--dur-fast, 0.16s), var(--dur-press, 0.08s), var(--dur-press, 0.08s);
  }
}
@media (hover: none) {
  .provider-card:active {
    transform: scale(0.96);
    transition-duration: var(--dur-fast, 0.16s), var(--dur-press, 0.08s), var(--dur-press, 0.08s);
  }
}
.provider-logo-img {
  max-width: 100%;
  max-height: 76%;
  object-fit: contain;
  opacity: 1;                          /* the logos in their brand colours, at full strength (owner 2026-10-23) */
  transition: opacity var(--dur-fast, 0.16s) var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1));
}
/* Last card of the row: a text link to every provider (the Slots tab). */
.provider-card--all {
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  white-space: nowrap;
}
@media (hover: hover) and (pointer: fine) {
  .provider-card--all:hover { color: #fff; }
}

/* ===== LIVE CASINO TAB ===== */
/* One plain line under the heading: these games can't be played yet. */
.live-soon-note {
  margin: -4px 0 0;
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: 1.4;
}

/* ===== ORIGINALS ===== */
.originals-grid {
  display: flex; gap: 12px; flex-wrap: wrap;
}
.original-card {
  flex: none;
  width: 160px; height: 222px;
  background: linear-gradient(135deg, var(--bg-card) 0%, var(--bg-elevated) 100%);
  border-radius: var(--radius-lg); overflow: hidden;
  box-shadow: var(--shadow-md);
  text-decoration: none; position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  cursor: pointer;
}
.original-card__icon {
  width: 64px; height: 64px;
  background: rgba(255,196,0,0.1);
  border-radius: var(--radius-sm);
  display: flex; align-items: center; justify-content: center;
  font-size: 34px; flex-shrink: 0;
}
.original-card__info {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
}
.original-card__name {
  font-size: var(--fs-sm); font-weight: 700; color: #fff;
}
.original-card__edge {
  font-size: var(--fs-xs); color: var(--text-dim); font-weight: 500;
}

/* ===== ORIGINALS INDEX GRID ===== */
.originals-index-grid {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 12px;
}
.originals-index-card {
  display: flex;
  flex-direction: column;
  width: 100%;
  aspect-ratio: 3 / 4;
  background: linear-gradient(135deg, var(--bg-card) 0%, var(--bg-elevated) 100%);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  overflow: hidden;
  text-decoration: none;
  position: relative;
  cursor: pointer;
}
.originals-index-card img {
  width: 100%;
  flex: 1;
  object-fit: cover;
  display: block;
}
.originals-index-label {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px 4px;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: #fff;
  background: rgba(0,0,0,0.35);
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ===== TAB CONTENT ANIMATION ===== */
/* A small local entrance acknowledges the new collection without sweeping the
   catalogue sideways. Visited panels keep their state and data below. */
@keyframes tab-content-rise {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}
.tab-content-enter {
  animation: tab-content-rise 0.18s var(--ease-out, cubic-bezier(.33, 1, .68, 1));
  display: flex;
  flex-direction: column;
  gap: 24px;
}
/* Lazy rails render a same-height skeleton until they load (see LazyVisible in
   Lobby.tsx), so they take their real space from the start and the page below
   them never jumps.
   Visited tabs stay mounted; only the active panel is shown. Going from
   display:none -> flex re-runs the tab-content-rise animation, so switching
   tabs keeps its enter effect without remounting (and re-fetching) the grid. */
.tab-content-host { display: flex; flex-direction: column; }
.lobby > .rb-container { margin-top: 0; }
.tab-panel[hidden] { display: none; }
/* Phones: no Lobby tab in the row of game types — Lobby is in the bottom bar (owner 2026-10-16: "remove the lobby button
   from the different types of casino games - mobile"); the other tabs are pages of their own there (Lobby.tsx
   usePhoneBar). Undo ../removed-features-backup/slots-page-mobile-2026-10-16/README.txt */
@media (max-width: 768px) {
  .category-tabs .lobby-tab--home { display: none; }
  /* …and no row of game types on the lobby home at all (owner 2026-10-16: "get rid of this from homescreen on mobile",
     the search button + Slots / Live Casino / Game Shows row under the banner): the bottom bar, the rows' View All and
     the side menu lead to those pages; the game-type pages keep their row (.lobby--category). Undo
     ../removed-features-backup/home-tab-row-mobile-2026-10-16/README.txt */
  .lobby:not(.lobby--category) .category-nav { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .tab-content-enter { animation: none; }
}

/* ── TAB LOADING SCREEN (owner 2026-10-14: "make there a little loading screen with an icon until everythings full in
   place … it should have animation then load in position"; Lobby.tsx TAB_VEIL / tabPanelReady): while a new tab gets
   ready its panel stays invisible behind the tab's own icon (gold, bobbing in pixel steps), "Loading Slots" and three
   blinking dots; then the panel rises into place, its rows one after another and its first tiles settling in turn.
   Fill mode "backwards" only, so nothing overrides a tile's own hover lift afterwards. Undo:
   ../removed-features-backup/tab-loading-2026-10-14/ ── */
.tab-content-host { position: relative; }
.tab-content-host.is-veiled { min-height: 340px; }
.tab-panel.is-veiled { opacity: 0; animation: none; pointer-events: none; }
.tab-veil {
  position: absolute;
  z-index: 3;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding-top: 84px;                   /* just under the tab bar, on screen */
  pointer-events: none;
  animation: tab-veil-in 0.18s ease-out both;
}
/* the tab's own pixel icon (SiteIcon, inline SVG) in gold — 60 px = 5 screen px a block (2026-10-18; was the old picture
   through a CSS mask) */
.tab-veil__icon {
  display: block;
  color: var(--accent);
  animation: tab-veil-bob 0.9s steps(4, end) infinite;
}
svg.is-px.tab-veil__icon { width: 60px !important; height: 60px !important; }
.tab-veil__label { font-size: 19px; line-height: 1; color: var(--text-primary); text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.5); }
.tab-veil__dots { display: flex; gap: 8px; }
.tab-veil__dots i { display: block; width: 7px; height: 7px; background: var(--accent); animation: tab-veil-dot 1.2s steps(1, end) infinite; }
.tab-veil__dots i:nth-child(2) { animation-delay: 0.2s; }
.tab-veil__dots i:nth-child(3) { animation-delay: 0.4s; }
@media (max-width: 768px) {
  .tab-content-host.is-veiled { min-height: 240px; }
  .tab-veil { padding-top: 26px; gap: 10px; }      /* the tab bar sits low on a phone: the icon right under it */
  svg.is-px.tab-veil__icon { width: 48px !important; height: 48px !important; }
}
@keyframes tab-veil-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes tab-veil-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
@keyframes tab-veil-dot { 0%, 60% { opacity: 1; } 61%, 100% { opacity: 0.25; } }
/* the reveal: the panel rises, its rows follow one another, the first 16 tiles settle in turn */
.tab-panel.is-revealed { animation: tab-panel-in 0.42s cubic-bezier(0.22, 1, 0.36, 1) backwards; }
.tab-panel.is-revealed > :nth-child(1) { animation: tab-row-in 0.42s cubic-bezier(0.22, 1, 0.36, 1) 0ms backwards; }
.tab-panel.is-revealed > :nth-child(2) { animation: tab-row-in 0.42s cubic-bezier(0.22, 1, 0.36, 1) 70ms backwards; }
.tab-panel.is-revealed > :nth-child(3) { animation: tab-row-in 0.42s cubic-bezier(0.22, 1, 0.36, 1) 140ms backwards; }
.tab-panel.is-revealed > :nth-child(4) { animation: tab-row-in 0.42s cubic-bezier(0.22, 1, 0.36, 1) 210ms backwards; }
.tab-panel.is-revealed > :nth-child(5) { animation: tab-row-in 0.42s cubic-bezier(0.22, 1, 0.36, 1) 280ms backwards; }
.tab-panel.is-revealed > :nth-child(6) { animation: tab-row-in 0.42s cubic-bezier(0.22, 1, 0.36, 1) 350ms backwards; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(-n + 16) { animation: tab-tile-in 0.38s cubic-bezier(0.22, 1, 0.36, 1) backwards; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(1) { animation-delay: 100ms; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(2) { animation-delay: 128ms; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(3) { animation-delay: 156ms; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(4) { animation-delay: 184ms; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(5) { animation-delay: 212ms; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(6) { animation-delay: 240ms; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(7) { animation-delay: 268ms; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(8) { animation-delay: 296ms; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(9) { animation-delay: 324ms; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(10) { animation-delay: 352ms; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(11) { animation-delay: 380ms; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(12) { animation-delay: 408ms; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(13) { animation-delay: 436ms; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(14) { animation-delay: 464ms; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(15) { animation-delay: 492ms; }
.tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(16) { animation-delay: 520ms; }
@keyframes tab-panel-in { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }
@keyframes tab-row-in { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes tab-tile-in { from { opacity: 0; transform: translateY(10px) scale(0.96); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .tab-veil, .tab-veil__icon, .tab-veil__dots i, .tab-panel.is-revealed, .tab-panel.is-revealed > *,
  .tab-panel.is-revealed :is(.game-grid, .slots-grid) > * { animation: none; }
}
/* Phones: nothing moves when a tab appears — one quick fade of the whole panel; no rise, no rows or tiles settling in
   turn (owner 2026-10-16: "On mobile — When you switch to a new tab for example lobby to slots everything shakes a tiny
   bit stop that from happening": a phone showed the panel rising 16 px and its first 16 tiles growing from 96 % one
   after another). The loading screen stays. Same for pages (pageVeil.ts revealPage). (n) selectors: as strong as the
   per-row / per-tile rules above. Undo ../removed-features-backup/phone-tab-still-2026-10-16/README.txt */
@keyframes tab-fade-in { from { opacity: 0; } to { opacity: 1; } }
@media (max-width: 768px) {
  .tab-content-enter { animation-name: tab-fade-in; }
  .tab-panel.is-revealed { animation: tab-fade-in 0.22s ease-out backwards; }
  .tab-panel.is-revealed > :nth-child(n),
  .tab-panel.is-revealed :is(.game-grid, .slots-grid) > :nth-child(n) { animation: none; }
}
@media (max-width: 768px) and (prefers-reduced-motion: reduce) {
  .tab-content-enter, .tab-panel.is-revealed { animation: none; }
}

/* ===== MOBILE ===== */
@media (max-width: 600px) {
  .lobby { gap: 16px; padding: 4px 0 0; }
  .lobby > *:not(.banners-wrapper):not(.category-nav):not(.tab-content-host) { overflow: hidden; }
  .banners-wrapper { gap: 12px; }
  .banners-wrapper { margin-left: -16px; margin-right: -16px; }
  .banners { margin-top: -10px; margin-bottom: -10px; padding: 10px 16px; gap: 12px; scroll-padding-inline: 16px; }
  .banner-card { width: 360px; min-width: 360px; max-width: 360px; height: 154px; border-radius: var(--radius-lg); }
  .category-nav { flex-wrap: wrap; padding-top: 0; padding-bottom: 0; margin-top: 0; margin-bottom: 0; margin-left: -16px; margin-right: -16px; }
  .category-tabs-scroll { width: 100%; overflow: visible; }
  .category-tabs-scroll { padding: 0 16px; box-sizing: border-box; }
  /* The tab row (search button + 4 tabs) is wider than a phone, so it scrolls
     sideways like Stake's; tabs keep their natural width and share any spare
     room. CategoryNav scrolls the selected tab into view (row only). */
  .category-tabs {
    gap: 2px; overflow-x: auto; overflow-y: hidden; padding: 4px; margin: 0;
    width: 100%; max-width: 100%; box-sizing: border-box;
    scrollbar-width: none;
    overscroll-behavior-x: contain;
    touch-action: manipulation;
  }
  .lobby-tab {
    flex: 1 0 auto; min-width: 0; height: 40px; padding: 0 12px 0 8px;
    border-radius: var(--radius-md); font-size: var(--fs-sm); letter-spacing: 0.12px; gap: 8px;
    justify-content: center;
  }
  .lobby-tab .tab-icon { width: 20px; height: 20px; flex-shrink: 0; }
  .lobby-tab:not(.search-tab) > span:not(.tab-icon):not(.search-icon-tab) { transform: translateY(1px); }
  .search-tab { display: none; }
  .category-nav__tools { display: none; }
  .catnav-search { display: none; }
  .catnav-provider-dd { display: none; }
  .search-btn-mobile { display: flex; flex: 0 0 40px; width: 40px; height: 40px; padding: 0; gap: 0; justify-content: center; align-items: center; }
  .tab-content-enter { gap: 16px; }
  .game-section { gap: 12px; padding-top: 0; }
  .section-title { gap: 10px; }
  .section-title h2 { font-size: var(--fs-lg); font-weight: 700; }
  .section-controls { justify-content: flex-end; gap: 6px; height: auto; }
  /* View All next to the arrows on phones too (owner 2026-10-16: "put a view all next to these which takes you to the slot
     page - mobile"; it was hidden here): Popular Slots / Trending -> /slots, New Releases -> /slots?sort=newest, the
     other rows their own page; as tall as the arrows look, a little tighter. Undo ../removed-features-backup/view-all-mobile-2026-10-16/README.txt */
  .btn-view-all { height: 32px; padding: 0 8px; }   /* the arrows' visible 32 px (on touch screens they are 40 with a 4 px see-through edge) */
  .lobby-skel--view-all { width: 64px; height: 32px; }
  .btn-arrow {
    display: flex; width: 32px; height: 32px;
    border-radius: var(--radius-md);
  }
  .btn-arrow::before { width: 18px; height: 18px; }
  .game-grid-wrapper { overflow: hidden; margin-left: -16px; margin-right: -16px; padding-left: 16px; padding-right: 16px; }
  .game-grid-wrapper::before,
  .game-grid-wrapper::after {
    width: 55px; top: 0; bottom: 0; transform: none;
  }
  .game-grid-wrapper::after {
    right: 0;
    background: linear-gradient(to left, var(--bg-primary) 0%, var(--bg-primary) 18%, rgba(var(--bg-primary-rgb), 0) 100%);
  }
  .game-grid-wrapper::before {
    left: 0;
    background: linear-gradient(to right, var(--bg-primary) 0%, var(--bg-primary) 18%, rgba(var(--bg-primary-rgb), 0) 100%);
  }
  .game-grid { gap: 6px; padding: 0; margin: 0; }
  /* Owner 2026-10-08: bigger tiles on phones. The row (100vw - 32px wide) shows 3 whole tiles plus a
     quarter of the next one (was 4 whole tiles): 3.25 tiles + 3 gaps of 6px = 100vw - 32px. */
  .game-card,
  .lobby-skel-tile { width: calc((100vw - 50px) / 3.25); aspect-ratio: 3 / 4; height: auto; border-radius: var(--radius-lg); }
  .providers-grid { display: flex; gap: 7px; overflow-x: auto; touch-action: manipulation; scrollbar-width: none; -ms-overflow-style: none; margin-left: -16px; margin-right: -16px; padding-left: 16px; padding-right: 16px; }
  .providers-grid::-webkit-scrollbar { display: none; }
  .provider-card { flex: none; width: calc((100vw - 32px - 21px) / 3.2); height: 54px; border-radius: var(--radius-lg); padding: 8px; }
  .provider-card--all { font-size: var(--fs-xs); }
  .lobby-tile__soon { top: 4px; right: 4px; padding: 2px 5px; font-size: 10px; }
  .originals-index-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; } /* owner 2026-10-08: bigger tiles, 3 per row on phones (was 4) */
  .originals-index-card { border-radius: var(--radius-lg); }
  .originals-index-label { font-size: var(--fs-xs); padding: 6px 4px; }
  .btn-arrow:active { background-color: var(--bg-chip-hover); color: #fff; }
}

/* Touch screens: the row arrows keep their 32px look but are 40px tap targets themselves (mobile QA
   2026-10-08, LG-29): a 4px transparent border that belongs to the button (taps on it count), the
   colour clipped inside it, the corner radius grown by the border so the visible corners stay, and
   negative margins so nothing around them moves. The two arrows are 8px apart (was 6px) so their tap
   areas meet without overlapping. */
@media (hover: none) and (pointer: coarse) {
  .section-controls { gap: 8px; }
  .btn-arrow {
    width: 40px; height: 40px;
    border: 4px solid transparent;
    background-clip: padding-box;
    border-radius: calc(var(--radius-md) + 4px);
    margin: -4px;
  }
}

/* Favourites and Recently Played grids (Favourites.tsx / RecentlyPlayed.tsx load this file too).
   A grid item's automatic minimum width is its content's, and the game name under each tile is one
   line (nowrap + ellipsis), so one long title ("John Hunter and the Tomb of the Scarab Queen") made
   its column as wide as the title: cards of uneven sizes, the page 469–900px wide on phones and games
   pushed off the right edge where they could not be reached. With min-width 0 every column keeps its
   equal share and a long name ends in "…" inside its card (mobile QA 2026-10-08, LG-01 / LG-02;
   the grid columns themselves live in favourites.css / recent.css). */
.fav-grid > *,
.rp-grid > * { min-width: 0; }
/* Favourites / Recently Played: the sections under the list keep their place while the list loads
   but are not painted yet, so the list arriving above them moves nothing that is on screen. */
.lobby-loading-reserve { display: contents; }
.lobby-loading-reserve.is-loading { visibility: hidden; }

/* ===== ORIGINALS SHOWCASE =====
   The lobby's Originals on PC are their own showcase, not a scrolling row (owner 2026-10-15: "no scroll or view all all
   the games should fit and glass bridge should be in the centre other ones spaced slightly away from it making it like
   some speical game"; Lobby.tsx OriginalsShowcase): one line at every PC width — three games, Glass Bridge in the
   exact middle, three games (Wheel left out for now: "remove wheel for now so its equal 3 on each side"). Glass Bridge
   is the owner's shield, a touch taller than the tiles on the same bottom line (owner: "make this the icon for the game and add cool decor around it but
   same height as other game"), with blue fire burning round its edge; pointing at it lights up cracks in the stone
   either side with blue fire (owner: "a blue flame around it then when you hover over it it lights up cracks in the
   cement with a kinda blue flame ish look"; the stone pillars tried first were dropped: "no not the pitch fork pillior
   things"). Every tile ends on the same bottom line, so the row ends
   where a normal row does and Popular Slots sits as usual. Phones (<= 768 px) keep the old scrolling row.
   One flat grid (the wings are display: contents): every game column 1fr, the middle one 78/54 fr (64/54 since 2026-10-18, below) — the decor box
   is 78 x 72 art pixels with the tile's 54 x 72 in it, so with aspect-ratio 78 / 72 it is exactly a tile high (11 art
   px of stone a side: "make the other original games slightly bigger so they are closer to glass bridge but not too
   close"; it was 18).
   Art: ../banner-work/glass-bridge-2026-10-15/tools/make-showcase-decor.mjs (public/theme/castle/showcase/); every
   place below is art pixels / 78 (x) or / 72 (y). The tiles keep the lobby tile's look, hover lift, shine and loading
   states (.game-card.lobby-tile). Undo: ../removed-features-backup/originals-showcase-2026-10-15/README.txt */
/* The other games sit closer to Glass Bridge since 2026-10-18 (owner: "i want less space between glass bridge and other
   originals can you move them closer to glass bridge either making them bigger or putting more distance between the
   other origianls"): the middle column is 64 art px instead of 78 (64 / 54 fr), so the six tiles grow ~3.5 %; the
   box keeps its 78 x 72 (still exactly a tile high) and reaches 7 art px into the gap on each side, so the shield is
   ~19 px from its neighbours on a 1280 px row (was 40; the tiles keep 12 px between them). Undo:
   ../removed-features-backup/originals-closer-2026-10-18/README.txt */
.originals-showcase__stage {
  --os-gap: 12px;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr)) minmax(0, 1.185185fr) repeat(3, minmax(0, 1fr));
  column-gap: var(--os-gap);
  align-items: end;                  /* one bottom line for every tile */
}
@media (min-width: 561px) {
  .originals-showcase__feature:not(.originals-showcase__feature--m) {
    width: calc(100% * 78 / 64);     /* the box's 78 art px on a 64 art px column */
    margin-left: calc(-100% * 7 / 64);
  }
}
.originals-showcase__wing { display: contents; }
/* The Study's shield in Blackjack's / Limbo's place on computers (owner 2026-10-18: "replace blackjack and limbo with the
   study"; Lobby.tsx SHOWCASE_STUDY_FOR, never in the phone layout): a tile's box (3 : 4, on the row's bottom line, above
   the cracks like the tiles), the shield as tall as the tile — its 552 x 720 is a touch wider, so it reaches ~1 % into
   the gap each side —, a still picture with the Glass Bridge shield's shadow; nothing moves on hover. */
.os-side {
  position: relative;
  z-index: 1;
  display: flex;
  justify-content: center;
  width: 100%;
  aspect-ratio: 3 / 4;
  align-self: end;
}
.os-side__img {
  flex: none;
  height: 100%;
  width: auto;
  max-width: none;
  display: block;
  filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.45));
  transition: opacity 0.35s var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1));
}
.os-side:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
/* PC: a row like Popular Slots (owner 2026-10-18: "add text like popular games saying originals and add the next and back
   button" → the heading with ‹ ›; Lobby.tsx .originals-showcase--rail, never in the phone layout): the line opens exactly
   as before (the seven columns fill the row: --os-t = one tile) and Blackjack and Limbo stand after HiLo past the right
   edge; › slides there, ‹ back. The scroll box keeps room above for Glass Bridge (grown 6 % up) and below for a tile's
   hover shadow. */
/* closer to the tab bar (owner 2026-10-18: "make originals closer to the options tabs"): no top padding of its own — the
   heading sits the lobby's usual 20 px under the tabs, like every row's heading (it was 40) */
.originals-showcase.originals-showcase--rail { padding-top: 0; }
.originals-showcase--rail .originals-showcase__stage {
  --os-t: calc((100% - 6 * var(--os-gap)) / 7.185185);
  grid-template-columns: repeat(3, var(--os-t)) calc(var(--os-t) * 1.185185) repeat(5, var(--os-t));
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  padding-top: 34px;           /* room for Glass Bridge grown 6 % up + its thin flame's licks (~30 px above the tiles) */
  margin-top: -33px;           /* the heading as far above Mines as "Popular Slots" is above its first game (owner 2026-10-18:
                                  "make the text and logo above mines same distance popular slots is from gates") */
  padding-bottom: 20px;
  margin-bottom: -20px;
}
.originals-showcase--rail .originals-showcase__stage::-webkit-scrollbar { display: none; }
/* the Study as far from Glass Bridge as from the game on its other side (owner 2026-10-18: "move the studys closer to
   glass bridge so they are same distance away from glass bridge as originals on the other side"): its outer edge on its
   tile's edge, the picture 4.2963 % wider toward Glass Bridge — whose shield sits 0.03625 of its 1.185185-tile column
   inside it (the box's 7 / 64 overhang, its 11 / 78 inset, grown 6 % from the middle) — so every gap along the line is
   the column gap; a touch taller, grown up from the bottom line */
.originals-showcase--rail .os-side { display: block; }
.originals-showcase--rail .os-side__img { position: absolute; bottom: 0; width: calc(100% * 1.042963); height: auto; }
.originals-showcase--rail .os-side--left .os-side__img { left: 0; }
.originals-showcase--rail .os-side--right .os-side__img { right: 0; }
/* THE FLAMES round Glass Bridge, Warlord Run and The Study (owner 2026-10-18: "add a very thin layer of flame around
   glass bridge and the study" … then "get rid of the [flames] and re do them pixel perfect" — "on pc around the warlord
   run glass and the study"): src/components/showcase-flames/ draws them in the page — each shield measured as it is
   shown, a canvas per shield whose pixels are the screen's own (its size and place set from the script in whole device
   pixels), so every flame pixel is the same crisp square and the burning line sits on the real edge. The row is their
   containing block, so they scroll with it; they take no clicks. */
.originals-showcase__stage { position: relative; }        /* (phones too since 2026-10-20: the same flames there) */
/* …which lifts the row over the heading its top 33 px reach under (the room for Glass Bridge): the heading and its ‹ ›
   stay on top, so the arrows still take the clicks */
.originals-showcase--rail .section-header { position: relative; z-index: 4; }
.os-flame {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 3;
  pointer-events: none;
  image-rendering: pixelated;
}
/* no "Originals" heading on screen (owner 2026-10-15: "remove this text"): still read out. The games sit close under the
   tab bar ("move all games slightly closer to the options still make sure glass is above others"): 20 px, Glass Bridge
   still the tallest; the tips of its fire may reach the tab bar's lower edge and draw over it (.os-grow z-index 2; the
   Lobby tab's bar has no menus that open over the row) */
.originals-showcase__title {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}
.originals-showcase { padding-top: 20px; }
html .originals-showcase .originals-showcase__stage .game-card {
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 4;
}
@media (max-width: 1100px) {
  .originals-showcase__stage { --os-gap: 8px; }
}
/* ON PHONES (owner 2026-10-16: "make the originals section on mobile 3 top row even size including glass bridge and 4 row
   under even size"; tried before it the same day, all in ../removed-features-backup/originals-showcase-phones-2026-10-16/:
   the shield over a 3 x 2 grid, the small PC line, the owner's picture with Blackjack / HiLo as puzzle pieces under a
   big shield): up to 560 px wide —
       Mines   [shield]   Limbo           three even tiles
       Keno  Blackjack  Dice  HiLo        four even tiles
   one 12-track grid (a top tile spans 4 tracks, a bottom one 3, so both rows share the outer edges and the 8 px gap).
   Glass Bridge's decor box is 150 % of its cell (78 x 72 art px, the shield the middle 56), standing on the row's bottom
   line, so the shield is ~10 % taller and wider than the tiles beside it and rises above them, its bottom level with
   theirs (owner: "make glass bridge a bit bigger than the ones next to it and taller but not lower same level low"; it
   was 136 % = the tiles' size); its fire round the edge. A visitor: the blue games on
   the left, the red on the right. The wings are display: contents, so each game is placed by its place in its wing.
   Tablets and phones held sideways (561–768 px) keep the PC line.
   Undo: ../removed-features-backup/originals-showcase-phones-2026-10-16/README.txt */
@media (max-width: 560px) {
  /* no "ORIGINALS" heading on phones either (owner 2026-10-16: "remove this and make games higher"; it was shown between a
     blue and a red line — the hidden h2 is still read out). Closer to the grass since 2026-10-23 (owner: "Move the game
     tiles up so they sit closer to the grass layer. Reduce the gap … by about 50% … Keep spacing consistent across screen
     sizes"): the phone home has no tab bar over the row any more, so the top row starts ~32 px under the grass line (was
     58: 36 px here + the lobby's 16 px gap), the same on every phone; Glass Bridge, lifted ~8 % of the column above the
     row, never reaches the grass (the max() keeps its top ≥ 2 px under it on the widest phones). Undo
     ../removed-features-backup/mobile-list-2026-10-23/README.txt
     A strip of dirt above it since the evening of 2026-10-23 (owner: "Mobile need slightly more of a gap between grass
     and game should show some dirt"): Glass Bridge's top ~20 px under the grass line on every phone (it was 3–7 px:
     its fire border sat on the grass); undo ../removed-features-backup/phone-grass-gap-2026-10-23/README.txt */
  .originals-showcase { padding-top: max(24px, calc(8% - 2px)); }
  .originals-showcase__stage {
    --os-gap: 8px;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    /* between the fire row (Warlord Run, Glass Bridge, The Study) and the four games under it: 14 px since the afternoon
       of 2026-10-25 (owner: "Add gap between the multiplayer house games (the ones on fire) and the normal originals
       move the normal ones ever so slightly lower"; it was 8 px — the fire reaches 3–5 px under the three, so it all
       but touched them). Undo ../removed-features-backup/phone-originals-gap-2026-10-25/README.txt */
    row-gap: 14px;
    align-items: start;
  }
  /* its size and decor: ".originals-showcase__feature--m" below (the phone thumbnail, set by Lobby.tsx at the same width) */
  .originals-showcase__feature {
    grid-area: 1 / 5 / 2 / 9;
    align-self: end;
  }
  .originals-showcase__wing--left > :nth-child(1) { grid-area: 1 / 1 / 2 / 5; }
  .originals-showcase__wing--right > :nth-child(1) { grid-area: 1 / 9 / 2 / 13; }
  /* Mines / Limbo 91 % of their cell, at the outer edges, their bottoms on the row's bottom line: ~11 px clear on each side
     of the shield (owner 2026-10-16: "leave more gap on the right and left of glass bridge"; at full width the shield all
     but touched them). The html … .game-card selector outranks the showcase's width: 100 % rule. */
  html .originals-showcase .originals-showcase__wing--left > .game-card:nth-child(1) { width: 91%; justify-self: start; align-self: end; }
  html .originals-showcase .originals-showcase__wing--right > .game-card:nth-child(1) { width: 91%; justify-self: end; align-self: end; }
  /* Mobile Warlord Run / The Study use the new 432 x 549 artwork in Mines / Limbo's places.
     Preserve their outer-edge spacing; the transparent corners remain visible. They stand on Glass Bridge's bottom line
     since 2026-10-25 (owner: "bring the study and warlord so that the bottom of the thumbnail is inline with glass
     bridge"; they were ~8 px lower, Glass Bridge being lifted): the row's bottom line IS Glass Bridge's bottom now
     (".originals-showcase__feature--m" below: no margin under it), and their -4 % top margin keeps them from setting the
     row's height (they are 1.156 x the area's width tall, Glass Bridge's box with its -20 % top margin 1.139 x), so
     Glass Bridge stays exactly where it was and they rise ~8 px. Undo
     ../removed-features-backup/phone-originals-row-2026-10-25/README.txt */
  .originals-showcase .os-side--phone { width: 91%; aspect-ratio: 432 / 549; align-self: end; margin-top: -4%; }
  .originals-showcase .os-side--phone.os-side--left { justify-self: start; }
  .originals-showcase .os-side--phone.os-side--right { justify-self: end; }
  .originals-showcase .os-side--phone .os-side__img { width: 100%; height: 100%; max-width: 100%; object-fit: contain; }

  /* the four games under them: the second row, 14 px (the row gap above; 8 px that morning) under the three's bottom line —
     since 2026-10-25 (owner:
     "Remove 1st 2nd and 3rd … and move all the other games under it up"): 1ST / 2ND / 3RD stood in a row of their own
     between the two, 39 px of space on an iPhone 14 */
  .originals-showcase__wing--left > :nth-child(2) { grid-area: 2 / 1 / 3 / 4; }
  .originals-showcase__wing--left > :nth-child(3) { grid-area: 2 / 4 / 3 / 7; }
  .originals-showcase__wing--right > :nth-child(2) { grid-area: 2 / 7 / 3 / 10; }
  .originals-showcase__wing--right > :nth-child(3) { grid-area: 2 / 10 / 3 / 13; }
}

/* Glass Bridge's box (78 x 72 art pixels, a tile high): faint cracks in the stone, the cracks burning blue (on hover /
   focus), then .os-grow: a blue light and blue fire round the shield's edge and the shield in the middle 56, all grown
   6 % from the bottom line (owner: "make glass bridge slightly slightly bigger not going below the other games but
   slightly taller"). Nothing is cut at an edge (owner: "make sure the flames arent blocked off like the cracks in
   cement are blocked off on the bottom"): the fire / light canvas is 90 x 90 with the box at x 6, y 10; the cracks
   canvas 94 x 98 with the box at x 8, y 10 — both reach past the row's bottom line, and every crack thins out.
   The cracks are short at the sides and run a little further out of the shield's point along the floor below the row
   ("make the cracks smaller again but little more length coming out the bottom of thumbnail"), with some by the
   shoulders reaching up past the row's top ("add some cracks in this area") and the same amount left, right and
   underneath but never mirrored ("make sure its even but not symetrical"; a version reaching
   under two games a side was tried just before). They lie behind the tiles (the box makes no stacking layer of its
   own: the cracks are z-index 0, the tiles 1, .os-grow 2). At rest the fire is calm (small dim licks, slower); pointing at the game brings the
   full fire ("calm the fire down unless player is hovering over game"). */
.originals-showcase__feature {
  position: relative;               /* no z-index: the cracks go behind the neighbouring tiles */
  aspect-ratio: 78 / 72;
}
.os-decor--ground { z-index: 0; }
.os-decor { position: absolute; inset: 0; pointer-events: none; }
.os-decor > span {
  position: absolute;
  background-repeat: no-repeat;
  image-rendering: pixelated;
}
.os-decor__cracks,
.os-decor__cracks-lit {
  left: -10.256%;                    /* 8 / 78 */
  top: -13.889%;                     /* 10 / 72 */
  width: 120.513%;                   /* 94 / 78 */
  height: 136.111%;                  /* 98 / 72 */
}
.os-decor__cracks {
  background-image: url("/theme/castle/showcase/cracks.png");
  background-size: 100% 100%;
  opacity: 0.8;
}
/* the lit cracks: the original two-frame flicker (owner 2026-10-16: "These flames at bottom look weird make them look like
   normal" — the 12-frame flame version cracks-lit-v2 of that morning is in ../removed-features-backup/showcase-cracks-normal-2026-10-16/) */
.os-decor__cracks-lit {
  background-image: url("/theme/castle/showcase/cracks-lit.png");
  background-size: 200% 100%;
  opacity: 0;
  clip-path: circle(0% at 50% 60%);   /* the canvas's 60 % = the middle of the shield */
  transition: clip-path 0.22s ease-in, opacity 0.22s ease-in;
  animation: os-cracks 0.34s step-end infinite;
}
.os-decor__glow,
.os-decor__flame {
  left: -7.692%;                     /* 6 / 78 */
  top: -13.889%;                     /* 10 / 72 */
  width: 115.385%;                   /* 90 / 78 */
  height: 125%;                      /* 90 / 72 */
}
.os-grow {
  position: absolute;
  inset: 0;
  z-index: 2;                        /* above the tiles (1) and the cracks (0) */
  transform: scale(1.06);
  transform-origin: 50% 100%;        /* the bottom line stays where every tile ends */
  pointer-events: none;
}
.os-grow .os-shield { pointer-events: auto; }
/* COMPUTERS DRAW NONE OF THE DECOR since 2026-10-18 (owner: "also remove the flames and the cracks"; Lobby.tsx
   SHOWCASE_PC_DECOR = false): the PC pictures named by the rules below (cracks*, glow / glow-red*, flame-calm / -mid*)
   are in ../removed-features-backup/showcase-pc-decor-removed-2026-10-18/; phones draw none since 2026-10-20 either (the page
   draws the pixel-perfect flame there too, ShowcaseFlames). */
.os-decor__glow {
  background-image: url("/theme/castle/showcase/glow.png");
  background-size: 100% 100%;
  mix-blend-mode: screen;
  opacity: 0.5;
  transition: opacity 0.3s ease;
  animation: os-glow 2.8s ease-in-out infinite;
}
.os-decor__flame {
  background-size: 1200% 100%;
  transition: opacity 0.3s ease, filter 0.3s ease;
  animation: os-flame 1.2s step-end infinite;
}
.os-decor__flame--calm { background-image: url("/theme/castle/showcase/flame-calm.png"); animation-duration: 2.2s; }
/* the hover fire is the gentler "mid" fire since 2026-10-18 (owner: "the flame is too much can you lessen the flame when you
   hover over it"): shorter tongues, no second band down the sides, no brightness boost, the light at 75 % — between the
   calm fire at rest and the old full one (flame.png / flame-red.png, now in
   ../removed-features-backup/glass-bridge-flame-softer-2026-10-18/); drawn by
   ../banner-work/originals-gap-2026-10-18/tools/make-flame-mid.mjs. */
.os-decor__flame--full { background-image: url("/theme/castle/showcase/flame-mid.png"); opacity: 0; }
/* pointed at, focused or pressed (phones have no pointing: a finger on it — owner 2026-10-16): the cracks catch fire
   out from the shield, the fire and its light burn brighter */
.originals-showcase__feature:has(.os-shield:hover, .os-shield:focus-visible, .os-shield:active) .os-decor__cracks-lit {
  opacity: 1;
  clip-path: circle(80% at 50% 60%);
  transition: clip-path 0.6s cubic-bezier(0.2, 0.8, 0.3, 1), opacity 0.1s linear;
}
.originals-showcase__feature:has(.os-shield:hover, .os-shield:focus-visible, .os-shield:active) .os-decor__flame--calm { opacity: 0; }
.originals-showcase__feature:has(.os-shield:hover, .os-shield:focus-visible, .os-shield:active) .os-decor__flame--full { opacity: 1; }
.originals-showcase__feature:has(.os-shield:hover, .os-shield:focus-visible, .os-shield:active) .os-decor__glow { opacity: 0.75; animation-duration: 1.1s; }
@keyframes os-flame {
  0% { background-position: 0 0; }
  8.333% { background-position: 9.091% 0; }
  16.667% { background-position: 18.182% 0; }
  25% { background-position: 27.273% 0; }
  33.333% { background-position: 36.364% 0; }
  41.667% { background-position: 45.455% 0; }
  50% { background-position: 54.545% 0; }
  58.333% { background-position: 63.636% 0; }
  66.667% { background-position: 72.727% 0; }
  75% { background-position: 81.818% 0; }
  83.333% { background-position: 90.909% 0; }
  91.667% { background-position: 100% 0; }
}
@keyframes os-cracks {
  0% { background-position: 0 0; }
  50% { background-position: 100% 0; }
}
@keyframes os-glow {
  0%, 100% { opacity: 0.75; }
  50% { opacity: 1; }
}

/* the shield: in the middle 56 of the 78, a tile high, standing on the bottom line (it stays put on hover — the
   cracks lighting up are its hover; the fire behind it would come apart from its edge if it lifted) */
.os-shield {
  position: absolute;
  z-index: 1;
  left: 14.103%;
  top: 0;
  width: 71.795%;
  height: 100%;
  display: block;
}
.os-shield__img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center bottom;
  display: block;
  filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.45));
  /* nothing on the picture itself animates when it is pointed at (owner 2026-10-18: "why does the glass bridge game kinda
     go blurry and unblurry when you hover or dont"): the 0.3 s brightness fade made Chrome draw the shrunken picture with
     its fast filter until the fade ended, then the careful one — soft / sharp. The fire and the cracks are the hover; the
     pictures are made at the size they are shown (720 px tall, ../banner-work/glass-bridge-blur-2026-10-18/tools/
     make-shield-sized.mjs). Undo: ../removed-features-backup/glass-bridge-blur-2026-10-18/README.txt */
  transition: opacity 0.35s var(--ease-out, cubic-bezier(0.33, 1, 0.68, 1));
}
.os-shield:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
@media (prefers-reduced-motion: reduce) {
  .os-decor__glow, .os-decor__flame, .os-decor__cracks-lit { animation: none; }
  .os-decor__cracks-lit { clip-path: none; transition: opacity 0.2s linear; }
  .originals-showcase__feature:has(.os-shield:hover, .os-shield:focus-visible, .os-shield:active) .os-decor__cracks-lit { clip-path: none; transition: opacity 0.2s linear; }
}
/* A Red Crown player (owner 2026-10-16: "if player is on red team change the game to this with red flames"): the red
   shield (Lobby.tsx FEATURED_SHIELD_RED) with the same decor in red fire — the same sizes and frames, drawn by
   make-showcase-decor.mjs --red (its cracks fit the red shield's own outline). Undo:
   ../removed-features-backup/red-glass-bridge-shield-2026-10-16/README.txt */
.originals-showcase__feature--red .os-decor__cracks { background-image: url("/theme/castle/showcase/cracks-red.png"); }
.originals-showcase__feature--red .os-decor__cracks-lit { background-image: url("/theme/castle/showcase/cracks-lit-red.png"); }
.originals-showcase__feature--red .os-decor__glow { background-image: url("/theme/castle/showcase/glow-red.png"); }
.originals-showcase__feature--red .os-decor__flame--calm { background-image: url("/theme/castle/showcase/flame-calm-red.png"); }
.originals-showcase__feature--red .os-decor__flame--full { background-image: url("/theme/castle/showcase/flame-mid-red.png"); }



/* Visitor PC showcase: blue left / red right, including both halves of Glass Bridge.
   Masks preserve the cracks' circular hover reveal and the overflowing flames. */
.originals-showcase__feature--split .os-shield__img--blue-half,
.originals-showcase__feature--split .os-shield__img--red-half {
  position: absolute;
  inset: 0;
}
/* Keep a full blue image under the red fade so the artwork never becomes see-through. */
.originals-showcase__feature--split .os-shield__img--blue-half { clip-path: none; }
.originals-showcase__feature--split .os-shield__img--red-half {
  clip-path: none;
  -webkit-mask-image: linear-gradient(to right, transparent 0 42%, #000 58% 100%);
  mask-image: linear-gradient(to right, transparent 0 42%, #000 58% 100%);
  /* no shadow of its own (owner 2026-10-18: "theres most blackborder around the right side than the left"): the full blue
     picture under it already casts the shield's shadow; a second one doubled the dark band down the right side */
  filter: none;
}
/* The fire overlaps through a wider violet transition, independent of the crack reveal. */
.originals-showcase__feature--split .os-decor--blue-half > span {
  -webkit-mask-image: linear-gradient(to right, #000 0 36%, transparent 64% 100%);
  mask-image: linear-gradient(to right, #000 0 36%, transparent 64% 100%);
}
.originals-showcase__feature--split .os-decor--red-half > span {
  -webkit-mask-image: linear-gradient(to right, transparent 0 36%, #000 64% 100%);
  mask-image: linear-gradient(to right, transparent 0 36%, #000 64% 100%);
}
.originals-showcase__feature--split .os-decor--blue-half > .os-decor__glow {
  -webkit-mask-image: linear-gradient(to right, #000 0 24%, transparent 76% 100%);
  mask-image: linear-gradient(to right, #000 0 24%, transparent 76% 100%);
}
.originals-showcase__feature--split .os-decor--red-half > .os-decor__glow {
  -webkit-mask-image: linear-gradient(to right, transparent 0 24%, #000 76% 100%);
  mask-image: linear-gradient(to right, transparent 0 24%, #000 76% 100%);
}
/* Add coloured light rather than fading both flame layers into a dark stripe. */
.originals-showcase__feature--split .os-decor__glow,
.originals-showcase__feature--split .os-decor__flame,
.originals-showcase__feature--split .os-decor__cracks-lit {
  mix-blend-mode: screen;
  mix-blend-mode: plus-lighter;
}
.originals-showcase__feature--split .os-decor--blue-half > .os-decor__cracks {
  -webkit-mask-image: none;
  mask-image: none;
}
/* the split's red fire is as bright as its blue fire (owner 2026-10-18: "flames need to be even on both sides around glass
   bridge theres more showing on bottom left than bottom right"): the *-red-split pictures = the red fire with each tone
   lifted so that, drawn here — added to the stone with its glow —, it is as light as its blue twin
   (banner-work/glass-bridge-border-2026-10-18/tools/make-split-red.mjs); the Red Crown's own fire (feature--red) keeps
   the red pictures. The lit cracks keep each shield's own drawing (even but not symmetrical): cracks-lit-red-split.png =
   the red drawing, its colours lifted the same way and fitted so the bottom right is as lit as the bottom left */
.os-decor--red-half .os-decor__cracks { background-image: url("/theme/castle/showcase/cracks-red.png"); }
.os-decor--red-half .os-decor__cracks-lit { background-image: url("/theme/castle/showcase/cracks-lit-red-split.png"); }
.os-decor--red-half .os-decor__glow { background-image: url("/theme/castle/showcase/glow-red-split.png"); }
.os-decor--red-half .os-decor__flame--calm { background-image: url("/theme/castle/showcase/flame-calm-red-split.png"); }
.os-decor--red-half .os-decor__flame--full { background-image: url("/theme/castle/showcase/flame-mid-red-split.png"); }

/* ON PHONES: Glass Bridge's own thumbnail (owner 2026-10-16: three thumbnails with a flat top and bottom — split, red,
   blue — "these are for mobile leave pc one how it is adjust the flame and cracks according to the new thumbnail size").
   Lobby.tsx adds .originals-showcase__feature--m up to 560 px (the phone 3 + 4 layout) and picks the picture (visitors:
   the one split picture, so no second masked image). The decor box = the thumbnail's box, 57 x 72 art px (its shape),
   the thumbnail filling it; 106 % of its cell wide (~15 px clear of Mines / Limbo; it was 114 %), its bottom on the row's
   bottom line, growing up out of the row (margin-top -13 %, so the row keeps Mines / Limbo's height); no extra scale-up. The fire /
   light canvas reaches 6 / 10 / 6 / 8 art px past the box (69 x 90), the cracks canvas 8 / 10 / 8 / 16 (73 x 98); the
   "-m" art follows the thumbnail's outline (../banner-work/glass-bridge-2026-10-15/tools/make-showcase-decor-mobile.mjs).
   Selectors carry the --m class so they outrank the PC rules above. Undo:
   ../removed-features-backup/glass-bridge-mobile-thumb-2026-10-16/README.txt */
.originals-showcase .originals-showcase__feature--m {
  aspect-ratio: 57 / 72;
  width: 106%;                       /* "make the glass bridge slightly smaller dont make ones next to it bigger just leave a gap" (was 114 %) */
  margin-inline: -3%;
  margin-top: -20%;                  /* -13 % - the 7 % it is lifted by ("move the glass bridge game a bit higher not much just a bit") */
  margin-bottom: 0;                  /* its bottom = the row's bottom line, which Warlord Run / The Study share since 2026-10-25
                                        (it was 7 %: the row's line then was theirs, ~8 px under Glass Bridge on an iPhone 14) */
}
.originals-showcase__feature--m .os-grow { transform: none; }
.originals-showcase__feature--m .os-shield { left: 0; width: 100%; }
/* No cracks and no fire pictures on phones: since 2026-10-20 the page draws the PC's pixel-perfect flame round the
   thumbnail too (ShowcaseFlames; owner: "fix the flames on mobile now it still has the old one make it pixel perfect around
   the game and same flame look as pc"). The old "-m" fire / glow pictures and their rules are in
   ../removed-features-backup/phone-flames-pixel-2026-10-20/ (undo there). */

/* PHONES: LOAD MORE (owner 2026-10-20: "on mobile under the house show an option like this and then when clicked it shows
   the missing house games also make it so it says show less and you can make back to normal"): under the showcase the
   house games it doesn't show (Lobby.tsx phoneMore), in a row of tiles the bottom row's size, opened by the divider
   button — a line, "Load More", a line — which then says "Show Less". Undo
   ../removed-features-backup/phone-originals-more-2026-10-20/README.txt */
.originals-more { display: none; }
@media (max-width: 560px) {
  /* close to the Originals above and Popular Slots below (owner 2026-10-20: "make this have less room between popular
     slots and the originals it should be close"): the bar keeps its 40 px tap height, the margins pull it in — ~12 px
     from the tiles to "Load More", ~14 px from it to the heading; open, the extra tiles sit 8 px under the row above and
     "Show Less" ~12 px under them */
  .originals-more { display: flex; flex-direction: column; gap: 12px; margin-top: -10px; margin-bottom: -16px; }
  .originals-more.is-open { margin-top: -4px; gap: 2px; }
  .originals-more__grid { display: flex; justify-content: center; gap: 8px; }
  html .originals-more__grid > .game-card { flex: 0 0 calc((100% - 24px) / 4); width: auto; height: auto; aspect-ratio: 3 / 4; }
  .originals-more__toggle {
    display: flex;
    align-items: center;
    gap: 14px;
    width: 100%;
    min-height: 40px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--text-muted);
    font: inherit;
    font-size: 16px;
    letter-spacing: 0.02em;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .originals-more__toggle::before,
  .originals-more__toggle::after { content: ''; flex: 1 1 auto; height: 1px; background: var(--border-strong, var(--border-color)); }
  .originals-more__toggle:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
}
@media (max-width: 560px) and (hover: hover) {
  .originals-more__toggle:hover { color: var(--text-primary); }
}
