/* =============================================================================
   soft-studio-chrome.css — the Soft Studio HEADER and FOOTER, sitewide.
   =============================================================================

   WHY THIS FILE EXISTS
   The v10 homepage carried the only correct Soft Studio nav, hardcoded in its
   own template with its CSS living in home-next-v10.css (homepage-only). Every
   other page rendered the legacy `.lr-navbar` — a different DOM, a different
   item set, different labels ("Sign In" vs "Log in"), and on /pricing and
   /gallery it laid out at x=-690, i.e. off the left edge of the viewport.

   This file is the single source of truth for that chrome. It is linked RAW
   and LAST in all four style chains AND on the homepage, so one definition
   paints the header and footer on every page. The nav rules were REMOVED from
   home-next-v10.css in the same change — two copies is how they drift.

   TRAPS THIS FILE IS WRITTEN AROUND (docs/DESIGN-SYSTEM-SOFT-STUDIO.md §3)
   1. Selectors may NOT depend on `body.v10`. Only the homepage carries that
      class; 241 other pages do not. Everything here is scoped to the chrome's
      own classes and prefixed with `html body` where a legacy sheet would
      otherwise win on specificity.
   2. theme-global.css applies `font-family: var(--font-clash) !important`
      universally. You cannot beat it with font-family — soft-studio.css
      re-points the variable, and the homepage restates the same repoint.
   3. theme-global.css:830 forces `color: var(--t-text-muted) !important` on
      every <span> inside `.use-case-page`. The nav and footer contain spans
      (mega descriptions, the language pill), and ~90 pages carry that body
      class, so those spans need an explicit !important reclaim below.
   4. Raw <link> assets are served `immutable, max-age=31536000` (app.js:389).
      This file's `?v=` token MUST be bumped on every edit or returning
      visitors keep the old bytes for a year — a CloudFront invalidation
      cannot reach it.

   POSITIONING NOTE
   The homepage nav was `position: sticky`, which occupies flow space. Every
   other page was built against a `position: fixed` nav and already carries its
   own hero top padding. Switching 241 pages to sticky would push every hero
   down by ~74px. So the shared nav is FIXED, and the homepage — which had no
   such padding — gets an explicit flow spacer instead. Both render the capsule
   at the same y, at the same width, over content, at rest and when scrolled.
   ========================================================================== */

/* --------------------------------------------------------------- tokens */
/* Duplicated from home-next-v10.css deliberately: this file has to stand on
   its own on the 241 pages that never load that sheet. Values are identical,
   so on the homepage (which loads both) either winner is the same colour. */
:root {
    --ink:    #141414;
    --ink-2:  #57534E;
    --ink-3:  #6B6660;   /* 4.8:1 on canvas — WCAG AA for small text */
    --paper:  #F4F2EF;   /* the canvas */
    --card:   #FFFFFF;
    --line:   #E7E4DF;

    --pink:   #FFD3F6;   /* brand — THE one hue */
    --pink-2: #FFE7FA;
    --pink-3: #FFF3FC;

    --r-pill: 999px;

    --ss-fd: 'GeneralSans', system-ui, -apple-system, sans-serif;
    --ss-ft: 'GeneralSans', system-ui, -apple-system, sans-serif;

    --ss-gut: clamp(18px, 4vw, 56px);
    --ss-max: 1380px;
    --ss-ease: cubic-bezier(0.22, 0.7, 0.28, 1);

    /* Height the fixed capsule reserves, for pages that need a flow spacer. */
    --ss-nav-h: 74px;
}

/* --------------------------------------------------- kill the legacy nav */
/* The old markup still renders — frontend_header.pug includes the shared
   Soft Studio nav now, but several templates inline their own copies of the
   legacy bars. Hiding rather than deleting keeps any JS that queries them
   from throwing. `display: none` on a fixed bar also releases its layout. */
html body .lr-navbar,
html body .tab-bar,
html body #mobile-menu.mobile-menu-drawer,
html body .lr-navbar-spacer {
    display: none !important;
}

/* ------------------------------------------------------------- skip link */
/* Hidden by CLIP, not by `left: -9999px`.
   The off-screen-left trick is LTR-only: in an RTL document the browser counts
   left overflow toward the scroll box, so a 128px link parked at -9999px made
   documentElement.scrollWidth 10389px on a 390px viewport (9999 + 390, exactly)
   — /ur/pricing was the single horizontally-scrolling page in the whole mobile
   sweep, and every RTL locale shared the bug. Clip occupies no space in any
   writing direction. */
.v10-skip {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
    white-space: nowrap; border: 0;
    background: var(--ink); color: #fff;
    border-radius: 0 0 12px 0; font-family: var(--ss-ft);
    font-size: 14px; font-weight: 600; text-decoration: none;
    z-index: 300;
}
/* `a { color: inherit }` in several sheets scores high enough to grey this
   out against the ink fill, so restate the colour at element strength. */
