/* @alc-notice */
/*!
 * Copyright (c) 2026 Alien Life Creations. All rights reserved.
 *
 * This file is part of a proprietary work. It is served to your browser
 * because a browser cannot run code it has not received; that is a technical
 * necessity and not a grant of any licence. You may not copy, redistribute,
 * or create derivative works from it.
 *
 * alienlifecreations.com | alienlifearcade.com | alienlifestudio.com
 */
/* @alc-notice-end */
/* ALIEN LIFE ARCADE — shared chrome
 *
 * ONE SOURCE OF TRUTH for tokens and chrome (AEONGRADE Gate 4). Every page
 * mounts this; no page forks it and no page inlines a second copy of a token.
 *
 * The palette is inherited VERBATIM from alienlifecreations.com's _shared/
 * styles.css so the two sites read as siblings rather than as two studios.
 * Values were copied from the live file, not from a doc, because the standard's
 * prose describes the Theories of Anything TIER palette (gold/cyan/violet/stone,
 * where colour is an evidence claim) and that is a different argument for a
 * different site. Here colour identifies a game, not a confidence level.
 */

:root {
  /* ---- inherited from ALC, do not drift ---- */
  --green:#48FF2B;  --green-deep:#2ECF1A;
  --cyan:#3FFAF5;   --cyan-deep:#1F9AA5;
  --violet:#A35AAF; --violet-deep:#6E3C79;
  --lime:#93FB06;   --lime-deep:#5FA400;
  --gold:#DBFF07;   --gold-deep:#A6C000;

  --space:#0A0A12;
  --space-2:#0E1420;
  --card:#0F1620;
  --card-2:#0C121b;
  --card-line:#1E3A2A;
  --ink:#EAF2E8;
  --ink-soft:#9DB2A6;
  --ink-label:#7FBF6A;

  --maxw:1160px;
  --font:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;

  /* ---- borrowed, not invented ----
   * --neon is theoriesofanything.com's --violet, live there and brighter than
   * ALC's #A35AAF. --flow-pink is alienlifeshop.com's --pink, the same hex the
   * studio uses for its edge. Both are declared in _build/BORROWED.json and
   * `family_gate.py` reads those sites' own stylesheets, so if either repaints
   * this goes red and names the token rather than drifting quietly. */
  --neon: #9B5DE5;
  --flow-pink: #FF4FD8;

  /* THE TUBE (Gortiva, 2026-09-18). A repeating gradient with a FIXED PIXEL
   * PERIOD, animated by exactly that period, so the loop is seamless by
   * construction rather than by a percentage that happens to line up. Every
   * stop is a live colour from one of the four sibling sites.
   *
   * A repeating-linear-gradient and not a percentage one, deliberately: with
   * percentages the cycle length changes with the element, so a wide footer
   * and a narrow card would flow at different speeds and the page would look
   * like two animations. A pixel period makes every tube on the page one
   * continuous piece of tubing running at one speed. */
  --flow-period: 280px;
  --flow: repeating-linear-gradient(90deg,
    var(--neon)       0px,
    var(--flow-pink) 70px,
    var(--cyan)     140px,
    var(--green)    210px,
    var(--neon)     280px);

  /* ---- arcade's own, additive only ---- */
  --accent: var(--green);          /* per-page accent, overridden inline */
  --rule: color-mix(in srgb, var(--accent) 22%, transparent);
  --glow: color-mix(in srgb, var(--accent) 45%, transparent);
}

* { box-sizing: border-box; }

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

/* Thin alien-green scrollbars, carried over from ALC's own sheet. Cheap, and it
 * is one of the few chrome details a visitor reads as "this is a made thing". */
html { scrollbar-width: thin; scrollbar-color: rgba(46,207,26,.55) transparent; }
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(46,207,26,.55); border-radius: 99px; }
::-webkit-scrollbar-thumb:hover { background: var(--green); }

body {
  margin: 0;
  /* 100vh FIRST as the fallback, then 100dvh, per the estate rule for any
   * mobile-reachable page: on iOS the dynamic bar makes 100vh overflow. */
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--space);
  color: var(--ink);
  font: 16px/1.65 var(--font);
  overflow-x: clip;                /* U3: no horizontal scroll, ever */
  -webkit-font-smoothing: antialiased;
}

