@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap");

/*
 * javierbits.com shared chrome: header + footer.
 *
 * Loaded root-relative (/assets/chrome.css) by every page on javierbits.com, including project
 * pages served from other repos (Tailwind on SolDecode, custom CSS on murmur, tok-sim,
 * dgx-spark-bench). Contract: CHROME.md / AGENTS.md.
 *
 * Rules:
 * - Every selector is scoped under .jx-header or .jx-footer (or a jx- class).
 * - Reason: host pages ship resets (Tailwind preflight), global `a`/`p`/`footer`/`header`
 *   rules and even inline body fonts, so every property the chrome relies on is set
 *   explicitly here instead of inherited from <body>.
 * - Custom properties live on the two roots, not :root, so they never shadow a host's vars.
 */

.jx-header,
.jx-footer {
  --jx-bg: #0a0e14;
  --jx-bg-card: #0f1419;
  --jx-border: #1e2a36;
  --jx-green: #00ff41;
  --jx-green-dim: #00cc33;
  --jx-cyan: #00d4ff;
  --jx-text: #c5cdd8;
  --jx-text-dim: #5a6a7a;
  --jx-white: #e8edf3;
  --jx-font: "JetBrains Mono", "Fira Code", "Cascadia Code", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  display: block;
  box-sizing: border-box;
  width: 100%;
  max-width: none;
  margin: 0;
  background: var(--jx-bg);
  color: var(--jx-text);
  font-family: var(--jx-font);
  font-size: 14px;
  font-weight: 400;
  font-style: normal;
  line-height: 1.6;
  letter-spacing: normal;
  text-align: left;
  text-transform: none;
  -webkit-font-smoothing: antialiased;
  position: relative;
  z-index: 50;
}

.jx-header *,
.jx-header *::before,
.jx-header *::after,
.jx-footer *,
.jx-footer *::before,
.jx-footer *::after {
  box-sizing: border-box;
  font-family: var(--jx-font);
}

/* ── Links (shared) ─────────────────────────── */
.jx-header a,
.jx-footer a {
  color: var(--jx-text-dim);
  background: transparent;
  text-decoration: none;
  border: 0 solid transparent;
  margin: 0;
  padding: 0;
  font-size: inherit;
  font-weight: 400;
  line-height: inherit;
  transition: color 0.2s, border-color 0.2s;
  overflow-wrap: anywhere;
}

.jx-header a:hover,
.jx-footer a:hover {
  color: var(--jx-green);
  text-decoration: none;
}

.jx-header a:focus,
.jx-footer a:focus {
  outline: none;
}

.jx-header a:focus-visible,
.jx-footer a:focus-visible {
  outline: 2px solid var(--jx-green);
  outline-offset: 3px;
  border-radius: 2px;
  box-shadow: none;
  color: var(--jx-green);
}

/* ── Header ─────────────────────────────────── */
.jx-header {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem 1.5rem;
  padding: 1rem 2rem;
  border: 0 solid var(--jx-border);
  border-bottom-width: 1px;
}

.jx-header .jx-logo {
  color: var(--jx-green);
  font-size: 1.1rem;
  font-weight: 700;
  line-height: 1.4;
  white-space: nowrap;
}

.jx-header .jx-logo:hover {
  color: var(--jx-cyan);
}

.jx-header .jx-blink {
  color: inherit;
  animation: jx-blink 1s step-end infinite;
}

@keyframes jx-blink {
  50% { opacity: 0; }
}

.jx-header .jx-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 1.25rem;
  margin: 0;
  padding: 0;
  background: transparent;
  border: 0;
}

.jx-header .jx-nav a {
  font-size: 0.85rem;
  line-height: 1.6;
  white-space: nowrap;
}

/* ── Footer ─────────────────────────────────── */
.jx-footer {
  /* Reason: side padding grows to center an 800px column, so children need no auto
     margins (which their own explicit margin resets would otherwise cancel). */
  padding: 2.5rem max(2rem, calc((100% - 800px) / 2)) 2rem;
  margin-top: 3rem;
  border: 0 solid var(--jx-border);
  border-top-width: 1px;
}

