/* Bridge marketing site.
 *
 * Hand-written, no framework. The palette is lifted from the app
 * (packages/web/src/index.css) so the site and the product look like the same
 * thing: VS Code Dark+ greys with the #3794ff button blue as the only accent.
 *
 * Everything is sized in rem, matching the house rule in the app: a visitor
 * with a larger default font size gets a proportionally larger page.
 */

:root {
  --bg: #1e1e1e;
  --bg-deep: #181818;
  --bg-raised: #252526;
  --line: #3c3c3c;
  --line-soft: #2d2d2d;
  --text: #d4d4d4;
  --text-bright: #f3f3f3;
  --text-dim: #9d9d9d;
  --accent: #3794ff;
  --accent-deep: #1177bb;

  --font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    Helvetica, Arial, sans-serif;
  --font-mono: "Berkeley Mono", ui-monospace, Menlo, Consolas, monospace;

  --wrap: 68rem;
  --radius: 0.75rem;
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  * {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
}

a {
  color: var(--accent);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

h1,
h2,
h3 {
  color: var(--text-bright);
  line-height: 1.2;
  letter-spacing: -0.02em;
  margin: 0 0 0.5em;
}

h1 {
  font-size: clamp(2.2rem, 5vw, 3.4rem);
}

h2 {
  font-size: clamp(1.5rem, 3vw, 2rem);
}

h3 {
  font-size: 1.15rem;
}

p {
  margin: 0 0 1.1em;
}

hr {
  border: 0;
  border-top: 0.0625rem solid var(--line-soft);
  margin: 3rem 0;
}

code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--bg-deep);
  border: 0.0625rem solid var(--line-soft);
  border-radius: 0.3rem;
  padding: 0.1rem 0.35rem;
}

pre {
  background: var(--bg-deep);
  border: 0.0625rem solid var(--line-soft);
  border-radius: var(--radius);
  padding: 1rem 1.15rem;
  overflow-x: auto;
  font-size: 0.85rem;
  line-height: 1.6;
}

pre code {
  background: none;
  border: 0;
  padding: 0;
  font-size: inherit;
}

table {
  width: 100%;
  border-collapse: collapse;
  margin: 0 0 1.5rem;
  font-size: 0.95rem;
}

th,
td {
  text-align: left;
  padding: 0.6rem 0.75rem;
  border-bottom: 0.0625rem solid var(--line-soft);
  vertical-align: top;
}

th {
  color: var(--text-bright);
  font-weight: 600;
}

blockquote {
  margin: 1.5rem 0;
  padding: 0.25rem 0 0.25rem 1.25rem;
  border-left: 0.1875rem solid var(--accent);
  color: var(--text-bright);
}

blockquote p:last-child {
  margin-bottom: 0;
}

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 1.5rem;
}

.skip {
  position: absolute;
  left: -100vw;
}

.skip:focus {
  left: 1rem;
  top: 1rem;
  z-index: 10;
  background: var(--accent);
  color: #fff;
  padding: 0.5rem 0.9rem;
  border-radius: 0.4rem;
}

/* --- header / footer ---------------------------------------------------- */

.site-head {
  position: sticky;
  top: 0;
  z-index: 5;
  background: rgba(30, 30, 30, 0.85);
  backdrop-filter: blur(0.75rem);
  border-bottom: 0.0625rem solid var(--line-soft);
}

.head-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  height: 3.75rem;
}

.brand,
.foot-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--text-bright);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.brand:hover {
  text-decoration: none;
}

.mark {
  width: 1.5rem;
  height: 1.5rem;
  color: var(--accent);
  flex: none;
}

.site-nav {
  display: flex;
  gap: 1.5rem;
  font-size: 0.9rem;
}

.site-nav a {
  color: var(--text-dim);
}

.site-nav a:hover {
  color: var(--text-bright);
  text-decoration: none;
}

.site-foot {
  border-top: 0.0625rem solid var(--line-soft);
  margin-top: 5rem;
  padding: 2.5rem 0 3rem;
  color: var(--text-dim);
  font-size: 0.875rem;
}

