/* ==========================================================================
   05 — SECTIONS
   ==========================================================================
   One block per page section, in the same order they appear in index.html:

     1. Hero
     2. ID badge (lanyard card)
     3. Typed terminal strip
     4. ~/activity  (contribution heatmap + stats)
     5. ~/apps      (featured project cards)
     6. ~/work      (interactive terminal)
     7. ~/skills    (proficiency bars)
     8. ~/contact   (form + sidebar)
     9. ~/playground (games)

   Mobile adjustments for all of these live in 06-responsive.css.
   ========================================================================== */


/* ==========================================================================
   1. HERO
   ==========================================================================
   Two columns on desktop: intro text and the swinging ID badge.
   The intro comes first in the HTML for SEO; on mobile the badge is moved
   above it visually with `order` (see 06-responsive.css).
   ========================================================================== */
/* The `min(320px, 100%)` guard matters: a bare minmax(320px, 1fr) forces a
   320px-wide column even when the screen is narrower, which causes sideways
   page scroll on small phones. Same pattern is used on every grid below. */
.hero {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: clamp(26px, 4vw, 44px);
  align-items: start;
  padding: clamp(40px, 6vw, 64px) 0 44px;
}

.prompt {
  color: var(--green);
  font-size: 14px;
  margin-bottom: 6px;
}

.hero-name {
  font-size: clamp(38px, 8vw, 64px);
  line-height: 1.02;
  font-weight: 700;
  letter-spacing: -.02em;
  color: var(--ink);
  margin-bottom: 6px;
}

.hero-role {
  font-size: 15px;
  color: var(--dim2);
  margin-bottom: 26px;
}

.hero-manifesto {
  font-size: clamp(22px, 4.5vw, 30px);
  line-height: 1.25;
  font-weight: 500;
  color: var(--heading);
  margin-bottom: 14px;
}

.hero-blurb {
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--muted);
  max-width: 52ch;
  margin-bottom: 28px;
}

.hero-cta {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}


/* ==========================================================================
   2. ID BADGE
   ==========================================================================
   A card hanging from two straps. js/badge.js applies a rotation transform
   to .badge-swing every frame to simulate a pendulum; everything below just
   describes what the badge looks like at rest.
   ========================================================================== */
.badge-col {
  position: relative;
  display: flex;
  justify-content: center;
  min-height: 472px;
}

.badge-pivot {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
}

.badge-swing {
  transform-origin: top center;
  will-change: transform;
  touch-action: none;        /* lets us handle drag without the page scrolling */
  cursor: grab;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 266px;
}
.badge-swing.is-dragging { cursor: grabbing; }

/* The plastic clip at the very top. */
.badge-hook {
  width: 32px;
  height: 15px;
  background: var(--cell);
  border: 1px solid var(--line);
  border-radius: 4px;
  z-index: 3;
  box-shadow: 0 2px 6px var(--shadow);
}

/* Two crossed lanyard straps. */
.badge-straps {
  position: relative;
  width: 160px;
  height: 80px;
  margin-top: -3px;
}
.badge-strap {
  position: absolute;
  top: 2px;
  left: 50%;
  width: 12px;
  height: 92px;
  background: linear-gradient(var(--cell), var(--inner));
  border: 1px solid var(--line2);
  transform-origin: top center;
}
.badge-strap-l { transform: translateX(-50%) rotate(26deg); }
.badge-strap-r { transform: translateX(-50%) rotate(-26deg); }

.badge-card {
  width: 266px;
  margin-top: -18px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: 0 34px 80px -26px var(--shadow);
  overflow: hidden;
  position: relative;
  z-index: 2;
}

.badge-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 15px;
  background: var(--panel2);
  border-bottom: 1px solid var(--line2);
}
.badge-head-label {
  font-size: 10.5px;
  letter-spacing: .16em;
  color: var(--dim2);
}
.badge-head-id {
  margin-left: auto;
  font-size: 10.5px;
  color: var(--amber);
}

