/*
 * The marketing surface. One copy of the paint, for every page outside the app.
 *
 * WHY IT IS A FILE AND NOT AN IMPORT
 *
 * `src/styles.css` is imported by main.tsx, which means it is JavaScript: it
 * does not exist for a crawler, for a no-JS visitor, or for any of the static
 * pages in `public/`. The landing carried its own inline copy of these tokens
 * for that reason, and `bot.html` and `docs.html` carried two more. Four copies
 * of one palette, none of which could follow the others.
 *
 * IT IS DARK, AND ONLY DARK. That is the decision that makes this feel authored
 * rather than generated. The previous sheet forked into a light theme at
 * `prefers-color-scheme`, and the light half was where it read as a
 * documentation template: black text, white ground, three cards in a row. The
 * product's own sign-in screen is a cinematic dark panel with a canvas behind
 * it, and a marketing site that does not look like the thing it sells is
 * arguing against itself on the way in. The APP keeps both themes — a dashboard
 * somebody stares at for an hour is a different problem from a page they read
 * once.
 *
 * Scoped under `.uf-landing`, which React removes from #root on mount, so
 * nothing here outlives the SPA on the one page that is both.
 */

/*
 * The ground, on the ELEMENTS ABOVE the page.
 *
 * `.uf-landing` is a `<main>` with `min-height: 100dvh`, which covers the first
 * screen and nothing after it — so on a page whose content runs past the fold,
 * the last stretch below the footer was the browser's default white. A dark site
 * that flashes white at the bottom of every scroll is not a dark site.
 *
 * `:has()` rather than a class on `<body>`, because the marketing landing and
 * the app share one document: the moment React replaces #root's children the
 * `.uf-landing` is gone, this selector stops matching, and the app's own theme
 * takes the background back. A class would have had to be removed by somebody.
 */
html:has(.uf-landing),
body:has(.uf-landing) {
  background: #08090b;
  margin: 0;
}

.uf-landing {
  /* Ground. Not black — a near-black with a trace of blue, so the gold reads
     warm against it and the panels have somewhere to sit. */
  --uf-ground: #08090b;
  --uf-ground-lift: #0c0d10;
  --uf-panel: #101115;
  --uf-panel-hi: #16171c;

  /* Hairlines. Instruments are drawn in lines, not boxes: everything here
     divides with a 1px rule at low alpha rather than a filled border, which is
     what keeps density from becoming clutter. */
  --uf-hair: rgba(255, 255, 255, 0.07);
  --uf-hair-hi: rgba(255, 255, 255, 0.14);

  /* THE QUIET END OF THE RAMP IS STILL READABLE TEXT.
     `--uf-mute` was #4c4f56 and `--uf-faint` #74777f, and every use of both is
     TEXT under 13px — the code sample's comment and response spans (the only
     place the page states the API's response shape), the beta form's field
     guidance and placeholders, the ladder's meta column, the footer's column
     titles. Measured in sRGB against the four grounds below, mute ran
     2.18-2.43:1 and faint 3.99-4.45:1; AA needs 4.5:1 and nothing here is large
     enough for the 3:1 allowance. Both are lifted to the quietest values that
     clear it on the lightest ground the sheet has, which keeps four distinct
     steps (16.1 / 7.7 / 5.5 / 4.6) rather than collapsing two of them.
     `marketing-css.test.ts` measures this now, so the next quiet grey cannot
     land unmeasured. */
  --uf-ink: #f2f3f5;
  --uf-dim: #a7aab2;
  --uf-faint: #8a8e97;
  --uf-mute: #7d818a;

  /* The parked brand gold, one step brighter than the app's — on a darker
     ground the app's #c99a4b loses its warmth. Used sparingly and always to
     mean the same thing: this is the live one. */
  --uf-gold: #d9a85c;
  --uf-good: #4fc79a;
  --uf-bad: #e57a70;

  /* The agent tints, shared with fence.js so a chip beside the canvas is the
     same colour as the light going past it. */
  /*
   * Tier 1 is GREEN, and it is the dashboard's green: src/styles.css sets
   * --t1: #3fb88a for the same tier, with the comment that "it opened to a
   * plain fetch" and "it worked" are the same fact. Somebody who signs up
   * should not have to learn the colour twice.
   *
   * It was amber, which was the actual bug: amber is a hair off --uf-gold, so
   * the CHEAPEST tier looked like the destination it was travelling to. Gold
   * now means arrived and nothing else -- the markdown terminal on the tier
   * diagram, the primary button, the weather under the closer.
   */
  --uf-t1: #3fb88a;
  --uf-t2: #5b7fbf;
  --uf-t3: #8b7fd6;
  /*
   * The fourth numeral is the GOLD, not a fourth chart hue.
   *
   * It was #3fb88a, which stopped working the moment tier 1 became that exact
   * green: the row ran green, blue, violet, green, and the repeat read as a
   * mistake rather than a palette. Gold is the only colour left that means
   * something here, and it happens to land on the right card -- the fourth is
   * the signed receipt, which is the payoff the other three protect.
   */
  --uf-t4: var(--uf-gold);

  /*
   * The gutter scales; it does not fall off a cliff.
   *
   * At `100% - 48px` the shell was 1180px wide with 130px of air either side at
   * 1440, and then, the moment the viewport dropped under about 1230, the whole
   * page jammed against 24px of padding. Nothing was broken and it read as
   * broken - reported from a laptop at roughly 1245, where the text starts a
   * finger's width from the edge of the screen.
   *
   * `clamp` keeps the phone gutter where it was (8vw is under the floor on a
   * phone, so 48px total, 24 a side) and gives the middle widths room, while
   * anything wide enough to reach the 1180px cap is unchanged.
   */
  --uf-shell: min(1180px, 100% - clamp(48px, 8vw, 120px));
  --uf-column: min(720px, 100% - 48px);

  box-sizing: border-box;
  position: relative;
  min-height: 100dvh;
  margin: 0;
  background: var(--uf-ground);
  color: var(--uf-ink);
  font-family: "Inter", -apple-system, system-ui, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  font-feature-settings: "cv05" 1, "ss03" 1;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}

/*
 * Grain.
 *
 * A single fractal-noise SVG at 3% over the whole page. It is the cheapest
 * thing on this list and does the most: a flat near-black gradient bands
 * visibly on an 8-bit panel, and the noise dithers it away, which is why film
 * grain exists at all. `pointer-events: none` because it covers everything.
 */
.uf-landing::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

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

/*
 * THE LINK RESET, AND THE TRAP IN IT.
 *
 * `.uf-landing a` is specificity (0,1,1) — one class and one element — which
 * beats a bare component class like `.uf-btn-primary` at (0,1,0). So any rule
 * that sets a link's colour with a single class LOSES to this one, silently,
 * and the link inherits its parent's colour instead.
 *
 * That is not hypothetical: it shipped. The landing page's only primary call to
 * action was `<a class="uf-btn uf-btn-primary">`, whose rule set
 * `color: var(--uf-ground)` against a `var(--uf-ink)` background — and this
 * reset overrode it, so the button rendered as a solid black rectangle with
 * black text inside it. Unreadable, on the one control the whole page exists to
 * get clicked, for as long as the page had existed. Nothing failed; it just
 * quietly did not work.
 *
 * Every rule below that colours a LINK is therefore written `.uf-landing .thing`
 * (0,2,0) so it outranks this, and `marketing-css.test.ts` fails the build on
 * one that is not.
 */
.uf-landing a { color: inherit; text-decoration: none; }

/*
 * `hidden` must actually hide.
 *
 * The attribute works by a UA rule of `display: none`, and ANY author `display`
 * beats it — so `.uf-form { display: grid }` quietly cancelled it. That shipped
 * too, for as long as it took to submit the form once: the beta page sets
 * `form.hidden = true` on success, and the success card appeared while the
 * filled-in form sat underneath it, which reads as "that did not work, try
 * again" on the one screen where a second submission is the last thing we want.
 */
.uf-landing [hidden] { display: none !important; }

.uf-landing ::selection { background: rgba(217, 168, 92, 0.28); color: #fff; }

/* Every interactive thing gets the same visible focus ring. Keyboard users are
   not a fallback path on a page whose audience is developers. */
.uf-landing :focus-visible {
  outline: 2px solid var(--uf-gold);
  outline-offset: 3px;
  border-radius: 4px;
}

.uf-wrap { width: var(--uf-shell); margin-inline: auto; }
.uf-wrap-narrow { width: var(--uf-column); margin-inline: auto; }

/*
 * Room for the consent banner.
 *
 * `.consent-banner` is fixed to the bottom of the viewport and is rendered by
 * the app into its own root (see main.tsx's `mountConsentOnly`), so it knows
 * nothing about this page and this page cannot lay it out. On a phone it landed
 * squarely over the hero's primary call to action — the first thing a visitor
 * sees is the button they came to press, with a cookie bar on top of it.
 *
 * `:has()` lets the page react to a sibling it does not own: while the banner
 * exists, the whole surface reserves space for it, and the moment somebody
 * answers it the padding goes with it. Browsers without `:has()` simply keep
 * the old behaviour, which is why the padding is added here rather than
 * subtracted somewhere else.
 */
body:has(.consent-banner) .uf-landing { padding-bottom: 132px; }
@media (min-width: 720px) {
  body:has(.consent-banner) .uf-landing { padding-bottom: 96px; }
}

/* Skip link — the first tab stop on every page, visible only when focused. */
.uf-landing .uf-skip {
  position: absolute; left: -9999px; top: 12px; z-index: 40;
  padding: 10px 16px; border-radius: 8px;
  background: var(--uf-panel); border: 1px solid var(--uf-hair-hi); color: var(--uf-ink);
}
.uf-landing .uf-skip:focus { left: 24px; }

/* ---- Motion ------------------------------------------------------------
 *
 * One orchestrated page load, staggered — which lands better than a dozen
 * scattered micro-interactions — plus scroll-linked reveals further down.
 *
 * The scroll reveals are inside `@supports (animation-timeline: view())`, and
 * that guard is load-bearing: without it, `opacity: 0` waiting for an animation
 * that never runs is a blank page. Unsupported browsers simply see the content.
 */
@keyframes uf-in {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: none; }
}
@keyframes uf-fade { from { opacity: 0; } to { opacity: 1; } }

@media (prefers-reduced-motion: no-preference) {
  .uf-stagger > * { animation: uf-in 0.85s cubic-bezier(0.16, 1, 0.3, 1) both; }
  .uf-stagger > :nth-child(1) { animation-delay: 0.05s; }
  .uf-stagger > :nth-child(2) { animation-delay: 0.14s; }
  .uf-stagger > :nth-child(3) { animation-delay: 0.23s; }
  .uf-stagger > :nth-child(4) { animation-delay: 0.32s; }
  .uf-stagger > :nth-child(5) { animation-delay: 0.41s; }

  @supports (animation-timeline: view()) {
    .uf-reveal {
      animation: uf-in linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 46%;
    }
  }
}

/* ---- Header ------------------------------------------------------------- */