/* The drifting starfield, shared with alienlifecreations.com. Sits under every
 * layer of content: z-index 0, with `.wrap` and the chrome at 1 and above.
 *
 * `pointer-events: none` is NOT a mistake here even though the field is
 * interactive: the script binds click and mousemove on `document` and `window`,
 * so the canvas must stay transparent to the pointer or it would swallow every
 * click on the page. Matched to ALC's own value deliberately, because diverging
 * from a proven config is how you find out which half of it was load-bearing. */
#constellation {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}

/* The field. A very faint grid that reads as depth without competing with
 * anything. Static by default: it earns no motion, so it gets none. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(1200px 620px at 50% -12%,
      color-mix(in srgb, var(--accent) 9%, transparent), transparent 70%),
    repeating-linear-gradient(0deg, transparent 0 38px,
      color-mix(in srgb, var(--accent) 4%, transparent) 38px 39px),
    repeating-linear-gradient(90deg, transparent 0 38px,
      color-mix(in srgb, var(--accent) 4%, transparent) 38px 39px);
  mask-image: linear-gradient(180deg, #000 0%, #000 45%, transparent 92%);
}

.wrap {
  position: relative;
  z-index: 1;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 20px 96px;
}

/* ---------------------------------------------------------------- chrome */

.site-head {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 14px;
  max-width: var(--maxw);
  margin: 0 auto;
  /* THE BOTTOM PADDING IS THE TUBE'S CLEARANCE, not spacing for its own sake.
     It was 0, which was right when the header had no rule under it: the flow
     tube then landed on the bottom edge of the content box, which is exactly
     the wordmark's baseline, and the line ran straight through the medallion
     and the letters. 18px puts the rule below the mark instead of across it.
     Gortiva spotted it on the live site, 2026-09-19. */
  padding: 22px 20px 18px;
}

.wm {
  display: flex;
  align-items: center;
  gap: 11px;
  text-decoration: none;
  color: inherit;
}
/* The mark is the studio's own character, the SAME file the browser tab shows.
 * It replaced a drawn ring-and-dot: the ring was fine but it was a mark this
 * site invented for itself, and one identity across the tab, the header, the
 * home screen and the share card is worth more than a bespoke glyph. */
.wm-mark {
  width: 34px; height: 34px;
  flex: 0 0 34px;
  border-radius: 50%;
  display: block;
  box-shadow: 0 0 20px color-mix(in srgb, var(--green) 34%, transparent);
  transition: box-shadow .2s, transform .2s;
}
.wm:hover .wm-mark, .wm:focus-visible .wm-mark {
  box-shadow: 0 0 26px color-mix(in srgb, var(--green) 55%, transparent);
  transform: scale(1.04);
}
/* The wordmark is a div, NOT an h1. The page's single h1 is its subject. */
.wm-title {
  font: 600 15px/1 var(--mono);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink);
}
.wm-title b { color: var(--accent); font-weight: 600; }

.site-nav { margin-left: auto; display: flex; gap: 4px; }
.site-nav a {
  font: 500 13px/1 var(--font);
  color: var(--ink-soft);
  text-decoration: none;
  padding: 9px 12px;
  border-radius: 7px;
  transition: color .18s, background .18s;
}
.site-nav a:hover, .site-nav a:focus-visible {
  color: var(--ink);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}

/* ------------------------------------------------------- the bubble pass */

.hero-bubble {
  margin: 54px auto 0;
  padding: 46px 34px 42px;
  max-width: 880px;
  text-align: center;
  background:
    radial-gradient(120% 140% at 50% 0%,
      color-mix(in srgb, var(--accent) 8%, transparent), transparent 62%),
    var(--card-2);
  border: 1px solid var(--card-line);
  border-radius: 20px;
  /* A cool RIM rather than a warm smear. The first version threw a wide
   * accent-coloured shadow below the bubble and it read as a green puddle the
   * eye went to before the headline: a key that competes with the subject is
   * not a key. The light now describes the EDGE and stops. */
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 10%, transparent),
              0 1px 0 color-mix(in srgb, var(--accent) 16%, transparent) inset,
              0 26px 70px -60px #000;
}

