/* Everybody Robotics — shared styles for every page on the site. */

:root {
  --cream:      #f2ece0;
  --ink:        #241f18;
  --ink-soft:   #2b2317;
  --body:       #3a3226;
  --muted:      #5f5548;
  --rust:       #8a3b28;
  --rust-deep:  #7c2d21;
  --rule:       rgba(60, 50, 35, 0.22);

  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --sans: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  --header-h: 64px;
  --gutter: clamp(20px, 5vw, 72px);
  --measure: min(64%, 860px);
  --reading: 74ch;
}

@media (max-width: 900px) {
  :root { --header-h: 56px; --measure: 100%; }
}

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

/* Any `display` declaration outranks the UA's `[hidden] { display: none }`,
   so state it explicitly — the dialog's form relies on it. */
[hidden] { display: none !important; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 24px);
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--cream);
  color: var(--body);
  font-family: var(--mono);
  font-size: 17px;
  line-height: 1.68;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  min-height: 100svh;
}

::selection { background: #d8c9a8; color: var(--ink); }

a { color: var(--ink-soft); text-decoration: none; }
a:hover { color: var(--rust-deep); }

:focus-visible {
  outline: 2px solid var(--rust);
  outline-offset: 3px;
  border-radius: 2px;
}

img { max-width: 100%; display: block; }

/* ── Illustration backdrop (landing page) ────────────────────────────
   A fixed layer rather than `background-attachment: fixed`, which
   stutters or drops out entirely on iOS Safari. */
.backdrop {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: var(--cream);
}

.backdrop img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 100% 42%;
}

/* Cream scrim so body copy keeps its contrast over the painting. */
.backdrop::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    var(--cream) 0%,
    rgba(242, 236, 224, 0.94) 34%,
    rgba(242, 236, 224, 0.55) 56%,
    rgba(242, 236, 224, 0) 72%
  );
}

@media (max-width: 900px) {
  .backdrop img { object-position: 76% 40%; }
  .backdrop::after {
    background: linear-gradient(
      180deg,
      rgba(242, 236, 224, 0.9) 0%,
      rgba(242, 236, 224, 0.86) 60%,
      rgba(242, 236, 224, 0.94) 100%
    );
  }
}

/* ── Shell ───────────────────────────────────────────────────────── */
.shell {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  min-height: 100svh;
}

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

/* Zero-area targets are unreliable for IntersectionObserver — give the
   scroll sentinel a real box, out of flow so it costs no layout. */
#top-sentinel {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 1px;
}

.skip-link {
  position: absolute;
  left: 12px;
  top: 12px;
  z-index: 100;
  transform: translateY(-200%);
  background: var(--cream);
  color: var(--ink);
  border: 1px solid var(--rule);
  padding: 10px 16px;
  font-size: 13px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  transition: transform 160ms ease;
}
.skip-link:focus { transform: translateY(0); }

/* ── Sticky header ───────────────────────────────────────────────── */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(242, 236, 224, 0.72);
  border-bottom: 1px solid transparent;
  transition: background 220ms ease, border-color 220ms ease, box-shadow 220ms ease;
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .site-header {
    -webkit-backdrop-filter: blur(14px) saturate(1.4);
    backdrop-filter: blur(14px) saturate(1.4);
  }
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header { background: rgba(242, 236, 224, 0.96); }
}

.site-header[data-scrolled] {
  background: rgba(242, 236, 224, 0.9);
  border-bottom-color: var(--rule);
  box-shadow: 0 1px 18px rgba(60, 50, 35, 0.06);
}