/*
 * The header: full width, sticky, and transparent until you scroll.
 *
 * WHY FULL WIDTH. It used to sit inside the 1180px shell, so on a wide display
 * the wordmark started 370px from the left edge and the bar read as a floating
 * strip rather than as the top of the page. The BAR now spans the viewport and
 * its CONTENTS keep the shell's gutter, which is the arrangement every
 * convention here already uses.
 *
 * WHY IT STICKS. The only thing this page wants is a click on "Request beta
 * access", and a nav that scrolls away takes the second-best route to it —
 * "Sign in" — with it. Sticky is also why the height is a fixed custom property
 * rather than whatever the content happens to measure: `.uf-hero-wrap` pulls
 * itself up by exactly that much (see below) so the canvas still reaches y=0
 * behind the bar, and two rules sharing one number is the only version of that
 * which cannot drift.
 */
.uf-landing { --uf-head: 78px; }

.uf-top {
  position: sticky; top: 0; z-index: 30;
  height: var(--uf-head);
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 max(24px, calc((100% - var(--uf-shell)) / 2));
  border-bottom: 1px solid transparent;
  transition: background 200ms ease, border-color 200ms ease;
}

/*
 * The blur, and the one place on this site where it is the right tool.
 *
 * It was wrong behind the hero — the fence is 1.5px lines and 2px dots, and no
 * radius softens a dot without erasing a line. Here it is a 78px strip over
 * ordinary page content, which is exactly what `backdrop-filter` is for: the
 * bar reads as glass over the page rather than as a panel bolted on top of it.
 *
 * Only once scrolled. At the top the header has nothing to separate itself
 * from — it is over the hero canvas, which it is part of — so a border and a
 * fill there would be drawing a line for no reason.
 */
.uf-top[data-stuck="true"] {
  background: rgba(8, 9, 11, 0.72);
  border-bottom-color: var(--uf-hair);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  backdrop-filter: blur(14px) saturate(140%);
}
@media (prefers-reduced-motion: reduce) {
  .uf-top { transition: none; }
}
/* Rounded UF and lowercase wordmark. */
.uf-brand { display: inline-flex; align-items: center; gap: 7px; }
.uf-mark { width: 24px; height: 24px; flex: none; }
/* Sora, matching --wordmark in styles.css: the front door and the app show one
   logo. fonts.css is already linked on every generated page, so this costs no
   request the landing page was not already making. */
.uf-wordmark {
  font-family: "Sora", "Inter", -apple-system, system-ui, sans-serif;
  font-weight: 600; font-size: 17.5px; letter-spacing: -0.04em;
}
.uf-topnav { display: flex; align-items: center; gap: 26px; font-size: 14px; color: var(--uf-dim); }
.uf-topnav a { transition: color 140ms ease; }
.uf-topnav a:hover { color: var(--uf-ink); }
.uf-landing .uf-signin {
  display: inline-flex; align-items: center; padding: 7px 15px;
  border: 1px solid var(--uf-hair-hi); border-radius: 8px; color: var(--uf-ink);
  font-weight: 520; font-size: 14px;
  transition: border-color 140ms ease, background 140ms ease;
}
.uf-landing .uf-signin:hover { border-color: var(--uf-ink); background: var(--uf-panel-hi); }
@media (max-width: 680px) { .uf-topnav .uf-hide-sm { display: none; } }

/* ---- The hero, and the fence behind it ---------------------------------- */

/*
 * The hero pulls itself up under the sticky header.
 *
 * The header is in normal flow (sticky, not fixed), so without this the hero
 * would begin below it and the fence could not reach the top of the page — the
 * exact 22px-strip bug this page already had once. Negative margin of one
 * header height, padding of the same, from one custom property: the canvas
 * starts at y=0 and the copy starts below the bar.
 */
.uf-hero-wrap {
  position: relative;
  isolation: isolate;
  margin-top: calc(var(--uf-head) * -1);
  padding-top: var(--uf-head);
}

/*
 * A uniform dim over the fence, so the words carry.
 *
 * WHY SOMETHING IS NEEDED, measured rather than felt: sampling the canvas under
 * the headline and compositing it over the ground, the WORST-CASE contrast
 * against the text was 2.24:1 — an agent's bright core passing directly under a
 * letter, below the 3:1 WCAG asks for large text. The average was fine
 * (17.7:1), which is why it was easy to miss: for most of every second the
 * headline sits over near-black, and then a light crosses it.
 *
 * WHY NOT BLUR, which was tried properly and abandoned. The fence is 1.5px
 * lines and 2px dots, and there is no radius that softens the dots without
 * erasing the lines: at 22px the palings disappeared entirely, at 7px the
 * agents turned into smudges. Blur also does not remove light, it
 * REDISTRIBUTES it — 18px to 30px lifted the headline from 3.44:1 to 3.85:1
 * while pushing the lede DOWN from 4.40:1 to 4.14:1, because the extra spread
 * carried brightness out of one band into the next.
 *
 * WHY NOT A GRADIENT, which was also tried. Masking the treatment to the
 * reading column left the hero looking like two pictures stitched together:
 * soft on the left, hard little discs on the right. One treatment across the
 * whole field is the one that looks deliberate.
 *
 * So: a flat, neutral dim over everything. In the page's own ground colour and
 * NOT a tint — the job is to take light away, and a hue would grade the picture
 * rather than quiet it. The fence keeps every line and every point exactly as
 * the sign-in screen draws them; there is simply less of it.
 *
 * z-index 1: above the canvas at 0, below the hero copy at 10 and the header at
 * 20. `.uf-hero-wrap` sets `isolation: isolate`, so those numbers are local to
 * the hero and cannot be reordered by anything else on the page.
 */
.uf-hero-wrap::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /*
   * Heavier where the words are, lighter where they are not.
   *
   * THE DISTINCTION THAT MATTERS, because an earlier attempt at this failed: a
   * horizontal ramp is fine, a horizontal change of TREATMENT is not. Masking a
   * BLUR to the reading column left the hero looking like two pictures stitched
   * together — soft diffuse light on the left, hard little discs on the right —
   * because the two halves were rendered differently. A ramp in one flat dim
   * changes only how much of the same picture shows: the palings stay palings
   * and the agents stay points at every x, and there is no line to find.
   *
   * Full strength across the reading column (the headline runs to ~58% of the
   * shell), then off ENTIRELY by 94%. A first attempt only eased to 0.26 and was
   * indistinguishable from a flat dim: a quarter of the light still taken out of
   * the agents is enough to keep them looking muted, and the ramp read as no
   * ramp at all. Past the copy there is nothing to protect, so the right-hand
   * third is the sign-in screen's wall at full brightness — the points are as
   * bright there as they are on the login.
   */
  background: linear-gradient(
    100deg,
    rgba(8, 9, 11, 0.67) 0%,
    rgba(8, 9, 11, 0.67) 56%,
    rgba(8, 9, 11, 0.38) 70%,
    rgba(8, 9, 11, 0.1) 84%,
    rgba(8, 9, 11, 0) 94%
  );
  /* The foot fade is not about legibility: it lets the hero dissolve into the
     page instead of ending on a hard horizontal edge. */
  -webkit-mask-image: linear-gradient(to bottom, #000 72%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 72%, transparent 100%);
}

/*
 * On a phone the copy runs the full width, so there is no clear side to hand
 * back — the dim is even the whole way across.
 */
@media (max-width: 720px) {
  .uf-hero-wrap::after {
    background: rgba(8, 9, 11, 0.67);
  }
}

/*
 * The canvas is absolutely placed and full-bleed, and the copy sits on top of
 * it in normal flow. Legibility is the overlay's job, above; the canvas keeps
 * only the foot fade, so the field dissolves into the page rather than stopping
 * at an edge. A hero image with a visible bottom border is a banner; one that
 * fades is a space the page is standing in.
 */
.uf-fence {
  position: absolute;
  /* The whole box, including the header — which is why the header is rendered
     inside `.uf-hero-wrap` on a fence page. A negative inset guessed to clear
     the header left a 22px strip of bare ground across the top of the site the
     moment the header grew past it. */
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  display: block;
  /*
   * NO HORIZONTAL MASK. There was one, fading the wall out under the headline
   * on the left, and it was solving a problem the wall does not have: the
   * palings are stroked at alpha 0.09–0.18 and the agents are 2px, so a 5rem
   * headline sits over them with room to spare. What the mask actually did was
   * hide two-thirds of the picture — the hero showed a sparse right-hand corner
   * of the thing the sign-in screen shows in full.
   *
   * The one mask left is vertical, and it is not for legibility: it lets the
   * field dissolve into the page instead of stopping at an edge. A hero image
   * with a visible bottom border is a banner; one that fades is a space the
   * page is standing in.
   */
  -webkit-mask-image: linear-gradient(to bottom, #000 58%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 58%, transparent 100%);
}
@media (prefers-reduced-motion: no-preference) {
  .uf-fence { animation: uf-fade 1.6s ease both; animation-delay: 0.2s; }
}

/* If an extension neutered the canvas, put something there rather than a hole.
   fence.js sets this attribute after probing its own output. */
.uf-fence[data-fence="unavailable"] {
  background:
    radial-gradient(60% 80% at 78% 40%, rgba(201, 154, 75, 0.16), transparent 70%),
    radial-gradient(50% 70% at 92% 66%, rgba(91, 127, 191, 0.13), transparent 70%);
}

.uf-hero {
  position: relative; z-index: 10;
  padding: clamp(72px, 13vh, 132px) 0 clamp(64px, 11vh, 112px);
  max-width: 44rem;
}
/*
 * Tighter on a phone, so the call to action clears the consent banner.
 *
 * The banner is fixed to the bottom of the VIEWPORT, so page padding cannot
 * move anything out from under it — only a shorter hero can. At 844px tall the
 * generous desktop padding pushed the button to within a few pixels of the bar,
 * which is the one collision on this page that costs a signup rather than a
 * little polish.
 */
@media (max-width: 720px) {
  .uf-hero { padding: 44px 0 56px; }
  .uf-hero h1 { font-size: clamp(2.5rem, 10.5vw, 3.2rem); }
  .uf-lede { font-size: 1.02rem; margin-bottom: 28px; }
}

.uf-eyebrow {
  /*
   * Brighter than `--uf-faint`, for the same reason as `.uf-lede`.
   *
   * That token is tuned for a quiet label on flat panel; this one is 11.5px
   * uppercase mono sitting over a moving canvas, where the worst case over 40
   * frames measured 2.81:1 against #74777f. Small text wants 4.5:1 and gets no
   * size allowance, so the fix is the text rather than more dimming — the
   * alternative was darkening the whole hero to protect one line.
   *
   * The number moves ±0.5 between runs on a label this small (a single agent
   * crossing an 11px line is most of its worst case), so it is set with margin
   * rather than tuned to the threshold.
   */
  color: #a8abb3;
  display: inline-flex; align-items: center; gap: 10px;
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 11.5px; letter-spacing: 0.14em; text-transform: uppercase;
  margin: 0 0 26px;
}
.uf-eyebrow::before {
  content: ""; width: 26px; height: 1px; background: var(--uf-gold); opacity: 0.75;
}

.uf-hero h1 {
  margin: 0 0 26px;
  font-weight: 680;
  /* Tight tracking is what turns Inter from a UI font into a display face. At
     this size the default spacing reads slack and generic. */
  letter-spacing: -0.038em;
  font-size: clamp(2.9rem, 7.4vw, 5.1rem);
  line-height: 0.98;
  text-wrap: balance;
}
/* The one word the sentence turns on. Gold, and nothing else on the page is. */
.uf-hero h1 em { font-style: normal; color: var(--uf-gold); }

.uf-lede {
  /*
   * A step brighter than `--uf-dim`, and only here.
   *
   * Everywhere else that token sits on flat panel; this one paragraph sits over
   * a moving canvas, where the worst case is an agent crossing behind it. At
   * #a7aab2 the worst case over 40 frames measured 2.93:1 — this is 20.8px at
   * weight 400, which WCAG does not call large, so it wants 4.5:1. #c2c5cc gets
   * there alongside a slightly heavier dim, without making the lede compete
   * with the headline.
   */
  color: #d2d4d9;
  margin: 0 0 34px;
  font-size: clamp(1.08rem, 1.9vw, 1.3rem);
  line-height: 1.55;
  max-width: 34rem;
  text-wrap: pretty;
}
.uf-lede strong { color: var(--uf-ink); font-weight: 520; }

.uf-cta-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }

.uf-landing .uf-btn {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 13px 24px; border-radius: 10px;
  font-size: 15px; font-weight: 600; letter-spacing: -0.006em;
  border: 1px solid transparent; cursor: pointer; font-family: inherit;
  transition: transform 160ms cubic-bezier(0.16, 1, 0.3, 1), background 160ms ease,
    border-color 160ms ease, box-shadow 160ms ease;
}
.uf-landing .uf-btn-primary {
  background: var(--uf-ink); color: #08090b;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5) inset, 0 8px 30px -12px rgba(242, 243, 245, 0.5);
}
.uf-landing .uf-btn-primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.6) inset, 0 14px 40px -14px rgba(242, 243, 245, 0.62);
}
.uf-landing .uf-btn-ghost { border-color: var(--uf-hair-hi); color: var(--uf-ink); background: transparent; }
.uf-landing .uf-btn-ghost:hover { background: var(--uf-panel-hi); border-color: var(--uf-ink); }
.uf-landing .uf-btn[disabled] { opacity: 0.5; cursor: default; transform: none; box-shadow: none; }
.uf-btn .uf-arrow { transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1); }
.uf-btn:hover .uf-arrow { transform: translateX(3px); }

.uf-preview {
  display: inline-flex; align-items: center; gap: 9px; margin-left: 6px;
  /* Brighter than `--uf-faint` for the same reason as the eyebrow: 13px over a
     moving canvas, where the token measured 3.70:1 and small text wants 4.5. */
  font-size: 13px; color: #989ba3;
}
.uf-dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--uf-gold); flex: none;
  box-shadow: 0 0 0 0 rgba(217, 168, 92, 0.6);
}
@media (prefers-reduced-motion: no-preference) {
  .uf-dot { animation: uf-pulse 2.8s ease-out infinite; }
}
@keyframes uf-pulse {
  0% { box-shadow: 0 0 0 0 rgba(217, 168, 92, 0.55); }
  70%, 100% { box-shadow: 0 0 0 9px rgba(217, 168, 92, 0); }
}

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

.uf-section { position: relative; z-index: 10; padding: clamp(64px, 9vw, 104px) 0; }
.uf-section + .uf-section > .uf-wrap,
.uf-section + .uf-section > .uf-wrap-narrow { position: relative; }
/* Section rules are drawn as a hairline that fades at both ends rather than a
   full-width border — a hard edge-to-edge line boxes the page in. */
.uf-rule {
  height: 1px; border: 0; margin: 0;
  background: linear-gradient(to right, transparent, var(--uf-hair) 18%, var(--uf-hair) 82%, transparent);
}

.uf-kicker {
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 11.5px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--uf-faint); margin: 0 0 14px;
}
.uf-section h2 {
  margin: 0 0 14px;
  font-size: clamp(1.7rem, 3.4vw, 2.5rem);
  font-weight: 660; letter-spacing: -0.03em; line-height: 1.08;
  text-wrap: balance;
}
.uf-section h2 em { font-style: normal; color: var(--uf-gold); }
.uf-sub { margin: 0 0 40px; color: var(--uf-dim); max-width: 40rem; font-size: 1.03rem; }

/* ---- Outcomes: what your agent can actually do ------------------------- */

/*
 * TWO COLUMNS, NOT AUTO-FIT — and the difference was a visible bug.
 *
 * `repeat(auto-fit, minmax(19rem, 1fr))` with FOUR items lays out three across
 * and one alone, leaving an empty cell the size of half a row. On a dark page
 * with hairline dividers that does not read as whitespace, it reads as a cell
 * that failed to render. Auto-fit is right when the count is unknown; here it
 * is four, so the layout should say four.
 *
 * Two columns also buys each claim twice the width, which is what lets the copy
 * be a sentence rather than a fragment.
 */
.uf-outcomes {
  display: grid; gap: 1px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  background: var(--uf-hair);
  border: 1px solid var(--uf-hair);
  border-radius: 14px;
  overflow: hidden;
}
@media (max-width: 760px) {
  .uf-outcomes { grid-template-columns: minmax(0, 1fr); }
}

/*
 * The four agent tints, one per claim.
 *
 * They are already on the page — the hero animates all four, and until now the
 * document below it used exactly one of them, twice. Keying the numerals to the
 * same four ties the argument to the picture that introduced it, and gets
 * colour onto a very grey page without inventing a palette to do it.
 *
 * On the numeral only. These are chart hues, not brand colours: on a heading
 * they would compete with the gold, and on body text they would fail contrast.
 */
.uf-outcome:nth-child(1) { --uf-tint: var(--uf-t1); }
.uf-outcome:nth-child(2) { --uf-tint: var(--uf-t2); }
.uf-outcome:nth-child(3) { --uf-tint: var(--uf-t3); }
.uf-outcome:nth-child(4) { --uf-tint: var(--uf-t4); }
/*
 * A one-pixel grid gap over a hairline background, so the cells are separated
 * by rules rather than by margins — the whole block reads as one instrument
 * with divisions, which is what stops six cards looking like a template.
 */
.uf-outcome {
  background: var(--uf-ground-lift);
  padding: clamp(28px, 3.4vw, 42px);
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: clamp(20px, 2.4vw, 32px);
  row-gap: 10px;
  transition: background 220ms ease;
}
.uf-outcome:hover { background: var(--uf-panel-hi); }

/*
 * The numeral is a display element, not a label.
 *
 * At 11px in `--uf-mute` it was a piece of dust in the corner and the four cells
 * had nothing to tell them apart. At this size, in the cell's own tint, it does
 * the job an index is for — it makes the set legible as a set at a glance, and
 * gives the eye somewhere to land in a block that is otherwise four paragraphs
 * of grey.
 *
 * `tabular-nums` so 01 and 04 are exactly the same width; without it the four
 * titles start at four slightly different x positions, which is the kind of
 * thing nobody sees and everybody feels.
 */
.uf-outcome-n {
  grid-row: span 2;
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  font-size: clamp(1.6rem, 2.6vw, 2.1rem);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--uf-tint, var(--uf-gold));
  opacity: 0.85;
}
.uf-outcome h3 {
  margin: 0; font-size: 1.12rem; font-weight: 620; letter-spacing: -0.018em;
  line-height: 1.32; align-self: center;
}
.uf-outcome p { margin: 0; color: var(--uf-dim); font-size: 0.96rem; line-height: 1.65; }

@media (max-width: 760px) {
  .uf-outcome { grid-template-columns: minmax(0, 1fr); row-gap: 8px; }
  .uf-outcome-n { grid-row: auto; margin-bottom: 4px; }
}

/* ---- The manifesto ------------------------------------------------------ */

.uf-manifesto { text-align: center; padding: clamp(80px, 13vw, 150px) 0; }
.uf-manifesto blockquote {
  margin: 0 auto; max-width: 24ch;
  font-size: clamp(2rem, 5.4vw, 3.6rem);
  font-weight: 640; letter-spacing: -0.035em; line-height: 1.06;
  text-wrap: balance;
}
.uf-manifesto blockquote em { font-style: normal; color: var(--uf-gold); }
.uf-manifesto cite {
  display: block; margin-top: 26px; font-style: normal;
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 11.5px; letter-spacing: 0.13em; text-transform: uppercase; color: var(--uf-faint);
}

/* ---- The tier ladder ---------------------------------------------------- */

.uf-ladder { display: grid; gap: 0; border-top: 1px solid var(--uf-hair); }
.uf-rung {
  display: grid;
  grid-template-columns: 5.5rem 1fr auto;
  gap: 24px; align-items: baseline;
  padding: 26px 4px;
  border-bottom: 1px solid var(--uf-hair);
  transition: padding-left 260ms cubic-bezier(0.16, 1, 0.3, 1);
}
.uf-rung:hover { padding-left: 14px; }
.uf-rung-n {
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 11.5px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--uf-gold);
}
.uf-rung h3 { margin: 0 0 6px; font-size: 1.12rem; font-weight: 600; letter-spacing: -0.018em; }
.uf-rung p { margin: 0; color: var(--uf-dim); font-size: 0.95rem; max-width: 44ch; }
.uf-rung-meta {
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 11.5px; color: var(--uf-mute); white-space: nowrap;
}
@media (max-width: 680px) {
  .uf-rung { grid-template-columns: 1fr; gap: 8px; }
  .uf-rung-meta { display: none; }
}

/* ---- Code --------------------------------------------------------------- */

.uf-code {
  background: linear-gradient(180deg, var(--uf-panel) 0%, var(--uf-ground-lift) 100%);
  border: 1px solid var(--uf-hair);
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 40px 80px -50px rgba(0, 0, 0, 0.9);
}
.uf-code-head {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 18px; border-bottom: 1px solid var(--uf-hair);
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 11.5px; color: var(--uf-faint); letter-spacing: 0.04em;
}
.uf-code-dots { display: inline-flex; gap: 6px; margin-right: 6px; }
.uf-code-dots i { width: 8px; height: 8px; border-radius: 50%; background: var(--uf-hair-hi); }
.uf-code-head b { margin-left: auto; font-weight: 400; color: var(--uf-mute); }
/* A wide block scrolls INSIDE itself. A code sample is the one element long
   enough to push the whole document sideways on a phone, and a landing page
   that scrolls horizontally reads as broken before a word of it is read. */