.foot-inner {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.foot-links {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
}

.foot-links a {
  color: var(--text-dim);
}

.fine {
  margin: 0;
  color: var(--text-dim);
  font-size: 0.85rem;
}

/* --- hero --------------------------------------------------------------- */

.hero {
  padding: clamp(3rem, 9vw, 6.5rem) 0 3rem;
  text-align: center;
  border-bottom: 0.0625rem solid var(--line-soft);
  background:
    radial-gradient(50rem 25rem at 50% -8rem, rgba(55, 148, 255, 0.16), transparent 70%);
}

.hero h1 {
  max-width: 20ch;
  margin-inline: auto;
}

.hero .lede {
  max-width: 46rem;
  margin: 0 auto 2rem;
  font-size: clamp(1.05rem, 2vw, 1.3rem);
  color: var(--text);
}

.kicker {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.75rem;
}

/* --- download page ------------------------------------------------------ */

.dl-hero {
  max-width: 40rem;
  margin: 0 auto;
  padding: clamp(2.5rem, 8vh, 5rem) 0 4rem;
  text-align: center;
}

/*
 * The animated mark. A fixed aspect ratio so the box is the right shape before
 * bridge-mark.js writes the SVG into it -- without it the heading below sits
 * 100px too high for the first frame and then jumps. The mark's viewBox is
 * 1600x428, so the ratio is fixed by the artwork rather than picked.
 */
.hero-mark {
  width: min(18rem, 70vw);
  aspect-ratio: 1600 / 428;
  margin: 0 auto 1.25rem;
  color: var(--text-bright);
}

.hero-mark svg {
  display: block;
  width: 100%;
  height: 100%;
}

.hero-wordmark {
  font-size: clamp(2rem, 6vw, 2.75rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1;
  margin: 0 0 0.75rem;
  color: var(--text-bright);
}

.hero-what {
  font-size: 1.05rem;
  color: var(--text);
  margin: 0 0 0.15rem;
}

.hero-tag {
  color: var(--text-dim);
  font-size: 0.95rem;
  margin: 0 0 2.25rem;
}

.fineprint {
  color: var(--text-dim);
  font-size: 0.8rem;
  margin-top: 1.5rem;
}

/*
 * Channel tabs, driven entirely by :checked. The radios are visually hidden
 * rather than display:none -- a display:none input is removed from the
 * accessibility tree and stops being focusable, which would make the picker
 * unreachable by keyboard.
 */
.ch-radio {
  position: absolute;
  width: 0.0625rem;
  height: 0.0625rem;
  opacity: 0;
  pointer-events: none;
}

/*
 * Deliberately quiet: a thin segmented control in two greys, no accent colour
 * and no fill. Almost everyone wants stable and should be able to skip straight
 * past this to the buttons; the picker only needs to be findable by the few
 * people looking for it, not to compete with the thing it sits above.
 */
.channels {
  display: inline-block;
  padding: 0.1875rem;
  border-radius: 0.4375rem;
  background: var(--bg-deep);
  border: 0.0625rem solid var(--line-soft);
}

.ch-tab {
  display: inline-block;
  padding: 0.25rem 0.85rem;
  border-radius: 0.3125rem;
  color: var(--text-dim);
  font-size: 0.78rem;
  cursor: pointer;
  user-select: none;
  background: transparent;
  transition: color 0.12s ease, background-color 0.12s ease;
}

.ch-tab:hover {
  color: var(--text);
}

/*
 * Each radio selects its own tab and its own panel. Written out per channel
 * rather than with :nth-child arithmetic, which across two different parents is
 * the kind of clever that breaks silently when a third channel is added.
 *
 * The selected tab is a slightly lighter grey block -- the same idea as a macOS
 * segmented control. That is the entire visual difference, and it is enough
 * because the two labels are adjacent and directly comparable.
 */
#ch-stable:checked ~ .channels .ch-tab:first-child,
#ch-canary:checked ~ .channels .ch-tab:last-child {
  background: var(--bg-raised);
  color: var(--text-bright);
}

/* Focus lands on the radio, which is visually hidden, so the ring has to be
   drawn on the label it controls. Keyboard users would otherwise be tabbing
   into something with no visible focus at all. */
#ch-stable:focus-visible ~ .channels .ch-tab:first-child,
#ch-canary:focus-visible ~ .channels .ch-tab:last-child {
  outline: 0.125rem solid var(--accent);
  outline-offset: 0.125rem;
}

