/* BuddyCube website.
   Same "moulded plastic toy" identity as BuddyMKR (software/src/styles/toy.css):
   pegboard background, thick dark borders, hard offset shadows with no blur,
   pixel font for short labels only, reflective LCD green for anything standing
   in for the cube's screen.

   One deliberate departure from the app. BuddyMKR is fixed furniture that never
   scrolls and has a 1160px floor. This is a web page: it scrolls, it reflows,
   and it works on a phone. The vocabulary is shared, the layout rules are not. */

/* Press Start 2P, OFL licensed (see fonts/OFL.txt), bundled rather than linked
   from Google Fonts, matching the app and keeping the site free of third party
   requests. */
@font-face {
  font-family: "Press Start 2P";
  src: url("fonts/PressStart2P-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  /* One weight only. There is no bold cut, so a synthesised one turns a
     pixel grid face to mush. Every pixel font rule sets font-weight 400
     explicitly to override the user agent bold on h1 to h6. */
  --font-pixel: "Press Start 2P", ui-monospace, "Cascadia Code", monospace;
  --font-ui: -apple-system, "Segoe UI", system-ui, sans-serif;
  --font-mono: ui-monospace, "Cascadia Code", "SF Mono", "JetBrains Mono", Consolas, monospace;

  --plastic-dark: #262421;
  --plastic-mid: #423e38;
  --pegboard-bg: #d8d5cd;
  --pegboard-dot: #b9b5aa;

  --mode-orange: #d9611c;
  --mode-orange-deep: #b34f16;
  --mode-orange-soft: #e07a3c;
  --mode-blue: #1f4e8c;
  --mode-blue-deep: #163a68;

  --lcd-bg: #93a17c;
  --lcd-bg-deep: #7e8c68;
  --lcd-ink: #2b3320;
  --lcd-ink-dim: #4b5a3a;

  --pill-bg: #e7e4dc;
  --pill-bg-press: #d3d0c8;
  --panel-fill: rgba(255, 255, 255, 0.14);

  --ready-green: #2f9e44;
  --status-red: #e2483d;

  /* The slab a section is painted on sets --skin, and everything inside
     follows it, the way .app-housing repaints the Maker for each Buddy. */
  --skin: var(--mode-orange);
  --skin-deep: var(--mode-orange-deep);

  /* Shared page rhythm. */
  --gutter: clamp(16px, 4vw, 40px);
  --measure: 1180px;
  font-weight: 400;
}

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* Anchored headings clear the sticky site bar. */
  scroll-padding-top: 104px;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  background-color: var(--pegboard-bg);
  background-image: radial-gradient(var(--pegboard-dot) 1.6px, transparent 1.6px);
  background-size: 20px 20px;
  font-family: var(--font-ui);
  font-size: 16px;
  line-height: 1.65;
  color: var(--plastic-dark);
  -webkit-font-smoothing: antialiased;
}

img, svg { max-width: 100%; }
img { height: auto; }

/* Skip link, visible only once focused. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--plastic-dark);
  color: #fff;
  font-family: var(--font-pixel);
  font-size: 9px;
  line-height: 1.6;
  padding: 12px 16px;
  border-radius: 0 0 12px 0;
}
.skip-link:focus { left: 0; }

:focus-visible {
  outline: 3px solid var(--plastic-dark);
  outline-offset: 3px;
}

/* ---------- Layout ---------- */

.wrap {
  width: 100%;
  max-width: var(--measure);
  margin: 0 auto;
  padding-inline: var(--gutter);
}

.stack > * + * { margin-top: 18px; }

/* ---------- Site bar ---------- */

/* The app puts its wordmark and port tabs on one compact row inside the
   housing. Here that row becomes a floating plastic bar on the pegboard. */
.site-bar {
  position: sticky;
  top: 0;
  z-index: 40;
  padding: 14px var(--gutter) 0;
  background: linear-gradient(var(--pegboard-bg) 62%, rgba(216, 213, 205, 0));
}
.site-bar-inner {
  max-width: var(--measure);
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  background: var(--plastic-dark);
  border: 3px solid var(--plastic-dark);
  border-radius: 22px;
  box-shadow: 6px 6px 0 rgba(38, 36, 33, 0.35);
  padding: 10px 16px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  text-decoration: none;
  color: #fff;
  flex-shrink: 0;
}
.brand-mark { width: 30px; height: 30px; flex-shrink: 0; display: block; }
.brand-wordmark {
  font-family: var(--font-pixel);
  font-size: 13px;
  /* Press Start 2P fills its em box exactly, so a tight line-height clips
     glyph tops wherever something is overflow hidden. */
  line-height: 1.5;
  letter-spacing: 0.04em;
  color: #fff;
  text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.4);
  font-weight: 400;
  margin: 0;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-left: auto;
  flex-wrap: wrap;
}