.eyebrow {
  font: 600 11px/1 var(--mono);
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--ink-label);
  margin-bottom: 18px;
}

.hero-bubble h1 {
  margin: 0;
  font-size: clamp(30px, 6.4vw, 54px);
  line-height: 1.06;
  letter-spacing: -.022em;
  font-weight: 700;
}
.hero-bubble h1 .g {
  color: var(--accent);
  text-shadow: 0 0 34px var(--glow);
}

.hero-deck {
  margin: 20px auto 0;
  max-width: 62ch;
  color: var(--ink-soft);
  font-size: clamp(15px, 2.1vw, 18px);
}

.stat-row {
  margin-top: 26px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 16px;
  justify-content: center;
  font: 500 12px/1 var(--mono);
  letter-spacing: .08em;
  color: var(--ink-soft);
}
.stat-row b { color: var(--ink); font-weight: 600; }
.dot {
  width: 3px; height: 3px;
  border-radius: 50%;
  background: var(--ink-soft);
  opacity: .5;
  align-self: center;
}

/* A labelled divider. Labels are Capital-First; the node is the punctuation. */
.signal-rule {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 58px 0 24px;
  font: 600 11px/1 var(--mono);
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--ink-label);
}
.signal-rule::before, .signal-rule::after {
  content: "";
  height: 1px;
  flex: 1;
  background: linear-gradient(90deg, transparent, var(--rule), transparent);
}
.signal-rule .node {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 12px var(--accent);
}

.sec-head {
  text-align: center;
  font-size: clamp(21px, 3.4vw, 28px);
  letter-spacing: -.015em;
  margin: 0 0 6px;
}
.lead {
  max-width: 62ch;
  margin: 0 auto 26px;
  text-align: center;
  color: var(--ink-soft);
}

/* --------------------------------------------------------------- the grid */

.game-grid {
  display: grid;
  /* U3: minmax(min(Npx,100%),1fr), never a bare fixed minimum, or the track
   * overflows its container below Npx and the page scrolls sideways. */
  grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
  gap: 18px;
}

/* THE SHELF NOTE spans every column. It sits INSIDE .game-grid rather than
 * above it so the heading, the note and the cards are one landmark to a screen
 * reader instead of three; a grid child with no column span would otherwise
 * take one card's slot and leave a hole in the row. */
.game-grid > .shelf-note {
  grid-column: 1 / -1;
  margin: -6px 0 2px;
  max-width: 68ch;
  font: 400 14px/1.55 var(--font);
  color: var(--ink-soft);
}

/* THE CABINET. Gortiva, 2026-09-18: the arcade and the studio had byte-
 * identical colour tokens and read as one site. They keep the same GEOMETRY,
 * because U1 owns the layout and U3 owns the responsive floor, and take
 * different MATERIAL.
 *
 * This is a cabinet: a hard lit top edge where a machine's moulding catches
 * the room light, and the accent burning at the corners the way a bezel does.
 * The studio's container is the opposite, a film gate: matte plate, inner
 * bevel, sprocket perforation down the leading edge. Same bones, and nobody
 * would mistake one page for the other.
 *
 * Every value below is drawn from --ca (the per-card accent) or --accent (the
 * per-page one), so a card stays the colour its game already declared. */
.gcard {
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--card-line);
  border-radius: 14px;
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  position: relative;
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--ca, var(--accent)) 14%, transparent),
              0 1px 0 rgba(0, 0, 0, .5);
  transition: border-color .2s, transform .2s, box-shadow .2s;
}
/* the moulding: two short lit runs at the top corners, not a full rule, so it
 * reads as a moulded edge catching light rather than as another border. */
.gcard::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  pointer-events: none;
  z-index: 2;
  background:
    linear-gradient(90deg,
      var(--ca, var(--accent)) 0, transparent 34px),
    linear-gradient(270deg,
      var(--ca, var(--accent)) 0, transparent 34px);
  opacity: .5;
}
.gcard:hover::before, .gcard:focus-visible::before { opacity: .92; }
.gcard:hover, .gcard:focus-visible {
  border-color: color-mix(in srgb, var(--ca, var(--accent)) 55%, transparent);
  transform: translateY(-3px);
  box-shadow: 0 22px 50px -34px var(--ca, var(--accent));
}