.uf-code pre {
  margin: 0; padding: 22px 18px; overflow-x: auto;
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 12.8px; line-height: 1.75; color: #dfe1e6;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
.uf-code .c { color: var(--uf-mute); }
.uf-code .k { color: var(--uf-gold); }
.uf-code .s { color: #8fc9a8; }
.uf-code .o { color: var(--uf-t2); }

/* ---- Guarantees --------------------------------------------------------- */

/* ---- The four guarantees ------------------------------------------------
 *
 * These were four columns of grey prose under four identical hairlines: no
 * colour, no texture, nothing to look at, and no way to tell one guarantee from
 * the next at a glance. The weakest block on the page, next to a diagram and a
 * numbered grid.
 *
 * Each now carries its own tint on a 2px rule, which is the page's palette
 * doing work it was already defined for. Deliberately NOT boxed: `.uf-outcomes`
 * is the page's one hairline-grid instrument, and a second block built the same
 * way would read as a template rather than as a page that changes shape as you
 * go down it. Open columns under coloured rules stay a different object.
 */
.uf-guards {
  display: grid;
  gap: 26px 22px;
  grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr));
}
.uf-guard {
  border-top: 2px solid var(--uf-tint, var(--uf-hair-hi));
  padding-top: 22px;
}
.uf-guard:nth-child(1) { --uf-tint: var(--uf-t1); }
.uf-guard:nth-child(2) { --uf-tint: var(--uf-t2); }
.uf-guard:nth-child(3) { --uf-tint: var(--uf-t3); }
.uf-guard:nth-child(4) { --uf-tint: var(--uf-t4); }
.uf-guard h3 {
  margin: 0 0 10px;
  font-size: 1.06rem;
  font-weight: 600;
  letter-spacing: -0.014em;
}
.uf-guard p { margin: 0; color: var(--uf-dim); font-size: 0.94rem; line-height: 1.62; }
/*
 * The failure codes were the one piece of real texture in this section and they
 * were set as inline words, so they read as emphasis rather than as the literal
 * strings an agent gets back. As chips they are visibly VALUES -- which is the
 * whole point of that guard: a refusal you can branch on, not prose.
 */
.uf-guard code {
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.8em;
  color: var(--uf-ink);
  background: var(--uf-panel);
  border: 1px solid var(--uf-hair);
  border-radius: 5px;
  padding: 2px 6px;
  white-space: nowrap;
}

.uf-tools { display: flex; flex-wrap: wrap; gap: 7px; margin: 18px 0 0; padding: 0; list-style: none; }
.uf-tools li {
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 12px; color: var(--uf-dim);
  background: var(--uf-panel); border: 1px solid var(--uf-hair);
  border-radius: 6px; padding: 4px 9px;
}

.uf-connect { display: flex; flex-wrap: wrap; gap: 10px; }
.uf-chip {
  display: inline-flex; align-items: center; gap: 9px; padding: 9px 15px;
  border: 1px solid var(--uf-hair); border-radius: 9px; color: var(--uf-dim); font-size: 14px;
  background: var(--uf-ground-lift);
}
.uf-chip b { color: var(--uf-ink); font-weight: 600; }

/* ---- Prose (guide pages) ------------------------------------------------ */

.uf-prose { font-size: 1.02rem; }
.uf-prose h2 { margin: 52px 0 14px; font-size: 1.5rem; font-weight: 660; letter-spacing: -0.026em; }
.uf-prose h3 { margin: 34px 0 10px; font-size: 1.08rem; font-weight: 600; letter-spacing: -0.014em; }
.uf-prose p { margin: 0 0 18px; color: var(--uf-dim); line-height: 1.72; }
.uf-prose ul { margin: 0 0 18px; padding-left: 20px; color: var(--uf-dim); }
.uf-prose li { margin: 0 0 10px; line-height: 1.7; }
.uf-prose strong { color: var(--uf-ink); font-weight: 600; }
.uf-prose em { color: var(--uf-ink); font-style: italic; }
/*
 * `:not(.uf-btn)` is load-bearing, and its absence shipped an invisible button.
 *
 * This rule is specificity (0,2,1). `.uf-btn-primary`, which paints the one
 * control on the page that is meant to be pressed, is (0,1,0). So inside a
 * prose block the reset won and the primary call to action rendered white text
 * on its own white pill: measured at 1.00:1, a button with nothing on it.
 *
 * Exactly the shape of the earlier black-on-black bug, one selector deeper -
 * `.uf-landing a` was the reset that time. Raising the button's specificity to
 * outrun this would have to be done again at the next level, so the reset
 * excludes buttons instead: a button is not prose link text, and saying so once
 * is cheaper than out-weighting it forever.
 */
.uf-landing .uf-prose a:not(.uf-btn) {
  color: var(--uf-ink); text-decoration: underline;
  text-decoration-color: var(--uf-hair-hi); text-underline-offset: 3px;
  transition: text-decoration-color 160ms ease;
}
.uf-landing .uf-prose a:not(.uf-btn):hover { text-decoration-color: var(--uf-gold); }
.uf-prose code {
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.87em; background: var(--uf-panel); border: 1px solid var(--uf-hair);
  border-radius: 5px; padding: 1.5px 6px; color: var(--uf-ink);
}

/* ---- FAQ ---------------------------------------------------------------- */

.uf-faq { border-top: 1px solid var(--uf-hair); }
.uf-faq details { border-bottom: 1px solid var(--uf-hair); }
.uf-faq summary {
  cursor: pointer; padding: 22px 0; font-weight: 560; font-size: 1.04rem;
  letter-spacing: -0.012em;
  list-style: none; display: flex; justify-content: space-between; gap: 20px;
  transition: color 160ms ease;
}
.uf-faq summary:hover { color: var(--uf-gold); }
.uf-faq summary::-webkit-details-marker { display: none; }
.uf-faq summary::after {
  content: "+"; color: var(--uf-faint); font-weight: 300; font-size: 1.25rem; line-height: 1;
  transition: transform 220ms cubic-bezier(0.16, 1, 0.3, 1);
}
.uf-faq details[open] summary::after { transform: rotate(45deg); }
.uf-faq details p { margin: 0 0 22px; color: var(--uf-dim); max-width: 46rem; line-height: 1.7; }
.uf-landing .uf-faq a { color: var(--uf-ink); text-decoration: underline; text-underline-offset: 3px; }

/* ---- Form --------------------------------------------------------------- */

.uf-form { display: grid; gap: 20px; max-width: 34rem; }
.uf-field { display: grid; gap: 8px; }
.uf-field > span {
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--uf-faint);
}
.uf-field .uf-help {
  font-size: 12.5px; color: var(--uf-mute); text-transform: none; letter-spacing: 0;
  font-family: inherit;
}
.uf-field input,
.uf-field textarea {
  width: 100%; padding: 13px 15px; border-radius: 10px;
  background: var(--uf-panel); border: 1px solid var(--uf-hair-hi); color: var(--uf-ink);
  font-family: inherit; font-size: 15.5px; line-height: 1.5;
  transition: border-color 160ms ease, background 160ms ease;
}
.uf-field textarea { resize: vertical; min-height: 104px; }
.uf-field input:focus,
.uf-field textarea:focus { border-color: var(--uf-gold); background: var(--uf-panel-hi); }
.uf-field input::placeholder,
.uf-field textarea::placeholder { color: var(--uf-mute); }

/*
 * The honeypot.
 *
 * Off-screen rather than `display: none`: some form-filling scripts skip a
 * field they can see is hidden, and the whole point is that the ones which do
 * not skip it fill it in. `aria-hidden` and `tabindex="-1"` in the markup keep
 * it away from a screen reader and out of the tab order, so a person never
 * meets it either way.
 */
.uf-hp {
  position: absolute; left: -9999px; width: 1px; height: 1px;
  overflow: hidden; opacity: 0; pointer-events: none;
}

.uf-note { font-size: 13px; color: var(--uf-faint); margin: 0; line-height: 1.65; }
.uf-landing .uf-note a { color: var(--uf-dim); text-decoration: underline; text-underline-offset: 3px; }
.uf-landing .uf-note a:hover { color: var(--uf-ink); }

.uf-error {
  padding: 12px 15px; border-radius: 10px; font-size: 14px;
  background: rgba(229, 122, 112, 0.1);
  border: 1px solid rgba(229, 122, 112, 0.34);
  color: var(--uf-bad);
}
.uf-done {
  background: linear-gradient(180deg, var(--uf-panel) 0%, var(--uf-ground-lift) 100%);
  border: 1px solid var(--uf-hair-hi); border-radius: 14px;
  padding: 30px; max-width: 34rem;
  box-shadow: 0 40px 80px -50px rgba(0, 0, 0, 0.9);
}
.uf-done h2 { margin: 0 0 14px; font-size: 1.35rem; font-weight: 640; letter-spacing: -0.024em; }
.uf-done p { margin: 0 0 14px; color: var(--uf-dim); }
.uf-done p:last-child { margin: 0; }
.uf-done .uf-tick { color: var(--uf-good); }

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

.uf-foot {
  position: relative; z-index: 10;
  border-top: 1px solid var(--uf-hair); margin-top: 40px;
  /* A column of blocks now, not a row of links: the sections stack above the
     bottom bar. The row behaviour moved to `.uf-foot-bar`. */
  padding: 34px 0 56px; display: block;
  align-items: center; justify-content: space-between; color: var(--uf-faint); font-size: 13.5px;
}
.uf-foot a { transition: color 140ms ease; }
.uf-foot a:hover { color: var(--uf-ink); }
.uf-foot-links { display: flex; flex-wrap: wrap; gap: 22px; }

/* Anything the page moves, it stops moving for somebody who asked it to. */
@media (prefers-reduced-motion: reduce) {
  .uf-landing *,
  .uf-landing *::before,
  .uf-landing *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .uf-landing .uf-btn-primary:hover { transform: none; }
  .uf-rung:hover { padding-left: 4px; }
}

/* ---- Guide pages: prose plus a contents rail ---------------------------- */

/*
 * The guides were a 720px column centred in a 1180px shell — the right MEASURE
 * and the wrong composition, reading as a narrow ribbon between two empty
 * margins. Widening the column would have fixed the picture and broken the
 * reading (1180px of 16px text is ~130 characters a line, about double what is
 * comfortable), so the PAGE takes the full shell and the PROSE keeps its
 * measure. The recovered width buys a contents rail, generated from the page's
 * own headings — see `withGuideRail` in scripts/build-marketing.mjs.
 */
.uf-guide {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 14rem;
  gap: clamp(40px, 6vw, 88px);
  align-items: start;
}
/*
 * The MEASURE belongs to the text, not to the column.
 *
 * `max-width: 68ch` on the whole block was right for prose and wrong for
 * everything documentation is made of: a worked example is a sequence of tool
 * calls with a trailing comment on each line, and at 68ch it scrolled with the
 * comments cut off mid-word while a third of the column sat empty beside it.
 * The reading measure now applies to the elements that are read as sentences,
 * and code and tables use the width that is actually there.
 *
 * Descendant selectors, not child ones: the docs page wraps its parts in
 * <section> so a `>` combinator would reach none of them.
 */
.uf-guide .uf-prose { max-width: none; }
.uf-guide .uf-prose :is(p, ul, ol, h2, h3, blockquote) { max-width: 68ch; }

.uf-guide-rail {
  position: sticky;
  /* Clears the sticky header, plus a little air. */
  top: calc(var(--uf-head) + 28px);
  font-size: 13.5px;
  border-left: 1px solid var(--uf-hair);
  padding-left: 20px;
}
.uf-guide-rail .uf-kicker { margin-bottom: 12px; }
.uf-guide-rail ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.uf-landing .uf-guide-rail a {
  color: var(--uf-faint);
  transition: color 140ms ease;
  display: block;
  line-height: 1.45;
}
.uf-landing .uf-guide-rail a:hover { color: var(--uf-ink); }