/* Magnetic port tabs, lifted from the app. The ring fills in when the tab
   is the one you are on, the same tell the app uses for the active mode. */
.port-tab {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 12px 5px 5px;
  border-radius: 999px;
  text-decoration: none;
  color: #fff;
  background: none;
  border: none;
  cursor: pointer;
}
.port-tab .ring {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 3px solid var(--plastic-dark);
  background: radial-gradient(circle at center, #fff 0 20%, var(--plastic-dark) 20% 28%, transparent 28% 62%, var(--plastic-dark) 62% 72%, transparent 72%);
  box-shadow: 0 2px 0 rgba(0, 0, 0, 0.45);
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.port-tab .label {
  font-family: var(--font-pixel);
  font-size: 9px;
  line-height: 1.6;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.4);
  font-weight: 400;
}
.port-tab[aria-current="page"] { background: rgba(255, 255, 255, 0.14); }
.port-tab[aria-current="page"] .ring {
  background: radial-gradient(circle at center, #fff 0 20%, var(--plastic-dark) 20% 28%, #fff 28% 62%, var(--plastic-dark) 62% 72%, transparent 72%);
  transform: translateY(2px);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.45);
}
.port-tab:not([aria-current="page"]):hover .ring { transform: translateY(1px); }

/* ---------- Slabs ---------- */

/* The app housing reduced to a section container: thick border, hard
   offset shadow, generous radius. Light by default, tinted by modifier. */
.slab {
  border: 5px solid var(--plastic-dark);
  border-radius: 26px;
  box-shadow: 10px 10px 0 var(--plastic-dark);
  padding: clamp(22px, 4vw, 40px);
  background-color: var(--pegboard-bg);
  background-image: radial-gradient(var(--pegboard-dot) 1.4px, transparent 1.4px);
  background-size: 16px 16px;
}
.slab--skin {
  background-color: var(--skin);
  background-image: none;
  color: #fff;
}
.slab--blue {
  --skin: var(--mode-blue);
  --skin-deep: var(--mode-blue-deep);
  background-color: var(--mode-blue);
  background-image: none;
  color: #fff;
}
.slab--dark {
  background-color: var(--plastic-dark);
  background-image: none;
  color: #fff;
}

/* Embossed control panel, for grouping inside a tinted slab. */
.panel {
  background: var(--panel-fill);
  border: 3px solid var(--plastic-dark);
  border-radius: 16px;
  padding: 16px 18px;
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.35), inset 0 -3px 0 rgba(0, 0, 0, 0.18);
}
/* On a light slab the same panel needs its own fill, translucent white
   disappears against pegboard. */
.slab:not(.slab--skin):not(.slab--blue):not(.slab--dark) .panel {
  background: rgba(255, 255, 255, 0.6);
}

/* ---------- Type ---------- */

.pixel {
  font-family: var(--font-pixel);
  font-weight: 400;
  letter-spacing: 0.02em;
  line-height: 1.6;
}

.page-title {
  font-family: var(--font-pixel);
  font-weight: 400;
  font-size: clamp(17px, 3.4vw, 26px);
  line-height: 1.5;
  letter-spacing: 0.02em;
  margin: 0 0 14px;
}
.slab--skin .page-title,
.slab--blue .page-title,
.slab--dark .page-title { text-shadow: 3px 3px 0 rgba(0, 0, 0, 0.28); }

.section-title {
  font-family: var(--font-pixel);
  font-weight: 400;
  font-size: clamp(12px, 2vw, 15px);
  line-height: 1.6;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  margin: 0 0 16px;
}
.slab--skin .section-title,
.slab--blue .section-title,
.slab--dark .section-title { text-shadow: 0 2px 0 rgba(0, 0, 0, 0.3); }

.sub-title {
  font-family: var(--font-pixel);
  font-weight: 400;
  font-size: 10px;
  line-height: 1.7;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  margin: 0 0 10px;
}

/* Body copy stays in the UI face. The pixel font is illegible at paragraph
   density, exactly as the app comments say. */