html body a.v10-skip { color: #fff; }
.v10-skip:focus {
    width: auto; height: auto; margin: 0; padding: 10px 16px;
    overflow: visible; clip: auto; clip-path: none;
    inset-inline-start: 12px; top: 12px;
}

/* ------------------------------------------------------------------ nav */

/* The floating capsule. Borderless and FLAT at rest — the elevation shadow
   only appears once the page is scrolled and the bar is actually floating
   over content. soft-studio-chrome.js sets .is-stuck past 8px. */
.v10-navwrap {
    position: fixed; top: 12px; left: 0; right: 0; z-index: 100;
    pointer-events: none;   /* the gutter beside the capsule stays clickable */
}
.v10-navwrap > .v10-wrap { pointer-events: none; }
.v10-navwrap .v10-nav,
.v10-navwrap .v10-mobile { pointer-events: auto; }

/* The flow spacer. Pages built against the old fixed nav already reserve
   their own top space, so this renders ONLY where the template asks for it
   (the homepage, which previously relied on the sticky nav's own flow box). */
.v10-navspacer { height: var(--ss-nav-h); }

.v10-wrap {
    max-width: var(--ss-max); margin: 0 auto;
    padding-inline: var(--ss-gut); box-sizing: border-box;
}

.v10-nav {
    background: #fff; color: var(--ink); border-radius: var(--r-pill);
    box-shadow: 0 0 0 rgba(20, 20, 20, 0);
    transition: box-shadow 220ms var(--ss-ease);
    box-sizing: border-box;
}
.v10-nav.is-stuck { box-shadow: 0 6px 24px rgba(20, 20, 20, 0.08); }
@media (prefers-reduced-motion: reduce) { .v10-nav { transition: none; } }

.v10-nav *, .v10-nav *::before, .v10-nav *::after,
.v10-mobile *, .v10-mobile *::before, .v10-mobile *::after { box-sizing: border-box; }

/* Foundation (bundled in the legacy app.css) ships `button { margin-bottom:
   1.25rem }`. On the ~11 pages that load it — /pricing, /gallery, /404,
   /size-charts and the locale pricing pages — that 20px landed under the
   burger and made the mobile capsule 64px tall against 58px everywhere else.
   Reset the block margins on the chrome's own interactive elements only, so
   .v10-mega__t (a <p>) keeps the 12px it needs and .v10-mega__row keeps its
   negative INLINE margin. */
html body .v10-nav a, html body .v10-nav button,
html body .v10-mobile a, html body .v10-mobile button {
    margin-top: 0; margin-bottom: 0;
}

.v10-nav__in {
    display: flex; align-items: center; gap: 8px;
    min-height: 62px; padding: 0 10px 0 20px;
}

/* min-height 44: the wordmark's text box is only 22px tall, which made the
   home link the smallest tap target in the capsule. The flex centring means
   the extra height costs no layout — the capsule is 62px regardless. */
.v10-logo {
    display: inline-flex; align-items: center; gap: 9px; min-height: 44px;
    font-family: var(--ss-fd); font-weight: 600; font-size: 20px;
    letter-spacing: -0.03em; margin-right: 14px; color: var(--ink);
    text-decoration: none; white-space: nowrap; flex: none;
}
html body a.v10-logo,
html body a.v10-logo:hover { color: var(--ink); text-decoration: none; }

.v10-nav__links { display: flex; align-items: center; gap: 2px; min-width: 0; }
.v10-nav__btn, .v10-nav__plain {
    display: inline-flex; align-items: center; gap: 6px;
    background: none; border: 0; border-radius: var(--r-pill);
    padding: 10px 15px; font-family: var(--ss-ft); font-size: 14.5px;
    font-weight: 500; color: var(--ink); cursor: pointer; white-space: nowrap;
    text-decoration: none; line-height: 1.2;
    transition: background-color 150ms var(--ss-ease);
}
html body .v10-nav a.v10-nav__plain,
html body .v10-nav a.v10-nav__plain:hover { color: var(--ink); text-decoration: none; }
.v10-nav__btn:hover, .v10-nav__plain:hover,
.v10-nav__btn[aria-expanded='true'] { background: var(--paper); }
.v10-caret { transition: transform 200ms var(--ss-ease); flex: none; }
.v10-nav__btn[aria-expanded='true'] .v10-caret { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .v10-caret { transition: none; } }

.v10-nav__cta { margin-left: auto; display: flex; gap: 8px; align-items: center; }

.v10-lang {
    display: inline-flex; align-items: center; gap: 6px;
    background: none; border: 0; border-radius: var(--r-pill);
    padding: 9px 12px; font-family: var(--ss-ft); font-size: 13px;
    font-weight: 600; color: var(--ink); cursor: pointer; white-space: nowrap;
    transition: background-color 150ms var(--ss-ease);
}
.v10-lang:hover { background: var(--paper); }
/* Trap #3: .use-case-page forces every span muted with !important. */
html body .v10-lang span,
html body .v10-nav span,
html body .v10-mobile span { color: inherit !important; }

/* nav CTA: ink pill on the light capsule. Written at `html body .v10-nav`
   strength because soft-studio.css re-skins a long list of legacy button
   classes at `html:root:root`, and a bare `.v10-btn` would lose to it. */
.v10-btn {
    display: inline-flex; align-items: center; justify-content: center;
    gap: 8px; border: 1px solid transparent; border-radius: var(--r-pill);
    background: var(--ink); color: #fff; font-family: var(--ss-ft);
    font-size: 14.5px; font-weight: 600; min-height: 42px; padding: 0 20px;
    cursor: pointer; text-decoration: none; white-space: nowrap;
    transition: background-color 150ms var(--ss-ease), border-color 150ms var(--ss-ease);
}
.v10-btn--ghost { background: var(--card); color: var(--ink); border-color: var(--line); }
.v10-btn--sm { min-height: 36px; padding: 0 15px; font-size: 13.5px; }
.v10-btn--lg { min-height: 46px; padding: 0 24px; font-size: 15px; }

html body .v10-nav a.v10-btn,
html body .v10-mobile a.v10-btn,
html body .v10-mobile button.v10-btn {
    background: var(--ink); color: #fff; border-color: transparent;
    min-height: 36px; padding: 0 16px; font-size: 13.5px;
    border-radius: var(--r-pill); box-shadow: none;
}
html body .v10-nav a.v10-btn:hover,
html body .v10-mobile a.v10-btn:hover { background: #000; color: #fff; }
html body .v10-nav a.v10-btn--ghost,
html body .v10-mobile a.v10-btn--ghost,
html body .v10-mobile button.v10-btn--ghost {
    background: transparent; color: var(--ink); border-color: var(--line);
}
html body .v10-nav a.v10-btn--ghost:hover,
html body .v10-mobile a.v10-btn--ghost:hover {
    border-color: var(--ink); background: transparent; color: var(--ink);
}
.v10-btn:active { transform: scale(0.98); }
@media (prefers-reduced-motion: reduce) { .v10-btn:active { transform: none; } }

/* ------------------------------------------------------------ mega panel */
/* The panel is a CARD centred under the capsule, not a full-width bar.
   `.v10-nav__item { position: static }` makes .v10-navwrap the containing
   block, so left/right:0 spans the capsule and margin-inline auto centres. */
/* `display: flex` is load-bearing, not cosmetic. As a block, the item's
   inline-flex button sat on a text baseline, so the line box grew to
   line-height + descender: 57px on the pages that load the legacy app.css
   (line-height: 24px) against 37px everywhere else — the nav items rendered
   10px higher on /pricing and /gallery than on / and /tools. Flex removes the
   baseline entirely, so the item is exactly as tall as its button on every
   page regardless of what line-height a legacy sheet inherits in. */
.v10-nav__item { position: static; display: flex; align-items: center; }
/* Same defence for the bar itself: normalise the inherited line-height so no
   legacy sheet can change the capsule's internal metrics. */
.v10-nav__in, .v10-nav__links, .v10-nav__cta { line-height: 1.2; }
.v10-mega {
    position: absolute; left: 0; right: 0; top: calc(100% + 8px);
    background: var(--card); color: var(--ink); border-radius: 24px;
    box-shadow: 0 18px 48px rgba(20, 20, 20, 0.10);
    opacity: 0; visibility: hidden; transform: translateY(-6px);
    transition: opacity 180ms var(--ss-ease), transform 180ms var(--ss-ease), visibility 180ms;
    pointer-events: auto; text-align: left;
}
.v10-nav__item[data-open] .v10-mega { opacity: 1; visibility: visible; transform: none; }
@media (prefers-reduced-motion: reduce) { .v10-mega { transition: none; } }
.v10-mega--wide { max-width: 1040px; margin-inline: auto; }
.v10-mega--mid  { max-width: 800px;  margin-inline: auto; }
.v10-mega .v10-wrap { max-width: none; padding-inline: 0; }
.v10-mega__in { padding: 26px 30px 22px; }

/* Column count comes from the data (navTree group length) via --cols, so a
   group that gains or loses a column re-lays itself with no CSS edit. */
.v10-mega__grid {
    display: grid; grid-template-columns: repeat(var(--cols, 4), minmax(0, 1fr));
    gap: 26px;
}
.v10-mega__grid--3 { --cols: 3; }
.v10-mega__t {
    font-family: var(--ss-ft); font-size: 11.5px; font-weight: 500;
    text-transform: uppercase; letter-spacing: 0.11em;
    color: var(--ink-3); margin: 0 0 12px;
}
html body .v10-mega__t { color: var(--ink-3); }
.v10-mega__row {
    display: block; padding: 8px 10px; margin: 0 -10px;
    border-radius: 12px; text-decoration: none;
    transition: background-color 130ms var(--ss-ease);
}
.v10-mega__row:hover { background: var(--paper); }
html body .v10-mega__row,
html body .v10-mega__row:hover { text-decoration: none; }
.v10-mega__row b {
    display: block; font-family: var(--ss-ft); font-weight: 700;
    font-size: 15.5px; letter-spacing: -0.01em; color: var(--ink);
}
html body .v10-mega__row b { color: var(--ink); }
/* Two lines, hard stop. A dropdown row is a signpost, not a paragraph: the
   Solutions descriptions are the full /for hub lines and ran to three lines
   each, which is what made that panel taller than the viewport. Clamping here
   caps the panel height no matter how long a future description gets, so the
   nav can never again be broken by a copy edit somewhere else. */
.v10-mega__row span {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: 13px; margin-top: 1px; line-height: 1.4;
}
html body .v10-mega__row span { color: var(--ink-2) !important; }
.v10-mega__foot {
    display: flex; flex-wrap: wrap; gap: 14px;
    justify-content: space-between; align-items: center;
    margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--line);
}
.v10-mega__foot .v10-sub { max-width: 62ch; margin: 0; font-size: 14px; }
html body .v10-mega__foot .v10-sub { color: var(--ink-2) !important; }

/* text link with arrow — padding grows the touch target without moving the
   baseline (40px tall against a 14px line) */
.v10-link {
    display: inline-flex; align-items: center; gap: 7px;
    font-family: var(--ss-ft); font-size: 14.5px; font-weight: 600;
    color: var(--ink); text-decoration: none;
    padding-block: 6px; margin-block: -6px;
}
html body a.v10-link { color: var(--ink); text-decoration: none; }
.v10-link::after { content: '\2192'; transition: transform 160ms var(--ss-ease); }
.v10-link:hover::after { transform: translateX(3px); }
@media (prefers-reduced-motion: reduce) { .v10-link:hover::after { transform: none; } }

/* ---------------------------------------------------------------- burger */
.v10-burger {
    display: none; margin-left: auto; width: 44px; height: 44px;
    background: var(--paper); border: 0; border-radius: 50%;
    cursor: pointer; flex-direction: column; align-items: center;
    justify-content: center; gap: 5px; flex: none; padding: 0;
}
.v10-burger span {
    display: block; width: 17px; height: 1.6px; background: var(--ink);
    transition: transform 200ms var(--ss-ease);
}
.v10-burger[aria-expanded='true'] span:first-child { transform: translateY(3.3px) rotate(45deg); }
.v10-burger[aria-expanded='true'] span:last-child { transform: translateY(-3.3px) rotate(-45deg); }
@media (prefers-reduced-motion: reduce) { .v10-burger span { transition: none; } }

/* ------------------------------------------------------------ mobile drawer */
.v10-mobile {
    background: var(--card); color: var(--ink);
    border-radius: 22px; box-shadow: 0 18px 48px rgba(20, 20, 20, 0.10);
    margin-top: 10px; padding: 10px 18px 18px; text-align: left;
}
.v10-mobile[hidden] { display: none; }
.v10-mobile__sec { border-bottom: 1px solid var(--line); }
.v10-mobile__sec:last-of-type { border-bottom: 0; margin-bottom: 8px; }
.v10-mobile__sec summary {
    list-style: none; cursor: pointer; padding: 14px 2px;
    font-family: var(--ss-fd); font-weight: 600; font-size: 17px;
    letter-spacing: -0.015em; position: relative; color: var(--ink);
}
.v10-mobile__sec summary::-webkit-details-marker { display: none; }
.v10-mobile__sec summary::after {
    content: '+'; position: absolute; right: 4px; top: 50%;
    transform: translateY(-50%); width: 26px; height: 26px;
    border-radius: 50%; background: var(--pink); color: var(--ink);
    font-size: 16px; display: flex; align-items: center; justify-content: center;
}
.v10-mobile__sec[open] summary::after { content: '\2013'; }
/* 44px minimum touch target on every drawer row (iOS HIG / WCAG 2.5.5). */
.v10-mobile__sec a {
    display: flex; align-items: center; min-height: 44px;
    padding: 9px 2px 9px 12px; font-size: 15px; text-decoration: none;
}
html body .v10-mobile__sec a { color: var(--ink-2); }
html body .v10-mobile__sec a:hover { color: var(--ink); }
.v10-mobile__foot { display: flex; flex-wrap: wrap; gap: 10px; padding-top: 12px; }
/* `html body .v10-mobile a.v10-btn` above scores (0,2,3) and was beating a bare
   `.v10-mobile__foot .v10-btn` (0,2,0), so the three drawer buttons kept the
   36px of `--sm` and were the only sub-44px targets left in the whole drawer.
   Matched at the same strength to win. */
html body .v10-mobile__foot a.v10-btn,
html body .v10-mobile__foot button.v10-btn {
    flex: 1 1 auto; min-height: 44px;
}

/* --------------------------------------------------------------- footer */
/* The footer markup was already shared (frontend_footer_course.pug), but it
   rendered on two different canvases: theme-global gives the HOMEPAGE
   --t-bg #FFFFFF under [data-theme=light], while soft-studio.css gives every
   other page --t-bg #F4F2EF. Same partial, two colours.
   Pinned to the HOMEPAGE's value (#FFFFFF), because the homepage is the design
   reference: other surfaces are matched to it, never the reverse. On a paper
   page this reads as a clean white band closing the document, and the footer
   itself is pixel-identical everywhere. */
html body #footerElem.dbf {
    background-color: #FFFFFF !important;
    /* --t-border, not --line. The two differ by 2/255 (#E5E5E5 vs #E7E4DF),
       which is invisible to the eye but is the ONLY thing that stopped the
       full-page homepage screenshot hashing identically before and after this
       stylesheet. --t-border is pinned to the homepage's value in the firewall
       block below, so this line is now the same colour on every page. */
    border-top: 1px solid var(--t-border) !important;
    background-image: none !important;
}