.badge-clip-row {
  display: flex;
  justify-content: center;
  padding-top: 11px;
}
.badge-clip {
  width: 56px;
  height: 8px;
  border-radius: 5px;
  background: var(--inner);
  border: 1px solid var(--line);
}

.badge-body { padding: 14px 18px 18px; }

.badge-id {
  display: flex;
  gap: 14px;
  align-items: center;
  margin-bottom: 14px;
}

.badge-avatar {
  width: 68px;
  height: 68px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--line);
  flex: none;
  background: var(--inner);
}

.badge-name  { font-size: 18px; font-weight: 700; color: var(--ink); line-height: 1.1; }
.badge-role  { font-size: 11.5px; color: var(--green); margin-top: 4px; line-height: 1.25; }
.badge-native{ font-size: 11px; color: var(--amber); margin-top: 3px; }

.badge-fields {
  border-top: 1px dashed var(--line);
  padding-top: 12px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 9px 10px;
  font-size: 11px;
}
.badge-field dt { color: var(--dim); }
.badge-field dd { color: var(--text); margin-top: 1px; }

/* Decorative barcode. Individual bars are appended by js/badge.js. */
.badge-barcode {
  margin-top: 15px;
  display: flex;
  gap: 2px;
  height: 36px;
  align-items: stretch;
}
.badge-bar { border-radius: 1px; }

.badge-foot {
  margin-top: 7px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 9.5px;
  letter-spacing: .1em;
  color: var(--dim);
}



/* ==========================================================================
   3. TYPED TERMINAL STRIP
   ========================================================================== */
.strip {
  background: var(--panel2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  overflow: hidden;
}

.strip-prompt { color: var(--green); flex: none; }

.strip-typed {
  color: var(--ink);
  white-space: pre;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}


/* ==========================================================================
   4. ~/activity
   ========================================================================== */
.activity-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr));
  gap: clamp(20px, 3vw, 28px);
  padding: clamp(16px, 3vw, 24px);
  align-items: center;
}

.activity-heat-head {
  display: flex;
  justify-content: space-between;
  font-size: 11.5px;
  color: var(--dim);
  margin-bottom: 10px;
}

/* Column count is set inline by js/activity.js based on how many weeks fit. */
.heat {
  display: grid;
  grid-auto-rows: 1fr;
  gap: 3px;
}

.heat-cell {
  width: 100%;
  aspect-ratio: 1;
  border-radius: 2px;
  background: var(--track);
}
/* Five contribution intensities. Level 0 keeps the faint --track default. */
.heat-cell[data-level="1"] { background: color-mix(in srgb, var(--green) 25%, transparent); }
.heat-cell[data-level="2"] { background: color-mix(in srgb, var(--green) 45%, transparent); }
.heat-cell[data-level="3"] { background: color-mix(in srgb, var(--green) 68%, transparent); }
.heat-cell[data-level="4"] { background: color-mix(in srgb, var(--green) 95%, transparent); }

/* Shown only when the contribution API is unreachable. We dim the grid and
   say so, rather than displaying invented data. */
.heat-note {
  margin-top: 10px;
  font-size: 11px;
  color: var(--dim);
}
.heat.is-empty { opacity: .45; }

.heat-legend {
  display: flex;
  align-items: center;
  gap: 6px;
  justify-content: flex-end;
  margin-top: 10px;
  font-size: 10.5px;
  color: var(--dim);
}
.heat-key { width: 11px; height: 11px; border-radius: 2px; }
.heat-key[data-level="1"] { background: color-mix(in srgb, var(--green) 25%, transparent); }
.heat-key[data-level="2"] { background: color-mix(in srgb, var(--green) 45%, transparent); }
.heat-key[data-level="3"] { background: color-mix(in srgb, var(--green) 68%, transparent); }
.heat-key[data-level="4"] { background: color-mix(in srgb, var(--green) 95%, transparent); }