.header-bar {
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.wordmark {
  font-family: var(--sans);
  font-weight: 600;
  font-size: clamp(17px, 1.4vw, 19px);
  letter-spacing: -0.005em;
  color: var(--ink-soft);
  white-space: nowrap;
}
.wordmark:hover { color: var(--ink-soft); }

.nav-list {
  display: flex;
  align-items: center;
  gap: clamp(20px, 2.4vw, 38px);
  list-style: none;
}

/* Scoped away from .nav-cta: `.nav-list a` has higher specificity than
   `.nav-cta`, so without :not() it overrides the pill's border and colour
   and the outline renders with a transparent bottom edge. */
.nav-list a:not(.nav-cta) {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
  padding-block: 6px;
  border-bottom: 1px solid transparent;
  transition: color 160ms ease, border-color 160ms ease;
}
.nav-list a:not(.nav-cta):hover { color: var(--rust-deep); }
.nav-list a:not(.nav-cta)[aria-current='page'] {
  color: var(--rust);
  border-bottom-color: rgba(138, 59, 40, 0.45);
}

.nav-cta {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--rust);
  border: 1px solid rgba(138, 59, 40, 0.4);
  border-radius: 999px;
  padding: 9px 18px;
  white-space: nowrap;
  transition: background 160ms ease, border-color 160ms ease, color 160ms ease;
}
.nav-cta:hover {
  color: var(--rust-deep);
  border-color: var(--rust-deep);
  background: rgba(138, 59, 40, 0.07);
}

.nav-toggle {
  display: none;
  width: 42px;
  height: 42px;
  margin-right: -9px;
  background: none;
  border: 0;
  color: var(--ink-soft);
  cursor: pointer;
  align-items: center;
  justify-content: center;
}
.nav-toggle span {
  display: block;
  position: relative;
  width: 20px;
  height: 1.5px;
  background: currentColor;
  transition: background 160ms ease;
}
.nav-toggle span::before,
.nav-toggle span::after {
  content: '';
  position: absolute;
  left: 0;
  width: 20px;
  height: 1.5px;
  background: currentColor;
  transition: transform 200ms ease;
}
.nav-toggle span::before { top: -6px; }
.nav-toggle span::after  { top: 6px; }

.nav-toggle[aria-expanded='true'] span { background: transparent; }
.nav-toggle[aria-expanded='true'] span::before { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded='true'] span::after  { transform: translateY(-6px) rotate(-45deg); }

@media (max-width: 900px) {
  .nav-toggle { display: flex; }

  .site-nav {
    position: absolute;
    inset-inline: 0;
    top: 100%;
    background: var(--cream);
    border-bottom: 1px solid var(--rule);
    box-shadow: 0 12px 24px rgba(60, 50, 35, 0.08);
    padding: 8px var(--gutter) 22px;
    display: none;
  }
  .site-nav[data-open] { display: block; }

  .nav-list {
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
  }
  .nav-list li { width: 100%; }
  .nav-list a:not(.nav-cta),
  .nav-cta {
    display: block;
    width: 100%;
    padding-block: 13px;
    font-size: 14px;
  }
  .nav-cta {
    text-align: center;
    margin-top: 14px;
    padding-block: 13px;
  }
}

/* ── Landing page content ────────────────────────────────────────── */
main { flex: 1; }

.column { max-width: var(--measure); }

.hero {
  padding-top: clamp(56px, 12vh, 132px);
  padding-bottom: 30px;
}

.eyebrow {
  font-size: 15px;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--rust);
  margin-bottom: 24px;
  text-wrap: balance;
}

h1 {
  font-family: var(--mono);
  font-weight: 400;
  font-size: clamp(24px, 2.5vw, 30px);
  line-height: 1.42;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-wrap: pretty;
}
h1 em { font-style: italic; }

.prose {
  display: flex;
  flex-direction: column;
  gap: 22px;
  max-width: 70ch;
}
.prose p { color: var(--body); }

.section {
  padding-block: 11px;
  scroll-margin-top: calc(var(--header-h) + 24px);
}

.pullquote {
  font-size: clamp(19px, 1.8vw, 21px);
  line-height: 1.5;
  color: var(--rust);
  margin-top: 38px;
  padding-left: 22px;
  border-left: 2px solid rgba(138, 59, 40, 0.35);
  max-width: 20em;
}

/* ── Blog ────────────────────────────────────────────────────────────
   Long technical prose gets a plain cream ground — the illustration
   backdrop belongs to the landing page, where the text is short.

   Reading pages set `data-layout="reading"` on <body>. That centres the
   column (the landing page's is deliberately left-aligned against the
   illustration) and makes the type fluid, so the measure stays ~74
   characters while growing physically with the viewport. `ch` resolves
   against each element's own font size, so the two move together. */