/* The giant DESIGNERBOX watermark across the footer floor. theme-global gives
   it #ededed under [data-theme=light] — a grey that is nearly the canvas
   itself — while soft-studio.css uses a token-derived ink tint. One value.
   `nowrap` + a viewport-scaled size makes it 499px wide on a 390px screen, so
   the row that holds it has to clip rather than push the document sideways. */
html body .footer-brand-statement-text { color: rgba(20, 20, 20, 0.055); }
html body .footer-brand-statement { overflow: hidden; }
html body .footer-brand-statement-text { max-width: 100%; }

/* The legal row sits at 20px tall — under WCAG 2.5.8 (AA, 24×24 minimum) on
   every page. Padding grows the hit area; the negative margin keeps the row's
   visual rhythm exactly where it was. */
html body .dbf-legal a,
html body .dbf-legal button.cookie-prefs-trigger {
    display: inline-flex; align-items: center;
    min-height: 24px; padding-block: 2px;
}

/* --------------------------------------------------------- language modal */
/* Both z-indexes clear Foundation's own modal layer (.reveal-modal-bg is 1004,
   .reveal-modal 1005, in app-critical.css). They used to be 300/299, which put
   the dialog UNDER any Foundation overlay — and that overlay carries
   backdrop-filter: blur(6px) plus rgba(0,0,0,.72) from theme-global.css, so it
   blurred and dimmed the language list itself instead of the page behind it.
   theme_v3.js no longer opens that overlay for this dialog; these two values
   are the belt-and-braces so no other caller can bury it again. */