.activity-stats {
  border-left: 1px solid var(--line2);
  padding-left: 26px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.stat-value {
  font-size: 30px;
  font-weight: 700;
  line-height: 1;
  color: var(--ink);
}
.stat-label {
  font-size: 11px;
  color: var(--dim);
  margin-top: 4px;
}


/* ==========================================================================
   5. ~/apps — featured project cards
   ==========================================================================
   Card markup is built by js/projects.js from the PROJECTS array in data.js.
   ========================================================================== */
.card-grid {
  display: grid;
  gap: 18px;
  grid-template-columns: repeat(auto-fit, minmax(min(255px, 100%), 1fr));
}

.project-card {
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* Screenshot. Fixed aspect ratio keeps the grid tidy and prevents layout
   shift while images load. */
.project-shot {
  width: 100%;
  /* `height: auto` is required. The <img> carries width/height attributes so
     the browser can reserve space before the file loads, but those attributes
     also apply as a presentational height — which would win over the ratio
     below and stretch every card image to a fixed 400px. */
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  background: var(--panel2);
  border-bottom: 1px solid var(--line2);
}

/* --------------------------------------------------------------------------
   CSS PLACEHOLDER
   --------------------------------------------------------------------------
   Rendered by js/projects.js whenever a project has no `image` in data.js.
   It mimics a terminal window opening the project.

   WHY CSS RATHER THAN AN IMAGE FILE
   ---------------------------------
   1. It follows the theme. An exported PNG/SVG bakes in whichever colours it
      was generated with, so it stays dark when the visitor switches to light
      mode. This is drawn from the same CSS variables as everything else, so
      it is always correct.
   2. It scales. Text and spacing are sized in container-query units, so the
      card looks deliberate at any width instead of scaling a fixed bitmap.
   3. It costs nothing — no extra file, no request, and adding a project needs
      no asset at all.

   Use a real image file when you have an actual screenshot, or when you need
   something shareable outside the page (README, social cards). Generate one
   with: node tools/make-placeholder.js
   -------------------------------------------------------------------------- */
.project-ph {
  /* Establishes the container so descendants can size themselves against the
     card's width (cqi units below) rather than the viewport. */
  container-type: inline-size;

  width: 100%;
  aspect-ratio: 16 / 10;
  background: var(--panel2);
  border-bottom: 1px solid var(--line2);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  position: relative;

  /* Per-project accent, set inline by projects.js from the language colour. */
  --ph-accent: var(--green);
}

/* Faint dot grid, so the panel doesn't read as a flat empty block. */
.project-ph::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: radial-gradient(
    circle at 1px 1px,
    color-mix(in srgb, var(--green) 22%, transparent) 1px,
    transparent 0
  );
  background-size: 22px 22px;
  opacity: .5;
  pointer-events: none;
}

.project-ph-bar {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 7px 10px;
  background: var(--panel);
  border-bottom: 1px solid var(--line2);
  flex: none;
  position: relative;
}
.project-ph-bar .dot { width: 7px; height: 7px; }

.project-ph-path {
  margin-left: 6px;
  font-size: 10px;
  color: var(--dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

.project-ph-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 6px;
  padding: 10px 16px;
  position: relative;
  min-width: 0;
}

.project-ph-cmd  { font-size: 11px; color: var(--green); }
.project-ph-name {
  font-size: 24px;
  font-weight: 700;
  color: var(--ink);
  line-height: 1.1;
  /* Long project names shrink rather than overflow the card. */
  overflow-wrap: anywhere;
}
.project-ph-lang { font-size: 11px; color: var(--ph-accent); }

.project-ph-tags {
  display: flex;
  gap: 5px;
  flex-wrap: wrap;
  margin-top: 2px;
}
.project-ph-tags .tag { font-size: 9.5px; padding: 1px 5px; }

/* Container queries let the placeholder scale with the CARD, not the window —
   important because card width changes with the grid, independent of viewport.
   The fixed px values above are the fallback for browsers without support. */
@supports (container-type: inline-size) {
  .project-ph-cmd  { font-size: clamp(9px, 3.6cqi, 13px); }
  .project-ph-name { font-size: clamp(16px, 8.5cqi, 32px); }
  .project-ph-lang { font-size: clamp(9px, 3.6cqi, 13px); }
  .project-ph-path { font-size: clamp(8px, 3cqi, 11px); }
  .project-ph-tags .tag { font-size: clamp(8px, 3cqi, 11px); }
  .project-ph-body { padding: clamp(8px, 5cqi, 22px); }
}

/* Very short cards (narrow grid columns): drop the tags so the name keeps
   room to breathe. */
@container (max-width: 210px) {
  .project-ph-tags { display: none; }
}

.project-body {
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  flex: 1;
}

/* Name on the left, language + stars pinned right, always on ONE line.
   Previously this wrapped, so a long project name pushed the language chip
   onto its own row and the card headers stopped lining up with each other. */
.project-head {
  display: flex;
  align-items: baseline;
  /* Tight gaps here buy a few characters of title before it has to truncate,
     which is often the difference between a name fitting and not. */
  gap: 6px;
  margin-bottom: 8px;
  flex-wrap: nowrap;
}

/* min-width: 0 is what actually allows the ellipsis — without it a flex item
   refuses to shrink below its content width and pushes its siblings out. */
.project-name {
  font-size: 16px;
  font-weight: 700;
  color: var(--ink);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* flex: none keeps the metadata at its natural width, so the name is what
   gives way rather than the language label being clipped. */
.project-meta {
  margin-left: auto;
  display: flex;
  align-items: baseline;
  gap: 6px;
  flex: none;
}
.project-lang { font-size: 11px; white-space: nowrap; }
.project-stars { font-size: 11px; color: var(--amber); white-space: nowrap; }

.project-tagline {
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--muted);
  margin-bottom: 12px;
  flex: 1;
}

.project-stack {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.project-links { display: flex; gap: 8px; }
.project-links .btn { flex: 1; }


/* ==========================================================================
   6. ~/work — interactive terminal
   ========================================================================== */
.term-chips {
  margin-left: auto;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.term-out {
  height: 440px;
  overflow-y: auto;
  padding: 18px 22px;
  font-size: 13.5px;
  line-height: 1.55;
  overscroll-behavior: contain;   /* stops scroll chaining to the page */
}

.term-entry { margin-bottom: 18px; }

.term-echo {
  color: var(--dim2);
  margin-bottom: 8px;
  word-break: break-word;
}
.term-echo .u { color: var(--green); }
.term-echo .p { color: var(--blue); }
.term-echo .c { color: var(--ink); }

.term-meta {
  color: var(--dim);
  margin-bottom: 6px;
  font-size: 12px;
}

.term-text {
  margin: 0;
  color: var(--soft);
  font: 400 13px/1.55 var(--font-mono);
  white-space: pre-wrap;
  word-break: break-word;
}

/* One project row in `ls` output. */
.term-row {
  display: grid;
  grid-template-columns: 22px 1fr auto;
  gap: 12px;
  align-items: center;
  padding: 7px 10px;
  border-radius: 7px;
  cursor: pointer;
  border: 1px solid transparent;
  width: 100%;
  text-align: left;
  background: none;
  font: inherit;
  color: inherit;
}
.term-row:hover { background: var(--hover); }
.term-row-glyph { color: var(--amber); }
.term-row-name  { color: var(--ink); font-weight: 500; }
.term-row-desc  { color: var(--dim2); }
.term-row-meta  { display: flex; gap: 12px; white-space: nowrap; font-size: 12px; }

/* Expanded project detail block from `open <name>`. */
.term-detail {
  border: 1px solid var(--line);
  border-radius: 9px;
  padding: 16px 18px;
  background: var(--hover);
}
.term-detail-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
.term-detail-title { font-size: 18px; font-weight: 700; color: var(--ink); }
.term-detail-desc { color: var(--soft); margin-bottom: 12px; font-size: 14px; }
.term-detail-links { display: flex; gap: 10px; flex-wrap: wrap; }

.term-line {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 22px 18px;
}
.term-prompt {
  color: var(--green);
  white-space: nowrap;
  font-size: 13.5px;
}
.term-input {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: none;
  outline: none;
  color: var(--ink);
  font: 400 13.5px var(--font-mono);
  caret-color: transparent;   /* we draw our own block caret instead */
}


/* ==========================================================================
   7. ~/skills
   ========================================================================== */
.skills-grid {
  padding: 22px 24px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(255px, 100%), 1fr));
  gap: 22px clamp(24px, 4vw, 40px);
}

.skill-group-label {
  color: var(--amber);
  font-size: 12px;
  margin-bottom: 12px;
  letter-spacing: .04em;
}

.skill-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.skill-row {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12.5px;
}
.skill-name {
  width: 118px;
  flex: none;
  color: var(--text);
}
.skill-track {
  flex: 1;
  height: 9px;
  background: var(--track);
  border-radius: 5px;
  overflow: hidden;
}
/* Width is set to 0 here and animated to the real value by js/skills.js
   once the section scrolls into view. */
.skill-bar {
  height: 100%;
  width: 0;
  background: linear-gradient(90deg, var(--green), var(--amber));
  border-radius: 5px;
  transition: width 1.1s var(--ease);
}
.skill-pct {
  width: 40px;
  flex: none;
  text-align: right;
  color: var(--dim);
  font-size: 11.5px;
}


/* ==========================================================================
   8. ~/contact
   ========================================================================== */
.contact-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: 18px;
  align-items: start;
}

.contact-body { padding: 24px 26px; font-size: 13.5px; }
.contact-cmd { margin-bottom: 4px; }
.contact-note {
  color: var(--muted);
  margin-bottom: 22px;
  font-size: 13px;
  line-height: 1.6;
}

.contact-form {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.field-row {
  display: flex;
  gap: 12px;
  align-items: baseline;
}
.field-row-top { align-items: flex-start; }

.field-label {
  width: 92px;
  flex: none;
  color: var(--green);
}
.field-row-top .field-label { padding-top: 4px; }

.form-error {
  color: var(--red);
  font-size: 12px;
}

.form-actions {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}
.form-actions .btn-primary { padding: 12px 22px; }

.form-alt { font-size: 12px; color: var(--dim); }

/* Terminal-style success report swapped in after a successful send. */
.form-sent { color: var(--soft); line-height: 1.95; font-size: 13.5px; }
.form-sent .arrow { color: var(--dim2); }
.form-sent .ok { color: var(--green); }
.form-sent-final { color: var(--green); margin-top: 8px; }

/* ---- Sidebar ---- */
.contact-side {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.json-block {
  padding: 16px 18px;
  font-size: 13px;
  line-height: 1.95;
}
.json-block .k       { color: var(--blue); }
.json-block .s-green { color: var(--green); }
.json-block .s-amber { color: var(--amber); }
.json-block > div:not(.dim) { padding-left: 16px; }

.service-list {
  display: flex;
  flex-direction: column;
  gap: 9px;
  font-size: 13px;
}
.service-item {
  display: flex;
  gap: 9px;
  align-items: flex-start;
}
.service-item::before {
  content: '✓';
  color: var(--green);
  flex: none;
}
.service-item span { color: var(--text); }

.channels {
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.channel {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--text);
  padding: 8px 10px;
  border: 1px solid var(--line2);
  border-radius: var(--radius-sm);
  transition: border-color var(--speed-fast) ease, background var(--speed-fast) ease;
}
.channel:hover { border-color: var(--green); background: var(--hover); color: var(--text); }
.channel-key { color: var(--green); width: 64px; flex: none; font-size: 11.5px; }
.channel-val { color: var(--muted); overflow: hidden; text-overflow: ellipsis; }
.channel-go  { margin-left: auto; color: var(--green); }


/* ==========================================================================
   9. ~/playground — games
   ==========================================================================
   Shared shells and overlays. Each game's own rules follow.
   ========================================================================== */
.play-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(400px, 100%), 1fr));
  gap: 18px;
  align-items: stretch;
}

