/* Atari 2600 — cartridge listing + game cabinet styling.
   Everything here is CSS-drawn: the woodgrain, the switch panel and the
   cartridges are gradients, not images. */

* { margin: 0; padding: 0; box-sizing: border-box; }

:root {
  --accent: #ff9d3c;
  --ink: #f2ece2;
  --muted: rgba(242, 236, 226, 0.55);
  --plastic: #171512;
  --plastic-hi: #2a2622;
  /* Console woodgrain */
  --wood1: #6b4a2a;
  --wood2: #8a5f34;
  --wood3: #4d3320;
  --mono: "SF Mono", ui-monospace, Menlo, Consolas, "DejaVu Sans Mono", monospace;
}

html, body { min-height: 100%; }

/* Painted on html as well as body so that when TV Type rotates the body the
   ground behind it is the same colour, and the turn reads as the whole
   screen moving rather than a rectangle spinning on black. */
html { background: #0b0908; }

body {
  font-family: var(--mono);
  color: var(--ink);
  background: #0b0908;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}

/* ==================================================================== */
/* listing                                                              */
/* ==================================================================== */

.listing {
  max-width: 820px;
  margin: 0 auto;
  padding: clamp(16px, 4vw, 40px) clamp(12px, 3.5vw, 24px) 40px;
}

/* ---------- the console ---------- */

.console {
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid rgba(0, 0, 0, 0.8);
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

/* Woodgrain: a wide base gradient for the plank tone, with fine repeating
   stripes over it for the grain lines. */
.woodgrain {
  height: clamp(26px, 7vw, 42px);
  background:
    repeating-linear-gradient(90deg,
      rgba(0, 0, 0, 0.22) 0 2px,
      rgba(0, 0, 0, 0) 2px 7px,
      rgba(255, 255, 255, 0.05) 7px 8px,
      rgba(0, 0, 0, 0) 8px 15px),
    linear-gradient(180deg, var(--wood2), var(--wood1) 55%, var(--wood3));
  border-bottom: 2px solid rgba(0, 0, 0, 0.55);
}

.fascia {
  background: linear-gradient(180deg, var(--plastic-hi), var(--plastic) 40%, #0f0d0b);
  padding: clamp(16px, 4vw, 26px) clamp(14px, 4vw, 28px) clamp(14px, 3.5vw, 22px);
  text-align: center;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: clamp(26px, 8vw, 46px);
  font-weight: 800;
  letter-spacing: 0.22em;
  color: var(--accent);
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.7);
}

/* The three-pronged Fuji mark, drawn with three bars of different heights. */
.brand-mark {
  position: relative;
  width: 0.72em;
  height: 0.72em;
  flex-shrink: 0;
}

.brand-mark::before,
.brand-mark::after {
  content: "";
  position: absolute;
  bottom: 0;
  width: 0.15em;
  background: var(--accent);
  border-radius: 0.04em;
}

.brand-mark::before { left: 0; height: 62%; box-shadow: 0.285em 0 0 var(--accent); }
.brand-mark::after  { left: 0.57em; height: 62%; }

/* Centre prong: taller than the outer two. */
.brand-mark {
  background: linear-gradient(var(--accent), var(--accent)) center bottom / 0.15em 100% no-repeat;
}

.brand-num {
  font-size: 0.52em;
  letter-spacing: 0.16em;
  color: var(--ink);
  align-self: flex-end;
  padding-bottom: 0.18em;
}

.tagline {
  margin-top: 8px;
  font-size: clamp(9px, 2.6vw, 12px);
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--muted);
}

.switches {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: clamp(12px, 5vw, 34px);
  margin-top: clamp(14px, 4vw, 22px);
  padding-top: clamp(12px, 3vw, 18px);
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.switch { display: grid; justify-items: center; gap: 6px; }

.switch-body {
  width: 12px;
  height: 22px;
  border-radius: 3px;
  background: linear-gradient(180deg, #d8d2c8, #8d867c 55%, #4a4540);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.6);
}

.switch-label {
  font-size: 8px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(242, 236, 226, 0.38);
  transition: color 0.16s ease;
}

/* The Power switch is a real link, so it carries padding for a comfortable
   hit area and its hover plate. Only the vertical padding is cancelled, to
   keep the row's height: cancelling it horizontally too would pull the
   painted box 7px nearer TV Type than the dummy switches are to each other,
   which reads as a tighter gap even though the layout boxes line up. */
.switch-live {
  padding: 3px 7px;
  margin: -3px 0;
  border-radius: 5px;
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  transition: background 0.16s ease;
}

.switch-live:focus-visible {
  background: rgba(255, 255, 255, 0.07);
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.switch-live:focus-visible .switch-label { color: var(--accent); }

.switch-live:focus-visible .switch-body {
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.6),
    0 0 9px var(--accent);
}

.switch-live:active .switch-body { transform: translateY(2px); }

/* TV Type is a button, but it must keep the exact box of the dummy switches
   it sits between — any padding here would shift the row's spacing. So its
   affordance is the glowing toggle and lit label, with no hover plate. */
.switch-btn {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

.switch-btn:focus-visible .switch-label { color: var(--accent); }

.switch-btn:focus-visible .switch-body {
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.6),
    0 0 9px var(--accent);
}

.switch-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.switch-btn:active .switch-body { transform: translateY(2px); }

/*
 * Hover effects are quarantined behind a real pointing device. A touchscreen
 * has no hover, so browsers fake one on tap and then leave it applied — the
 * control stays lit long after your finger has gone, until you happen to tap
 * something else. Gating on (hover: hover) means a phone never enters these
 * states at all, while mouse users keep them.
 */
@media (hover: hover) {
  .switch-live:hover { background: rgba(255, 255, 255, 0.07); }
  .switch-live:hover .switch-label,
  .switch-btn:hover .switch-label { color: var(--accent); }

  .switch-live:hover .switch-body,
  .switch-btn:hover .switch-body {
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.6),
      0 0 9px var(--accent);
  }

  .cart:hover {
    transform: translateY(-3px);
    box-shadow: 0 12px 26px rgba(0, 0, 0, 0.62), inset 0 1px 0 rgba(255, 255, 255, 0.1);
  }

  .btn-back:hover { border-color: var(--accent); color: var(--accent); }
}

/* ---------- TV Type: roll the picture ---------- */

@keyframes tv-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* A dying set rolls the picture; this one goes all the way round. The origin
   is set in JS to the middle of the viewport, so a scrolled page still turns
   about what you are actually looking at. */
body.is-spinning {
  animation: tv-spin 1.15s cubic-bezier(0.55, 0, 0.35, 1);
  will-change: transform;
}

/* Mid-turn the page sweeps well outside the viewport; clip it so the sweep
   cannot add scrollbars. */
html.is-spin-lock,
html.is-spin-lock body { overflow: hidden; }

/* Reduced-motion gets the other half of the joke — the picture switching
   standards — with no movement at all. */
@keyframes tv-flicker {
  0%   { filter: none; }
  40%  { filter: brightness(1.7) contrast(0.6) saturate(0.2); }
  70%  { filter: brightness(0.5) contrast(1.5); }
  100% { filter: none; }
}

body.is-flicker { animation: tv-flicker 0.45s steps(3, end) 2; }

/* ---------- Select: point out the cartridges ---------- */

.pick-arrow {
  position: fixed;
  z-index: 20;
  width: clamp(40px, 12vw, 72px);
  color: var(--accent);
  /* Never intercept a tap meant for the cartridge underneath. */
  pointer-events: none;
  filter: drop-shadow(0 0 11px rgba(255, 157, 60, 0.5))
          drop-shadow(0 3px 6px rgba(0, 0, 0, 0.85));
}

.pick-arrow[hidden] { display: none; }
.pick-arrow svg { display: block; width: 100%; height: auto; }

/* One second: drop in, jab twice at the carts, fade away. */
.pick-arrow.is-pointing { animation: pick-point 1s ease-out both; }

@keyframes pick-point {
  0%   { opacity: 0; transform: translateY(-16px) scale(0.8); }
  18%  { opacity: 1; transform: translateY(0) scale(1); }
  40%  { transform: translateY(10px); }
  58%  { transform: translateY(0); }
  /* Stay solid right through the jabbing — without this hold, opacity
     interpolates from the 18% mark and the arrow spends most of its second
     already fading out. */
  78%  { opacity: 1; transform: translateY(10px); }
  100% { opacity: 0; transform: translateY(4px) scale(0.96); }
}

@media (prefers-reduced-motion: reduce) {
  .pick-arrow.is-pointing { animation: pick-fade 1s ease-out both; }
}

@keyframes pick-fade {
  0%, 100% { opacity: 0; }
  15%, 72% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .switch-label, .switch-live { transition: none; }
}

.slot-hint {
  margin: clamp(16px, 4vw, 26px) 0 clamp(10px, 2.5vw, 16px);
  text-align: center;
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: rgba(242, 236, 226, 0.32);
}

/* ---------- cartridges ---------- */

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: clamp(10px, 2.5vw, 16px);
}

.cart {
  position: relative;
  display: flex;
  align-items: stretch;
  gap: 12px;
  padding: 10px 12px 10px 0;
  border-radius: 6px 6px 4px 4px;
  text-decoration: none;
  color: var(--ink);
  background: linear-gradient(180deg, #2b2723, #191614 42%, #221e1a);
  border: 1px solid rgba(0, 0, 0, 0.85);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.07);
  transition: transform 0.16s ease, box-shadow 0.16s ease;
}

/* The moulded grip ridges down the left edge of a 2600 cartridge. */
.cart-ridges {
  flex: 0 0 18px;
  border-radius: 5px 0 0 4px;
  background: repeating-linear-gradient(180deg,
    rgba(255, 255, 255, 0.09) 0 2px,
    rgba(0, 0, 0, 0.4) 2px 5px);
  border-right: 1px solid rgba(0, 0, 0, 0.6);
}

.cart-label {
  flex: 1 1 auto;
  display: grid;
  gap: 3px;
  align-content: center;
  padding: 9px 11px;
  border-radius: 3px;
  background: linear-gradient(135deg, var(--label2), var(--label1) 70%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
  min-width: 0;
}

.cart-title {
  text-align: center;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.cart-blurb {
  font-size: 10.5px;
  line-height: 1.4;
  color: rgba(255, 255, 255, 0.72);
}

.cart-badge {
  align-self: center;
  flex-shrink: 0;
  padding: 5px 9px;
  border-radius: 3px;
  border: 1px solid var(--accent);
  color: var(--accent);
  font-size: 9.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* The hover half of this lives in the (hover: hover) block further up. */
.cart:focus-visible {
  transform: translateY(-3px);
  box-shadow: 0 12px 26px rgba(0, 0, 0, 0.62), inset 0 1px 0 rgba(255, 255, 255, 0.1);
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.cart.is-stub {
  filter: saturate(0.25) brightness(0.62);
  cursor: default;
}

.foot {
  margin-top: 30px;
  text-align: center;
  font-size: 10px;
  line-height: 1.7;
  letter-spacing: 0.05em;
  color: rgba(242, 236, 226, 0.28);
}

/* ==================================================================== */
/* game cabinet                                                         */
/* ==================================================================== */

body.is-game {
  height: 100dvh;
  overflow: hidden;
  overscroll-behavior: none;
  touch-action: manipulation;
  background: #0b0908;
}

/* Literal halves: screen on top, controls below. */
.cab {
  height: 100dvh;
  display: grid;
  grid-template-rows: 1.1fr 1fr;
  max-width: 620px;
  margin: 0 auto;
  padding: max(6px, env(safe-area-inset-top)) 8px max(6px, env(safe-area-inset-bottom));
  gap: 8px;
}

.screen-wrap {
  min-height: 0;
  display: grid;
  grid-template-rows: 1fr auto;
  gap: 6px;
}

/* Wood-and-plastic surround for the picture. The container context is for the
   HUD below, which drops its title once the bezel is too narrow to seat all
   three readings. Its width comes from the layout, never from its contents,
   so inline-size containment costs nothing here. */
.bezel {
  container-type: inline-size;
  min-height: 0;
  display: grid;
  grid-template-rows: auto 1fr;
  padding: 6px;
  border-radius: 8px;
  background: linear-gradient(180deg, var(--plastic-hi), #0f0d0b);
  border: 1px solid rgba(0, 0, 0, 0.9);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 8px 20px rgba(0, 0, 0, 0.55);
}

.hud {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 2px 4px 6px;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  /* Last resort only: the title gives way long before anything is clipped. */
  overflow: hidden;
}

.hud b { color: var(--accent); font-weight: 700; }

/* Score and lives are live game state, so they neither wrap nor shrink — a
   score folded onto two lines was the whole problem. */
.hud-item {
  flex: 0 0 auto;
  white-space: nowrap;
}

/*
 * The title is decoration — it is in the tab, and you just picked the
 * cartridge off the shelf — so it is the one thing allowed to give. It is the
 * only flexible item, so it truncates as the bezel narrows and has shrunk to
 * nothing by the time the other two need the room. No breakpoint needed: the
 * longest title simply disappears soonest.
 */
.hud-title {
  flex: 0 1 auto;
  min-width: 0;
  color: rgba(242, 236, 226, 0.3);
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Below this the leftover is a few pixels of ellipsis, which reads as a stray
   mark rather than a title. Drop it and let the two readings breathe. */
@container (max-width: 190px) {
  .hud-title { display: none; }
}

.screen {
  position: relative;
  min-height: 0;
  display: grid;
  place-items: center;
  background: #000;
  border-radius: 4px;
  overflow: hidden;
  box-shadow: inset 0 0 0 2px #000, inset 0 0 34px rgba(0, 0, 0, 0.9);
}

/* The game sets an explicit pixel size on the canvas so its low-res buffer
   scales by a single uniform factor — a stretched buffer would squash the
   sprites on wide screens. Whatever is left over letterboxes to black. */
#screen {
  display: block;
  /* Chunky, console-era pixels rather than a smooth upscale. */
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}

.scanlines {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(180deg,
    rgba(0, 0, 0, 0.22) 0 1px,
    rgba(0, 0, 0, 0) 1px 3px);
  opacity: 0.55;
}

.overlay {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  gap: 8px;
  text-align: center;
  padding: 16px;
  background: rgba(0, 0, 0, 0.55);
  transition: opacity 0.2s ease;
}

.overlay[hidden] { display: none; }

.over-title {
  font-size: clamp(16px, 5vw, 24px);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}

.over-sub {
  font-size: clamp(10px, 3vw, 13px);
  letter-spacing: 0.1em;
  color: var(--ink);
  animation: blink 1.2s steps(2, end) infinite;
}

.over-sub b { color: #ff5b4a; }

@keyframes blink { 50% { opacity: 0.25; } }

.btn-back {
  justify-self: center;
  padding: 5px 14px;
  border-radius: 3px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  color: var(--muted);
  text-decoration: none;
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

/* The hover half lives in the (hover: hover) block near the top. */
.btn-back:focus-visible { border-color: var(--accent); color: var(--accent); }

/* ---------- control panel ---------- */

.panel {
  min-height: 0;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  justify-items: center;
  gap: clamp(8px, 3vw, 24px);
  padding: clamp(8px, 2.5vw, 16px);
  border-radius: 10px;
  background:
    repeating-linear-gradient(90deg,
      rgba(0, 0, 0, 0.2) 0 2px,
      rgba(0, 0, 0, 0) 2px 7px,
      rgba(255, 255, 255, 0.04) 7px 8px,
      rgba(0, 0, 0, 0) 8px 15px),
    linear-gradient(180deg, var(--wood2), var(--wood1) 60%, var(--wood3));
  border: 1px solid rgba(0, 0, 0, 0.8);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), 0 8px 20px rgba(0, 0, 0, 0.5);
}

/* Directional cluster, left thumb. Keys are square so they stay thumb-shaped
   however tall the panel happens to be. */
.pad {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(5px, 1.8vw, 9px);
  width: 100%;
  /* Capped against viewport height as well as width, so a short landscape
     phone doesn't push the two-row cluster out through the panel's bottom. */
  max-width: min(340px, 40dvh);
}

/* A wide bar across the top of the pad — thrust on one cartridge, jump on
   another — with the two side keys sharing the row beneath it. */
.key-thrust,
.key-jump { grid-column: 1 / -1; aspect-ratio: 3 / 1; }
.key-rot { aspect-ratio: 1; }

/* A cartridge that only needs left/right gets one row, so the keys can be
   taller and the cap on the cluster relaxes. */
.pad.is-single { max-width: min(340px, 52dvh); }
.pad.is-single .key-rot { aspect-ratio: 0.82; }

/* Four-way cartridges get a proper d-pad: a 3x3 grid with a hollow middle. */
.pad.is-dpad {
  grid-template-columns: repeat(3, 1fr);
  grid-template-areas:
    '.    up    .'
    'left .     right'
    '.    down  .';
  max-width: min(258px, 46dvh);
}

.pad.is-dpad .key { aspect-ratio: 1; }
.key-up { grid-area: up; }
.key-left { grid-area: left; }
.key-right { grid-area: right; }
.key-down { grid-area: down; }

/* Action cluster, right thumb: hyperspace pill above a round fire button. */
.actions {
  display: grid;
  justify-items: center;
  gap: clamp(7px, 2.4vw, 13px);
}

/* Buttons are black console plastic: chunky, high contrast, no rounded
   softness beyond what the mouldings had. */
.key {
  display: grid;
  place-content: center;
  gap: 2px;
  min-height: 0;
  padding: 4px;
  border: 1px solid rgba(0, 0, 0, 0.9);
  border-radius: 6px;
  background: linear-gradient(180deg, #35302b, #1a1714 60%, #100e0c);
  color: var(--ink);
  font-family: inherit;
  font-size: clamp(15px, 4.5vw, 22px);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: 0.04em;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 3px 0 rgba(0, 0, 0, 0.55);
  transition: transform 0.06s ease, background 0.06s ease;
}

.key-cap {
  display: block;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.key-thrust { color: #8fd7ff; }

.key-hyper {
  width: clamp(78px, min(29vw, 24dvh), 150px);
  aspect-ratio: 2.9 / 1;
  font-size: clamp(9px, 2.6vw, 12px);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #ffd571;
}

.key-jump { color: #9fe8ff; }

/* The CX-40's red button, scaled up to a thumb target. */
.key-fire {
  width: clamp(78px, min(29vw, 24dvh), 150px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(120% 120% at 38% 26%, #f4715a, #c0341f 52%, #7d1a0f);
  color: #fff4ee;
  font-size: clamp(13px, 4vw, 18px);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.28), 0 4px 0 rgba(0, 0, 0, 0.55);
}

.key.is-down,
.key:active {
  transform: translateY(3px);
  box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.7);
  background: linear-gradient(180deg, #1a1714, #262220);
}

.key-fire.is-down,
.key-fire:active {
  background: radial-gradient(120% 120% at 38% 26%, #c0341f, #8f1f11 60%, #5e120a);
  box-shadow: inset 0 3px 7px rgba(0, 0, 0, 0.6);
}

.key:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Landscape phones: the screen still leads, but the halves get uneven —
   controls need less height than the picture does. */
@media (orientation: landscape) and (max-height: 620px) {
  .cab { grid-template-rows: 1.35fr 1fr; max-width: 940px; }
  /* A full-width bezel on a short landscape screen is far wider than the
     world can be, so it would letterbox. Narrow it to roughly the picture's
     own proportions and centre it, like a small set on a shelf. */
  .bezel { width: min(100%, 82dvh); margin-inline: auto; }
  /* Two stacked rows in a short panel: tighten the cap so the rotate keys
     keep clear of the panel edge. */
  .pad { max-width: min(340px, 34dvh); }
  /* A d-pad is as tall as it is wide, so it needs the tightest cap of all. */
  .pad.is-dpad { max-width: min(258px, 33dvh); }
  .key-hyper { font-size: 10px; }
}

@media (prefers-reduced-motion: reduce) {
  .cart, .key { transition: none; }
  .over-sub { animation: none; }
}