/* `visibility` is set here, not left to Foundation. Its base rule is
   `.reveal-modal { visibility: hidden }` (app-critical.css) and only its own
   reveal JS cleared that, inline — so the v10 opener silently depended on
   Foundation opening the same dialog on the same click. */
html body #changelanguage.reveal-modal.v10-open {
    display: flex !important;
    visibility: visible !important;
    z-index: 1010;
}
.v10-scrim {
    display: none; position: fixed; inset: 0; z-index: 1009;
    background: rgba(20, 20, 20, 0.55);
}
.v10-scrim.v10-open { display: block; }

/* --------------------------------------------------------- tap targets */
/* WCAG 2.5.8 (AA, 2.2) wants 24×24 CSS px for any target that is not an
   inline link inside a block of text. These named page-level CTAs, chips and
   breadcrumbs all measured 19–23px in the mobile sweep. Growing the box with
   padding rather than font-size or margin keeps every layout identical —
   `align-items: center` absorbs the extra height inside the existing row. */
html body a.ah-card__cta,
html body a.for-ba-link,
html body a.ms-related-more,
html body a.ml-inline-link,
html body a.imj-cell-model,
html body a.uc-scenario-link,
html body a.ms-profile-link,
html body .gallery-breadcrumb a,
html body .ms-crumbs a,
html body .pl-crumb a,
html body #footer-sign-in a {
    display: inline-flex; align-items: center; min-height: 24px;
}

/* ------------------------------------------------------------ responsive */

/* 1080px is where the 5 top-level items + language pill + two buttons stop
   fitting inside the 1268px capsule. Below it the drawer takes over. */
@media (max-width: 1080px) {
    .v10-nav__links, .v10-nav__cta { display: none; }
    .v10-burger { display: flex; }
    .v10-nav__in { padding-right: 12px; }
    /* The drawer lives inside the fixed navwrap: it needs its own scroll or
       open accordions push the CTA foot off-screen forever. */
    .v10-mobile {
        max-height: calc(100dvh - 100px); overflow-y: auto;
        -webkit-overflow-scrolling: touch;
    }
}

@media (max-width: 560px) {
    /* Tighter capsule so the logo and burger keep their 44px targets on a
       390px viewport without the pill touching the gutter. */
    .v10-nav__in { min-height: 58px; padding: 0 8px 0 16px; }
    .v10-logo { font-size: 18px; margin-right: 0; }
    .v10-mobile { padding: 8px 14px 16px; }
    .v10-mobile__foot .v10-btn { flex: 1 1 100%; }
}