/*
 * Below the shell's own breakpoint the rail has nowhere to be: a 14rem column
 * beside a 68ch one needs about 1000px, and under that the two would fight for
 * the same space. It is removed rather than stacked — a contents list stacked
 * above prose on a phone is a screenful of links between the reader and the
 * thing they came for, and these pages are four to six sections long.
 */
@media (max-width: 1040px) {
  .uf-guide { grid-template-columns: minmax(0, 1fr); }
  .uf-guide-rail { display: none; }
}

/* ---- Diagrams ----------------------------------------------------------- */

/*
 * The two drawings below the hero, and the reason they exist: everything on
 * this page used to be prose. The tier ladder was three rows of text sitting
 * under a canvas that draws exactly what they describe, and the authority
 * boundary — the strongest and least believable claim the product makes — was
 * four paragraphs of assertion. A picture can show WHY the secret never reaches
 * the model; a paragraph can only promise it.
 *
 * They scale by viewBox rather than by breakpoint, so there is one drawing at
 * every width. Inline SVG rather than an image file for two reasons: the
 * palette is `var(--uf-*)`, so a token change moves the diagram with the rest of
 * the page, and the text inside is real text — selectable, searchable, and read
 * by a screen reader through the `role="img"` label.
 */
.uf-diagram {
  display: block;
  width: 100%;
  height: auto;
  margin: 8px 0 34px;
  overflow: visible;
}

/* Under about 720px an 1080-wide drawing puts its labels at ~8px. It scrolls
   inside its own box instead, at a legible size — the alternative is a diagram
   that is present and unreadable, which is worse than one you have to nudge. */
@media (max-width: 720px) {
  .uf-diagram-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .uf-diagram { min-width: 620px; }
}


/* ---- Section rhythm ------------------------------------------------------
 *
 * Seven sections that all opened with the same kicker / headline / paragraph
 * block read as one slide shown seven times, however much the content below
 * each differed. Two devices break that without inventing a new language:
 * the header can sit BESIDE its own summary rather than above it, and a section
 * can stand on a lifted ground instead of the page's.
 */
/*
 * A SECTION HEAD IS A COLUMN, like every hero on the site.
 *
 * It was two: the heading left, the paragraph that qualifies it right, meeting
 * on a shared baseline. Both were already dropped from the inner heroes for
 * reading in the wrong order, and the same argument applies here - a title and
 * its deck are read one after the other, not compared side by side, and the two
 * blocks are never the same height so one of them always hangs.
 *
 * The paragraph keeps a measure narrower than the heading's, which is what
 * stops a stacked head reading as the section's first paragraph.
 */
.uf-split {
  display: block;
  margin-bottom: 40px;
}
.uf-split h2 {
  margin-bottom: 14px;
  max-width: 24ch;
}
.uf-split .uf-sub {
  max-width: 52ch;
}

/*
 * One section on a lifted ground. Not a card — the panel runs the full width of
 * the viewport with hairlines top and bottom, so it reads as a band the page
 * passes through rather than as a box sitting on it.
 */
.uf-section-lift {
  background: var(--uf-ground-lift);
  border-block: 1px solid var(--uf-hair);
}

/* The closing call to action bookends the manifesto: centred, no rule above,
   the only other place on the page that is not left-aligned. */
.uf-closer { text-align: center; }
.uf-closer .uf-sub { margin-inline: auto; }
.uf-closer .uf-cta-row { justify-content: center; }

/* ---- The spec strip ------------------------------------------------------
 *
 * Five facts in mono between the hero and the first argument. It exists because
 * the page dropped from a 5rem headline straight into a grey paragraph, and
 * because nothing below the fold ever stated a number — a marketing page that
 * never gets concrete reads as being about a product rather than describing
 * one.
 *
 * Hairlines top and bottom, no fill: it is a rule with content in it, not a
 * band. A filled strip here would compete with the lifted section further down,
 * which is the page's one deliberate change of ground.
 */
.uf-spec {
  display: flex;
  flex-wrap: wrap;
  gap: 10px clamp(28px, 4vw, 56px);
  margin: 0;
  padding: 22px 0;
  list-style: none;
  border-block: 1px solid var(--uf-hair);
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 12.5px;
  letter-spacing: 0.02em;
  color: var(--uf-faint);
}
.uf-spec b { color: var(--uf-ink); font-weight: 500; margin-right: 6px; }

/* ---- Three ways in -------------------------------------------------------
 *
 * Replaced three grey pills that said a label and then restated the label.
 * Each entry now carries the thing you would actually paste, in the same mono
 * register as the spec strip — which is the page's convention for "this is a
 * fact, not a claim".
 */
.uf-ways {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
  gap: 1px;
  margin: 26px 0 0;
  padding: 0;
  list-style: none;
  background: var(--uf-hair);
  border: 1px solid var(--uf-hair);
  border-radius: 12px;
  overflow: hidden;
}
.uf-ways li {
  background: var(--uf-ground-lift);
  padding: 22px 22px 20px;
  display: grid;
  gap: 7px;
  align-content: start;
}
.uf-ways b {
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 12px; letter-spacing: 0.14em; color: var(--uf-gold); font-weight: 400;
}
.uf-ways span { color: var(--uf-dim); font-size: 0.94rem; line-height: 1.5; }
.uf-ways code {
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 12.5px; color: var(--uf-ink); word-break: break-all;
}
/* The one that is not available yet says so in the slot where the others put an
   address, rather than being quietly dropped or quietly implied. */
.uf-ways .uf-ways-soon { color: var(--uf-faint); }

/*
 * The travelling request in the tier ladder.
 *
 * Hidden rather than paused for somebody who asked for less motion: what is
 * left is the drawn path, which is the whole diagram. The movement was only
 * ever the part that stops it looking dead under an animated hero.
 */
@media (prefers-reduced-motion: reduce) {
  .uf-travel { display: none; }
}

/*
 * The routes are light, not ink.
 *
 * The diagram was gold-on-grey and flat: three hairlines over a grey fence,
 * which is a schematic. Two changes make it a picture instead. Each route now
 * carries its tier's own colour, and the whole lane group is blended as SCREEN
 * -- so where all three routes still share the trunk their colours add the way
 * light does, and the trunk is brightest exactly where the most traffic is.
 * Nothing computes that ramp; compositing does, so it cannot drift out of
 * agreement with the routes it describes.
 *
 * The blur is merged UNDER the source rather than replacing it (see the feMerge
 * in the filter), so the line stays crisp and only gains a halo. Blurring the
 * line itself would have done to these what it did to the hero: 2px strokes do
 * not survive a Gaussian, they dissolve.
 *
 * Dark-only, like the rest of this sheet. Screen over a near-black ground is
 * additive; over a light ground it would wash the lanes out entirely.
 */
.uf-lanes,
.uf-travel {
  mix-blend-mode: screen;
  filter: url(#uf-lume);
}

/* ---- The weather at the foot of the page --------------------------------
 *
 * The login screen is two canvases either side of a seam: a wall of palings
 * with agents forcing their way through it, and the same agents arriving as
 * slow coloured orbs on the other side. The landing page already carries the
 * left half -- the hero IS that wall -- so this is the right half, and putting
 * it at the tail means a visitor scrolling the page makes the same crossing
 * the login screen makes horizontally. Fence at the top, light at the end.
 *
 * ONE CANVAS ACROSS THE CLOSER AND THE FOOTER, not one in each. Two would meet
 * at the footer's hairline with independent drifts either side of it, and a
 * wash that changes on a rule is a wash you can see the edge of. It hangs off
 * `.uf-landing` rather than off either section, and orbs.js gives it a height
 * measured from the top of the closer to the end of the document.
 *
 * No `overflow: hidden` anywhere for it. Canvas drawing is clipped to the
 * bitmap, so orbs drawn past the edge cannot widen the page -- and the ancestor
 * that would have carried the clip also carries the sticky header, which any
 * overflow other than visible would silently un-stick.
 */
.uf-landing {
  position: relative;
  /* Makes z-index: -1 on the canvas mean "above this element's own background,
     below everything in it" rather than "behind the page". Without a stacking
     context here a negative child disappears under the ground colour. */
  isolation: isolate;
}
.uf-orbs {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  /*
   * `width: 100%` is REQUIRED here, and `left: 0; right: 0` is not a substitute.
   *
   * A canvas is a replaced element, and CSS 2.1 10.3.8 resolves an absolutely
   * positioned replaced element by taking its INTRINSIC width and dropping
   * `right` to satisfy the equation. So the element sized itself from its own
   * bitmap -- which orbs.js had sized from the previous measurement of the
   * element -- and the pair settled wherever they started: 1206px inside a
   * 1440px page, with a clean vertical edge where the wash stopped and no
   * padding or max-width anywhere to explain it.
   */
  width: 100%;
  /* orbs.js measures the real span; this is what a no-JS visitor gets, and the
     first paint before it runs. */
  height: var(--uf-orb-h, 62vh);
  /* Behind ALL content, because the canvas now starts above the closing section
     and overlaps the one before it. At z-index 0 a positioned element paints
     over static content, so the wash would have sat on top of that section's
     text -- faintly, which is the worst way for it to be wrong. */
  z-index: -1;
  pointer-events: none;
  /*
   * Four stops in, one out.
   *
   * A single stop at 30% was a straight ramp, and a straight ramp into a flat
   * ground shows its own start as a faint horizontal edge across the full width
   * -- the eye finds the discontinuity in the SLOPE, not in the value. The
   * intermediate stops bend it so nothing along the top has a beginning.
   *
   * And it dims again into the footer rather than running to the bottom of the
   * page at full strength. The wash is weather over the closing pitch; the
   * footer underneath it should read as the page ending, which means going
   * dark.
   */
  --uf-orb-mask: linear-gradient(
    to bottom,
    transparent 0%,
    rgba(0, 0, 0, 0.26) 22%,
    rgba(0, 0, 0, 0.72) 42%,
    #000 56%,
    #000 76%,
    rgba(0, 0, 0, 0.28) 100%
  );
  mask-image: var(--uf-orb-mask);
  -webkit-mask-image: var(--uf-orb-mask);
}
/* The copy and the buttons ride above the wash, not in it. `.uf-foot` already
   carries its own z-index for the same reason. */
.uf-closer {
  position: relative;
  z-index: 1;
}

/*
 * Everything that glows in the tier diagram, in one isolated layer.
 *
 * The lanes are blended as SCREEN so their colours add where routes share a
 * line. Screen against a near-black ground is additive and looks like light;
 * screen against WHITE is white. So the moment the gate became a solid white
 * arch, every coloured route crossing its post saturated and vanished into it —
 * the lines were drawn on top and still could not be seen, which is a confusing
 * way for a z-order to fail.
 *
 * `isolation: isolate` makes this group its own stacking context, so the blend
 * applies among the lanes and their riders and never reaches the gate behind
 * them. The group then composites over the gate normally, and the routes read
 * as passing in front of it. Over the dark ground the result is unchanged,
 * which is why this costs nothing to add.
 */
.uf-glow-layer {
  isolation: isolate;
}

/* ---- Prose that carries reference material ------------------------------
 *
 * `.uf-prose` grew up around argument pages - headings, paragraphs, the odd
 * list - and had nothing for the two things documentation is actually made of.
 * A public docs page written against it would fall back to the browser's own
 * `pre` and `table`, which on a dark ground means a serif-ish monospace on
 * white and a table with no rules at all.
 *
 * Kept deliberately plainer than `.uf-code`, the landing's framed terminal with
 * its title bar and window dots. That is a set piece for a page selling the
 * product; this is a line you copy while following instructions.
 */
.uf-prose pre {
  margin: 0 0 18px;
  padding: 13px 15px;
  overflow-x: auto;
  background: var(--uf-panel);
  border: 1px solid var(--uf-hair);
  border-radius: 9px;
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 13px;
  line-height: 1.6;
  color: var(--uf-ink);
  white-space: pre;
}
/* A code span inside a block is already in the block's face; the pill styling
   `.uf-prose code` gives an inline mention would draw a box inside a box. */
.uf-prose pre code {
  background: none;
  border: 0;
  padding: 0;
  font-size: inherit;
  color: inherit;
}

/*
 * A FIGURE, not a div.
 *
 * `withGuideRail` slices a prose block from its opening tag to the first
 * `</div>` it finds, so one nested div anywhere inside closes the block early
 * and swallows the rest of the page into the rail's markup. The wrapper a
 * horizontally scrollable table needs is therefore a figure, and the same rule
 * applies to anything else wrapped in here later.
 */
.uf-table-scroll {
  margin: 0 0 18px;
  overflow-x: auto;
  border: 1px solid var(--uf-hair);
  border-radius: 9px;
}
.uf-prose table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.94rem;
}
.uf-prose th,
.uf-prose td {
  padding: 10px 14px;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--uf-hair);
  color: var(--uf-dim);
  line-height: 1.6;
}
.uf-prose th {
  color: var(--uf-ink);
  font-weight: 600;
  white-space: nowrap;
  background: var(--uf-panel);
}
.uf-prose tbody tr:last-child td { border-bottom: 0; }
.uf-prose td code { white-space: nowrap; }