body[data-layout='reading'] {
  font-size: clamp(16px, 0.25vw + 14.5px, 18.5px);
}

[data-layout='reading'] .page-head,
[data-layout='reading'] .post-list,
[data-layout='reading'] .article,
[data-layout='reading'] .post-foot,
[data-layout='reading'] .footer-inner {
  max-width: var(--reading);
  margin-inline: auto;
}

.page-head {
  /* Matches .article so the title sits on the same measure as the body. */
  max-width: var(--reading);
  padding-top: clamp(44px, 9vh, 88px);
  padding-bottom: clamp(28px, 4vh, 44px);
}

.page-title {
  font-family: var(--mono);
  font-weight: 400;
  font-size: clamp(26px, 3vw, 34px);
  line-height: 1.3;
  letter-spacing: -0.015em;
  color: var(--ink);
  text-wrap: balance;
}

.page-lede {
  margin-top: 16px;
  max-width: 58ch;
  color: var(--muted);
}

.post-list {
  list-style: none;
  max-width: var(--reading);
  border-top: 1px solid var(--rule);
  margin-bottom: clamp(40px, 8vh, 80px);
}

.post-list li { border-bottom: 1px solid var(--rule); }

.post-list a {
  display: block;
  padding-block: clamp(24px, 4vh, 34px);
  transition: opacity 160ms ease;
}
.post-list a:hover { opacity: 0.72; }
.post-list a:hover .post-link-title { color: var(--rust-deep); }

.post-meta {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--muted);
}

.post-link-title {
  margin-top: 12px;
  font-size: clamp(20px, 2.2vw, 24px);
  line-height: 1.36;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-wrap: pretty;
  transition: color 160ms ease;
}

.post-link-dek {
  margin-top: 10px;
  font-size: 16px;
  line-height: 1.6;
  color: var(--muted);
  max-width: 62ch;
}

/* ── Article ─────────────────────────────────────────────────────── */
.article {
  max-width: var(--reading);
  padding-bottom: clamp(40px, 8vh, 72px);
}

.article > * + * { margin-top: 24px; }

.article p { color: var(--body); }

.article h2 {
  margin-top: clamp(48px, 7vh, 68px);
  font-family: var(--mono);
  font-weight: 500;
  font-size: clamp(19px, 2vw, 22px);
  line-height: 1.4;
  letter-spacing: -0.005em;
  color: var(--ink);
  scroll-margin-top: calc(var(--header-h) + 24px);
}

.article h3 {
  margin-top: clamp(32px, 5vh, 44px);
  font-family: var(--mono);
  font-weight: 500;
  font-size: 15px;
  line-height: 1.5;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--rust);
  scroll-margin-top: calc(var(--header-h) + 24px);
}

.article strong { font-weight: 500; color: var(--ink); }
.article em { font-style: italic; }

.article ul { list-style: none; }
.article li + li { margin-top: 12px; }
.article ul li {
  position: relative;
  padding-left: 24px;
}
.article ul li::before {
  content: '';
  position: absolute;
  left: 2px;
  top: 0.72em;
  width: 6px;
  height: 1px;
  background: var(--rust);
}

.article hr {
  border: 0;
  border-top: 1px solid var(--rule);
  margin-block: clamp(40px, 6vh, 56px);
}

.article a:not(.nav-cta) {
  color: var(--ink);
  border-bottom: 1px solid rgba(36, 31, 24, 0.35);
  transition: color 160ms ease, border-color 160ms ease;
}
.article a:not(.nav-cta):hover { color: var(--rust-deep); border-bottom-color: var(--rust-deep); }

/* Inline code and blocks. `pre` scrolls in its own box so the page body
   never scrolls sideways. */
.article code {
  font-family: var(--mono);
  font-size: 0.92em;
  background: rgba(60, 50, 35, 0.07);
  border-radius: 3px;
  padding: 0.15em 0.4em;
}

.article pre {
  overflow-x: auto;
  padding: 22px 24px;
  background: rgba(60, 50, 35, 0.05);
  border: 1px solid var(--rule);
  border-radius: 4px;
  font-size: 13.5px;
  line-height: 1.62;
  color: var(--ink);
  -webkit-overflow-scrolling: touch;
}
.article pre code {
  background: none;
  padding: 0;
  font-size: inherit;
  white-space: pre;
}