/* =============================================================================
   CASCADE FIREWALL — keep this block LAST in the file
   =============================================================================

   Identical markup is not identical rendering. The header and footer come from
   one partial and this one stylesheet, but they render on two very different
   cascades:

     homepage   theme-global.css + home-next-v10.css + this file        (3 sheets)
     every else + app.css + landing-redesign.css + app-ai.css +
                  app-redesign.css + soft-studio.css + uc-pages.css …  (14 sheets)

   So the chrome only looked identical on the page with no competitors. Two
   independent mechanisms broke it everywhere else, and both are invisible in
   the source — they only show up when you force the pseudo-state and read the
   computed style back out of the engine.

   ---------------------------------------------------------------------------
   MECHANISM 1 — the same token name, two different values
   ---------------------------------------------------------------------------
   soft-studio.css re-declares the whole --t-* / --db-* palette in warm Soft
   Studio neutrals. The homepage deliberately does NOT load it (see
   docs/DESIGN-SYSTEM-SOFT-STUDIO.md — loading it there repaints surfaces that
   are already signed off), so the homepage keeps theme-global's cool greys.
   Measured on #footerElem, 50 tokens resolved differently, including every one
   the footer actually paints with:

       --t-footer-link        #777777  vs  #6B6660
       --t-footer-link-hover  #333333  vs  #141414
       --db-muted             #555555  vs  #6B6660
       --t-text               #111111  vs  #141414

   Custom properties resolve where they are USED, so declaring them on the two
   chrome containers is enough: everything inside inherits these and nothing
   outside the chrome is touched. Values are the HOMEPAGE's, because the
   homepage is the design reference — other surfaces are matched to it, never
   the reverse. On the homepage this block is a no-op by construction.

   Known trade-off, flagged rather than silently "improved": #777777 on white
   is 4.48:1, a hair under the 4.5:1 WCAG AA floor for small text. That is the
   homepage's current live value. Darkening it to #6B6660 (5.68:1) is a
   one-line change here, but it would alter the homepage, so it needs a call.

   ---------------------------------------------------------------------------
   MECHANISM 2 — legacy element+state rules outrank single-class rules
   ---------------------------------------------------------------------------
   app.css carries Foundation-era rules that match bare elements:

       button, .button      { background-color: var(--primary); color: #fff }   (0,0,1)
       button:hover, :focus { background-color: var(--primary-dark); color: #fff } (0,1,1)
       a:where(…):hover, :focus { color: #4645c9 }                              (0,1,1)

   At REST a single class beats a bare element, so the chrome looked right and
   the review passed. Adding :hover puts the legacy rule at (0,1,1), which
   outranks every (0,1,0) rule in this file. Result on all 241 non-homepage
   pages: hovering a nav trigger painted its label #fff on the paper pill —
   1.09:1, i.e. invisible, which is what got reported. The same rule turned the
   mobile burger into a #4338CA indigo circle on hover and focus.

   Re-pointing --primary inside the chrome disarms every legacy rule that reads
   it, including ones not enumerated here. #4645c9 is hardcoded rather than a
   variable, so the states below are also pinned explicitly.

   Regression gate: scratchpad/chrome-state-sweep.js forces :hover and :focus on
   every interactive descendant of .v10-navwrap and #footerElem at 1440 and 390,
   and diffs the computed colours against the homepage. It must report 0.
   ========================================================================== */

html body .v10-navwrap,
html body #footerElem.dbf {
    /* Mechanism 1 — pin to the homepage's resolved values. */
    --t-text:               #111111;
    --t-text-secondary:     #555555;
    /* #6B6660, not the #777777 this block originally pinned.
       soft-studio.css:136 already corrected the GLOBAL --t-text-muted to
       #6B6660 (5.09:1 on the canvas) precisely because the old value failed
       the 4.5 AA floor for small text. This block re-pinned the pre-correction
       value inside the chrome, so the nav and footer kept shipping #777777 at
       4.48:1 — under AA, on every page of the site including the homepage.
       Measured 2026-08-12 by scripts/seo/audit-soft-studio.js against
       production: 8 distinct chrome elements failed on every page sampled
       (.dbf-tagline, .dbf-desc, .dbf-copyright, .dbf-builtby,
       .dbf-langpill__label, .app-badge__soon, .cookie-prefs-trigger, footer a).
       It read as "4 lowcontrast" on the reference page itself, which is what
       made it look like baseline noise rather than a defect.
       This raises the homepage too — an accessibility correction applied to the
       reference, NOT the reference being changed to match another page. The
       chrome stays byte-identical across every page, which is this block's
       whole purpose, so chrome-state-sweep.js still diffs to 0. */
    --t-text-muted:         #6B6660;
    --t-text-faint:         #999999;
    --t-footer-link:        #6B6660;
    --t-footer-link-hover:  #333333;
    --t-nav-link:           #555555;
    --t-nav-link-hover:     #111111;
    --t-border:             #E5E5E5;
    --t-border-mid:         #D4D4D4;
    --t-bg-card-hover:      #F3F3F3;   /* social icon discs on hover */
    --db-muted:             #555555;
    --db-ash:               #888888;
    --db-silver:            #999999;

    /* Mechanism 2 — disarm the inherited legacy accent at the source, so
       `a { color: var(--primary) }` and `button { background: var(--primary) }`
       resolve to the chrome's own ink instead of the LoadFocus-heritage indigo
       (#5D5FEF / #4338CA). */
    --primary:      #141414;
    --primary-dark: #000000;
}

/* ---------------------------------------------------------------------------
   MECHANISM 3 — inherited typography
   ---------------------------------------------------------------------------
   The chrome lives inside <body>, so it inherits whatever the page sets.
   app.css ships `body { font-weight: 300; line-height: 1.7 }`; the homepage's
   chain does not. Nothing in the chrome declared either, so both leaked in.

   Measured on the Products dropdown: the column headings computed a 19.55px
   line-height off the page (11.5px x 1.7) against 13.8px on the homepage
   (x 1.2), which by itself made the panel 6px taller, and every row
   description rendered at weight 300 instead of 400 — visibly lighter.

   Declared on the containers, not with a `*` selector: b (700), .v10-btn (600)
   and .v10-nav__btn (500) set their own weight and must keep it.

   Font FAMILY is deliberately NOT pinned here. The two chains resolve
   GeneralSans first either way and differ only in the fallbacks behind it, and
   the longer stack carries the Noto/Malgun faces that the ja, ko and zh
   locales fall back to. Matching the homepage's shorter stack would make the
   chrome's CJK rendering worse to fix something that is invisible.

   1.2 and 400 are the HOMEPAGE's own inherited values, recovered by deleting
   this rule out of the live CSSOM and re-reading the computed style — not
   picked by eye. A first attempt at 1.4 looked reasonable and made the
   homepage's own dropdown 16px taller. */