/* ---- The hero on a page that is not the front page ----------------------
 *
 * A COLUMN, like the landing's. Headline, then the paragraph that qualifies it,
 * then the way in - read in the order they are written, which is what a hero is
 * for.
 *
 * It spent a while as two columns, headline left and paragraph right. That came
 * from a real complaint - `.uf-hero` is a 44rem column with up to 132px of air
 * above it because on the landing it sits beside the fence animation, and on a
 * page with no animation the right half is just empty. But splitting it fixed
 * the emptiness by breaking the reading order, and it never sat right: two
 * blocks of unequal height with nothing relating them.
 *
 * The emptiness was never the problem. The landing's hero has the same space to
 * its right and reads as composed, because a wide measure of white beside a
 * short column is a deliberate shape. What actually needed fixing was the
 * padding, and that is fixed here: a reference page gets you to the content
 * instead of opening with a third of a screen of nothing.
 */
.uf-inner .uf-hero {
  max-width: 44rem;
  padding: clamp(30px, 4.5vh, 52px) 0 clamp(26px, 3.5vh, 40px);
  /* A rule under the hero, the width of the shell rather than of the text. It
     gives the page a masthead-and-body structure, and it is the thing that
     stops a stacked hero reading as the first paragraph of the article. */
  border-bottom: 1px solid var(--uf-hair);
  margin-bottom: clamp(20px, 3vh, 34px);
}
.uf-inner .uf-hero > h1 {
  margin-bottom: 16px;
}
/* Shorter than the headline's measure on purpose: a deck that runs the full
   width of a 44rem hero reads as body copy that happens to be first. */
.uf-inner .uf-hero > .uf-lede {
  max-width: 40ch;
  margin-bottom: 0;
}
.uf-inner .uf-hero > .uf-cta-row {
  margin-top: 26px;
}

/* The rule belongs to the shell, not the text column, so it is pulled back out
   to the full width the wrap gives it. */
.uf-inner .uf-hero {
  max-width: none;
}
.uf-inner .uf-hero > :where(.uf-eyebrow, h1, .uf-lede, .uf-cta-row) {
  max-width: 44rem;
}
.uf-inner .uf-hero > .uf-lede {
  max-width: 40ch;
}


/*
 * The page you are already on, in its own nav and footer.
 *
 * Marked rather than linked: every page used to list itself, so on /docs the
 * "Docs" entry navigated to /docs and the only visible effect was being thrown
 * back to the top. Dimmer than a link and not interactive - no pointer, no
 * hover - so it reads as a position rather than as a destination.
 */
.uf-landing .uf-current {
  color: var(--uf-faint);
  cursor: default;
}
.uf-topnav .uf-current { color: var(--uf-ink); }

/*
 * An anchor jump has to clear the sticky masthead.
 *
 * The rail scrolls a heading to y=0, and y=0 is behind `.uf-top` - so clicking
 * "Get an API key" landed with the heading hidden under the bar and the first
 * paragraph as the topmost thing on screen. The reader is left looking at an
 * answer with the question covered up.
 *
 * `scroll-margin-top` is the fix for exactly this and costs nothing: it only
 * affects where scrolling STOPS, not layout. Applied to anything with an id,
 * because the rail is not the only thing that links into a page - the docs page
 * links between its own sections, and every heading gets an id from
 * `withGuideRail`.
 */
.uf-landing :where(h1, h2, h3, section, article)[id] {
  scroll-margin-top: calc(var(--uf-head) + 26px);
}


/*
 * The section you are reading, in the rail.
 *
 * `aria-current="true"` is set by the scrollspy in the page's own script, so the
 * marker is a real state a screen reader can announce rather than a class that
 * only means something visually. Full-strength ink and a heavier weight: the
 * rest of the rail is deliberately quiet, and one line being brighter is the
 * whole signal.
 */
.uf-landing .uf-guide-rail a[aria-current="true"] {
  color: var(--uf-ink);
  font-weight: 560;
}

/*
 * A ground behind an inner page's masthead.
 *
 * NOT THE FENCE. The wall is the landing's statement and it is a full screen of
 * vertical palings; repeating it behind six inner heroes would turn it into
 * wallpaper, and at a 200px band the palings are the short floating stubs that
 * were already cut from the tier diagram for reading as stray dashes. fence.js
 * says as much about itself: a version "tuned for a hero" was tried and read as
 * a stock particle background.
 *
 * The other half of the same language does fit. The weather under the closer is
 * soft, has no edges to crop, and carries the tier colours - and an inner page
 * is where a reader has arrived, which is what that canvas has always meant.
 * Dimmer than the tail (see orbs.js) because text sits directly on this one.
 *
 * Masked to nothing at the bottom so it ends where the hero's rule begins,
 * rather than stopping at an edge of its own.
 */
.uf-hero > .uf-orbs {
  position: absolute;
  /*
   * UP BEHIND THE MASTHEAD. The hero starts below the header, so a wash that
   * began at the hero's top edge ended in a horizontal seam right under the
   * bar: a lit band with a flat strip above it, which reads as two surfaces
   * rather than one page. The landing has never had this - its header is drawn
   * inside the hero wrap, over the fence - and the inner pages should not
   * either.
   *
   * The header is transparent until it sticks, so the wash simply shows
   * through it. Once you scroll, `data-stuck` gives the bar its glass and the
   * wash is behind that instead, which is the same thing the landing does.
   */
  top: calc(-1 * var(--uf-head));
  bottom: 0;
  /*
   * FULL BLEED, or it reads as a rectangle rather than as a ground.
   *
   * Inside the wrap it spanned only the shell - 130px to 1310px of a 1440px
   * window - so the wash ended in two hard vertical edges a third of the way in
   * from each side, which is a box drawn behind the text, not an atmosphere
   * behind the page. Reaching the viewport edges means there is no edge to see.
   *
   * `overflow-x: clip` on the page (below) is what keeps 100vw from adding a
   * horizontal scrollbar. `clip` rather than `hidden` deliberately: hidden
   * would make an ancestor a scroll container and silently un-stick the header.
   */
  left: 50%;
  width: 100vw;
  transform: translateX(-50%);
  z-index: -1;
  pointer-events: none;
  /* Strong from the top now, because the top is the masthead rather than the
     first thing under it, and a wash that fades IN under a bar puts the seam
     back where it was. Only the bottom fades, into the hero's own rule. */
  --uf-hero-mask: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.72) 0%,
    #000 22%,
    #000 64%,
    transparent 100%
  );
  mask-image: var(--uf-hero-mask);
  -webkit-mask-image: var(--uf-hero-mask);
}
/* The hero needs to be the canvas's containing block, and its own stacking
   context, or a z-index of -1 drops the wash behind the page's ground. */
.uf-inner .uf-hero {
  position: relative;
  isolation: isolate;
}
.uf-inner {
  overflow-x: clip;
}

/*
 * A rule and real air between sections.
 *
 * A reference page is a stack of independent answers, and at 52px of margin
 * with nothing between them they ran together: scrolling past "Get an API key"
 * into "Connect an agent" felt like one long column rather than like arriving
 * somewhere new. The rail says which section you are in; this is what makes the
 * page agree with it.
 *
 * On the H2, not on the section wrapper, because only some of these pages use
 * <section> at all - the docs page does, the guides do not, and a rule that
 * only appeared on one of them would be worse than none.
 */
.uf-prose h2 {
  margin-top: 78px;
  padding-top: 34px;
  border-top: 1px solid var(--uf-hair);
}
/*
 * ...except the first, which would draw a line immediately under the hero's
 * own rule. Both shapes are cancelled: an H2 that opens the prose block, and
 * one that opens the first <section> in it.
 */
.uf-prose > h2:first-child,
.uf-prose > section:first-of-type > h2:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

/* ---- The footer, in sections --------------------------------------------
 *
 * It was one row of seven links, which is what a footer looks like when a site
 * has three pages. This one has eight and a legal set, and the header only
 * ever showed three - so the guides were reachable from a link in someone
 * else's prose and nowhere else.
 *
 * `auto-fit` rather than a fixed four: a column count that survives a phone
 * without a media query, and survives a fifth section being added without
 * anyone remembering to change a number.
 */
.uf-foot-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr));
  gap: clamp(26px, 4vw, 56px) clamp(20px, 3vw, 40px);
  padding: 6px 0 40px;
}
.uf-foot-col {
  display: grid;
  align-content: start;
  gap: 11px;
  font-size: 13.5px;
}
.uf-foot-title {
  margin: 0 0 2px;
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 11px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--uf-mute);
}
.uf-landing .uf-foot-col a {
  color: var(--uf-dim);
  transition: color 140ms ease;
}
.uf-landing .uf-foot-col a:hover { color: var(--uf-ink); }

/* The bottom bar keeps what the old single row was: a copyright and the legal
   set, on one line, separated from the columns by a rule. */
.uf-foot-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 22px;
  align-items: center;
  justify-content: space-between;
  padding-top: 22px;
  border-top: 1px solid var(--uf-hair);
}

