/* The marketing site on a phone.
 *
 * One file, one band. Everything here is inside `@media (max-width:767px)`, so no rule in it can
 * reach a desktop viewport: "remove nothing from desktop" is kept by construction rather than by
 * review. It is the LAST stylesheet in every page's head, so at equal specificity it wins over the
 * page's own inline block without needing !important for ordinary cases.
 *
 * The rules, in the order Connor gave them:
 *
 *   TYPE      body 16px and 1.5, nothing under 13px outside a mockup, headlines clamped so the
 *             biggest is about 34px at 390 and never breaks a word or leaves one word alone
 *   SPACING   48px top and bottom per section, 20px at the sides, one column, text above mockup
 *   TARGETS   every tap target at least 44px tall with 8px between them, primary buttons full width
 *   NAV       one menu, keyboard openable, one group open at a time, demo CTA at the bottom
 *   FLOAT     one floating button, never over a control
 *   MOCK      a readable region, capped height, a bottom fade when cropped
 *   TABLES    stacked cards, never a sideways scroll
 *
 * Why 767 and not the 760 the pages already use: 768 is the width live-mock.js already calls
 * MOBILE, and a component and its stylesheet disagreeing about where the phone starts is a class
 * of bug on its own. The pages' own 760 and 560 blocks are untouched; this file lands after them.
 */
/* The only two rules in this file outside the phone band, and both exist so that desktop is
   unchanged rather than changed. The menu's demo CTA and the phone floating button are elements
   this arc ADDS; they are hidden by default and shown only inside the band below, the same way the
   pages' own `.nl-signin` is. Nothing that was on the page before is touched here. */
.nl-demo { display: none; }
.fsmob-more { display: none; }
.fsmob-fab, .fsmob-choice, .fsmob-menubtn { display: none; }
.fsp { display: none; }
/* The footer headings are real buttons, built only at phone width. If the window is then widened
   past 768 they stay in the document, and every rule that makes them look like the span they
   replaced lives inside the phone media query, so a resized window showed four default grey
   browser buttons in the footer. This strips the browser's own chrome at every width; the phone
   block below adds the row, the rule and the chevron. */
.fsfoot-t {
  appearance: none; -webkit-appearance: none;
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}