html body .v10-nav,
html body .v10-mega,
html body .v10-mobile {
    font-weight: 400;
    line-height: 1.2;
}
html body .v10-mega__t { line-height: 1.2; }
html body .v10-mega__row span { line-height: 1.4; font-weight: 400; }

/* The footer inherits the same way, and had further to fall: measured against
   the homepage, 353 footer nodes rendered at weight 300, 171 at 14.4px instead
   of 16px, and on the /tools chain 535 nodes carried a -0.16px letter-spacing
   the homepage does not have. Most of that is invisible because the leaf
   elements set their own size — but not all of it: seven badge and link boxes
   measured 2-4px narrower than the homepage's.
   Root-level only. Anything inside the footer that declares its own size or
   weight keeps it; this just stops the PAGE deciding what the shared footer
   inherits. Values are the homepage's own computed ones (16px / 1.6 / 400). */
/* Container pins only reach elements that NO rule matches — an inherited value
   loses to any matching declaration, however weak. app.css:5134 styles the bare
   element (`p { font-size: 0.9rem; font-weight: 300; line-height: 1.7 }`), so
   the chrome's two <p> classes had to be named directly. After the container
   pins these were the ONLY two boxes left differing anywhere in the header or
   footer: the mega panel's footer line measured 351x17 on the homepage and
   344x24 elsewhere. The width moved because `max-width: 62ch` resolves against
   the rendered font, and weight 300 has a narrower `0` than weight 400 — so
   fixing the weight fixed the width too. */
html body .v10-mega .v10-sub,
html body .v10-mega__foot .v10-sub {
    font-weight: 400;
    line-height: 1.2;
}

/* Values are the homepage's own computed ones (16px / 1.6 / 400 / normal).
   Verified against the homepage with scratchpad/homepage-guard.js, which
   ignores elements that occupy no space in either run — without that filter
   the mobile drawer (display:none at 1440) reports 77 line-height deltas that
   paint nothing, and reading those as a regression is how the footer pins got
   removed once and had to be put back. */
html body .v10-navwrap {
    font-size: 16px;
    letter-spacing: normal;
}
html body #footerElem.dbf {
    font-size: 16px;
    font-weight: 400;
    line-height: 1.6;
    letter-spacing: normal;
}

/* Mechanism 2, explicit states. Written at `html body` + class + state so the
   score clears the (0,1,1) legacy rules with room to spare. Per component, not
   blanket: `.v10-btn` is an ink pill whose label is legitimately #fff, and a
   blanket `color: ink` reset would break it. */
html body .v10-nav__btn:hover,
html body .v10-nav__btn:focus,
html body .v10-nav__btn:focus-visible,
html body .v10-nav__btn[aria-expanded='true'],
html body .v10-nav__plain:hover,
html body .v10-nav__plain:focus,
html body .v10-lang:hover,
html body .v10-lang:focus,
html body .v10-lang:focus-visible {
    color: var(--ink);
    background-color: var(--paper);
    border-color: transparent;
}

/* The burger is a paper disc with two ink bars, in every state. Its bars are
   painted with `background`, so only the disc and the inherited text colour
   could drift — both are pinned here. */
html body .v10-burger,
html body .v10-burger:hover,
html body .v10-burger:focus,
html body .v10-burger:focus-visible {
    color: var(--ink);
    background-color: var(--paper);
    border-color: transparent;
}
html body .v10-burger span { background: var(--ink); }

/* Mega rows: the legacy link hover also sets `border-bottom-width: 2px` and an
   indigo `border-bottom-color`. It is invisible today only because nothing sets
   a border-style — one legacy edit away from a blue underline under every row. */
html body a.v10-mega__row,
html body a.v10-mega__row:hover,
html body a.v10-mega__row:focus {
    color: var(--ink);
    border-bottom: 0;
    text-decoration: none;
}
html body a.v10-mega__row:hover { background-color: var(--paper); }

/* Footer links that are their own element rather than a `.dbf-links` child, so
   the existing `.dbf .dbf-links a` rules never covered them. */
/* --t-footer-link, NOT --t-text. The obvious-looking `--t-text` moved the
   homepage's footer wordmark from #777777 to #111111 — caught by the no-op
   check below, which is the whole reason that check exists. */
html body #footerElem a.dbf-logo,
html body #footerElem a.dbf-logo:hover,
html body #footerElem a.dbf-logo:focus {
    color: var(--t-footer-link); border-bottom: 0; text-decoration: none;
}
html body #footerElem a.app-badge,
html body #footerElem a.app-badge:hover,
html body #footerElem a.app-badge:focus,
html body #footerElem a.dbf-qr,
html body #footerElem a.dbf-qr:hover,
html body #footerElem a.dbf-qr:focus {
    color: var(--t-footer-link); border-bottom: 0; text-decoration: none;
}
html body #footerElem button.cookie-prefs-trigger,
html body #footerElem button.cookie-prefs-trigger:hover,
html body #footerElem button.cookie-prefs-trigger:focus {
    color: var(--t-footer-link);
    background-color: transparent;
    border-color: transparent;
}