.lede {
  font-size: clamp(16px, 2.1vw, 19px);
  line-height: 1.65;
  margin: 0 0 20px;
  max-width: 62ch;
}
p { margin: 0 0 16px; max-width: 72ch; }
p:last-child { margin-bottom: 0; }

a { color: var(--mode-orange-deep); }
/* White prose links on a tinted slab, but never pills. A pill carries its
   own light background, and this selector outweighs .pill on specificity,
   so without the exclusion it paints white text on a near white button. */
.slab--skin a:not(.pill),
.slab--blue a:not(.pill),
.slab--dark a:not(.pill) { color: #fff; }
a:hover { text-decoration-thickness: 2px; }

.muted { opacity: 0.78; font-size: 14.5px; }

code, .mono { font-family: var(--font-mono); font-size: 0.92em; }
:not(pre) > code {
  background: var(--lcd-bg);
  color: var(--lcd-ink);
  border: 2px solid var(--plastic-dark);
  border-radius: 6px;
  padding: 1px 5px;
  white-space: nowrap;
}

/* ---------- Buttons ---------- */

.pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  font-family: var(--font-pixel);
  font-weight: 400;
  font-size: 10px;
  line-height: 1.6;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  text-align: center;
  text-decoration: none;
  padding: 15px 22px;
  border-radius: 999px;
  border: 3px solid var(--plastic-dark);
  background: var(--pill-bg);
  color: var(--plastic-dark);
  cursor: pointer;
  box-shadow: 0 6px 0 var(--plastic-dark);
  transition: transform 0.08s ease, box-shadow 0.08s ease, background-color 0.12s ease;
}
.pill:hover:not(:disabled):not([aria-disabled="true"]) { background: #fff; }
.pill:active:not(:disabled):not([aria-disabled="true"]) {
  transform: translateY(6px);
  box-shadow: 0 0 0 var(--plastic-dark);
}
.pill svg { width: 1.5em; height: 1.5em; flex-shrink: 0; }
/* The deep variant, not the base skin. On a light slab --skin is the raw
   house orange, and white on that is 3.7:1, which is under AA for text this
   size. --skin-deep takes it to 5.2:1 and still reads as the same orange. */
.pill--primary { background: var(--skin-deep); color: #fff; }
.pill--primary:hover:not(:disabled):not([aria-disabled="true"]) { background: var(--plastic-dark); }
.pill--small { font-size: 8px; padding: 11px 16px; box-shadow: 0 4px 0 var(--plastic-dark); }
.pill--small:active:not(:disabled) { transform: translateY(4px); }
.pill:disabled,
.pill[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  box-shadow: 0 6px 0 var(--plastic-dark);
}

.button-row {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: center;
  margin-top: 26px;
}

/* ---------- LCD ---------- */

/* Dark plastic bezel with the reflective green panel inside it, the same
   construction the app uses around every preview. */
.bezel {
  background: var(--plastic-dark);
  border-radius: 20px;
  padding: 14px;
  box-shadow: inset 0 0 0 3px #000;
}
.lcd {
  position: relative;
  background: var(--lcd-bg);
  border-radius: 5px;
  overflow: hidden;
  color: var(--lcd-ink);
  font-family: var(--font-mono);
}
/* The pixel grid a real reflective panel shows under raking light. */
.lcd::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(0, 0, 0, 0.07) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(0, 0, 0, 0.07) 1px, transparent 1px);
  background-size: 8px 8px;
}

/* ---------- Hero ---------- */

.hero {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  gap: clamp(24px, 4vw, 48px);
  align-items: center;
}
.hero-title {
  font-family: var(--font-pixel);
  font-weight: 400;
  font-size: clamp(24px, 6vw, 46px);
  line-height: 1.45;
  letter-spacing: 0.01em;
  margin: 0 0 18px;
  text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.3);
}
.hero-lede { font-size: clamp(16px, 2.2vw, 20px); max-width: 46ch; margin: 0; }
.hero-art { width: 100%; display: block; }

/* After the base rules, for the same cascade reason as the docs sidebar:
   the art is moved above the copy on a narrow screen, so the cube is the
   first thing you see rather than a wall of text. */
@media (max-width: 860px) {
  .hero { grid-template-columns: minmax(0, 1fr); }
  .hero-art { order: -1; max-width: 300px; margin-inline: auto; }
}

/* Idle animation on the hero cube. Two frames, held, the way an LCD toy
   moves, not a smooth tween. Steps keep it on the pixel grid. */