/* Grid and flex children default to `min-width: auto`, which means they refuse
   to shrink below their content's intrinsic width. The games contain wide
   fixed-size pieces (the canvas, the D-pad, the score readout), so without
   this they blow past a narrow column and give the whole page a horizontal
   scrollbar. Setting min-width: 0 lets them shrink properly. */
.play-grid > * { min-width: 0; }

.game { height: 100%; display: flex; flex-direction: column; min-width: 0; }
.game-body { min-width: 0; }
.game-body {
  padding: 18px 20px;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 16px;
  position: relative;
}
.game-score { margin-left: auto; font-size: 12px; color: var(--amber); flex: none; }
.game-hint  { font-size: 12.5px; color: var(--green); }
.game-hint.is-error { color: var(--red); }
.game-hint.is-watch { color: var(--amber); }

/* Start / game-over overlay. */
.game-ov {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  border-radius: var(--radius-sm);
  text-align: center;
  padding: 16px;
}
.game-ov[hidden] { display: none; }
.game-ov-title { font-size: 19px; font-weight: 700; color: var(--ink); }
.game-ov-sub   { font-size: 12.5px; color: var(--muted); max-width: 34ch; }

/* ---- Snake ---- */
.snake-body { padding: 16px 16px 8px; position: relative; flex: 1; }
.snake-canvas {
  width: 100%;
  height: auto;
  display: block;
  background: var(--canvas);
  border: 1px solid var(--line2);
  border-radius: var(--radius-sm);
  image-rendering: pixelated;
}
.snake-ov { inset: 16px 16px 8px; }
.snake-foot {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 16px 16px;
  flex-wrap: wrap;
}
.snake-foot-hint { font-size: 11.5px; color: var(--dim); }
/* On-screen D-pad for touch devices. */
.dpad {
  display: grid;
  grid-template-columns: repeat(3, 34px);
  grid-template-rows: repeat(2, 30px);
  gap: 4px;
  margin-left: auto;
}
.dpad .chip { font-size: 14px; }