/* Thumbnail-led card, so the accent rides the EYEBROW rather than a 3px left
 * bar. That is the documented exemption for media cards (episodes, videos) and
 * it is recorded here as a decision rather than left as an accident. */
.gcard .art {
  position: relative;
  aspect-ratio: 16 / 9;
  background: linear-gradient(140deg, var(--space-2), var(--card-2));
  display: grid;
  place-items: center;
  border-bottom: 1px solid var(--card-line);
}
.gcard .art img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* An empty art slot must read as WAITING, not as a broken image. A card with a
 * blank rectangle is the same failure as a 404 thumbnail: the visitor cannot
 * tell "not made yet" from "went wrong", so the slot says which. Drawn in CSS,
 * so it costs no request and cannot itself 404. */
.gcard .art:not(:has(img))::after {
  content: "";
  width: 46px; height: 46px;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--ca, var(--accent)) 42%, transparent);
  box-shadow: 0 0 0 7px color-mix(in srgb, var(--ca, var(--accent)) 7%, transparent),
              0 0 26px color-mix(in srgb, var(--ca, var(--accent)) 22%, transparent);
  background:
    radial-gradient(circle at 50% 50%,
      color-mix(in srgb, var(--ca, var(--accent)) 55%, transparent) 0 2.5px,
      transparent 3px);
}

.gcard .genre {
  position: absolute;
  top: 10px; left: 10px;
  font: 600 10px/1 var(--mono);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ca, var(--accent));
  background: color-mix(in srgb, var(--space) 78%, transparent);
  border: 1px solid color-mix(in srgb, var(--ca, var(--accent)) 30%, transparent);
  padding: 6px 9px;
  border-radius: 6px;
  backdrop-filter: blur(4px);
}

.gcard .body { padding: 16px 17px 18px; display: flex; flex-direction: column; gap: 9px; flex: 1; }
.gcard h3 { margin: 0; font-size: 18px; letter-spacing: -.01em; }
.gcard p { margin: 0; color: var(--ink-soft); font-size: 14.5px; flex: 1; }

/* Capability strip. Every chip here is CHECKABLE by the bench against the
 * built game, which is the whole reason it exists: a claim a player can read
 * before spending a click, and that a gate can falsify. */
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  font: 500 11px/1 var(--mono);
  letter-spacing: .06em;
  color: var(--ink-soft);
  border: 1px solid var(--card-line);
  border-radius: 5px;
  padding: 5px 7px;
}
/* The SHAPE chip is the one fact a player needs before they tap: which way to
 * hold the phone. Accented so it reads first among the input chips. */
.chip.shape { color: var(--ca, var(--accent)); border-color: color-mix(in srgb, var(--ca, var(--accent)) 34%, transparent); }
.chip.on { color: var(--ca, var(--accent)); border-color: color-mix(in srgb, var(--ca, var(--accent)) 34%, transparent); }

.go {
  margin-top: 4px;
  font: 600 13px/1 var(--font);
  color: var(--ca, var(--accent));
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

/* The honest empty state. Not a fake card: it says what is true. */
.gcard.soon { opacity: .62; pointer-events: none; }
.gcard.soon .art { background: repeating-linear-gradient(135deg,
  var(--card-2) 0 11px, var(--space-2) 11px 22px); }
.gcard.soon .go { color: var(--ink-soft); }

/* The empty cabinet. An honest state, not a placeholder card: a card that goes
 * nowhere is a promise the page cannot keep, and Gate 3 applies to a hub's own
 * copy exactly as it applies to an article's. */
.empty-cabinet {
  grid-column: 1 / -1;
  text-align: center;
  padding: 54px 24px 58px;
  border: 1px dashed color-mix(in srgb, var(--accent) 24%, var(--card-line));
  border-radius: 14px;
  background: var(--card-2);
}
.empty-mark {
  display: block;
  width: 54px; height: 54px;
  margin: 0 auto 18px;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  box-shadow: 0 0 0 8px color-mix(in srgb, var(--accent) 6%, transparent);
  background: radial-gradient(circle at 50% 50%,
    color-mix(in srgb, var(--accent) 55%, transparent) 0 2.5px, transparent 3px);
}
.empty-cabinet h3 { margin: 0 0 8px; font-size: 19px; }
.empty-cabinet p { margin: 0 auto; max-width: 52ch; color: var(--ink-soft); font-size: 14.5px; }

/* ------------------------------------------------------ the game surface */

.stage-frame {
  position: relative;
  border: 1px solid var(--card-line);
  border-radius: 14px;
  overflow: hidden;
  background: #06060c;
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 9%, transparent);
}
.game-frame {
  display: block;
  width: 100%;
  /* Explicit ratio so the box is RESERVED before the frame loads. A lazy iframe
   * with no reserved height is the commonest cause of layout shift on a page
   * like this, and CLS is measured in the field even though the parent's own
   * JavaScript cannot see inside the frame. */
  aspect-ratio: 16 / 10;
  border: 0;
}