@keyframes buddy-idle {
  0%, 49.9% { transform: translateY(0); }
  50%, 100% { transform: translateY(3px); }
}
.buddy-bob { animation: buddy-idle 1.1s steps(1, end) infinite; }
@media (prefers-reduced-motion: reduce) {
  .buddy-bob { animation: none; }
}

/* ---------- Sections ---------- */

.section { margin-top: clamp(34px, 6vw, 64px); }
.section:first-of-type { margin-top: 0; }

main { 
  padding-block: clamp(22px, 4vw, 40px) clamp(48px, 8vw, 90px); 
  flex-grow: 1; /* Add this */
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
  gap: 18px;
}

.card {
  background: var(--pill-bg);
  border: 3px solid var(--plastic-dark);
  border-radius: 18px;
  box-shadow: 6px 6px 0 var(--plastic-dark);
  padding: 20px;
  color: var(--plastic-dark);
}
.card h3 {
  font-family: var(--font-pixel);
  font-weight: 400;
  font-size: 10px;
  line-height: 1.7;
  text-transform: uppercase;
  margin: 0 0 12px;
}
.card p { font-size: 14.5px; margin: 0; max-width: none; }
.card-icon {
  width: 34px;
  height: 34px;
  display: block;
  margin-bottom: 12px;
  color: var(--mode-orange-deep);
}

/* ---------- Video ---------- */

.video-frame { max-width: 900px; margin-inline: auto; }
.video-lcd {
  position: relative;
  aspect-ratio: 16 / 9;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 18px;
  text-align: center;
  padding: 20px;
  border: 0;
  cursor: pointer;
  font: inherit;
}
.video-lcd iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  z-index: 2;
}
/* Once a real player is mounted the grid overlay must not sit on top of it. */
.lcd.is-playing::after { display: none; }
.video-note {
  font-family: var(--font-pixel);
  font-weight: 400;
  font-size: 10px;
  line-height: 1.8;
  text-transform: uppercase;
  color: var(--lcd-ink);
  margin: 0;
  max-width: 30ch;
}
.video-caption {
  margin: 14px 0 0;
  text-align: center;
  font-size: 14px;
  max-width: none;
}
.play-badge {
  width: 84px;
  height: 84px;
  border-radius: 50%;
  border: 4px solid var(--lcd-ink);
  background: var(--lcd-bg-deep);
  color: var(--lcd-ink);
  display: grid;
  place-items: center;
  flex-shrink: 0;
  transition: transform 0.12s ease;
}
.video-lcd:hover .play-badge { transform: scale(1.06); }
.play-badge svg { width: 34px; height: 34px; }

/* ---------- Tables ---------- */

.table-scroll {
  overflow-x: auto;
  border: 3px solid var(--plastic-dark);
  border-radius: 14px;
  background: var(--pill-bg);
}
table { border-collapse: collapse; width: 100%; min-width: 460px; }
th, td {
  text-align: left;
  padding: 11px 14px;
  border-bottom: 2px solid rgba(38, 36, 33, 0.18);
  font-size: 14.5px;
  vertical-align: top;
}
th {
  font-family: var(--font-pixel);
  font-weight: 400;
  font-size: 8px;
  line-height: 1.8;
  text-transform: uppercase;
  background: var(--plastic-dark);
  color: #fff;
  border-bottom: 3px solid var(--plastic-dark);
}
tbody tr:last-child td { border-bottom: 0; }

/* ---------- Docs ---------- */