/* ---- Typing test ---- */
.type-area { position: relative; cursor: text; flex: 1; }
.type-line {
  font-size: 17.5px;
  line-height: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
}
.type-word { display: inline-flex; white-space: pre; }
.type-char { border-bottom: 2px solid transparent; border-radius: 2px; color: var(--dim2); }
.type-char.ok  { color: var(--green); }
.type-char.bad { color: var(--red); background: color-mix(in srgb, var(--red) 18%, transparent); }
.type-char.cur { border-bottom-color: var(--green); }
.type-author { font-size: 12px; color: var(--dim); margin-top: 12px; }
/* Invisible input that captures keystrokes over the quote. */
.type-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: text;
  border: 0;
  padding: 0;
}
.type-foot { font-size: 11.5px; color: var(--dim); }
.type-result {
  display: flex;
  border: 1px solid var(--line);
  background: var(--hover);
  border-radius: 9px;
  padding: 14px 16px;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  font-size: 13px;
  color: var(--text);
}
.type-result[hidden] { display: none; }
.type-result b { color: var(--ink); }
.type-result .win { color: var(--green); font-size: 14px; }
.type-result .btn { margin-left: auto; }

/* ---- Memory matrix ---- */
.mem-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 8px;
  max-width: 330px;
  margin: 8px auto 0;
  width: 100%;
}
.mem-cell {
  aspect-ratio: 1;
  border-radius: var(--radius-sm);
  background: var(--cell);
  border: 1px solid var(--line2);
  transition: background var(--speed-fast);
  padding: 0;
  cursor: default;
}
.mem-cell.is-lit  { background: var(--green); }
.mem-cell.is-miss { background: var(--amber); }
.mem-cell.is-playable { cursor: pointer; }

/* ---- Sequence ---- */
.seq-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  max-width: 300px;
  margin: 8px auto 0;
  width: 100%;
}
.seq-tile {
  aspect-ratio: 1;
  border-radius: 14px;
  cursor: pointer;
  border: 0;
  padding: 0;
  transition: background .14s, box-shadow .14s, transform .14s;
  /* --tint is set per tile by js/games/sequence.js */
  background: rgba(var(--tint), .26);
}
.seq-tile.is-on {
  background: rgba(var(--tint), 1);
  box-shadow: 0 0 26px rgba(var(--tint), .75);
  transform: scale(1.05);
}
.seq-grid.is-locked { pointer-events: none; }