.ch-panels {
  margin-top: 1.75rem;
}

.ch-panel {
  display: none;
}

#ch-stable:checked ~ .ch-panels .ch-panel[data-channel="stable"],
#ch-canary:checked ~ .ch-panels .ch-panel[data-channel="canary"] {
  display: block;
}

/* The radios are positioned, so the picker has to be their containing block --
   otherwise they are offset against the viewport and can scroll the page when
   focused. */
.picker {
  position: relative;
}

/* Only canary has one. Reserving a matching line under stable would put an
   empty gap on the page almost everyone sees, to avoid a shift almost nobody
   will. */
.ch-note {
  color: var(--text-dim);
  font-size: 0.78rem;
  margin: 0.25rem 0 0;
}

/* --- releases page ------------------------------------------------------- */

.rel-page {
  max-width: 44rem;
  margin: 0 auto;
  padding: 3rem 0 4rem;
}

.rel-page h1 {
  font-size: 1.6rem;
  margin: 0 0 0.35rem;
}

.rel-page .lede {
  color: var(--text-dim);
  font-size: 0.9rem;
  margin: 0 0 2rem;
}

.rel {
  border-top: 0.0625rem solid var(--line-soft);
  padding: 1.1rem 0;
}

.rel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}

.rel-head h2 {
  font-size: 1rem;
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.rel-head time {
  color: var(--text-dim);
  font-size: 0.8rem;
}

.rel-assets {
  list-style: none;
  margin: 0.6rem 0 0;
  padding: 0;
}

.rel-assets li {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  padding: 0.2rem 0;
  font-size: 0.85rem;
}

.rel-assets a {
  min-width: 5rem;
}

/* The filename is the least important thing on the row -- it is there so a
   checksum or a bug report can name the exact file -- so it takes the leftover
   space and truncates first. */
.rel-file {
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rel-size {
  color: var(--text-dim);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

.rel-empty {
  color: var(--text-dim);
  font-size: 0.9rem;
}

/* --- downloads ---------------------------------------------------------- */

.downloads {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: center;
  align-items: flex-start;
  margin: 0 0 1.25rem;
}

.dl {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
}

.dl small {
  color: var(--text-dim);
  font-size: 0.78rem;
}

.btn {
  display: inline-block;
  padding: 0.7rem 1.4rem;
  border-radius: 0.5rem;
  font-size: 0.95rem;
  font-weight: 600;
  border: 0.0625rem solid transparent;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.btn:hover {
  text-decoration: none;
}

.btn.primary {
  background: var(--accent-deep);
  color: #fff;
}

.btn.primary:hover {
  background: var(--accent);
}

/* download.js demotes the non-matching platform once it knows what you're on.
 * Both buttons are primary in the markup, so with JS off you simply get two
 * equally weighted choices rather than a broken-looking page. */
.btn.secondary {
  background: transparent;
  color: var(--text);
  border-color: var(--line);
}

.btn.secondary:hover {
  border-color: var(--text-dim);
  color: var(--text-bright);
}

.note {
  color: var(--text-dim);
  font-size: 0.85rem;
  text-align: center;
}

/* --- sections and cards ------------------------------------------------- */

section {
  padding: clamp(2.5rem, 6vw, 4.5rem) 0;
}

section > .wrap > h2 {
  max-width: 24ch;
}

.section-lede {
  max-width: 42rem;
  color: var(--text-dim);
  font-size: 1.05rem;
  margin-bottom: 2.5rem;
}

.grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}

.card {
  display: block;
  background: var(--bg-raised);
  border: 0.0625rem solid var(--line-soft);
  border-radius: var(--radius);
  padding: 1.5rem;
}

.card h3 {
  margin-bottom: 0.4rem;
}

.card p {
  margin: 0;
  color: var(--text-dim);
  font-size: 0.95rem;
}

.card p + p {
  margin-top: 0.75rem;
}

a.card {
  transition: border-color 0.15s ease, background-color 0.15s ease;
}

a.card:hover {
  border-color: var(--accent);
  text-decoration: none;
}

.teaser .kicker {
  margin-bottom: 0.5rem;
}

.teaser .more {
  display: inline-block;
  margin-top: 1rem;
  color: var(--accent);
  font-size: 0.9rem;
  font-weight: 600;
}

.alt {
  background: var(--bg-deep);
  border-top: 0.0625rem solid var(--line-soft);
  border-bottom: 0.0625rem solid var(--line-soft);
}

/* Numbered "how it works" steps. */
.steps {
  counter-reset: step;
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.steps li {
  counter-increment: step;
  background: var(--bg-raised);
  border: 0.0625rem solid var(--line-soft);
  border-radius: var(--radius);
  padding: 1.5rem;
}

.steps li::before {
  content: counter(step);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  margin-bottom: 0.75rem;
  border-radius: 50%;
  background: rgba(55, 148, 255, 0.15);
  color: var(--accent);
  font-size: 0.85rem;
  font-weight: 700;
}

.steps strong {
  display: block;
  color: var(--text-bright);
  margin-bottom: 0.25rem;
}

.steps p {
  margin: 0;
  color: var(--text-dim);
  font-size: 0.95rem;
}

/* --- blog --------------------------------------------------------------- */

.page-head {
  padding: clamp(2.5rem, 6vw, 4rem) 0 1rem;
}

.page-head .lede {
  font-size: 1.15rem;
  color: var(--text-dim);
  max-width: 48rem;
}

.meta {
  color: var(--text-dim);
  font-size: 0.85rem;
}

.post-list {
  list-style: none;
  padding: 0;
  margin: 1rem 0 0;
}

.post-list li {
  border-top: 0.0625rem solid var(--line-soft);
}

.post-list a {
  display: block;
  padding: 1.75rem 0;
  color: inherit;
}

.post-list a:hover {
  text-decoration: none;
}

.post-list a:hover h2 {
  color: var(--accent);
}

.post-list h2 {
  font-size: 1.4rem;
  margin-bottom: 0.35rem;
}

.post-list p {
  color: var(--text-dim);
  margin-bottom: 0.5rem;
}

/* --- long-form article -------------------------------------------------- */

.prose {
  max-width: 44rem;
  font-size: 1.05rem;
}

.prose h2 {
  margin-top: 2.5rem;
  font-size: 1.6rem;
}

.prose h3 {
  margin-top: 2rem;
}

.prose ul,
.prose ol {
  padding-left: 1.25rem;
  margin: 0 0 1.25rem;
}

.prose li {
  margin-bottom: 0.5rem;
}

.prose .page-head {
  padding-bottom: 0;
}

.post-cta {
  background: var(--bg-raised);
  border: 0.0625rem solid var(--line-soft);
  border-radius: var(--radius);
  padding: 2rem 1.5rem;
  text-align: center;
}

.post-cta h2 {
  margin-top: 0;
  font-size: 1.3rem;
}

.post-cta > p {
  color: var(--text-dim);
  max-width: 34rem;
  margin-inline: auto;
}

/* Source-citation footer on posts: "check this claim yourself". */
.source {
  font-size: 0.9rem;
  color: var(--text-dim);
  background: var(--bg-deep);
  border-left: 0.1875rem solid var(--line);
  border-radius: 0 0.4rem 0.4rem 0;
  padding: 1rem 1.25rem;
}

.source p {
  margin: 0;
}

.source code {
  color: var(--text);
}

/* --- diagram ------------------------------------------------------------ */

.diagram {
  display: block;
  width: 100%;
  height: auto;
  max-width: 46rem;
  margin: 0 auto;
}

.diagram .box {
  fill: var(--bg-raised);
  stroke: var(--line);
}

.diagram .box-accent {
  fill: rgba(55, 148, 255, 0.12);
  stroke: var(--accent);
}

.diagram text {
  fill: var(--text);
  font-family: var(--font-sans);
  font-size: 0.75rem;
}

.diagram .label {
  fill: var(--text-bright);
  font-weight: 600;
  font-size: 0.85rem;
}

.diagram .wire {
  stroke: var(--line);
  stroke-width: 0.125rem;
  fill: none;
}

@media (max-width: 40rem) {
  .site-nav {
    gap: 1rem;
    font-size: 0.85rem;
  }

  .downloads {
    flex-direction: column;
    align-items: stretch;
  }

  .dl {
    align-items: stretch;
  }

  .btn {
    text-align: center;
  }
}