@media (max-width: 767px) {
  /* ============================================================ TYPE */
  /* 16px is the floor for anything that reads as a sentence, and 1.5 the floor for its leading.
     The page's own body rule is 16px/1.55 already; this pins it so a page-local override cannot
     drop under it. */
  html body { font-size: 16px; line-height: 1.5; }  html p, html li, html dd, html dt, html blockquote, html .lead, html .hsub, html .dtext p,
  html .side p, html .pcard p, html .tcard p, html .cbox li, html .dtext li, html .side li,
  html .acard .af, html .scoutb, html .hc-body, html .msg .tx, html .csig, html .agent .lb {
    font-size: 16px;
    line-height: 1.5;
  }  html .lead, html .hsub { font-size: 17px; line-height: 1.5; }  /* Nothing outside a mockup reads under 13px. Every selector below was measured at 13px or less
     on a 390 viewport (before/audit.json); the list is the measurement, not a guess. Mono eyebrows
     go to 13px and prose-ish labels to 14px, so the hierarchy survives the lift. */
  html .eyebrow, html .mono, html .ph, html .fcol .ft, html .lstage .k, html .myles .mtag,
  html .doc-eyebrow, html .success-eyebrow, html .acard .lay, html .walllab, html .logos .t,
  html .msg .who, html .step .tag, html .agent .nm, html .cover-tag, html .cover-eyebrow,
  html .cover-logo, html .page-num, html .section-label, html .who, html .range, html .hero-badge,
  html .cta-url, html .guide-bestfor, html .nlr-rhead, html .press-attr, html .asc-cite,
  html .doc-updated, html .optional, html .nf-code {
    font-size: 13px;
    letter-spacing: .04em;
  }  html .hc-meta, html .hc-tt small, html .hc-st, html .scoutb .meta, html .sent, html .mchip,
  html .side .tag, html .calert .d, html .lstage .d, html .step .sd, html .callto, html .logged,
  html .intg span, html .af, html .label, html .k, html .icon, html .section-title,
  html .page-header-left, html .form-privacy, html .nlr-toast, html .meta, html .tk-live,
  html .tk-body, html .ex-tag, html .ex-state, html .ph .live {
    font-size: 14px;
  }  /* The generic-tag cases the measurement found, each scoped to where it lives rather than to its
     tag: the contact form's field labels, the doc pages' mono h3, the reporting table's own head
     cells, and the `small` used as a card subtitle. */
  html form label, html .field label, html label[for] { font-size: 14px; }  /* The line above is three type selectors and the contact form's own rule is a class, so the     page won and its labels stayed at 10.5px on a phone. Measured 2026-09-20 at 390. The     consent block is the one a 10DLC reviewer reads, so its checkbox gets a real target and     its fine print gets a real size. */  html .form-group label { font-size: 14px; }  html .form-group label .optional { font-size: 14px; }  html .consent-row input[type=checkbox] { width: 24px; height: 24px; }  html .consent-row label, html .consent-fine, html .privacy-note { font-size: 14px; }  html .doc h3 { font-size: 14px; letter-spacing: .06em; }  html small { font-size: 14px; }  html th, html td { font-size: 14px; }  /* An inline style beats a stylesheet, so the page-local `style="font-size:1Npx"` labels the
     measurement found need the one place in this file that raises specificity deliberately. */
  html [style*="font-size:10px"], html [style*="font-size:11px"], html [style*="font-size:12px"],
  html [style*="font-size:12.5px"], html [style*="font-size:11.5px"],
  html [style*="font-size:10.5px"] {
    font-size: 14px !important;
  }  /* Inside a mockup none of the above applies: a mock document is a faithful copy of the app and
     is measured by its own rule (effective 10px or larger), not by this one. */
  html .fsm *, html .fsm-sheet * { font-size: revert; }  /* Headlines. clamp() so the biggest is about 34px at 390, text-wrap:balance so the last line is
     never one orphaned word, and no word is ever broken. */
  html h1, html .fcard h2 {
    font-size: clamp(27px, 8.7vw, 34px);
    line-height: 1.12;
    letter-spacing: -0.03em;
    text-wrap: balance;
    overflow-wrap: normal;
    word-break: normal;
    hyphens: none;
  }  html h2 {
    font-size: clamp(24px, 7.4vw, 29px);
    line-height: 1.16;
    text-wrap: balance;
    overflow-wrap: normal;
    word-break: normal;
    hyphens: none;
  }  html h3, html .dtext h3, html .myles h3, html .side h3 {
    font-size: clamp(20px, 5.9vw, 23px);
    line-height: 1.2;
    text-wrap: balance;
    word-break: normal;
    hyphens: none;
  }  html h4, html .pcard h4, html .tcard h4, html .cbox h3 { font-size: 17px; line-height: 1.3; text-wrap: balance; }  /* The sticky bar is 60px on a phone, so a heading scrolled to must clear it. */
  html h1, html h2, html h3, html [id] { scroll-margin-top: 76px; }  /* ============================================================ SPACING AND ONE COLUMN */
  html .wrap { padding: 0 20px; }  html .sec, html .logos, html .final { padding: 48px 0; }  html .hero { padding: 32px 0 48px; }  html .fcard { padding: 36px 22px; border-radius: 18px; }  /* One column, everywhere. Text first, mockup under it: `.demorow.rev` reverses the two on
     desktop, and on a phone the reversal has to go or the picture lands above its own words. */
  html .hgrid, html .demorow, html .two, html .sides, html .pill, html .myles, html .swarm,
  html .trust, html .agrid, html .nlr-grid {
    grid-template-columns: 1fr !important;
  }  html .loop, html .fcols { flex-direction: column; }  html .demorow, html .demorow.rev { direction: ltr !important; }  html .demorow.rev > * { direction: ltr; }  html .demorow > .dtext { order: 1; }  html .demorow > *:not(.dtext) { order: 2; }  html .demorow { display: flex; flex-direction: column; }  html .demorow + .demorow { margin-top: 44px; }  html .hgrid { gap: 28px; }  html .demorow, html .two, html .sides, html .pill, html .swarm, html .trust, html .agrid { gap: 16px; }  /* Cards that were grid cells with 1px gutters become separate cards once stacked, or the
     borders double up. */
  html .pill, html .trust, html .agrid, html .swarm { background: transparent; border: none; border-radius: 0; }  html .pcard, html .tcard, html .acard, html .agent {
    border: 1px solid var(--line, #e8eaf0);
    border-radius: 14px;
    padding: 20px;
  }  html .pcard, html .side, html .cbox, html .tcard { padding: 20px; }  html .myles { border-radius: 16px; }  html .myles .mtext { padding: 26px 22px; }  html .myles .mvis { border-left: none; border-top: 1px solid rgba(255,255,255,.08); padding: 26px; }  /* The stats row is a 2 by 2 grid with each number on one line. */
  html .stats {
    grid-template-columns: 1fr 1fr !important;
    border-radius: 14px;
  }  html .stat {
    padding: 18px 10px;
    border-right: 1px solid var(--line2, #eef0f5);
    border-bottom: 1px solid var(--line2, #eef0f5);
  }  html .stat:nth-child(2n) { border-right: none; }  html .stat:nth-last-child(-n+2) { border-bottom: none; }  html .stat .n { white-space: nowrap; line-height: 1.15; }  /* A container query sizes the number to its own cell, so it is one line and never clipped. */
  @supports (container-type: inline-size) {
    html .stat .n { font-size: min(30px, 26cqw); }
  }  /* The loose inline stat rows (`.hproof` on the heroes) become a 2 by 2 grid too, so a divider
     is never left hanging at the end of a wrapped line. */
  html .hproof {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px 14px;
    font-size: 14px;
  }  html .hproof .dv { display: none; }  /* ============================================================ TAP TARGETS AND BUTTONS */
  /* 44px tall, 8px apart. min-height rather than height, so a label that wraps still grows. */
  html a.btn, html button.btn, html .btn, html .mchip, html .ex-stop, html .fsm-open,
  html .fsm-back, html summary, html input[type="submit"], html button[type="submit"] {
    min-height: 44px;
  }  html a.btn, html button.btn, html .btn, html input[type="submit"], html button[type="submit"] {
    padding: 12px 18px;
    font-size: 15.5px;
    /* The consent bar's "Turn analytics and advertising cookies off" is 439px of nowrap text and
       is what pushed privacy.html to 461 CSS px, which made the browser shrink the whole page to
       fit. A button label wraps on a phone. */
    white-space: normal;
    text-align: center;
    justify-content: center;
  }  html .dlink, html .fcol a, html .nlinks a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
  /* A link that is the only thing in a list item IS the row, so it is a tap target rather than a
     word in a sentence. Measured at 20px on the SEO pages' related-link lists. */
  /* A link that is the ONLY content of its parent is that row, whatever the parent is: a one-item
     breadcrumb paragraph, a list item, or a block link in a div. Measured at 19 to 21px across the
     SEO pages, /pricing and the guides before this rule; naming parent tags one at a time found a
     new one on every gate run, which is how this ended up as one selector. */
  html p > a:only-child,
  html li > a:only-child,
  html div > a:only-child {
    display: flex;
    align-items: center;
    min-height: 44px;
  }  /* Links that sit in a column need the gap between them, not just their own height. */
  html .fcol { gap: 0; }  html .dtext ul, html .side ul, html .cbox ul { gap: 12px; }  /* Primary buttons are full width, one per line, 8px apart. */
  html .hcta {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 24px;
    width: 100%;
  }  html .hcta > .btn, html .hcta > a, html .hcta > button {
    width: 100%;
    flex: none;
  }  /* The third hero CTA is a quiet button on desktop and read as loose stray text on a phone.
     It keeps its quiet role and gains a box, so it is visibly a button. */
  html .hcta > .btn.q {
    border-color: var(--line, #e8eaf0);
    background: #fff;
    color: var(--s5, #414a5c);
  }  html .fcard .btn, html .final .btn { width: 100%; }  /* The logo and the hamburger are the two smallest targets in the bar. */
  html .logo { min-height: 44px; }  html .hamb { padding: 12px 10px; min-width: 44px; min-height: 44px; justify-content: center; }  /* ============================================================ NAV */
  html nav { position: sticky; top: 0; }  html .nav { height: 60px; gap: 12px; }  html .logo .fsmark { width: 30px; height: 30px; }  html .logo .lw-b { font-size: 16px; }  /* At 360 the bar held the logo, a black demo pill and the hamburger. The demo CTA moves into the
     menu, where it is a full width button at the bottom; nothing is removed, the bar's copy of it
     is simply not the one a phone shows. */
  html nav .btn.k, html nav .btn.signin { display: none; }  /* The menu is a panel under the bar, not a dropdown: it owns the screen while it is open. */
  html .nlinks {
    display: none;
    position: fixed;
    top: 60px;
    left: 0;
    right: 0;
    bottom: 0;
    flex-direction: column;
    gap: 0;
    background: #fff;
    border-bottom: none;
    box-shadow: none;
    padding: 8px 20px 24px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    z-index: 65;
    white-space: normal;
  }  html #navtoggle:checked ~ .nlinks { display: flex; }  html .nlinks a {
    font-size: 16px;
    padding: 0;
    border-bottom: 1px solid var(--line2, #eef0f5);
  }  html .nlinks a:last-child { border-bottom: 1px solid var(--line2, #eef0f5); }  html .nlinks .nd > summary {
    font-size: 16px;
    min-height: 52px;
    padding: 0;
    align-items: center;
  }  html .nlinks .ndp { padding: 0 0 8px 12px; }  html .nlinks .ndp a { font-size: 15px; min-height: 44px; border-bottom: none; line-height: 1.4; }  html .nlinks .ndp b { font-size: 15px; }  html .nl-signin { display: flex !important; }  /* The demo CTA, full width, at the bottom of the menu. It is a second anchor in `.nlinks`,
     hidden above this band exactly the way `.nl-signin` already is, so desktop is unchanged. */
  html .nl-demo {
    display: flex !important;
    width: 100%;
    margin-top: auto;
    margin-bottom: 4px;
    min-height: 50px;
    border-bottom: none !important;
    border-radius: 12px;
    font-size: 16px;
    justify-content: center;
  }  /* `margin-top:auto` only pushes it to the bottom if the panel is taller than its content, which
     it is: the panel is pinned to the bottom of the viewport. Above that first screen of links
     the menu scrolls, and the CTA travels with the end of the list, which is where it belongs. */
  /* The body does not scroll behind an open menu. Set by mobile.js on the html element, because a
     CSS-only checkbox cannot reach past its own subtree. */
  html.fsmob-locked, html.fsmob-locked body { overflow: hidden; }  /* The hamburger is a real button with a tab stop. The page's own <label> stays in the DOM for
     the no-script path; mobile.js hides it and drives the same checkbox from this button, so there
     is one state and not two. */
  html .fsmob-menubtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 4px;
    min-width: 44px;
    min-height: 44px;
    border: 0;
    background: none;
    padding: 12px 10px;
    cursor: pointer;
    color: var(--ink, #0b0f19);
  }
  html .fsmob-menubtn span {
    display: block;
    width: 20px;
    height: 2px;
    border-radius: 2px;
    background: currentColor;
  }

  /* ============================================================ ONE FLOATING BUTTON */
  /* Two fixed pills, "Chat with Scout" bottom-left and "Talk to Scout" bottom-right, covered
     headlines, body text and the mockups' own Open button. On a phone there is one button, and a
     tap opens a two choice sheet. The originals are still in the DOM and still do the work; the
     phone simply does not show them as pills. */
  html .fsc-launch, html .voice-float { display: none !important; }  /* A 48px ROUND ICON, no label. Connor's call, 2026-09-21.
     It was a 106x48 pill reading "Scout". A pill that wide, fixed to the bottom right of a phone,
     lands on the text column whatever it does: measured across 643 scroll positions on five pages
     at 360, 390 and 430, it covered a word of body text at 195 of them. The icon is the smallest
     thing that still reads as a control and still takes a 48px tap. */
  html .fsmob-fab {
    position: fixed;
    right: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom, 0px));
    z-index: 140;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0;
    width: 48px;
    min-width: 48px;
    height: 48px;
    min-height: 48px;
    padding: 0;
    border-radius: 50%;
    border: 1px solid var(--line, #e8eaf0);
    background: #fff;
    color: var(--ink, #0b0f19);
    font-family: 'Inter', system-ui, sans-serif;
    box-shadow: 0 2px 4px rgba(11,15,25,.04), 0 16px 36px -14px rgba(11,15,25,.28);
    cursor: pointer;
    transition: opacity .2s, transform .2s;
  }
  /* The word is still in the button for a screen reader; the accessible name is on the button
     itself, and this is what stops the label taking up the room the pill took. */
  html .fsmob-fab > span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  html .fsmob-fab svg { width: 20px; height: 20px; color: var(--accent, #2f5fe6); }
  /* ⚠ THE TWO LIFTS ARE THE HOME PAGE'S, AND NOWHERE ELSE'S, since 2026-09-21. Every page used
     to try three positions and then hide. Off the home page the button does not move at all now:
     it is a circle in the corner, and mobile.js hides it outright when a word would be under it.
     The home page keeps the dance because its hero types its draft on a loop, so the words under
     the button arrive, leave and arrive again, and no fixed position answers that. */
  html .fsmob-fab.is-lifted { bottom: calc(104px + env(safe-area-inset-bottom, 0px)); }
  html .fsmob-fab.is-lifted2 { bottom: calc(196px + env(safe-area-inset-bottom, 0px)); }  html .fsmob-fab.is-away { opacity: 0; pointer-events: none; transform: translateY(12px); }
  /* ⚠ STEPPING ASIDE IS INSTANT, BECAUSE A FADE IS STILL COVERING THE WORDS WHILE IT PLAYS.
     The button hides itself when every resting place is occupied, and with the 0.2s opacity
     transition it stayed legible on top of a link for the whole of that fade. Measured at 360 and
     390 sampling three times at each 400px of scroll: three readings caught it mid fade over the
     same footer link, and nothing else. Removing the class still fades it back IN, which is
     fine, because it only ever comes back to a place that is already clear. */
  html .fsmob-fab.is-away { transition: none; }
  /* ⚠ AND ON THE PILOT PAGE IT DOES NOT FADE IN EITHER, WHICH IS THE OTHER HALF OF THE SAME BUG.
     Hiding instantly fixed the way out; the way back in was still a 0.2s ramp from transparent,
     and the button is at its most wrong exactly then, because keepClear brings it back the frame
     it judges a place clear and can judge the next frame that it is not. For 0.2s it was
     half visible on top of a link while it made its mind up. Measured at 390: two readings at
     scroll 18400 over "Automate check calls for freight brokers" and two of its neighbours, with
     the button at rest correctly hidden at opacity 0 the whole time, which is why this reads as
     a flicker rather than as a resting overlap. The button pops rather than fades here. That is
     the trade against it being legible on top of a sentence, and the rule is that it never is. */
  html.fsp-on .fsmob-fab { transition: none; }  html .fsmob-choice {
    position: fixed;
    inset: 0;
    z-index: 190;
    display: none;
    align-items: flex-end;
    background: rgba(11,15,25,.44);
  }  html .fsmob-choice.is-on { display: flex; }  html .fsmob-choice-card {
    width: 100%;
    background: #fff;
    border-radius: 18px 18px 0 0;
    padding: 20px 20px calc(20px + env(safe-area-inset-bottom, 0px));
    display: flex;
    flex-direction: column;
    gap: 10px;
  }  html .fsmob-choice-card h2 { font-size: 19px; margin-bottom: 4px; }  html .fsmob-choice-card p { font-size: 15px; color: var(--s6, #545c6e); }  html .fsmob-choice-card .btn { width: 100%; }  /* ⚠ SAID EXPLICITLY, BECAUSE THE hidden ATTRIBUTE LOSES HERE. The pages set .btn{display:inline-flex}, an author rule, and the browser's own [hidden]{display:none} is a user-agent rule, so .btn wins and a hidden button still renders. Measured 2026-09-21 with the voice control removed: the Call choice carried hidden and computed display:flex. The sheet hides its Call choice on a page with no voice control, and this is what makes that true. */
  html .fsmob-choice-card .btn[hidden] { display: none !important; }  /* ============================================================ MOCKUPS */
  /* A MOCKUP IS NOT SHOWN ON A PHONE AT ALL, since 2026-09-21. Under 768px every placement renders
     a summary card from assets/phone-panels.data.js instead, and the rule at the bottom of this
     file hides the figure outright. What stood here sized the figure for a 3x poster of a cropped
     region: the full-bleed stage, the height caps, and a fade over the crop. All three served
     _build/render-phone-posters.mjs, which is deleted, along with its 44 posters.

     check-phone-panels.mjs refuses a page that places a screen without a panel, or that places one
     and never loads the component, so there is no page left where a phone falls back to the
     figure. */
  html .fsm-open {
    position: static;
    /* The Open bar is page furniture rather than part of the picture, so it keeps the gutter the
       full-bleed stage gave up. */
    width: calc(100% - 40px);
    min-height: 44px;
    margin: 8px 20px 0;
    border-radius: 10px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    font-size: 15px;
    font-weight: 600;
    background: #fff;
    border: 1px solid var(--line, #e8eaf0);
    color: var(--ink, #0b0f19);
    box-shadow: none;
  }  /* The desktop control is a transparent hit area with a small pill for a label. On a phone the
     bar carries its own words, so the pill goes or the button reads "Open the full screen Open". */
  html .fsm-openlabel { display: none; }  /* One mockup per section. Where desktop shows two side by side, the phone shows the stronger
     one and the second is reachable in the sheet the first one opens; `data-phone-second` marks
     the one that steps aside, and its alt text and label stay in the DOM. */
  html .fsm[data-phone-second="1"] { display: none; }
  html .fsmob-more {
    display: flex;
    width: calc(100% - 40px);
    margin: 4px 20px 8px;
    min-height: 44px;
    justify-content: center;
  }  /* The pulsing dot does nothing useful on a 350px poster, so it is not offered there. Inside the
     sheet it works by tap. */
  html .fsm-hot { display: none; }  html .fsm-sheet-bar { min-height: 56px; }  html .fsm-sheet-close { min-height: 44px; min-width: 88px; font-size: 15px; }  html .fsm-sheet-hint { font-size: 14px; }  /* ============================================================ TABLES */
  /* A table's own container clipped its right column mid-word on 28 pages, and nothing reported
     it because a clipping container does not grow the document. On a phone a data table is a
     stack of cards: one card per row, the head cell printed as the label above each value. The
     labels are written in by mobile.js from the table's own thead, so no page markup changes and
     no cell text leaves the DOM. */
  html table.fsmob-cards, html table.fsmob-cards tbody, html table.fsmob-cards tr,
  html table.fsmob-cards td {
    display: block;
    width: 100%;
  }  html table.fsmob-cards { border-collapse: separate; border-spacing: 0; }
  /* The SEO pages pin min-width:640px on these tables and wrap them in an overflow-x:auto div, so
     as cards they kept the 640 and the wrapper scrolled sideways, which is the thing the brief
     forbids. Once a table is a stack of cards there is nothing left to scroll. */
  html table.fsmob-cards { min-width: 0 !important; max-width: 100%; }
  html .fsmob-cardwrap { overflow-x: visible !important; }  html table.fsmob-cards thead { display: none; }  html table.fsmob-cards tr {
    border: 1px solid var(--line, #e8eaf0);
    border-radius: 12px;
    padding: 4px 14px;
    margin-bottom: 10px;
    background: #fff;
  }  html table.fsmob-cards td {
    border: none;
    border-bottom: 1px solid var(--line2, #eef0f5);
    padding: 10px 0;
    font-size: 15px;
    line-height: 1.45;
    text-align: left !important;
    white-space: normal !important;
  }  html table.fsmob-cards tr td:last-child { border-bottom: none; }  html table.fsmob-cards td[data-fsmob-label]::before {
    content: attr(data-fsmob-label);
    display: block;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 13px;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--s7, #6a7284);
    margin-bottom: 3px;
  }  /* The first cell of a row is the row's own name, so it reads as the card's heading. */
  html table.fsmob-cards tr td:first-child { font-weight: 700; font-size: 16px; }  html table.fsmob-cards tr td:first-child[data-fsmob-label]::before { content: none; }
  /* A link that is the ONLY thing in a cell owns its row once the table is a stack of cards, so it
     is a tap target rather than a word in a sentence. Measured at 19px on the SEO pages' link
     tables before this rule. */
  html table.fsmob-cards td > a:only-child {
    display: flex;
    align-items: center;
    min-height: 44px;
  }  /* The last of the measured text-size offenders, and the one place in this file that needs
     !important for a reason rather than out of habit: each of these is set by a page-local rule of
     two classes (`.page .label`, `.asc-turn .who`), which outranks one class plus an element. They
     were measured at 10 to 11.5px on /scorecard, /scorecard-guide and /scout after the rest of this
     file had already landed. */
  html .cover-cta, html .range, html .icon, html .label, html .who, html .section-label,
  html .page-num, html .cover-tag, html .cover-logo {
    font-size: 13.5px !important;
  }

  /* /scorecard-guide's letter pages reflow to the phone's width, and at 360 two of their own
     blocks were still wider than that, which put the whole page back into browser zoom-out. */
  html .cover-top, html .cover-bottom, html .cover-cta, html .page-header {
    flex-wrap: wrap;
    max-width: 100%;
    white-space: normal;
    word-break: normal;
  }
  html .cover-cta { overflow-wrap: anywhere; }
  /* The cover footer is one nowrap row of a logo and a URL, and raising the URL to a readable
     size pushed it 24px past a 360 phone, which put the page back into browser zoom-out. */
  html .cover-bottom, html .page-footer { flex-wrap: wrap; row-gap: 6px; }
  html .cover-bottom span, html .page-footer span { overflow-wrap: anywhere; }

  /* ============================================================ WIDE BLOCKS */
  /* Nothing lays out wider than the viewport. A page that does gets silently zoomed out by the
     browser, which is why /scorecard-guide read at 816 CSS px and every word on it shrank. */
  html img, html svg, html video, html iframe, html pre, html table { max-width: 100%; }
  /* Except the full-screen sheet's iframe, which is deliberately 1440 wide so the whole app screen
     is reachable by panning sideways. Capping it to 100% is what stopped it panning the first time
     this rule was written, and the sheet is the ONLY place the whole screen can be read. */
  html .fsm-sheet-body iframe { max-width: none; }  html .marq, html .mtrack { max-width: 100%; }  /* /scorecard-guide reproduces five 816 by 1056 letter pages. Scaling them to a phone would put
     its body text near 6px, so they reflow to the phone's width and keep their own type size.
     Nothing in them is removed. */
  html .page, html .page.cover, html .page.interior {
    width: 100% !important;
    min-height: 0 !important;
    height: auto !important;
    overflow: visible !important;
    margin: 16px 0 !important;
  }  html .page .grid-lines { display: none; }
  /* A decorative 600px radial glow, absolutely positioned at right:-200px inside the cover. It was
     contained by `.page{overflow:hidden}`, which the reflow above has to turn off so the content
     is not clipped; with it off the glow grew the layout to 560 CSS px and put the whole page back
     into browser zoom-out. It is decoration, so on a phone it goes. */
  html .cover::before { display: none; }
  /* The scorecard's answer options are a two-column grid of 13px prose with a 40px left indent.
     At 360 each column is 155px of usable width, so they overflowed the page by 6 to 31px. One
     column on a phone. Found only once rule A stopped excusing elements inside a clipping
     ancestor, which is what had hidden them. */
  html .score-options { grid-template-columns: 1fr !important; }
  /* Two 10px labels in the cover's own header and footer rows, set by a bare `span` rule. */
  html .cover-top span, html .cover-bottom span, html .page-footer span,
  html .cover-stat .num, html .cover-stat .label { font-size: 13.5px !important; }
  html .cover-stat-row { flex-wrap: wrap; gap: 10px 18px; }  html .cover, html .cover-top, html .cover-content, html .cover-bottom { height: auto !important; }  /* ============================================================ EXPLORER, TABS, EXPLAINERS */
  /* The capability explorer. Its own stylesheet already turns the same DOM into an accordion
     under 767 with one open at a time, so nothing here re-does that. What was missing was the
     heading clearing the sticky bar when opening one scrolls it to the top, and a heading tall
     enough to tap. explorer.js does the scrolling. */
  html .cx-item {
    min-height: 56px;
    font-size: 16.5px;
    scroll-margin-top: 72px;
  }  html .cx-copy p { font-size: 16px; line-height: 1.5; }  /* The /scout question tiles are one column (the `.agrid` rule above), and the answer card is
     moved by mobile.js to sit directly under the tile that was tapped. This is the slot it lands
     in, so the card is never a screen away from the question. */
  html #floorTiles .acard { min-height: 56px; text-align: left; }  html #floorTiles .acard .an { font-size: 16.5px; }  html .fsmob-answer-slot { margin: 4px 0 14px; }  /* The dial: the track and its thumb go, and the three labels become one full width segmented
     control above the rows. No sideways drag, and each segment is 48px tall. */
  html .ex-dial { margin-top: 12px; }  html .ex-track { display: none; }  html .ex-stops {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0;
    margin: 0 0 4px;
    border: 1px solid var(--line, #e8eaf0);
    border-radius: 12px;
    overflow: hidden;
    background: #fff;
  }  html .ex-stop {
    width: 100%;
    min-height: 48px;
    font-size: 14.5px;
    font-weight: 600;
    border: 0;
    border-left: 1px solid var(--line2, #eef0f5);
    border-radius: 0;
    padding: 8px 4px;
    background: #fff;
    color: var(--s5, #414a5c);
  }  html .ex-stop:first-child { border-left: 0; }  html .ex-stop.is-on {
    background: var(--ink, #0b0f19);
    border-color: var(--ink, #0b0f19);
    color: #fff;
  }  /* Play is a full width button and the scrubber sits under it on its own line. */
  html .ex-ctl { flex-direction: column; align-items: stretch; gap: 10px; }  html .ex-btn { width: 100%; min-height: 48px; font-size: 15.5px; }  html .ex-range { width: 100%; height: 44px; }  /* The POD stepper runs down the page with big targets rather than wrapping into pill soup. */
  html .ex-steps { flex-direction: column; align-items: stretch; gap: 8px; }  html .ex-step { min-height: 48px; font-size: 15px; border-radius: 10px; text-align: left; }  /* An explainer's own SVG labels are content, not a mockup, so they obey the 13px floor too.
     They cannot be fixed from here: a viewBox of 860 shown in 350px renders its 13 user-unit
     text at 5.3 CSS px, and no CSS font-size on the <svg> changes a user unit. explainer.js
     therefore lays every explainer out for the phone, with its own viewBox. */
  /* An explainer is built head, controls, text alternative, drawing, at every width, because the
     builder appends its svg last. At 1440 the alternative is one line and reads as a caption above
     the picture. Stacked on a phone it is eight lines, so the drawing ends up detached from the
     Play button that drives it. Reordered for the phone only: the heading, then the drawing, then
     Play, then the words. Nothing is removed and the DOM is untouched. */
  html .ex { padding: 18px 16px 16px; display: flex; flex-direction: column; }
  html .ex > .ex-head { order: 1; }
  html .ex > svg { order: 2; }
  html .ex > .ex-dial, html .ex > .ex-rows, html .ex > .ex-steps { order: 3; }
  html .ex > .ex-ctl { order: 4; }
  html .ex > .ex-alt { order: 5; margin-top: 12px; }  html .ex-title { font-size: 16.5px; }  html .ex-alt { font-size: 15px; line-height: 1.5; }  /* ============================================================ ODDS AND ENDS MEASURED */
  /* The live ticker above the nav was 9px mono, the smallest text on the site. */
  html .ticker .ticker-in { padding: 6px 20px; flex-wrap: wrap; height: auto; overflow: visible; white-space: normal; }  html .tk-live, html .tk-body { font-size: 14px; letter-spacing: .03em; }  /* The wrap was already here and bought nothing: .ticker-in also carries a fixed 30px height     and overflow:hidden from index.html's own rule, so the second line was cut and the band     read as the single word LIVE. The site's most prominent proof claim was invisible on a     phone. Measured 2026-09-20 at 390: scrollWidth 446 in a 350px box. */  html .tk-body { overflow: visible; }  /* The hero badge wraps to two lines at 390; it reads better as two lines that breathe than as
     one line that nearly fits. */
  html .badge { font-size: 14px; padding: 8px 14px; margin-bottom: 18px; align-items: flex-start; }  html .badge .d { flex: 0 0 auto; }  /* Logo walls and marquees: fewer, bigger, and they do not force a scroll. */
  html .logorow, html .wallrow { gap: 18px 26px; }  html .logorow span, html .wallrow span { font-size: 16px; }  html .mtrack { gap: 32px; }  html .mtrack span { font-size: 18px; }  /* The loop diagram runs down the page and its arrows turn with it. */
  html .loop { gap: 10px; }  html .lstage { width: 100%; min-width: 0; padding: 16px 18px; }  html .larr { transform: rotate(90deg); }  /* The consent bar is fixed and sits where the floating button and the mockups' Open bar want to
     be, so it is the thing everything else measures itself against. */
  html .ghl-consent, html #ghl-consent, html .consent-bar { padding-bottom: env(safe-area-inset-bottom, 0px); }

  /* ============================================================ PHONE PANELS */
  /* A 1440 app screen cannot be made to look right at 390 by scaling, cropping or dropping
     columns, so under this width it is not shown at all. assets/phone-panels.js builds a panel
     in its place out of the site's own tokens: the site's fonts, radii, spacing and card styles,
     at full content width. Every mockup on the page is hidden, panelled or not, and so is the
     "Open the full screen" bar and the pannable sheet it used to open. Nothing here looks
     tappable, because nothing here is. */
  /* The page reveals each section with an 0.8s fade and a 20px rise. On a phone that costs twice.
     It renders body text pale grey while a reader is scrolling past it, which reads as broken
     rather than as motion; and because a transform moves an element's measured box, the floating
     button below judges a position clear and then has the text settle on top of it. Sections are
     simply present at phone width. */
  html.fsp-on .rv { opacity: 1 !important; transform: none !important; transition: none !important; }

  html.fsp-on .fsm { display: none !important; }
  html.fsp-on .fsm-sheet, html.fsp-on .fsm-open, html.fsp-on .fsmob-more { display: none !important; }

  html.fsp-on .fsp { display: block; margin: 22px 0 0; }
  /* The screen's own name, in the site's mono eyebrow style rather than app chrome. */
  html.fsp-on .fsp-label {
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 13px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
    color: var(--accent, #2f5fe6); margin-bottom: 8px;
  }
  /* One line of plain summary, in the app's own words. It is body copy, so it takes the 16px
     floor and the 1.5 leading like every other sentence on the phone. */
  html.fsp-on .fsp-sum {
    font-size: 16px; line-height: 1.5; color: var(--s6, #545c6e);
    margin: 0 0 14px; max-width: none;
  }
  html.fsp-on .fsp-rows { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
  /* One row, one card. Whole rows only: the list ends where the last card ends, so there is no
     slice through a sentence at a bottom edge and nothing to fade. */
  html.fsp-on .fsp-row {
    border: 1px solid var(--line, #e8eaf0); border-radius: 14px; background: #fff;
    padding: 14px 16px; font-size: 16px; line-height: 1.5; color: var(--ink, #0b0f19);
    overflow-wrap: anywhere;
  }
  /* The chip leads the line and the sentence flows after it, the way the app reads the row out.
     Inline, so it can never be a lone chip on a line with empty space beside it. */
  html.fsp-on .fsp-chip {
    display: inline; white-space: nowrap;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 13px; font-weight: 700; letter-spacing: .01em;
    color: var(--s6, #545c6e);
    background: var(--mist2, #f2f4f7); border-radius: 999px;
    padding: 3px 9px; margin-right: 7px;
    box-decoration-break: clone; -webkit-box-decoration-break: clone;
  }
  /* ============================================================ FOOTER GROUPS */
  /* The four link groups, closed. Written under `fsfoot-on`, which assets/mobile.js adds only
     after it has actually built the groups, so a page with no script keeps the full stack of
     links and reads exactly as it does today. Every link stays in the document either way. */
  html.fsfoot-on footer .fcols { gap: 0; }
  html.fsfoot-on footer .fcol { min-width: 0; width: 100%; }
  html.fsfoot-on footer .fsfoot-t {
    display: flex; align-items: center; justify-content: space-between;
    width: 100%; min-height: 52px; padding: 14px 0; margin: 0;
    background: none; border: 0; border-top: 1px solid var(--line, #e8eaf0);
    text-align: left; cursor: pointer;
    /* The heading keeps the type it has as a span, so the footer reads the same. */
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 13px; letter-spacing: .06em; text-transform: uppercase;
    font-weight: 600; color: var(--s7, #6a7284);
  }
  /* The chevron is drawn, not a glyph, so it needs no font and cannot go missing. */
  html.fsfoot-on footer .fsfoot-t::after {
    content: ''; width: 9px; height: 9px; margin-right: 4px;
    border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
    transform: translateY(-3px) rotate(45deg); transition: transform .18s ease;
  }
  html.fsfoot-on footer .fsfoot-t[aria-expanded="true"]::after { transform: translateY(2px) rotate(-135deg); }
  html.fsfoot-on footer .fsfoot-t[aria-expanded="false"] + .fsfoot-g { display: none; }
  html.fsfoot-on footer .fsfoot-g { display: flex; flex-direction: column; padding: 0 0 14px; }
  html.fsfoot-on footer .fsfoot-g a { min-height: 44px; display: flex; align-items: center; }

  html.fsp-on .fsp-chip.is-bad  { color: #b4272b; background: #fdf3f3; }
  html.fsp-on .fsp-chip.is-warn { color: #8a4900; background: #fdf6ec; }
  html.fsp-on .fsp-chip.is-good { color: #0b6f49; background: #eef7f2; }
}
