/* SoftBo website. Hand-written, no framework, no build step.
   Form is normative from the design canvas (Current page); copy is not.
   WEBSITE F1. */

@import url("tokens.css");

/* ── Fonts ───────────────────────────────────────────────────────────────
   Self-hosted. A Google Fonts <link> would be a third-party request on every
   page load, and the privacy page promises there are none. Until the WOFF2
   files are dropped in (see fonts/README.md) the fallback stacks render, which
   is correct but not the design. */
@font-face { font-family:'EB Garamond'; font-style:normal; font-weight:400;
  src:url("fonts/eb-garamond-400.woff2") format("woff2"); font-display:swap; }
@font-face { font-family:'EB Garamond'; font-style:normal; font-weight:500;
  src:url("fonts/eb-garamond-500.woff2") format("woff2"); font-display:swap; }
@font-face { font-family:'EB Garamond'; font-style:normal; font-weight:700;
  src:url("fonts/eb-garamond-700.woff2") format("woff2"); font-display:swap; }
@font-face { font-family:'Geist'; font-style:normal; font-weight:400;
  src:url("fonts/geist-400.woff2") format("woff2"); font-display:swap; }
@font-face { font-family:'Geist'; font-style:normal; font-weight:500;
  src:url("fonts/geist-500.woff2") format("woff2"); font-display:swap; }
@font-face { font-family:'Geist'; font-style:normal; font-weight:600;
  src:url("fonts/geist-600.woff2") format("woff2"); font-display:swap; }

/* ── Reset ───────────────────────────────────────────────────────────────
   box-sizing is here from the first line and not by habit: the canvas build
   found five mobile pages scrolling sideways, and every one was a full-width
   button whose horizontal padding was added to its 100% width. */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--t-body);
  line-height: 1.68;
  -webkit-font-smoothing: antialiased;
}

img, svg, video { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
p a, li a, .prose a { text-decoration: underline; text-underline-offset: 2px; }
h1, h2, h3, h4, p, ul, ol, figure { margin: 0; }
h1, h2, h3, h4 { font-weight: inherit; }
p { text-wrap: pretty; }
ul, ol { padding: 0; list-style: none; }
code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.92em; }
details summary::-webkit-details-marker { display: none; }

:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; border-radius: 3px; }
/* An ink ring on an ink surface is not a focus indicator. The header is the first
   thing a keyboard user reaches and it is the darkest thing on the site, so the
   ring inverts on every ink-backed surface. */
.nav :focus-visible, .band-ink :focus-visible { outline-color: var(--page); }

/* ── Layout ──────────────────────────────────────────────────────────── */
.wrap { width: var(--wrap); max-width: 100%; margin: 0 auto;
        padding-left: var(--gutter); padding-right: var(--gutter); }
.stack { display: flex; flex-direction: column; }
.section { padding-block: var(--section); }
.section-b { padding-bottom: var(--section); }

/* Grids collapse to one column below the mobile breakpoint. .grid-2-keep is
   the exception — platform cards carry four words each, so two-up wastes no
   space and halves the scroll. */