.jx-footer p {
  margin: 0 0 0.8rem;
  padding: 0;
  color: var(--jx-text);
  font-size: 0.85rem;
  line-height: 1.6;
  text-align: left;
  max-width: none;
}

.jx-footer .jx-footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.5rem;
  margin-bottom: 1.2rem;
  padding: 0;
  font-size: 0.85rem;
}

.jx-footer .jx-footer-links a {
  border-bottom: 1px dashed var(--jx-border);
  padding-bottom: 2px;
}

.jx-footer .jx-footer-links a:hover {
  border-bottom-color: var(--jx-green);
}

.jx-footer .jx-sig {
  color: var(--jx-text-dim);
  font-size: 0.8rem;
  margin: 0;
}

/*
 * Substack embed (https://agicheckpoint.com/embed) for page content, as
 * <div class="jx-embed-frame"><iframe class="jx-embed" ...></iframe></div> (home and /newsletter only).
 * Reason: the embed is cross-origin, so it can't report its own height. Heights below are
 * the measured content height at each iframe width (Playwright, tools/measure_embed.py; see
 * AGENTS.md) plus ~24px above and below, which also keeps Substack's bottom-right watermark
 * off the terms text. With scrolling="no" too short means clipped, so each step uses the
 * tallest content in its width range.
 *   iframe >= 448px wide: content 457px  -> 508px
 *   iframe 358-447px:     content <= 480 -> 528px
 *   iframe 326-357px:     content <= 519 -> 568px
 *   iframe < 326px:       content 556 at 300px -> 610px
 * Breakpoints are viewport widths: iframe width = viewport - 2 * 16px gutter on phones.
 *
 * Dark: Substack serves the embed light and only follows the publication's own theme (it has
 * no dark query parameter and ignores prefers-color-scheme), so the document inside is
 * flipped here. hue-rotate(180deg) after invert(1) puts the hues back where they were and
 * leaves only luminance inverted, so the teal button stays teal and Substack's black wordmark
 * comes out light. The frame (border, panel background, radius) sits outside the filter so it
 * keeps the site colours exactly; the iframe itself stays transparent to show that panel while
 * the third-party document is still loading.
 */
.jx-embed-frame {
  display: block;
  width: 100%;
  max-width: 480px;
  margin: 0.8rem 0 0;
  padding: 0;
  border: 1px solid var(--jx-border, #1e2a36);
  border-radius: 8px;
  background: var(--jx-bg-card, #0f1419);
  overflow: hidden;
}

.jx-embed {
  display: block;
  width: 100%;
  max-width: 480px;
  height: 508px;
  min-height: 0;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color-scheme: light;
  filter: invert(1) hue-rotate(180deg);
  overflow: hidden;
}

@media (max-width: 640px) {
  .jx-header {
    padding: 0.8rem 16px;
    gap: 0.4rem 1rem;
  }

  .jx-header .jx-nav {
    gap: 0.2rem 0.9rem;
  }

  .jx-header .jx-nav a {
    font-size: 0.8rem;
  }

  .jx-footer {
    padding: 2rem 16px 1.5rem;
  }
}

@media (max-width: 479px) {
  .jx-embed {
    height: 528px;
  }
}

@media (max-width: 389px) {
  .jx-embed {
    height: 568px;
  }
}

@media (max-width: 357px) {
  .jx-embed {
    height: 610px;
  }
}

@media (prefers-reduced-motion: reduce) {
  /* Reason: the logo caret only fades its opacity at 1Hz, so it is not motion and stays as is
     (one blink per second is far below the 3 flashes/second threshold, and stopping it made the
     prompt look frozen for anyone whose OS asks for reduced motion). Colour transitions are the
     part here worth removing. */
  .jx-header a,
  .jx-footer a {
    transition: none;
  }
}