/* ==========================================================================
   PHONE PASS — legibility floor and tap-target floor (2026-08-09)
   ==========================================================================
   WHY THIS FILE. It is the only stylesheet linked on ALL FIVE style chains
   (v3 slim, v3 ai, v3 legacy, the signup/login chain, and the v10 homepage),
   and it is a raw <link> loaded after every bundle. One rule here reaches the
   whole site; anywhere else needs the same rule in three to five places.

   WHAT WAS MEASURED. A hard 360px viewport (never Playwright's isMobile — that
   inflates innerWidth and hides every break) across 33 pages in the 7 live
   locales. Two defects recurred in every one of the six design systems on this
   site (uc-, hp-/lr-, ms-/msd-, mcp-, tp-/ai-, dbf-):

     1. MICRO-TYPE. Eyebrows, tags, chips, provider names, captions, spec
        labels and price units were authored at 8.5–12.8px. Those sizes are at
        the edge on a 27" display; on a phone they are past it — and most of
        them carry the meaning (the model name, the price unit, the plan tag,
        the before/after label). Worst measured: 8.5px, on the footer's
        "Coming soon" badge, in every locale.
     2. TAP TARGETS. Breadcrumbs, footer links, card CTAs and chat-card pills
        rendered 17–36px tall. WCAG 2.5.8 AA asks 24px; 44px is what Apple and
        Google both publish and what this site's own buttons already meet.

   WHY !important AND WHY html:root. Both defects live inside six systems whose
   own rules score (0,2,0) or higher — `.hp-modelstrip__tile .hp-tile__tag`
   beats any plain-class fix — and 18 page templates carry forked copies of
   their layout in an inline <head><style>, which resolves after every <link>.
   Chasing that with specificity means re-deriving a winning selector per
   system and re-checking it whenever a fork changes. This is the same pattern
   the button radius/padding standard at the bottom of theme-global.css uses,
   for the same reason: a site-wide floor that must not be quietly lost.

   WHAT THIS IS NOT. It is a FLOOR, not a rescale. Anything already at or above
   13px is untouched, no colour or font family moves, and the whole block is
   inert above 768px — the desktop rendering is byte-identical.
   ========================================================================== */

@media (max-width: 768px) {

    /* ------------------------------------------------- 1 · legibility floor */

    /* Eyebrows and section kickers, across all six systems. */
    html:root .hp-eyebrow,
    html:root .ai-hero-eyebrow,
    html:root .ent-eyebrow,
    html:root .mcp-eyebrow,
    html:root .wfx-eyebrow,
    html:root .dm-eyebrow,
    html:root .uc-stage-kicker { font-size: 13px !important; }

    /* Tags, chips and pill labels. These NAME the thing — the studio, the
       provider, the plan, the media type — so they are content, not chrome. */
    html:root .hp-tile__tag,
    html:root .hp-studio__label,
    html:root .hp-studio__chip,
    html:root .hp-modelrow .prov,
    html:root .hp-stack__rowhead span,
    html:root .hp-stack__note,
    html:root .ml-mtile__tag,
    html:root .ml-card__prov,
    html:root .ms-related-prov,
    html:root .ms-pill-seg,
    html:root .ms-char-count,
    html:root .msd-frame-label,
    html:root .uc-scenario-tool,
    html:root .uc-model-chip-type,
    html:root .uc-stage-stat-label,
    html:root .uc-stage-rail-label,
    html:root .uc-outputs-tile span,
    html:root .fl-prompt__cue,
    html:root .fa-tile-ba-label,
    html:root .pricing-studio__chip,
    html:root .credit-usage,
    html:root .discount-amount,
    html:root .badge-popular,
    html:root .dm-consent { font-size: 13px !important; }

    /* The /mcp page ships its own private mini-system of two-letter class
       names (.lbl .mp .mt .tc .fl .s .rf .pill) inside the chat mockups. Eight
       distinct sizes between 10.5 and 12.5px, all of them product copy. */
    html:root .mcp-clients .lbl,
    html:root .mcp-sc-tag,
    html:root .mcp-chat-chips span,
    html:root .mcp-chat-actions .pill,
    html:root .mcp-chat-vtime,
    html:root .mcp-audit-head .s,
    html:root .mcp-audit-row .rf,
    html:root .mcp-card .mp,
    html:root .mcp-card .mt,
    html:root .mcp-tool-h .tc,
    html:root .mcp-badge,
    html:root .mcp-tier .fl,
    html:root .mcp-row code { font-size: 13px !important; }

    /* Figure captions, spec terms, and the before/after labels on comparison
       imagery — the label is the only thing that says which frame you are
       looking at, so it cannot be the smallest type on the page. */
    html:root .ms-spec dt,
    html:root .ms-showcase-cap span,
    html:root .ms-gallery-card figcaption,
    html:root .uc-ba-item figcaption,
    html:root figure figcaption { font-size: 13px !important; }

    /* 8.5px, in the footer, on every page, in all 43 locales. The German and
       French strings ("Demnächst verfügbar", "Bientôt disponible") are three
       times the length of "Coming soon" at a third of a legible size. 11px is
       the ceiling here rather than 13 — the badge is absolutely positioned
       over the corner of a 135x40 store badge and 13px overflows it. */
    html:root .dbf .dbf-badges .app-badge__soon { font-size: 11px !important; }

    /* Same ceiling, same reason, on the app pages' floating hero cards: the
       .fl-card--b tile is ~120px wide on a phone and the tag is an absolutely
       positioned overlay inside it, so 13px wraps to two lines over the art.
       11px -> 12px is what fits. Fifteen app templates carry this inline. */
    html:root .fl-card__tag { font-size: 12px !important; }

    /* The homepage carousel panel keeps its own 12px lines (set in
       home-next-v10.css against a fixed 285px card, and measured there).
       Excluded on purpose — it is not covered by any selector above. */

    /* ------------------------------------------------ 2 · tap-target floor */

    /* Breadcrumbs. 35x19 and 35x24 — the smallest targets measured anywhere. */
    html:root .tp-breadcrumb-item a,
    html:root .ms-crumbs a {
        display: inline-block;
        padding-block: 12px !important;
    }

    /* Standalone links that close a card or a section. All were 17–24px. */
    html:root a.ah-card__cta,
    html:root a.ml-inline-link,
    html:root a.ms-related-more,
    html:root a.db-prose-link,
    html:root a.v10-link,
    html:root a.v10-tag,
    html:root .mcp-cc-foot a,
    html:root .db-auth__signup a,
    html:root .db-auth__col--form a {
        display: inline-block;
        padding-block: 11px !important;
    }

    /* Filter pills, tabs and small buttons: 29–38px. min-height guarantees the
       result rather than trusting the leading to land there. */
    html:root .filter-pill,
    html:root .trending-pill,
    html:root .ms-gen-tab,
    html:root .ms-pill,
    html:root .wfx-tab,
    html:root .v10-chip,
    html:root .mcp-copy,
    html:root .v10-btn--sm {
        min-height: 44px;
        padding-block: 10px;
    }

    /* Wordmark links box to their 26px image on the auth pages and the footer. */
    html:root a.db-auth__logo { display: inline-block; padding-block: 9px; }

    /* Nothing above animates and every property is direction-neutral or
       logical (padding-block), so reduced-motion and RTL are unaffected. */
}