.grid { display: grid; gap: 20px; }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid-2-keep { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.skip { position: absolute; left: -9999px; top: 0; z-index: 20;
        background: var(--ink); color: var(--page); padding: 10px 16px;
        border-radius: 0 0 var(--r-btn) 0; }
.skip:focus { left: 0; }

/* ── Type ────────────────────────────────────────────────────────────── */
.h1  { font-family: var(--serif); font-size: var(--t-h1); line-height: var(--t-h1-lh);
       font-weight: 500; letter-spacing: -0.015em; text-wrap: balance; }
.h2  { font-family: var(--serif); font-size: var(--t-h2); line-height: var(--t-h2-lh);
       font-weight: 500; letter-spacing: -0.012em; text-wrap: balance; }
.h3  { font-size: var(--t-h3); line-height: 1.35; font-weight: 600; letter-spacing: -0.005em; }
.stat { font-family: var(--serif); font-size: var(--t-stat); line-height: 1.15;
        font-weight: 500; letter-spacing: -0.01em; }
.lede { font-size: var(--t-lede); line-height: 1.6; color: var(--muted); max-width: var(--measure-lede); }
.p    { font-size: var(--t-body); line-height: 1.68; color: var(--muted); }
.small{ font-size: var(--t-small); line-height: 1.5; color: var(--soft); }
.eyebrow { font-size: var(--t-eyebrow); font-weight: 500; color: var(--soft); }
.step-n  { font-family: var(--serif); font-size: 15px; color: var(--soft); letter-spacing: 0.06em; }
.measure { max-width: var(--measure-body); }
.on-ink  { color: var(--page); }
.on-ink-muted { color: var(--on-dark); }
.ink { color: var(--ink); }

/* ── Buttons ─────────────────────────────────────────────────────────────
   One primary style, and it is the only place the accent becomes a fill on a
   light page. Every button gets its four states; a disabled control says so
   rather than just looking tired. */
.btn, .btn-ghost, .btn-light, .btn-outline, .btn-nav {
  display: inline-flex; align-items: center; justify-content: center;
  height: var(--btn-h); padding-inline: 24px; border-radius: var(--r-btn);
  font-size: var(--t-body); font-weight: 500; white-space: nowrap;
  border: 1px solid transparent; cursor: pointer; font-family: inherit;
  transition: background-color .15s ease, border-color .15s ease, transform .06s ease;
}
.btn         { background: var(--ink); color: var(--page); box-shadow: var(--lift-btn); }
.btn:hover   { background: var(--ink-hover); }
.btn:active  { transform: translateY(1px); }

.btn-ghost        { background: var(--surface); color: var(--ink); border-color: var(--border);
                    padding-inline: 22px; box-shadow: 0 1px 2px rgba(10,26,36,.04); }
.btn-ghost:hover  { border-color: #CFCCC2; }
.btn-ghost:active { transform: translateY(1px); }

.btn-light        { background: var(--page); color: var(--ink); }
.btn-light:hover  { background: #FFFFFF; }

.btn-outline        { color: var(--page); border-color: rgba(252,251,248,.32); padding-inline: 22px; }
.btn-outline:hover  { border-color: rgba(252,251,248,.65); }

.btn-nav        { height: 40px; padding-inline: 20px; background: var(--page); color: var(--ink); }
.btn-nav:hover  { background: #FFFFFF; }

.btn[aria-disabled="true"], .btn-ghost[aria-disabled="true"] {
  opacity: .5; cursor: not-allowed; box-shadow: none; pointer-events: none;
}
.btn-full { width: 100%; }

.link { font-size: var(--t-body); font-weight: 500; color: var(--ink); }
.link:hover { color: var(--muted); }

/* ── Surfaces ────────────────────────────────────────────────────────────
   Two elevation levels only. Cards, and the product window a little higher
   because it is the subject of the page. */
.card { background: var(--surface); border: 1px solid var(--border);
        border-radius: var(--r-card); box-shadow: var(--lift-1); --mk-bg: var(--surface); }
.flat { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-card); }
.raised { box-shadow: var(--lift-2); }
.band-wash { background: var(--wash); }
.band-ink  { background: var(--ink); color: var(--page); --mk-bg: var(--ink); }
.panel { background: var(--wash); border-radius: var(--r-band); }
.pad   { padding: 28px; }
.pad-lg{ padding: 40px 44px; }
@media (max-width: 900px) { .pad-lg { padding: 22px; } .pad { padding: 22px; } }

.rule { height: 1px; background: var(--border); }
.chip { width: 36px; height: 36px; border-radius: var(--r-chip); background: var(--tint);
        display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.tag  { display: inline-flex; align-items: center; height: 24px; padding-inline: 10px;
        border-radius: 6px; background: var(--tint); color: var(--ink);
        font-size: 12px; font-weight: 500; }
.tag-off { background: var(--wash); color: var(--soft); }

/* ── Forms ───────────────────────────────────────────────────────────────
   The portal (F11) reuses these, so the account pages are not a second
   design system. */
.field { width: 100%; height: 46px; padding-inline: 14px; background: var(--surface);
         border: 1px solid var(--border); border-radius: var(--r-btn);
         font-family: inherit; font-size: var(--t-body); color: var(--ink); }
.field::placeholder { color: var(--soft); }
.field:hover { border-color: #CFCCC2; }
.field:focus-visible { outline: 2px solid var(--ink); outline-offset: 1px; border-color: var(--ink); }
.field[aria-invalid="true"] { border-color: #A2402F; }
.field-label { font-size: var(--t-small); font-weight: 500; color: var(--ink); }
.field-error { font-size: var(--t-small); color: #A2402F; }

/* ── Count map ───────────────────────────────────────────────────────── */
.bay { aspect-ratio: 1; border-radius: 2px; background: var(--cell-none); display: block; }
.bay-part { background: var(--cell-part); }
.bay-done { background: var(--cell-done); }

/* ── Content slots ───────────────────────────────────────────────────────
   Visible placeholders. Every one names what belongs there and why it earns
   the room; a page phase is not finished while one is still in the markup. */
.slot { border: 1px dashed #C7CAC3; border-radius: var(--r-btn);
        padding: 11px 13px; background: rgba(10,26,36,.018);
        color: var(--soft); font-size: 12px; line-height: 1.5; }
.slot b { font-weight: 600; color: var(--muted); }

/* ── The wordmark ────────────────────────────────────────────────────────
   One outlined path — the glyphs unioned, the two original crossbars subtracted,
   the drawn f-t join unioned in. Built by tools/site/build-logo.py and committed,
   so there is no font dependency, no background-matching eraser, and nothing to
   go wrong if EB Garamond fails to load.

   Two colour variants because the mark sits on both grounds. Set width and height
   on the element so the space is reserved before the file arrives.
   Aspect ratio 4.0167 : 1. */
.mk { display: block; width: auto; height: 30px; }
.mk-lg { height: 56px; }
.mk-sm { height: 24px; }
/* Clear space: half the cap height on every side. Never crowd it. */
.mk-link { display: inline-flex; align-items: center; padding: 6px; margin: -6px; }

/* ── Navigation ──────────────────────────────────────────────────────────
   The accent bar. Downloads sits in the link row; Sign in is the button.

   The disclosure is a checkbox, not <details>. <details> is the semantically
   nicer element, but its content is hidden by the UA through ::details-content
   / content-visibility, which a child's `display` cannot override — the links
   were laid out and simply never painted on desktop. A checkbox has no UA
   behaviour to fight, works without JavaScript, and is operable from the
   keyboard. The cost is that a screen reader announces "checkbox" rather than
   "button"; that is a real trade and it is made knowingly. */
.nav { background: var(--ink); color: var(--page); --mk-bg: var(--ink); }
.nav-in { display: flex; align-items: center; justify-content: space-between;
          height: 78px; gap: 24px; position: relative; }
.nav-links { display: flex; align-items: center; gap: 32px; }
.nav-links a { color: rgba(252,251,248,.78); font-size: var(--t-body); }
.nav-links a:hover, .nav-links a[aria-current="page"] { color: var(--page); }
/* opacity:0 hid this from the accessibility tree as well as from the eye, and
   the five nav links are display:none until it is checked — so on a phone a
   screen reader had a header containing the wordmark, "Sign in", and no way to
   reach the navigation. Clipping hides it visually and keeps it announced. */
.nav-check { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
             border: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
             pointer-events: none; }
.nav-toggle { display: none; }

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

@media (max-width: 900px) {
  .nav-in { height: 64px; }
  .nav-toggle { display: flex; flex-direction: column; align-items: center; justify-content: center;
                gap: 4px; width: 40px; height: 40px; border-radius: var(--r-btn);
                border: 1px solid rgba(252,251,248,.25); cursor: pointer; }
  .nav-toggle span:not(.vh) { display: block; width: 16px; height: 1.5px; background: var(--page); }
  .nav-check:focus-visible + .nav-toggle { outline: 2px solid var(--page); outline-offset: 3px; }

  /* The two most-tapped controls on a phone measured 40px, and the wordmark 42.
     The bar is 64px tall with 24px gaps, so the hit area can reach 44 without
     moving anything: an overlay costs no layout height, and the pages with one
     pixel of scroll budget left cannot afford the honest version. */
  .nav-toggle, .btn-nav, .mk-link { position: relative; }
  .nav-toggle::after, .btn-nav::after, .mk-link::after {
    content: ""; position: absolute; top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    width: max(100%, 44px); height: 44px;
  }
  .nav-links { display: none; position: absolute; right: 0; top: calc(100% + 10px);
               flex-direction: column; align-items: stretch; gap: 0;
               background: var(--ink); border: 1px solid rgba(252,251,248,.18);
               border-radius: var(--r-card); padding: 6px; min-width: 220px; z-index: 15; }
  .nav-check:checked ~ .nav-links { display: flex; }
  .nav-links a { padding: 11px 12px; border-radius: 6px; }
}

/* ── Footer ──────────────────────────────────────────────────────────────
   The three-column footer cost 522px on mobile — a quarter of the 2.5-screen
   budget — so below 900px it collapses to a wrapped link row. */
.foot { border-top: 1px solid var(--border); --mk-bg: var(--page); }
.foot a { color: var(--muted); font-size: 14px; }
.foot a:hover { color: var(--ink); }
.foot-cols { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 56px; }
.foot-row { display: none; }
@media (max-width: 900px) {
  .foot-cols { display: none; }
  .foot-row { display: flex; flex-wrap: wrap; gap: 10px 18px; }
}


/* ── The hub window ──────────────────────────────────────────────────────
   The product, and the one element on the page at elevation two. On mobile the
   rail and the device list are cut and the map crops to eleven columns: a
   sixteen-column grid inside a 350px card is a smear, and one thing legible
   beats three as texture. */
.hub-bar { display: flex; align-items: center; justify-content: space-between;
           height: 46px; padding-inline: 18px; border-bottom: 1px solid var(--border); gap: 12px; }
.hub-dots { display: flex; gap: 8px; }
.hub-dots i { width: 9px; height: 9px; border-radius: 50%; background: var(--border); }
.hub-body { display: grid; grid-template-columns: 132px minmax(0, 1fr) 208px; }
.hub-rail { display: flex; flex-direction: column; gap: 2px; padding: 16px 14px;
            border-right: 1px solid var(--border); }
.hub-rail span { font-size: 13px; padding: 7px 10px; border-radius: 7px; color: var(--muted); }
.hub-rail .is-on { background: var(--tint); color: var(--ink); font-weight: 500; }
.hub-main { padding: 18px 22px; display: flex; flex-direction: column; gap: 14px; }
.hub-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.hub-side { padding: 16px 18px; border-left: 1px solid var(--border);
            display: flex; flex-direction: column; }
.hub-row { display: flex; justify-content: space-between; align-items: baseline; gap: 10px;
           padding: 9px 0; border-bottom: 1px solid var(--border); font-size: 13px; font-weight: 500; }
.hub-row-last { border-bottom: 0; }
.hub-var { display: flex; justify-content: space-between; align-items: baseline;
           margin-top: auto; padding-top: 10px; border-top: 1px solid var(--border);
           font-size: 14px; font-weight: 600; }
.map { display: grid; grid-template-columns: repeat(16, minmax(0, 1fr)); gap: 4px; }
.legend { display: flex; flex-wrap: wrap; gap: 6px 16px; }
.legend li { display: flex; align-items: center; gap: 7px; font-size: var(--t-small); color: var(--soft); }
.legend .bay { width: 9px; height: 9px; aspect-ratio: auto; }

@media (max-width: 900px) {
  .hub-body { grid-template-columns: 1fr; }
  .hub-main { padding: 14px; }
  .map { grid-template-columns: repeat(11, minmax(0, 1fr)); }
  .col-hide { display: none; }
  /* four rows, not six: the map is already a crop at eleven columns, and two
     fewer rows is real budget. Three rows still reads as a filling map. */
  .map .bay:nth-child(n+49) { display: none; }
}

/* ── Home-page rhythm ────────────────────────────────────────────────────
   Vertical space is the scarcest thing on a phone and the 2.5-screen budget is
   spent in these six places. Desktop values first, mobile overrides below. */
.hero { gap: 26px; padding-block: 88px 52px; }
.board-wrap { gap: 10px; padding-bottom: 40px; }
.closing { gap: 16px; padding-block: var(--section); }
.foot-in { gap: 30px; padding-block: 52px 36px; }

/* ── Writes-back strip ───────────────────────────────────────────────── */
.logos { display: flex; align-items: baseline; flex-wrap: wrap; gap: 14px 32px;
         padding-bottom: var(--section); }
.logo-name { font-family: var(--serif); font-size: 25px; color: var(--ink); }
.logo-soon { color: var(--soft); }
@media (max-width: 900px) { .logo-name { font-size: 21px; } .logos { gap: 12px 20px; } }

/* ── Sections the home page introduces ───────────────────────────────── */
.step { gap: 10px; border-top: 1px solid var(--ink); padding-top: 16px; }
.offline { padding: 56px 60px; display: grid; grid-template-columns: 1fr 1fr;
           gap: 40px; align-items: center; }
.pull { margin: 0; font-family: var(--serif); font-size: 27px; line-height: 1.5;
        color: var(--ink); border-left: 2px solid var(--border); padding-left: 20px; }
.price-teaser { display: flex; align-items: center; justify-content: space-between; gap: 28px; }
.price-inline { display: flex; align-items: baseline; gap: 10px; }
.price-inline span:first-child { font-family: var(--serif); font-size: 26px; color: var(--page); }
.foot-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 60px; }

@media (max-width: 900px) {
  .hero { gap: 15px; padding-block: 30px 24px; }
  .board-wrap { gap: 8px; padding-bottom: 26px; }
  .logos { gap: 8px 18px; padding-bottom: 30px; }
  .closing { gap: 12px; padding-block: 32px; }
  .foot-in { gap: 16px; padding-block: 28px 24px; }
  /* The qualification cards become compact rows: a card's border, padding and
     shadow cost roughly 90px each here, and three of them is a tenth of the
     whole budget spent on chrome. */
  .qualify { gap: 12px; }
  .qualify-sec, .offline-sec { padding-bottom: 32px !important; }
  .qualify .card { background: none; border: 0; border-top: 1px solid var(--border);
                   border-radius: 0; box-shadow: none; padding: 13px 0 0 0; gap: 5px; }
  .qualify .stat { font-size: 21px; }
  .offline { padding: 20px; grid-template-columns: 1fr; gap: 8px; }
  .offline .h2 { font-size: 17px; font-weight: 600; font-family: var(--sans); letter-spacing: 0; }
  .pull { font-size: 20px; padding-left: 16px; }
  .price-teaser { flex-direction: column; align-items: stretch; }
  .foot-top { flex-direction: column; gap: 20px; }
  .qualify .card { box-shadow: none; }
}


/* ── Product: five parts ─────────────────────────────────────────────────
   Text and media alternate sides on desktop so the eye has somewhere to go.
   On a phone they stack, the media becomes one hero capture at the top, and
   each part becomes a row on a rule — five screenshots would be four screens
   of scroll and none of them would be read. */
.parts { gap: 40px; padding-bottom: var(--section); }
.part { display: grid; grid-template-columns: 1fr 1.15fr; gap: 48px; align-items: center;
        border-top: 1px solid var(--border); padding-top: 40px; }
/* The DOM is always text then media, so the reading order is right for a screen
   reader and for a phone. Only the visual order alternates. */
.part-flip > *:first-child { order: 2; }
.part-flip > *:last-child { order: 1; }
/* the media slot stands in for a real capture, so it holds a capture's space —
   otherwise the alternation is invisible and the page reads as five paragraphs */
.part .slot { min-height: 250px; display: flex; align-items: center; justify-content: center;
              text-align: center; }
.part-portrait .slot { min-height: 340px; }

/* ── Product: what it runs on ────────────────────────────────────────── */
.spec { display: flex; flex-direction: column; }
.spec-row { display: grid; grid-template-columns: 280px 1fr; gap: 32px;
            padding: 14px 0; border-top: 1px solid var(--border); }
.spec-row:last-child { border-bottom: 1px solid var(--border); }

/* ── Integrations ────────────────────────────────────────────────────────
   A system that is not usable yet gets the flat card, not the raised one: the
   elevation itself is a claim about readiness. */
.sys-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.sys-name { font-family: var(--serif); font-weight: 500; font-size: 23px; letter-spacing: -0.01em; }
.sys-facts { display: grid; grid-template-columns: auto 1fr; gap: 4px 14px; margin: 0;
             padding-top: 10px; border-top: 1px solid var(--border); }
.sys-facts dt { font-size: 12px; color: var(--soft); }
.sys-facts dd { margin: 0; font-size: 12px; color: var(--muted); }

@media (max-width: 900px) {
  .parts { gap: 0; padding-bottom: 30px; }
  .part { grid-template-columns: 1fr; gap: 12px; padding-top: 16px; }
  /* the per-part screenshot slots are replaced by the single hero capture */
  .part .slot { display: none; }
  .part .h2 { font-size: 19px; }
  /* the chips are decorative and the titles carry the section without them */
  .part .chip { display: none; }
  .spec-row { grid-template-columns: 1fr; gap: 1px; padding: 9px 0; }
  .spec-row .p { line-height: 1.5; }   /* 15px stands: this is the table a buyer reads before downloading */
  .systems { gap: 12px; padding-bottom: 30px !important; }
  .systems .card, .systems .flat { background: none; border: 0; border-radius: 0;
                                   border-top: 1px solid var(--border); box-shadow: none;
                                   padding: 13px 0 0 0; gap: 8px; }
  .sys-name { font-size: 20px; }
  /* Only the verification date survives on a phone. "Not yet" and "You supply"
     are what a buyer reads at a desk before committing; keeping all three cost
     roughly 130px per system, and six of them is half the scroll budget. */
  .sys-facts { grid-template-columns: auto 1fr; gap: 2px 10px; padding-top: 8px; }
  .sys-facts > :nth-child(-n+4) { display: none; }
}


/* ── The essay ───────────────────────────────────────────────────────────
   The one page where a long read is the point, so it gets a longer line-height
   than anything else on the site and one column at both widths. Nothing here
   competes with the prose: no cards, no pull quotes, no sidebar. */
.essay { display: flex; flex-direction: column; gap: 24px;
         max-width: var(--measure-essay); padding-bottom: var(--section); }
.essay-lead { font-family: var(--serif); font-size: 27px; line-height: 1.45;
              color: var(--ink); text-wrap: pretty; max-width: 660px; }
.essay-p { font-size: 17px; line-height: 1.78; color: var(--ink); text-wrap: pretty; }

.sign { display: flex; align-items: center; gap: 20px; margin-top: 12px;
        padding-top: 24px; border-top: 1px solid var(--border); }
.sign-photo { width: 96px; height: 96px; flex-shrink: 0; display: flex;
              align-items: center; justify-content: center; text-align: center;
              border-radius: 50%; padding: 8px; overflow: hidden; }
.sign-name { font-family: var(--serif); font-size: 20px; color: var(--ink); }
.essay-cta { display: flex; gap: 12px; padding-top: 8px; }

@media (max-width: 900px) {
  .essay { gap: 18px; max-width: 100%; padding-bottom: 32px; }
  .essay-lead { max-width: 100%; }
  .essay-lead { font-size: 21px; line-height: 1.42; }
  .essay-p { font-size: 16px; line-height: 1.7; }
  .sign { gap: 14px; margin-top: 6px; padding-top: 18px; }
  .sign-photo { width: 76px; height: 76px; }
}


/* ── Downloads and releases ──────────────────────────────────────────────
   The hub and the counting app are different things and people conflate them,
   so they are two labelled groups rather than one row of four. Platform cards
   stay two-up on a phone: four words each, so one-up would double the scroll
   and buy nothing. */
.dl-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; }
.dl-card { gap: 12px; }
.dl-name { font-family: var(--serif); font-weight: 500; font-size: 23px; letter-spacing: -0.01em; }
.dl-meta { display: grid; grid-template-columns: auto 1fr; gap: 3px 12px; margin: 0;
           padding-top: 10px; border-top: 1px solid var(--border); }
.dl-meta dt { font-size: 12px; color: var(--soft); }
.dl-meta dd { margin: 0; font-size: 12px; color: var(--muted); }
.dl-sum { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
          font-size: 11px; word-break: break-all; }

.rel { display: grid; grid-template-columns: 150px 1fr; gap: 32px;
       padding: 18px 0; border-top: 1px solid var(--border); }
.rel:last-of-type { border-bottom: 1px solid var(--border); }
.rel-date { padding-top: 2px; }
.rel-title { font-size: 15px; font-weight: 500; color: var(--ink); }

@media (max-width: 900px) {
  .dl-head { flex-direction: column; align-items: flex-start; gap: 4px; }
  .dl-card { gap: 10px; padding: 16px; }
  .dl-name { font-size: 19px; }
  /* the checksum is unreadable and unverifiable on a phone; it lives on the
     release notes page, where somebody at a desk will actually use it */
  .dl-meta { grid-template-columns: 1fr; gap: 1px; padding-top: 8px; }
  .dl-meta dt { font-weight: 600; }
  .dl-meta > :nth-child(n+5) { display: none; }
  .rel { grid-template-columns: 1fr; gap: 6px; padding: 14px 0; }
  .rel-date { padding-top: 0; }
}


/* ── Docs ────────────────────────────────────────────────────────────────
   An article is a rail and a column of numbered steps. The rail is desktop
   only: three articles of four or five steps do not need a table of contents
   on a phone, and it would cost a third of a screen before the first word. */
.doc-hero .eyebrow a { text-decoration: underline; text-underline-offset: 2px; }
.doc-body { display: grid; grid-template-columns: 200px minmax(0, 1fr); gap: 56px;
            padding-bottom: var(--section); align-items: start; }
.doc-rail { display: flex; flex-direction: column; gap: 8px; position: sticky; top: 32px; }
.doc-rail a { font-size: 14px; color: var(--muted); }
.doc-rail a:hover { color: var(--ink); }
.doc-main { max-width: var(--measure-essay); }

.steps { display: flex; flex-direction: column; }
.step-item { display: grid; grid-template-columns: 52px minmax(0, 1fr); gap: 20px;
             padding: 22px 0; border-top: 1px solid var(--border); }
.steps > .step-item:last-child { border-bottom: 1px solid var(--border); }
.step-item .step-n { font-family: var(--serif); font-size: 15px; color: var(--soft);
                     letter-spacing: 0.06em; padding-top: 3px; }
.step-title { font-size: 19px; }
.step-body { font-size: 16px; line-height: 1.72; color: var(--ink); }
.step-body a { text-decoration: underline; text-underline-offset: 2px; }

.doc-next { display: flex; flex-direction: column; gap: 4px;
            margin: 26px 0 18px 0; padding: 18px 20px; background: var(--wash);
            border-radius: var(--r-card); }

.doc-card { text-decoration: none; }
.doc-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.doc-card-title { font-family: var(--serif); font-weight: 500; font-size: 22px; letter-spacing: -0.01em; }
.doc-card-time { white-space: nowrap; }

@media (max-width: 900px) {
  .doc-body { grid-template-columns: 1fr; gap: 0; padding-bottom: 30px; }
  .doc-main { max-width: 100%; }
  .step-item { grid-template-columns: 34px minmax(0, 1fr); gap: 12px; padding: 16px 0; }
  .step-title { font-size: 17px; }
  .step-body { font-size: 15px; line-height: 1.68; }
  .doc-next { margin: 18px 0 14px 0; padding: 14px 16px; }
  .doc-card-title { font-size: 19px; }
}


/* ── Legal pages ─────────────────────────────────────────────────────────
   Reference material, not a marketing page: somebody arrives with a question
   and needs their section. So it gets a jump list rather than a scroll budget,
   and the section heading sits beside the text on desktop where it works as a
   scannable margin. The 2.5-screen cap is deliberately not applied here —
   a privacy policy cannot be shortened without removing information, which is
   the opposite of the point. */
.legal { display: flex; flex-direction: column; padding-bottom: var(--section); }
.legal-row { display: grid; grid-template-columns: 250px minmax(0, 1fr); gap: 40px;
             padding: 24px 0; border-top: 1px solid var(--border); scroll-margin-top: 24px; }
.legal-row:last-child { border-bottom: 1px solid var(--border); }
.legal-h { font-size: 17px; }
.legal-t { display: flex; flex-direction: column; gap: 14px; max-width: var(--measure-legal); }
.legal-p { font-size: 16px; line-height: 1.72; color: var(--ink); }
.legal-p a { text-decoration: underline; text-underline-offset: 2px; }

.legal-jump { display: flex; flex-direction: column; gap: 10px; padding-bottom: 30px; }
.legal-jump-links { display: flex; flex-wrap: wrap; gap: 8px 18px; }
.legal-jump-links a { font-size: 14px; color: var(--muted);
                      text-decoration: underline; text-underline-offset: 2px; }
.legal-jump-links a:hover { color: var(--ink); }

/* A draft awaiting legal review says so where it cannot be missed. */
.slot-loud { border-style: solid; border-color: var(--ink); background: var(--tint);
             color: var(--ink); font-size: 13px; padding: 14px 16px; }
.slot-loud b { color: var(--ink); }

@media (max-width: 900px) {
  .legal-row { grid-template-columns: 1fr; gap: 8px; padding: 18px 0; }
  .legal-t { gap: 12px; }
  .legal-p { font-size: 15px; line-height: 1.68; }
  .legal-jump { padding-bottom: 22px; }
}

/* ── Responsive ───────────────────────────────────────────────────────── */
@media (max-width: 900px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
  .grid { gap: 14px; }
  .cta-row { flex-direction: column; align-items: stretch; }
  .cta-row .btn, .cta-row .btn-ghost, .cta-row .btn-light, .cta-row .btn-outline { width: 100%; }
  .hide-mobile { display: none !important; }
}
@media (min-width: 901px) { .only-mobile { display: none !important; } }

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