.docs-layout {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  gap: clamp(20px, 3vw, 36px);
  align-items: start;
}
.docs-side {
  position: sticky;
  top: 96px;
  background: var(--pill-bg);
  border: 3px solid var(--plastic-dark);
  border-radius: 18px;
  box-shadow: 6px 6px 0 var(--plastic-dark);
  padding: 16px;
}
.docs-side ul { list-style: none; margin: 0; padding: 0; }
.docs-side li + li { margin-top: 6px; }
.docs-side a {
  display: block;
  padding: 9px 11px;
  border-radius: 10px;
  border: 2px solid transparent;
  text-decoration: none;
  color: var(--plastic-dark);
  font-family: var(--font-pixel);
  font-weight: 400;
  font-size: 8px;
  line-height: 1.8;
  text-transform: uppercase;
}
.docs-side a:hover { background: #fff; border-color: var(--plastic-dark); }
.docs-side a[aria-current="page"] {
  background: var(--plastic-dark);
  color: #fff;
  border-color: var(--plastic-dark);
}

/* Declared after the base rules, not before them. Both selectors carry the
   same specificity, so a narrow-screen override placed above .docs-side
   loses the cascade and the sidebar stays stuck to the viewport. */
@media (max-width: 800px) {
  .docs-layout { grid-template-columns: minmax(0, 1fr); }
  .docs-side { position: static; }
}

.doc-body h2 {
  font-family: var(--font-pixel);
  font-weight: 400;
  font-size: clamp(12px, 2vw, 14px);
  line-height: 1.7;
  text-transform: uppercase;
  margin: 34px 0 14px;
  padding-top: 4px;
}
.doc-body h2:first-child { margin-top: 0; }
.doc-body h3 {
  font-family: var(--font-pixel);
  font-weight: 400;
  font-size: 10px;
  line-height: 1.8;
  text-transform: uppercase;
  margin: 24px 0 10px;
}
.doc-body ul, .doc-body ol { padding-left: 22px; margin: 0 0 16px; max-width: 72ch; }
.doc-body li { margin-bottom: 7px; }
.doc-body li:last-child { margin-bottom: 0; }

/* Numbered steps drawn as physical chips rather than list markers. */
.steps { list-style: none; padding: 0; margin: 0; counter-reset: step; }
.steps > li {
  counter-increment: step;
  position: relative;
  padding: 0 0 0 52px;
  margin-bottom: 20px;
  min-height: 36px;
}
.steps > li::before {
  content: counter(step);
  position: absolute;
  left: 0;
  top: 0;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 3px solid var(--plastic-dark);
  /* Deep variant for the same contrast reason as .pill--primary. */
  background: var(--skin-deep);
  color: #fff;
  font-family: var(--font-pixel);
  font-weight: 400;
  font-size: 11px;
  line-height: 1;
  box-shadow: 0 3px 0 var(--plastic-dark);
}

/* Callout, the dialog-detail strip from the app reused for asides. */
.note {
  background: var(--lcd-bg);
  border: 3px solid var(--plastic-dark);
  border-radius: 12px;
  padding: 14px 16px;
  color: var(--lcd-ink);
  margin: 20px 0;
}
.note p { max-width: none; }
.note .sub-title { margin-bottom: 6px; }
.note--warn { background: #f0d9d4; color: #5a1f16; }

/* ---------- Forms ---------- */

.field { display: block; margin-bottom: 18px; }
.field > span {
  display: block;
  font-family: var(--font-pixel);
  font-weight: 400;
  font-size: 9px;
  line-height: 1.8;
  text-transform: uppercase;
  margin-bottom: 8px;
}
.chunky-input,
.chunky-textarea {
  width: 100%;
  border: 3px solid var(--plastic-dark);
  border-radius: 10px;
  padding: 12px 13px;
  font-family: var(--font-mono);
  font-size: 15px;
  line-height: 1.55;
  background: var(--pill-bg);
  color: var(--plastic-dark);
}
.chunky-input:focus,
.chunky-textarea:focus {
  background: #fff;
  outline: 3px solid var(--plastic-dark);
  outline-offset: 2px;
}
.chunky-textarea { min-height: 170px; resize: vertical; }
.form-status {
  margin-top: 16px;
  font-family: var(--font-pixel);
  font-weight: 400;
  font-size: 9px;
  line-height: 1.9;
  text-transform: uppercase;
}
.form-status[data-state="ok"] { color: var(--ready-green); }
.form-status[data-state="err"] { color: var(--status-red); }
.slab--blue .form-status[data-state="ok"] { color: #9be8b3; }
.slab--blue .form-status[data-state="err"] { color: #ffc2bd; }

/* ---------- Footer ---------- */

.site-footer {
  border-top: 5px solid var(--plastic-dark);
  background: var(--plastic-dark);
  color: #fff;
  padding: 34px 0 40px;
  margin-top: auto;
}
.footer-inner {
  display: flex;
  flex-wrap: wrap;
  gap: 26px;
  justify-content: space-between;
  align-items: flex-start;
}
.footer-links { display: flex; flex-wrap: wrap; gap: 8px 22px; }
.footer-links a {
  color: #fff;
  text-decoration: none;
  font-family: var(--font-pixel);
  font-weight: 400;
  font-size: 8px;
  line-height: 2;
  text-transform: uppercase;
}
.footer-links a:hover { text-decoration: underline; }
.footer-note { font-size: 13px; opacity: 0.72; margin: 0; max-width: 44ch; }