.howto-list {
  max-width: 62ch;
  margin: 0 auto;
  padding-left: 1.1em;
  color: var(--ink-soft);
}
.howto-list li { margin: 6px 0; }
.howto-list b, .howto-list kbd { color: var(--ink); }

.changelog { max-width: 62ch; margin: 0 auto; padding-left: 1.2em; color: var(--ink-soft); }
.changelog > li { margin: 14px 0; }
.changelog b { color: var(--accent); font: 600 13px/1 var(--mono); }
.changelog .when { font: 500 12px/1 var(--mono); margin-left: 9px; opacity: .7; }
.changelog ul { margin: 7px 0 0; padding-left: 1.1em; }

/* ------------------------------------------------- the split story panel */

/* Ported from ALC's about page, where the studio's character sits beside the
 * copy rather than above it. Two columns on desktop; on a phone the ART GOES
 * FIRST (order: -1), which is ALC's own rule: a wall of text with a picture
 * stranded under it reads as an afterthought on the narrow layout. */
.story {
  display: grid;
  grid-template-columns: 1.15fr .85fr;
  gap: 40px;
  align-items: center;
  margin: 8px 0 4px;
  padding: 34px 38px;
  border-radius: 20px;
  border: 1px solid var(--card-line);
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--green) 6%, transparent),
    color-mix(in srgb, var(--cyan) 4%, transparent) 60%,
    color-mix(in srgb, var(--violet) 5%, transparent));
}
.story .sec-head { text-align: left; margin: 0 0 14px; }
.story p { margin: 0 0 13px; color: var(--ink-soft); font-size: 15px; }
.story p:last-child { margin-bottom: 0; }
.story p b { color: var(--green); font-weight: 600; }

.story-art { display: flex; justify-content: center; }
.story-art img {
  width: auto;
  max-width: 100%;
  max-height: 380px;
  height: auto;                    /* the ONE scale factor; never a squash */
  filter: drop-shadow(0 14px 44px color-mix(in srgb, var(--green) 26%, transparent));
}

/* THE HEADER MUST WRAP BEFORE THE PHONE MENU CAN DROP (2026-09-21). The UFO
   panel is a sibling of the saucer with `flex-basis:100%`, which only moves to
   its own row if this flex container is allowed to wrap. Without it the panel
   tries to share the row with the wordmark and opens to a sliver. One line,
   here in the site's own hand-written sheet, because the parent belongs to the
   site: `_shared/ufo-menu.css` is derived and styles only the menu itself. */
@media (max-width: 700px) {
  .site-head { flex-wrap: wrap; }
}

@media (max-width: 820px) {
  .story { grid-template-columns: 1fr; gap: 22px; padding: 28px 22px; }
  .story-art { order: -1; }
  .story-art img { max-height: 260px; }
  .story .sec-head { text-align: center; }
}

/* ---------------------------------------------------------------- footer */

.site-foot {
  position: relative;
  z-index: 1;
  margin-top: 64px;
  border-top: 2px solid var(--green-deep);
  background: linear-gradient(0deg, #0E160E 0%, #080B08 100%);
  color: var(--ink-soft);
  font-size: 13.5px;
}
.site-foot a { color: var(--ink-soft); text-decoration: none; transition: color .18s; }
.site-foot a:hover, .site-foot a:focus-visible { color: var(--green); }

.foot-inner {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 38px 20px 26px;
  display: grid;
  grid-template-columns: 1.4fr repeat(3, 1fr);
  gap: 26px 30px;
}

.foot-brand { display: flex; align-items: center; gap: 13px; }
.foot-mark { width: 38px; height: 38px; border-radius: 50%; flex: 0 0 38px; }
.foot-name {
  font: 600 14px/1.2 var(--mono);
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ink);
}
.foot-name b { color: var(--green); font-weight: 600; }
.foot-tag {
  margin-top: 5px;
  font: 500 11px/1 var(--mono);
  letter-spacing: .1em;
  color: var(--ink-soft);
}