/* Tables scroll inside their own container rather than widening the page. */
.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--rule);
  border-radius: 4px;
}

.article table {
  border-collapse: collapse;
  width: 100%;
  min-width: 560px;
  font-size: 14px;
  line-height: 1.5;
}

.article th,
.article td {
  padding: 12px 16px;
  text-align: right;
  border-bottom: 1px solid var(--rule);
  white-space: nowrap;
}

/* Pin the label column so rows stay identifiable while the numbers
   scroll sideways. Backgrounds must be opaque or the scrolled cells
   show through, so these are the flat equivalents of the translucent
   fills used on the header row and the highlighted row. */
.article th:first-child,
.article td:first-child {
  text-align: left;
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--cream);
  box-shadow: 1px 0 0 var(--rule);
}

.article thead th:first-child { background: #ebe5d8; }
.article tbody tr.is-ours th:first-child,
.article tbody tr.is-ours td:first-child { background: #ece1d5; }

.article thead th {
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
  background: rgba(60, 50, 35, 0.04);
}

.article tbody tr:last-child td { border-bottom: 0; }

/* `is-ours` tints either a whole row or a single column's cells. */
.article tbody tr.is-ours { background: rgba(138, 59, 40, 0.06); }
.article tbody tr.is-ours td { color: var(--ink); }
.article tbody td.is-ours {
  background: rgba(138, 59, 40, 0.06);
  color: var(--ink);
}
.article thead th.is-ours {
  background: #e9ded2; /* header tint and column tint, flattened */
  color: var(--rust);
}

/* Diagrams. The video ships without audio and loops; `site.js` pauses it
   and exposes controls when the visitor prefers reduced motion. The
   width/height attributes reserve the box so nothing shifts on load. */
.diagram {
  display: block;
  width: 100%;
  height: auto;
  background: var(--cream);
  border: 1px solid var(--rule);
  border-radius: 4px;
}

.article figcaption {
  margin-top: 12px;
}

.article figcaption,
.article .note {
  font-size: 14px;
  line-height: 1.62;
  color: var(--muted);
}

.article .note em { font-style: italic; }

/* Unresolved placeholder — impossible to miss before publishing. */
.todo {
  background: rgba(138, 59, 40, 0.14);
  color: var(--rust-deep);
  padding: 0.1em 0.4em;
  border-radius: 3px;
  font-weight: 500;
}

.post-foot {
  margin-top: clamp(48px, 7vh, 68px);
  padding-top: 30px;
  border-top: 1px solid var(--rule);
  max-width: var(--reading);
}

.back-link {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--muted);
}
.back-link:hover { color: var(--rust-deep); }

/* ── Footer ──────────────────────────────────────────────────────── */
.site-footer {
  margin-top: clamp(48px, 9vh, 74px);
  padding-block: 34px clamp(48px, 8vh, 64px);
  scroll-margin-top: calc(var(--header-h) + 24px);
}

.footer-inner {
  max-width: var(--measure);
  padding-top: 34px;
  border-top: 1px solid var(--rule);
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 36px 72px;
}

.field-label {
  font-size: 13px;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 10px;
}

.field-value {
  font-size: clamp(17px, 1.6vw, 20px);
  line-height: 1.4;
  color: var(--ink);
  overflow-wrap: anywhere;
}

a.field-value {
  border-bottom: 1px solid rgba(36, 31, 24, 0.35);
  padding-bottom: 2px;
  transition: color 160ms ease, border-color 160ms ease;
}
a.field-value:hover { color: var(--rust-deep); border-bottom-color: var(--rust-deep); }

.colophon {
  font-size: 13px;
  line-height: 1.6;
  color: var(--muted);
  margin-left: auto;
}

@media (max-width: 600px) {
  body { font-size: 16px; }
  .footer-inner { gap: 28px; }
  .colophon { margin-left: 0; width: 100%; }
  .article pre { font-size: 12px; padding: 16px 18px; }
}

/* ── Say hello dialog ────────────────────────────────────────────── */
.dialog {
  width: min(520px, calc(100vw - 32px));
  /* The `* { margin: 0 }` reset above wipes out the UA's `margin: auto`,
     which is what centres a modal dialog in the viewport. */
  margin: auto;
  max-height: calc(100dvh - 32px);
  overflow-y: auto;
  padding: clamp(28px, 4vw, 40px);
  border: 1px solid var(--rule);
  border-radius: 4px;
  background: var(--cream);
  color: var(--body);
  font-family: var(--mono);
  box-shadow: 0 24px 60px rgba(36, 31, 24, 0.18);
}

/* Stop the page behind the modal from scrolling. */
html:has(.dialog[open]) { overflow: hidden; }

.dialog::backdrop {
  background: rgba(36, 31, 24, 0.42);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

.dialog[open] { animation: dialog-in 240ms cubic-bezier(0.2, 0.7, 0.3, 1); }
.dialog[open]::backdrop { animation: fade-in 240ms ease; }

@keyframes dialog-in {
  from { opacity: 0; transform: translateY(10px) scale(0.99); }
  to   { opacity: 1; transform: none; }
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

.dialog-close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  background: none;
  border: 0;
  border-radius: 50%;
  color: var(--muted);
  cursor: pointer;
  transition: color 160ms ease, background 160ms ease;
}
.dialog-close:hover { color: var(--rust-deep); background: rgba(138, 59, 40, 0.07); }

.dialog-title {
  font-family: var(--mono);
  font-weight: 400;
  font-size: clamp(21px, 2.2vw, 25px);
  line-height: 1.35;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.dialog-lede {
  margin-top: 10px;
  font-size: 15px;
  line-height: 1.6;
  color: var(--muted);
}

.hello-form {
  margin-top: 26px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.field { display: flex; flex-direction: column; gap: 8px; }

.field label {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--muted);
}

.field input,
.field textarea {
  width: 100%;
  padding: 11px 13px;
  font: inherit;
  font-size: 16px; /* 16px keeps iOS Safari from zooming on focus */
  line-height: 1.5;
  color: var(--ink);
  background: rgba(255, 255, 255, 0.5);
  border: 1px solid var(--rule);
  border-radius: 3px;
  transition: border-color 160ms ease, background 160ms ease;
}
.field textarea { resize: vertical; min-height: 108px; }

.field input:hover,
.field textarea:hover { border-color: rgba(60, 50, 35, 0.4); }

.field input:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--rust);
  background: rgba(255, 255, 255, 0.78);
  box-shadow: 0 0 0 3px rgba(138, 59, 40, 0.12);
}

.field [aria-invalid='true'] { border-color: var(--rust); }

.field-error {
  font-size: 13px;
  line-height: 1.5;
  color: var(--rust-deep);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Honeypot — hidden from people, still reachable by bots. */
.hp {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.dialog-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 22px;
  margin-top: 4px;
}

.btn-send {
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--cream);
  background: var(--rust);
  border: 1px solid var(--rust);
  border-radius: 999px;
  padding: 12px 30px;
  cursor: pointer;
  transition: background 160ms ease, border-color 160ms ease, opacity 160ms ease;
}
.btn-send:hover { background: var(--rust-deep); border-color: var(--rust-deep); }
.btn-send[disabled] { opacity: 0.55; cursor: default; }

.dialog-alt { font-size: 13px; color: var(--muted); border-bottom: 1px solid var(--rule); }
.dialog-alt:hover { color: var(--rust-deep); border-bottom-color: var(--rust-deep); }

.form-status {
  font-size: 14px;
  line-height: 1.6;
  color: var(--muted);
}
.form-status:empty { display: none; }
.form-status[data-state='error'] { color: var(--rust-deep); }
.form-status[data-state='ok'] { color: var(--rust); }

/* Sent state replaces the form body. */
.dialog-sent {
  margin-top: 24px;
  font-size: 17px;
  line-height: 1.68;
  color: var(--body);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}

@media print {
  .backdrop, .site-header, .skip-link, .dialog { display: none !important; }
  body { background: #fff; color: #000; font-size: 12pt; }
  :root { --measure: 100%; }
  .article { max-width: 100%; }
  .article pre, .table-scroll { overflow: visible; }
}