/*
 * The landing's wash sits in the hero WRAP, not in a `.uf-hero`.
 *
 * Same object as the inner pages', one container out: the landing's hero is a
 * wrap that also holds the fence and the header, so the selector that finds it
 * there does not reach here. It is already full-bleed, so it needs no bleed of
 * its own - only the same mask, and to sit under the wall rather than over it.
 */
.uf-hero-wrap {
  position: relative;
  isolation: isolate;
}
.uf-hero-wrap > .uf-orbs {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  pointer-events: none;
  mask-image: linear-gradient(to bottom, #000 0%, #000 58%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 58%, transparent 100%);
}

/*
 * One footer, not two.
 *
 * `.uf-foot` draws a rule above the columns and `.uf-foot-bar` drew another
 * above the copyright, so the foot of the page read as two stacked footers
 * with a divider each. The bar keeps its spacing and loses its line: one rule
 * says "the page ends here", and a second one immediately below says nothing.
 */
.uf-foot-bar {
  border-top: 0;
  padding-top: 4px;
}

/*
 * The beta page is as wide as every other page; its FORM is not.
 *
 * It used to declare `narrow`, which made the whole shell 720px - masthead,
 * copy, footer and all - so it was the one page that looked like a different
 * width of site. Now the page takes the shell and the form keeps a measure, the
 * same split the heroes use: the page is wide, the thing you read or type into
 * is not. A text input stretched to 1180px is harder to use, not easier.
 */
.uf-form,
.uf-done,
.uf-error {
  max-width: 34rem;
}

/* ---- A page with one thing to do, centred ------------------------------
 *
 * The beta page is a conversion page: one headline, one paragraph, one form.
 * Left-aligned in a 1180px shell it read as an article that happened to end in
 * fields, with the form hanging off the left edge of a lot of empty space.
 *
 * Centred, it reads as the single act it is - the same composition the closing
 * section on the landing uses, and for the same reason.
 *
 * The HERO's text centres; the FORM's does not. A centred label above a
 * centred input is a well-known way to make a form harder to fill in: the eye
 * loses the left edge it scans down. So the form block is centred and its
 * contents stay left-aligned, which is why the two rules below are separate.
 */
.uf-center > .uf-hero {
  margin-inline: auto;
  text-align: center;
}
.uf-center > .uf-hero .uf-lede {
  margin-inline: auto;
}
.uf-center > .uf-hero .uf-cta-row {
  justify-content: center;
}
.uf-center > .uf-form,
.uf-center > .uf-done,
.uf-center > .uf-error {
  margin-inline: auto;
  text-align: left;
}

/* ==========================================================================
   The phone
   ========================================================================== */

/*
 * STOP THE BROWSER RESIZING THE TYPE.
 *
 * Without this, mobile browsers apply their own text inflation: the hero asked
 * for 41px and rendered at 46.4px, the lede asked for 16.3px and rendered at
 * 17.3px. Every size on this site is tuned - the lede's colour is set against a
 * measured contrast at a stated size - and all of it was being scaled by a
 * number nobody chose.
 *
 * It is also why the hero felt too big on a phone: it WAS too big, by 13%, and
 * no amount of tuning the clamp would have found it because the clamp was
 * already right.
 */
html:has(.uf-landing),
body:has(.uf-landing),
.uf-landing {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

@media (max-width: 620px) {
  /*
   * A smaller hero, now that the size asked for is the size drawn.
   *
   * Four lines of headline plus seven of lede pushed the one button on the page
   * below the fold on a 390px screen. The headline still leads; it just stops
   * being the entire first screen.
   */
  .uf-hero h1 {
    font-size: clamp(2.05rem, 8.6vw, 2.6rem);
    letter-spacing: -0.03em;
    margin-bottom: 18px;
  }
  .uf-lede {
    font-size: 1rem;
    line-height: 1.58;
    margin-bottom: 24px;
  }
  .uf-hero {
    padding: 34px 0 40px;
  }

  /* A label at 11px in letterspaced uppercase reads smaller than it measures,
     and these are the smallest things on the page. */
  .uf-eyebrow {
    font-size: 12px;
    letter-spacing: 0.11em;
    margin-bottom: 20px;
  }
  .uf-foot-title,
  .uf-kicker {
    font-size: 12px;
  }

  /*
   * TAP TARGETS.
   *
   * Footer and rail entries were 20-22px tall - a line of text with no padding,
   * which is a link you aim at rather than press. 44px is the size a thumb
   * actually is; the padding does the work so the type does not have to grow.
   */
  .uf-foot-col a,
  .uf-foot-col .uf-current,
  .uf-foot-links a,
  .uf-foot-links .uf-current,
  .uf-guide-rail a {
    display: block;
    padding-block: 11px;
  }
  .uf-foot-col {
    gap: 0;
  }
  .uf-foot-links {
    gap: 0 18px;
  }
  /* The brand reaches 44px on its mark alone; the sign-in button is a 38px pill
     and needs the height added rather than the padding, so its shape holds. */
  .uf-brand {
    padding-block: 8px;
  }
  .uf-landing .uf-signin {
    min-height: 44px;
    padding-inline: 18px;
  }

  /*
   * Two columns, not eleven rows. One column turned the footer into a full
   * screen of links you scroll past; the sections are short enough to pair up.
   */
  .uf-foot-cols {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 22px 18px;
    padding-bottom: 28px;
  }
  .uf-foot {
    padding: 26px 0 40px;
  }
}

/*
 * One ladder at a time.
 *
 * The wide drawing is 1080 units across, which on a phone is a diagram you
 * scroll sideways to read - the worst thing a page can ask a thumb to do, and
 * on the section that explains what the product is. The tall one runs top to
 * bottom, which is the direction a phone scrolls anyway.
 *
 * `display: none` rather than a visibility trick, deliberately: a hidden canvas
 * still animates, and both drawings carry six riders and six arrival rings.
 * Only one of them should ever be running.
 */
.uf-diagram-tall { display: none; }

@media (max-width: 620px) {
  .uf-diagram { display: none; }
  .uf-diagram-tall {
    display: block;
    /* The wide drawing is given `min-width: 620px` further up so it can be
       scrolled on a narrow screen. The tall one wears the same class and was
       inheriting that floor, which beats any max-width: it rendered 620px wide
       inside a 342px column, which is the exact problem the tall drawing exists
       to avoid. */
    min-width: 0;
    max-width: 360px;
    margin-inline: auto;
  }
  /* Nothing to scroll to any more, so the container stops offering. */
  .uf-diagram-scroll { overflow-x: visible; }
}

/* The example keeps the source and its useful output readable at every width. */
.uf-conversion { margin-top: 48px; }
.uf-conversion-panels { display: grid; grid-template-columns: minmax(0, 1fr) 56px minmax(0, 1fr); align-items: stretch; }
.uf-page-preview, .uf-markdown-preview { min-width: 0; border: 1px solid var(--uf-hair); border-radius: 9px; overflow: hidden; background: var(--uf-panel, #141517); }
.uf-preview-bar { display: flex; justify-content: space-between; align-items: center; gap: 12px; min-height: 48px; padding: 12px 20px; border-bottom: 1px solid var(--uf-hair); color: var(--uf-dim); font: 10px/1.5 "JetBrains Mono", monospace; letter-spacing: .04em; }
.uf-preview-address { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.uf-preview-article { padding: 28px; }
.uf-article-category { font: 10px "JetBrains Mono", monospace; color: var(--uf-dim); letter-spacing: .15em; }
.uf-preview-article h3 { font-size: clamp(20px, 2.4vw, 28px); line-height: 1.2; letter-spacing: -.03em; margin: 14px 0 10px; }
.uf-preview-article p, .uf-preview-article li { font-size: 14px; line-height: 1.6; color: var(--uf-dim); }
.uf-preview-article p { margin: 0; }
.uf-preview-article h4 { font-size: 14px; margin: 18px 0 6px; }
.uf-preview-article ul { padding-left: 18px; margin: 0; }
.uf-article-layout { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 8px; height: 44px; margin-top: 20px; }
.uf-article-layout span { border: 1px solid var(--uf-hair); background: rgba(255,255,255,.025); border-radius: 3px; }
.uf-conversion-arrow { display: grid; place-items: center; color: var(--uf-dim); font-size: 24px; }
.uf-markdown-preview pre { margin: 0; padding: 28px; white-space: pre-wrap; overflow-wrap: anywhere; font: 13px/1.85 "JetBrains Mono", monospace; color: var(--uf-dim); }
.uf-md-heading { color: var(--uf-ink); }
.uf-output-ready { letter-spacing: 0; }
.uf-conversion-tiers { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px; padding-top: 28px; }
.uf-tier-label { color: var(--uf-ink); font: 11px/1.5 "JetBrains Mono", monospace; }
.uf-conversion-tiers p { margin: 8px 0 0; color: var(--uf-dim); font-size: 13px; line-height: 1.6; }
@media (min-width: 721px) and (max-height: 950px), (min-width: 721px) and (max-width: 1280px) {
  .uf-landing-hero { padding-top: clamp(48px, 8vh, 76px); padding-bottom: 64px; }
  .uf-landing-hero h1 { font-size: clamp(3rem, 6.2vw, 4.5rem); }
  .uf-landing-hero .uf-lede { font-size: 1.16rem; line-height: 1.55; max-width: 34rem; margin-bottom: 28px; }
}
@media (max-width: 720px) {
  .uf-conversion { margin-top: 32px; }
  .uf-conversion-panels { grid-template-columns: minmax(0, 1fr); }
  .uf-conversion-arrow { height: 44px; transform: rotate(90deg); }
  .uf-conversion-tiers { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .uf-conversion-tiers > div { border-bottom: 1px solid var(--uf-hair); padding-bottom: 16px; }
  .uf-preview-article, .uf-markdown-preview pre { padding: 22px; }
  .uf-landing-hero { padding-top: 26px; }
}
@media (min-width: 721px) and (max-height: 780px) {
  .uf-landing-hero { padding-top: 44px; padding-bottom: 48px; }
  .uf-landing-hero h1 { font-size: clamp(3rem, 5.6vw, 4rem); margin-bottom: 22px; }
  .uf-landing-hero .uf-lede { font-size: 1.1rem; margin-bottom: 24px; }
}

/* The demo cycles automatically; visitors can select a specific example. */
.uf-demo-controls[hidden], .uf-demo-status[hidden] { display: none; }
.uf-demo-controls { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 20px; flex-wrap: wrap; }
.uf-demo-examples { display: flex; gap: 4px; padding: 4px; border: 1px solid var(--uf-hair); border-radius: 8px; }
.uf-demo-controls button { font: inherit; font-size: 12px; color: var(--uf-dim); background: transparent; border: 0; border-radius: 5px; padding: 10px 12px; cursor: pointer; }
.uf-demo-controls button:hover { color: var(--uf-ink); }
.uf-demo-controls button[aria-pressed="true"] { background: rgba(255,255,255,.09); color: var(--uf-ink); }
.uf-demo-controls button:focus-visible { outline: 2px solid var(--uf-gold); outline-offset: 3px; }
.uf-demo-controls button:disabled { opacity: .4; cursor: default; }
.uf-preview-article, .uf-markdown-preview { position: relative; }
.uf-demo-scan, .uf-demo-wait { display: none; }
.uf-demo-status { min-height: 40px; margin: 20px 0 0; color: var(--uf-dim); font: 12px/1.7 "JetBrains Mono", monospace; }
.uf-conversion[data-enhanced] .uf-conversion-tiers { padding-top: 12px; }
.uf-conversion[data-enhanced] .uf-conversion-tiers > div { position: relative; border-top: 2px solid var(--uf-hair); padding-top: 16px; transition: border-color .25s, opacity .25s; }
.uf-conversion[data-enhanced] .uf-conversion-tiers > div[data-state="active"] { border-color: var(--uf-gold); }
.uf-conversion[data-enhanced] .uf-conversion-tiers > div[data-state="done"] { border-color: var(--uf-ink); }
.uf-conversion[data-enhanced] .uf-conversion-tiers > div[data-state="skipped"] { opacity: .4; }
.uf-tier-state { display: block; min-height: 15px; margin-top: 8px; color: var(--uf-dim); font: 10px "JetBrains Mono", monospace; }
.uf-conversion:not([data-enhanced]) .uf-tier-state { display: none; }
.uf-conversion[data-phase="fetch"] .uf-demo-scan { display: block; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(transparent 35%, rgba(221,173,91,.08) 48%, rgba(221,173,91,.5) 50%, transparent 51%); background-size: 100% 200%; animation: uf-read-page 1.6s linear infinite; }
.uf-conversion[data-phase="fetch"] .uf-conversion-arrow > span { animation: uf-send-page 1s ease-in-out infinite; color: var(--uf-gold); }
.uf-conversion[data-enhanced]:not([data-phase="complete"]):not([data-phase="extract"]) .uf-markdown-preview pre { visibility: hidden; }
.uf-conversion[data-enhanced]:not([data-phase="complete"]):not([data-phase="extract"]) .uf-demo-wait { display: grid; place-content: center; text-align: center; position: absolute; inset: 48px 16px 0; color: var(--uf-ink); font-size: 14px; }
.uf-demo-wait > span { display: block; margin-top: 10px; font-size: 12px; color: var(--uf-dim); }
.uf-demo-line { display: block; min-height: 1.85em; }
.uf-conversion[data-phase="extract"] .uf-demo-line { animation: uf-output-line .28s both; animation-delay: calc(var(--line) * .11s); }
.uf-conversion[data-paused="true"] *, .uf-conversion[data-paused="true"] *::after { animation-play-state: paused !important; }
@keyframes uf-read-page { from { background-position: 0 100%; } to { background-position: 0 -100%; } }
@keyframes uf-send-page { 0%,100% { opacity: .35; transform: translateX(-4px); } 50% { opacity: 1; transform: translateX(4px); } }
@keyframes uf-output-line { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@media (max-width: 720px) {
  .uf-demo-controls { gap: 10px; }
  .uf-demo-examples { width: 100%; }
  .uf-demo-examples button { flex: 1; padding: 10px 5px; min-height: 44px; }
}
@media (prefers-reduced-motion: reduce) {
  .uf-conversion *, .uf-conversion *::after { animation: none !important; transition: none !important; }
}

/* Each fictional site has its own visual language inside the browser window. */
.uf-conversion { --demo-green: #46bd95; --demo-blue: #689be3; --demo-purple: #aa86e8; --demo-gold: #ddb062; --demo-step: var(--demo-green); }
.uf-conversion[data-step="2"] { --demo-step: var(--demo-blue); }
.uf-conversion[data-step="3"] { --demo-step: var(--demo-purple); }
.uf-demo-examples button[data-example="1"][aria-pressed="true"] { color: var(--demo-green); background: #46bd9518; }
.uf-demo-examples button[data-example="2"][aria-pressed="true"] { color: var(--demo-blue); background: #689be318; }
.uf-demo-examples button[data-example="3"][aria-pressed="true"] { color: var(--demo-purple); background: #aa86e818; }
.uf-conversion[data-enhanced] .uf-conversion-tiers > div:nth-child(1) { --tier-color: var(--demo-green); }
.uf-conversion[data-enhanced] .uf-conversion-tiers > div:nth-child(2) { --tier-color: var(--demo-blue); }
.uf-conversion[data-enhanced] .uf-conversion-tiers > div:nth-child(3) { --tier-color: var(--demo-purple); }
.uf-conversion[data-enhanced] .uf-conversion-tiers > div:is([data-state="active"],[data-state="done"]) { border-color: var(--tier-color); }
.uf-conversion[data-enhanced] .uf-tier-label { color: var(--tier-color); }
.uf-conversion .uf-md-heading, .uf-conversion .uf-output-ready { color: var(--demo-gold); }
.uf-conversion[data-phase="extract"] .uf-markdown-preview, .uf-conversion[data-phase="complete"] .uf-markdown-preview { border-color: #ddb06270; }
.uf-conversion[data-phase="fetch"] .uf-conversion-arrow > span, .uf-conversion[data-phase="browse"] .uf-conversion-arrow > span { color: var(--demo-step); }
.uf-conversion[data-phase="extract"] .uf-conversion-arrow > span, .uf-conversion[data-phase="complete"] .uf-conversion-arrow > span { color: var(--demo-gold); }
.uf-conversion .uf-browser-viewport { padding: 0; height: 410px; overflow: hidden; background: #f5f2eb; isolation: isolate; }
.uf-site { color: #24352d; background: #f5f2eb; font-family: Arial, sans-serif; min-height: 100%; font-size: 12px; }
.uf-site nav { position: relative; z-index: 2; display: flex; justify-content: space-between; align-items: center; gap: 12px; height: 45px; padding: 0 22px; background: inherit; border-bottom: 1px solid #23362c18; }
.uf-site nav > b { font-size: 16px; letter-spacing: -.05em; }
.uf-site nav > span { font-size: 10px; color: #59655e; }
.uf-site-scroll { padding: 20px 24px; }
.uf-site .uf-site-kicker { font-size: 9px; letter-spacing: .13em; color: #667166; margin: 0 0 8px; }
.uf-site h3 { font-family: Georgia, serif; font-size: 29px; font-weight: 500; color: #23382e; margin: 0 0 14px; line-height: 1.05; }
.uf-site h4 { color: #23382e; margin: 14px 0 6px; font-family: Georgia, serif; font-size: 18px; }
.uf-site p { font: 12px/1.5 Arial,sans-serif; color: #506054; margin: 10px 0; }
.uf-site img { display: block; width: 100%; height: 155px; object-fit: cover; border-radius: 3px; }
.uf-site-shop { background: #f2eee8; color: #342f29; }
.uf-site-shop h3 { font: 600 25px/1.15 Arial,sans-serif; letter-spacing: -.06em; }
.uf-shop-filters { display: flex; gap: 6px; margin: 15px 0; font-size: 10px; }
.uf-shop-filters span { padding: 6px 9px; border: 1px solid #34342c30; border-radius: 20px; }
.uf-shop-filters .is-selected { background: #293b31; color: white; }
.uf-shop-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.uf-shop-grid img { border: 10px solid #e0d2bb; border-radius: 0; height: 135px; box-shadow: 1px 4px 8px #2221; }
.uf-shop-grid article:last-child img { object-position: right; }
.uf-shop-grid b, .uf-shop-grid span { display: block; margin-top: 10px; font-size: 11px; }
.uf-site .uf-shop-grid span { margin-top: 5px; color: #655f57; }
.uf-site-stays { background: #fff; }
.uf-site-stays nav b { font-weight: 800; letter-spacing: -.05em; }
.uf-site-stays nav b span { font-weight: 400; margin-left: 4px; }
.uf-site-stays h3 { font: 600 26px/1.1 Arial,sans-serif; letter-spacing: -.05em; }
.uf-stay-search { display: flex; justify-content: space-between; padding: 11px 12px; margin: 12px 0; border: 1px solid #cdd5cd; border-radius: 6px; font-size: 10px; }
.uf-stay-search span { font-weight: 700; }
.uf-stay-card { position: relative; }
.uf-stay-card img { height: 135px; border-radius: 6px; }
.uf-stay-rating { position: absolute; top: 8px; left: 8px; background: #fff; padding: 5px 8px; border-radius: 4px; font-size: 9px; }
.uf-stay-card > div { display: flex; justify-content: space-between; margin-top: 12px; }
.uf-stay-card > div b { font-size: 15px; }
.uf-stay-card > div span { font-size: 11px; }
.uf-stay-card > p { margin: 5px 0 9px; font-size: 10px; }
.uf-fake-button { display: block; width: fit-content; padding: 9px 13px; border-radius: 4px; background: #253f33; color: #fff; font-size: 10px; }
.uf-stay-detail img { height: 195px; }
.uf-stay-facts { padding-top: 18px; font-size: 14px; }
.uf-stay-amenities { padding: 12px 0; line-height: 2; font-size: 12px; }
.uf-stay-price { padding: 15px 0; border-top: 1px solid #ddd; font-size: 11px; }
.uf-stay-price strong { font-size: 20px; }
.uf-stay-price span { float: right; padding: 9px; background: #253f33; color: white; border-radius: 4px; }
.uf-agent-cursor { position: absolute; left: 0; top: 0; z-index: 4; color: var(--demo-step); opacity: 0; pointer-events: none; filter: drop-shadow(0 2px 3px #0004); }
.uf-agent-cursor svg { width: 22px; height: 28px; }
.uf-agent-cursor > span { position: absolute; top: -24px; left: 16px; background: var(--demo-step); color: #15171b; border-radius: 4px; padding: 4px 8px; font: 10px Arial,sans-serif; }
.uf-agent-click .uf-agent-cursor::before { content: ''; position: absolute; width: 30px; height: 30px; left: -12px; top: -12px; border: 2px solid var(--demo-step); border-radius: 50%; animation: uf-click-ring .5s both; }
.uf-conversion[data-phase="fetch"][data-blocked="true"] .uf-browser-viewport::after { content: 'Loading the page…'; position: absolute; z-index: 3; inset: 45px 0 0; display: grid; place-items: center; color: #46534c; background: #f5f2eb; font: 13px Arial,sans-serif; border-top: 2px solid var(--demo-step); }
.uf-conversion[data-example="3"][data-step="2"][data-phase="fetch"] .uf-browser-viewport::after { content: 'This page needs a full browser.'; }
.uf-conversion[data-phase="fetch"] .uf-site-scroll { animation: uf-site-read 1.6s ease-in-out; }
@keyframes uf-click-ring { from { opacity: .9; transform: scale(.3); } to { opacity: 0; transform: scale(1.6); } }
@keyframes uf-site-read { from { opacity: .5; } to { opacity: 1; } }
@media (max-width: 720px) {
  .uf-site nav { padding-inline: 15px; }
  .uf-site-scroll { padding: 18px; }
  .uf-site h3 { font-size: 25px; }
  .uf-site-shop h3 { font-size: 23px; }
  .uf-site nav > span { font-size: 9px; }
}

.uf-demo-caption { margin: 0 0 16px; font-size: 12px; line-height: 1.6; color: var(--uf-dim); }