/* Real <h2>s, not styled divs: the footer's three link groups are landmarks a
 * screen reader lists, and a heading is how they get names. They sit below the
 * page's single <h1>, which stays the page subject. */
.foot-col { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.foot-col h2 {
  margin: 0 0 3px;
  font: 600 10.5px/1 var(--mono);
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-label);
}

.foot-base {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 18px 20px 34px;
  border-top: 1px solid color-mix(in srgb, var(--green) 12%, transparent);
  display: flex;
  align-items: center;
  gap: 18px 26px;
  flex-wrap: wrap;
}
.foot-base .social { display: flex; gap: 16px; }
.foot-base .social a { display: inline-flex; align-items: center; }
.foot-base .social svg { width: 18px; height: 18px; display: block; }
.foot-fine { margin: 0; flex: 1; min-width: 260px; font-size: 12.5px; line-height: 1.6; }
.foot-fine a { color: var(--ink); }
.foot-fine a:hover { color: var(--green); }

@media (max-width: 820px) {
  .foot-inner { grid-template-columns: 1fr 1fr; gap: 24px; }
  .foot-brand { grid-column: 1 / -1; }
}
@media (max-width: 460px) {
  .foot-inner { grid-template-columns: 1fr; }
  .foot-base { justify-content: center; text-align: center; }
}

/* ------------------------------------------------------------- a11y, V6 */

a:focus-visible, button:focus-visible, .gcard:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Reduced motion is honoured by REMOVING the motion, not by damping it.
 * The Accessible Games Initiative lists a slider that only reduces an effect
 * to a minimum as an explicit FAIL: damping is a fail, an off switch is a pass. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .gcard:hover, .gcard:focus-visible { transform: none; }
}


/* ============ THE MOBILE PLAY PATH ============================================
 *
 * A 16:10 iframe halfway down a scrolling page is a fine way to SHOW a game on
 * a desktop and a poor way to PLAY one on a phone: on a 390 px screen the
 * stage lands about 320x180, under a heading, above a how-to, with the browser
 * chrome taking a fifth of the viewport.
 *
 * So on a coarse pointer the frame is not the game -- it is a POSTER with a
 * play control over it, and the control goes to `/games/<id>/`, the chromeless
 * host page that already sizes itself to 100dvh. That page has existed since
 * the arcade shipped; nothing pointed a phone at it.
 *
 * WHY A TAP AND NOT A REDIRECT. An automatic bounce would cost the player the
 * how-to and the about text, fight the back button, and make the detail page
 * unreachable on the device most likely to arrive from a shared link. The
 * control is unmissable instead.
 *
 * WHY `dvh` AND NOT `vh`. On a phone `100vh` is the viewport WITHOUT the
 * browser chrome subtracted, so a 100vh box is taller than the screen and the
 * bottom of the game sits under the URL bar. `dvh` is the dynamic viewport and
 * is what the host page already uses.
 */
.play-cta { display: none; }