/* ==========================================================================
   PHONE PASS — the same two defects, caught STRUCTURALLY (2026-08-09)
   ==========================================================================
   The hand-listed selectors above fixed the ten systems that were audited.
   Then the sweep widened to 87 pages and found the identical pair of defects
   in ten MORE systems that had not been looked at yet — dtp- (the Claude and
   Codex landing pages), imc-/imj- (the model comparison hub and its job
   pages), st- (the four studio pages), pl- (prompts, personas, skills),
   fig- (the Figma plugin page), for- (the audience hubs).

   That is not ten coincidences. Every page family on this site is built by
   copying the last one, so each new family inherits a 10.5–12.5px eyebrow, a
   10.5px overlay tag, an 11px provider name and a 17–24px card-foot link. A
   list of class names can only ever describe the families that already exist;
   the next one will ship with the same defect and no rule waiting for it.

   So this block matches on the SEMANTIC SUFFIX instead. Across every system
   the same words name the same things — eyebrow, kicker, tag, label, chip,
   badge, cost, prov, caption, note, spec, flag — because they are all copies
   of one another. Matching the suffix covers the twenty systems found so far
   AND the twenty-first, on the day it is written.

   Bounded on purpose:
     · phones only (max-width: 768px) — desktop is byte-identical
     · font-size and hit area only — no colour, family, weight or layout
     · a FLOOR at 13px — anything already larger is untouched, so this can
       never shrink text
     · the two deliberate ceilings (the footer "Coming soon" corner badge and
       the app pages' photo-overlay tags) are restated AFTER this block, which
       is where they have to be to win the tie on source order.
   ========================================================================== */

@media (max-width: 768px) {

    /* ---- the recurring micro-label vocabulary, whatever system wrote it --- */
    html:root [class*="eyebrow"],
    html:root [class*="kicker"],
    html:root [class*="-tag"],     html:root [class*="__tag"],
    html:root [class*="-label"],   html:root [class*="__label"],
    html:root [class*="chip"],
    html:root [class*="-cost"],    html:root [class*="__cost"],
    html:root [class*="-prov"],    html:root [class*="__prov"],
    html:root [class*="caption"],
    html:root [class*="-badge"],   html:root [class*="__badge"],
    html:root [class*="-note"],    html:root [class*="__note"],
    html:root [class*="__spec"],   html:root [class*="__flag"],
    /* Two-letter class names from the chat/stage mockups on /mcp, the two
       developer landings and /plugins/figma. No suffix to match, and each one
       is a model name, a media type, a tool count or a plan label. */
    html:root .prov, html:root .lbl, html:root .nm, html:root .pv,
    html:root .mp,   html:root .mt,  html:root .tc, html:root .fl,
    html:root .txt,  html:root .inl {
        font-size: 13px !important;
    }

    /* Data tables shrink their own headers, and a column header is the only
       thing that says what the column holds. */
    html:root .st-table th,
    html:root .pl-table th,
    html:root table thead th { font-size: 13px !important; }

    /* Inline code and config snippets. `~/.codex/config.toml` at 12.5px is a
       string the reader has to retype correctly. */
    html:root code, html:root pre code, html:root .dtp-code pre {
        font-size: 13px !important;
    }

    /* A config block is the one place wrapping and shrinking are BOTH wrong —
       the reader is copying it verbatim, so a broken line is a broken command.
       At 13px the longest line in the Codex snippet measures 258px inside a
       240px box, so the block scrolls sideways instead of clipping. Caught by
       the regression pass: this exact block was the only element on 87 pages
       that the 12.5px -> 13px floor pushed past its container. */
    html:root pre {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    /* ---- hit areas, matched the same structural way ---------------------- */

    /* Breadcrumbs, and the link/button rows at the foot or head of a card —
       "Copy", "Run it", "Open", "View model", "Read the docs". Measured 17-39px
       across seven systems. These are standalone controls in their own row, so
       inline-flex is safe here in a way it would not be inside prose. */
    html:root nav[class*="crumb"] a,
    html:root [class*="__foot"] > a,
    html:root [class*="__foot"] > button,
    html:root [class*="-foot"] > a,
    html:root [class*="-foot"] > button,
    html:root a[class*="__cta"],
    html:root a[class*="chip"],
    html:root button[class*="copy"],
    html:root a[class*="copy"] {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
    }

    /* Links that may sit inside running prose get padding instead of a
       display change — padding grows the hit box without breaking the line. */
    html:root a[class*="-link"],
    html:root a[class*="__link"],
    html:root a[class*="-model"],
    html:root a[class*="__go"] {
        padding-block: 10px;
    }

    /* ---- the last stragglers: names the suffix rules cannot see ---------- */
    /* Seven classes across five pages that carry no recurring suffix. Each is
       still the same kind of thing — a recommendation, a category, a verdict,
       a source citation, a tool name, a spec line. Listed rather than pattern
       matched because there is nothing in the name to pattern match on. */
    html:root .imc-job-rec strong,        /* "GPT Image 2" — the recommendation */
    html:root .cmphub-card__cat,          /* comparison card category           */
    html:root .cmphub-card__row .k,       /* "DesignerBox wins" / "Magnific wins" */
    html:root .dtp-copy span,             /* the Copy button's own label        */
    html:root .dtp-ex-chips span,         /* model names in the example chips   */
    html:root .for-metric__src,           /* the citation under a claimed number */
    html:root .for-ba-tool,               /* which tool made the After frame    */
    html:root .tc-technique-node span {   /* "2 inputs · 1 output"              */
        font-size: 13px !important;
    }

    /* ---- the deliberate ceilings, restated so they win ------------------- */
    /* Both are absolutely positioned over artwork inside a box under ~140px
       wide, where 13px wraps to a second line and covers the image. They are
       labels ON a picture, not text the reader has to parse. */
    html:root .dbf .dbf-badges .app-badge__soon { font-size: 11px !important; }
    html:root .fl-card__tag { font-size: 12px !important; }
    /* Same shape on /mobile-app: a corner flag pinned inside a 135x40 store
       badge. "Android coming soon" is already the longest string that fits. */
    html:root .ma2-gp-soon { font-size: 11px !important; }
}