@media (pointer: coarse), (max-width: 720px) {
  .stage-frame { position: relative; }
  /* The frame stays in the DOM and keeps its reserved box, so nothing shifts
     when the poster is dismissed or when a desktop-width tablet rotates. */
  .stage-frame .game-frame { pointer-events: none; filter: brightness(.55); }
  .play-cta {
    display: flex; position: absolute; inset: 0;
    align-items: center; justify-content: center; flex-direction: column;
    gap: .5rem; text-decoration: none; border: 0; cursor: pointer;
    background: linear-gradient(rgba(8,11,17,.35), rgba(8,11,17,.72));
    color: var(--ink, #e9edf4); font: inherit;
  }
  .play-cta .k {
    font-size: 1.05rem; letter-spacing: .14em; text-transform: uppercase;
    padding: .7rem 1.4rem; border-radius: .6rem;
    border: 2px solid var(--cyan, #3fe8f0); color: var(--cyan, #3fe8f0);
    background: rgba(8,11,17,.55);
  }
  .play-cta .sub { font-size: .78rem; opacity: .78; letter-spacing: .04em; }
  .play-cta:focus-visible { outline: 3px solid var(--gold, #d9b46a); outline-offset: -6px; }
}

/* ======================================================================
 * FROM THE STUDIO -- the sibling shelf (2026-09-18).
 *
 * The studio's slate, shown here. It is baked at build time from the
 * studio's own films.json, never fetched: the arcade is a different origin
 * from alienlifestudio.com and this page must not depend on that site's
 * uptime to finish rendering. Same argument that made constellation.js a
 * copy instead of a <script src> at the sister site.
 *
 * IT CARRIES THE STUDIO'S SIGNATURE, ON PURPOSE. The studio's ground, ink and
 * accent are the same family values this page uses; the one thing that is
 * ITS OWN is the pink line around everything. So these cards are this page's
 * own plate wearing the studio's edge, which is exactly what a visitor will
 * find when they click through. The pink is alienlifeshop.com's --pink,
 * already live there, so it is a family colour and not one invented for this
 * strip. The hexes are literal ON PURPOSE: they are the SIBLING's tokens, not
 * this site's, and defining them as arcade tokens would invite an arcade
 * component to start using them.
 * ====================================================================== */
.from-studio { margin: 0 0 6px; }
.from-studio .sec-note {
  max-width: 64ch;
  margin: 0 auto 18px;
  text-align: center;
  color: var(--ink-soft);
  font-size: 14.5px;
}
.film-shelf {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 16px;
  /* U3.1: minmax(min(..),1fr), never a bare fixed min, or the track cannot
     shrink below its floor and the whole document scrolls sideways. */
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
}
.film-card {
  min-width: 0;
  border: 1px solid #C2299E;
  border-radius: 14px;
  background: linear-gradient(180deg, #111A24, #0B1118);
  position: relative;
  overflow: hidden;
  padding-left: 10px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .035),
              inset 0 0 0 1px rgba(0, 0, 0, .45);
  transition: border-color .2s, transform .2s;
}
/* the film gate's sprocket run, the studio's own container signature */
.film-card::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 9px;
  pointer-events: none;
  border-right: 1px solid #C2299E;
  background: repeating-linear-gradient(180deg,
    transparent 0 9px, #2A1220 9px 17px);
}
.film-card:hover, .film-card:focus-within {
  border-color: #C2299E;
  transform: translateY(-3px);
}
.film-card > a {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 16px 17px 18px;
  text-decoration: none;
  color: inherit;
  height: 100%;
}
.film-card h3 { margin: 0; font-size: 17px; color: var(--ink); }
.film-card p { margin: 0; font-size: 14px; color: var(--ink-soft); }
.film-status {
  align-self: flex-start;
  font: 700 10px/1 var(--mono);
  letter-spacing: .16em;
  text-transform: uppercase;
  padding: 5px 9px;
  border-radius: 999px;
  border: 1px solid var(--violet-deep);
  color: #C9A6D2;
}
/* the three statuses stay distinct from each other AND from the cyan the
 * strip is painted in, so a status never reads as decoration */
.film-status.s-filming { border-color: var(--gold-deep); color: #E8F58A; }
.film-status.s-released { border-color: var(--green-deep); color: #A9F59B; }
.film-go {
  margin-top: auto;
  padding-top: 4px;
  font: 700 11px/1 var(--mono);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #FF4FD8;
}
.film-all {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 18px;
  border-radius: 999px;
  border: 1px solid #C2299E;
  color: #FF4FD8;
  text-decoration: none;
  font-weight: 700;
  font-size: 14px;
}
.film-all:hover { background: color-mix(in srgb, #FF4FD8 10%, transparent); }
@media (prefers-reduced-motion: reduce) {
  .film-card:hover, .film-card:focus-within { transform: none; }
}

/* ======================================================================
 * THE FLOW TUBE (Gortiva, 2026-09-18).
 *
 * "can we make it where the lines change gradients or colors in a left to
 * right position so it makes a flow like tube of colors for a futuristic
 * vibe for the footer and header and containers"
 *
 * One animation, one period, one direction, on every chrome edge. Because
 * the period is in PIXELS (see --flow-period), the header's tube, the
 * footer's tube and every container's tube are the same tubing at the same
 * speed, rather than N animations that happen to be running at once.
 *
 * GATE 5 SAYS ANIMATION PAUSES WHEN UNWATCHED, so this stops on a hidden
 * tab (the `paused` class, set by the four lines at the bottom of this
 * file's companion in the page) and never starts at all under
 * prefers-reduced-motion, where the gradient stays as a still band of
 * colour rather than disappearing. Motion is the decoration; the colour
 * carries the identity, so removing the motion loses nothing.
 * ====================================================================== */
@keyframes ala-flow { to { background-position: var(--flow-period) 0; } }

/* The two rules: under the header, over the footer. Full bleed on purpose,
 * because a chrome rule that stops at the content column reads as a divider
 * inside the page rather than as the edge of the chrome. 100vw is safe here
 * and only here: body carries `overflow-x: clip`, which is U3.3's regression
 * guard and exactly what it is for. */
.site-head::after,
.site-foot::before {
  content: "";
  position: absolute;
  left: calc(50% - 50vw);
  width: 100vw;
  height: 2px;
  pointer-events: none;
  background: var(--flow);
  background-size: var(--flow-period) 100%;
  animation: ala-flow 9s linear infinite;
}
.site-head::after { bottom: -1px; }
.site-foot::before { top: -2px; }

.site-head { position: relative; }
.site-foot { position: relative; }
/* the footer's old flat green rule is replaced by the tube above it */
.site-foot { border-top: 0; }

/* ----------------------------------------------------------------------
 * CONTAINERS. The border itself is the tube, via the two-layer padding-box
 * / border-box idiom: the card's own fill paints the padding box, the
 * gradient paints the border box, and the border is transparent so the
 * gradient shows through exactly where the border is.
 * ---------------------------------------------------------------------- */
.hero-bubble, .story {
  border-color: transparent;
  background:
    radial-gradient(120% 140% at 50% 0%,
      color-mix(in srgb, var(--accent) 8%, transparent), transparent 62%) padding-box,
    linear-gradient(var(--card-2), var(--card-2)) padding-box,
    var(--flow) border-box;
  background-size: auto, auto, var(--flow-period) 100%;
  animation: ala-flow 9s linear infinite;
}

/* A GAME CARD'S TUBE RUNS THROUGH ITS OWN COLOUR, twice per cycle.
 *
 * On this site a card's colour is a MEANING claim, not decoration: it is how
 * a visitor tells one game from another before reading a word. Giving every
 * card the same rainbow would have made the page prettier and said less,
 * which is the Gate 2 failure exactly. So the tube is per-card: the game's
 * accent is the dominant stop and the neon and the pink are what it travels
 * through. Five cards, five different tubes, one speed. */
.gcard {
  border-color: transparent;
  background:
    linear-gradient(var(--card), var(--card)) padding-box,
    repeating-linear-gradient(90deg,
      var(--ca, var(--accent))  0px,
      var(--neon)              70px,
      var(--ca, var(--accent))140px,
      var(--flow-pink)        210px,
      var(--ca, var(--accent))280px) border-box;
  background-size: auto, var(--flow-period) 100%;
  animation: ala-flow 9s linear infinite;
}
/* the corner moulding stays: it is the cabinet, and it reads at a glance
 * where a 1px edge does not */
.gcard:hover, .gcard:focus-visible { border-color: transparent; }

/* The studio's strip keeps its OWN edge and does not flow. It is a window
 * into a site that has one pink line and no tube, and making it match this
 * page's chrome would be this page lying about what is next door. */
.film-card { animation: none; }

/* ---- the two off switches ---- */
@media (prefers-reduced-motion: reduce) {
  .site-head::after, .site-foot::before,
  .hero-bubble, .story, .gcard { animation: none; }
}
html.ala-hidden .site-head::after,
html.ala-hidden .site-foot::before,
html.ala-hidden .hero-bubble,
html.ala-hidden .story,
html.ala-hidden .gcard { animation-play-state: paused; }
