/* =====================================================================
   Proceptio Design System v2 ("Rectilinear")
   Distilled from design/cyber64-teardown.md — see design/proceptio-tokens.md
   Load BEFORE the Tailwind bundle so components can consume the tokens.
   ===================================================================== */

:root {
    /* ---- Color ---- */
    --ink: #1D1D1F;
    --ink-heading: #000000;
    --surface: #FFFFFF;
    --surface-alt: #F4F4F4;
    --brand: #7F1D1D;
    --brand-strong: #991B1B;
    --brand-deep: #450A0A;
    --brand-micro: #B45309;
    /* The SAME accent, legible on a dark ground. #B45309 measures 3.21-3.23:1 on the
       --brand-deep field, below the 4.5 AA floor for body text, which is why call sites kept
       inventing a lighter amber ad hoc. #E8A765 measures 7.8:1 on #450A0A. Do not use it on
       light grounds (it is too pale); use --brand-micro-ground and let the ground decide. */
    --brand-micro-on-dark: #E8A765;
    --brand-micro-ground: var(--brand-micro);
    --on-dark: #FFFFFF;
    /* The ONE muted step in each direction. Call sites had invented 23 ad-hoc alphas of these
       two inks (0.35 / 0.40 / 0.45 / 0.50 / 0.55 / 0.60 ...), most of which land below AA.
       --ink-soft measures 4.74:1 on white; --on-dark-soft measures 8.58:1 on --brand-deep and
       5.1:1 on the lightest proof-wall ground. Use these, not a new alpha. */
    --on-dark-soft: rgba(255, 255, 255, 0.72);
    --ink-soft: rgba(29, 29, 31, 0.62);
    --hairline: #ECECEC;
    --hairline-faint: #F3F3F3;
    --hairline-on-dark: rgba(255, 255, 255, 0.14);
    --gradient-brand: linear-gradient(118deg, #2A0606 -10%, #6B1414 58%, #D97706 215%);

    /* ---- Type ---- */
    --font-sans: 'Sora', 'Inter', ui-sans-serif, system-ui, sans-serif;
    --text-display: clamp(3rem, 6.25vw, 5.625rem);   /* 48 -> 90px, w600, lh 1.10 */
    --text-h2: clamp(2.5rem, 3.33vw, 3rem);          /* 40 -> 48px, w500, lh 1.10 */
    --text-h3: 2.125rem;                             /* 34px, w500, lh 1.20 */
    --text-stat: 1.5rem;                             /* 24px, w500 */
    --text-lede: 1.25rem;                            /* 20px, w400, lh 1.5 */
    --text-body: 0.9375rem;                          /* 15px, w300, lh 1.5 */
    --text-ui: 1.125rem;                             /* 18px, w500 */
    --text-nav: 1rem;                                /* 16px, w500 */

    /* ---- Layout ---- */
    --content-max: 1436px;
    --gutter: 80px;
    --section-pad-y: clamp(6rem, 10vw, 10rem);
    --block-gap: 4rem;
    --col-gap: 2rem;

    /* ---- Shape: flat, square, unshadowed ---- */
    --radius-avatar: 9999px;

    /* Legacy aliases — retire radius + shadow site-wide (see tokens doc D6) */
    --radius-sm: 0;
    --radius-md: 0;
    --radius-lg: 0;
    --radius-xl: 0;
    --shadow-sm: none;
    --shadow-md: none;
    --shadow-lg: none;
    --shadow-xl: none;

    /* ---- Motion ---- */
    --motion-color: 0.16s;
    --motion-ui: 0.22s;
    --motion-wipe: 0.28s;
    /* Motion system proposal (design/motion-plan.md) */
    --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
    --ease-inout: cubic-bezier(0.4, 0, 0.2, 1);
    /* Button wipe: the moment the bottom-up fill has risen PAST the label's
       cap height, so the label can swap colour over a settled ground.
       Measured, not guessed: at 24px padding / 18px-1.2 type the glyph band
       sits at 35.3%-67% of the wipe travel. 90ms is 32% into --motion-wipe,
       where the fill is at 67% under the cubic-bezier(0,0,.2,1) that Tailwind's
       own --ease-out shadows this file's with (app.css loads after this file),
       and at 85% under the one declared here — so the colour ramp starts as
       the fill clears the glyphs either way, with no dim gap in between.
       See the wipe-order note on .btn-line. */
    --wipe-cleared: 90ms;
    --motion-enter: 0.5s;
    --stagger: 90ms;
    /* Static SSR: no loading screen anymore — ignite starts almost
       immediately after first paint (app-ready lands on DOM ready). */
    --ignite-base: 120ms;
}

@media (max-width: 768px) {
    :root {
        --gutter: 24px;
        --text-h3: 1.75rem;
    }
}

/* =====================================================================
   Base type treatment
   ===================================================================== */

.t-display {
    font-size: var(--text-display);
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: normal;
}

.t-h2 {
    font-size: var(--text-h2);
    font-weight: 500;
    line-height: 1.1;
    color: var(--ink-heading);
}

.t-h3 {
    font-size: var(--text-h3);
    font-weight: 500;
    line-height: 1.2;
}

.t-lede {
    font-size: var(--text-lede);
    font-weight: 400;
    line-height: 1.5;
    letter-spacing: 0.31px;
}

/* =====================================================================
   Layout primitives
   ===================================================================== */

.shell {
    max-width: var(--content-max);
    margin-inline: auto;
    padding-inline: var(--gutter);
}

.section-pad {
    padding-block: var(--section-pad-y);
}

/* Architectural hairline frame behind section content.
   Two 1px lines at 0/100% of the content column (outer edges only; the
   25/50/75% interior lines were removed on founder note, 2026-07-21). */
.page-lines {
    position: relative;
    /* Establish a stacking context so the grid layers (::before/::after at
       z-index:-1) paint ABOVE the section background but BEHIND the content.
       Text therefore sits on top of the grid and is never sliced by a line. */
    z-index: 0;
}

.page-lines::before {
    content: "";
    position: absolute;
    z-index: -1;
    top: 0;
    bottom: 0;
    /* Span exactly the content column so background percentages are trivial */
    left: calc(max((100% - var(--content-max)) / 2, 0px) + var(--gutter));
    right: calc(max((100% - var(--content-max)) / 2, 0px) + var(--gutter));
    pointer-events: none;
    --pl-color: var(--hairline);
    background-image:
        linear-gradient(var(--pl-color), var(--pl-color)),
        linear-gradient(var(--pl-color), var(--pl-color));
    background-repeat: no-repeat;
    background-size: 1px 100%;
    background-position: 0 0, 100% 0;
}

.page-lines-dark::before {
    --pl-color: var(--hairline-on-dark);
}

/* Graph-paper layer: a single horizontal hairline at the section's TOP edge.
   Stacked full-width sections sit flush, so the top line of each section is
   also the divider from the section above — drawing a bottom line too would
   put a second hairline one pixel row below it at every boundary (the "doubled
   border", most visible where a light and a dark section meet).

   2026-07-22 (founder): the remaining top line is gone too, on full-width
   sections. Adjacent sections nearly always change background (#F4F4F4 -> white
   -> dark), and that step is ALREADY the divider; laying a darker #ECECEC
   hairline over it produced a three-tone sandwich (grey / line / white) that
   reads as a doubled border even though only one line is drawn. Sections now
   divide by their background change alone. The horizontals survive ONLY on
   nested framed cards (.page-lines-flush), which must close their own
   rectangle; the full-height VERTICALS from ::before are untouched, so the
   page grid still runs top to bottom. */
.page-lines::after {
    content: none;
    position: absolute;
    z-index: -1;
    top: 0;
    bottom: 0;
    /* Same content-column box as ::before */
    left: calc(max((100% - var(--content-max)) / 2, 0px) + var(--gutter));
    right: calc(max((100% - var(--content-max)) / 2, 0px) + var(--gutter));
    pointer-events: none;
    --pl-color: var(--hairline);
    background-repeat: no-repeat;
    background-image:
        linear-gradient(var(--pl-color), var(--pl-color));
    background-size: 100% 1px;
    background-position: 0 0;
}

.page-lines-dark::after {
    --pl-color: var(--hairline-on-dark);
}

/* Flush variant for page-lines hosts NESTED inside the content column (e.g.
   the featured partner card, which spans exactly L0-L4). The default rule
   re-applies the gutter inset inside the host, drawing its five lines 40-80px
   off the page grid; with zero inset the host's quarter-lines coincide with
   the page lines to the pixel. */
.page-lines-flush::before,
.page-lines-flush::after {
    left: 0;
    right: 0;
}

/* Nested framed cards close their own rectangle, so they are the one place that
   still draws horizontals — both top and bottom (full-width sections draw none;
   see above). content is re-enabled here because the base rule switches it off. */
.page-lines-flush::after {
    content: "";
    background-image:
        linear-gradient(var(--pl-color), var(--pl-color)),
        linear-gradient(var(--pl-color), var(--pl-color));
    background-size: 100% 1px, 100% 1px;
    background-position: 0 0, 0 100%;
}

/* No grid lines on phones (founder, 2026-07-22): below the 768px mobile
   breakpoint the content stacks to one narrow column, the gutter drops to
   24px, and the verticals sit right at the screen edges where they read as
   stray hairlines rather than an architectural grid. Drop every page-lines
   layer — the section verticals, the nested-card frames — and the logo's grid
   line in the bar. The section background steps still divide the page. */
@media (max-width: 768px) {
    .page-lines::before,
    .page-lines::after,
    .nav-cell-logo::before {
        display: none;
    }
}

/* Full-viewport hero: dark editorial photo under a brand grade, content vertically centered */
.hero-v2 {
    /* height of the client rail band at the hero's foot; the grid verticals
       stop here and the band is drawn exactly this tall */
    --rail-h: 57px;
    position: relative;
    display: flex;
    /* Column at EVERY width so the content and the trust strip can never
       collide: the content column takes the remaining height and centres
       itself in it, the trust strip sits after it. The trust strip used to be
       absolutely pinned to the hero bottom above 768px while the content was
       vertically centred in the full hero, so on a short viewport the content
       grew straight through it (108px overlap at 1024x600, the founder's
       Nest Hub). min-height (not height) lets the hero grow instead. */
    flex-direction: column;
    align-items: stretch;
    min-height: 100vh;
    min-height: 100svh;
    padding-top: 64px;
    background-color: #0A0101;
    background-image:
        linear-gradient(118deg, rgba(8, 1, 1, 0.88) 0%, rgba(16, 3, 3, 0.62) 50%, rgba(30, 6, 6, 0.28) 100%),
        url('/images/hero-lightson.webp');
    background-size: cover, cover;
    background-position: center, center;
    color: var(--on-dark);
}

/* Content column grows and centres itself in the space above the trust strip.
   Applies at every width (see the .hero-v2 note above) — it used to be
   mobile-only, which is why the desktop hero overlapped on short viewports. */
.hero-v2 > .shell {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    padding-top: 2rem;
    padding-bottom: 2.5rem;
}

.hero-trust {
    flex: 0 0 auto;
}

@media (max-width: 768px) {
    .hero-v2 {
        --rail-h: 52px;
        background-image:
            linear-gradient(118deg, rgba(8, 1, 1, 0.88) 0%, rgba(16, 3, 3, 0.66) 50%, rgba(30, 6, 6, 0.35) 100%),
            url('/images/hero-lightson-mobile.webp');
    }
}

/* Hero media stack: video(0) < grade(1) < page-lines(2) < content(3) */
.hero-v2-video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    z-index: 0;
    filter: brightness(0.78) saturate(0.95);
}

.hero-v2-grade {
    position: absolute;
    inset: 0;
    z-index: 1;
    /* Right end-stop lightened 0.45 -> 0.30 -> 0.12 (2026-07-24) so the film's
       lit-window P monogram actually READS instead of dissolving into the grade,
       and the warm building fills the right third that otherwise went empty on
       wide screens. Mid pulled 0.68@50% -> 0.60@48% so the lift starts sooner.
       Text sits left where the grade stays 0.92, so headline legibility is
       untouched. Founder call 2026-07-24: "let's try all we can" on the P. */
    background-image: linear-gradient(118deg, rgba(8, 1, 1, 0.92) 0%, rgba(14, 3, 3, 0.60) 48%, rgba(18, 4, 4, 0.12) 100%);
    pointer-events: none;
}

.hero-v2-lines {
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce), (max-width: 768px) {
    .hero-v2-video {
        display: none;
    }
}

/* Ghost button for dark surfaces */
.btn-ghost-dark {
    display: inline-flex;
    align-items: center;
    gap: 16px;
    padding: 24px;
    border: 1px solid rgba(255, 255, 255, 0.4);
    border-radius: 0;
    background-color: transparent;
    color: var(--on-dark);
    font-family: var(--font-sans);
    font-size: var(--text-ui);
    font-weight: 500;
    line-height: 1.2;
    text-decoration: none;
    cursor: pointer;
    position: relative;
    isolation: isolate;
    /* Mirror of .btn-line (see the long note there for both the compositor
       mechanism and the colour ordering): here the fill is WHITE rising over
       the dark hero, so the safe colour is again red — it reads on both
       grounds, white only reads on the dark one. Leave: hold red until the
       white fill has retreated past the glyphs, then go white. */
    transition: color var(--motion-color) var(--ease-out) var(--wipe-cleared), border-color var(--motion-ui) var(--ease-out);
}

.btn-ghost-dark::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background-color: #FFFFFF;
    transform: scaleY(0);
    transform-origin: bottom;
    transition: transform var(--motion-wipe) var(--ease-out);
}

.btn-ghost-dark:hover::before {
    transform: scaleY(1);
}

.btn-ghost-dark:hover {
    border-color: #FFFFFF;
    color: var(--brand-strong);
    /* Enter: go red at once, before the white fill reaches the glyph feet. */
    transition: color 0s, border-color var(--motion-ui) var(--ease-out);
}

.btn-ghost-dark::after {
    content: "";
    width: 16px;
    height: 16px;
    flex: none;
    background-color: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath d='M1 8h13M9 3l5 5-5 5' fill='none' stroke='black' stroke-width='1.6'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath d='M1 8h13M9 3l5 5-5 5' fill='none' stroke='black' stroke-width='1.6'/%3E%3C/svg%3E") center / contain no-repeat;
    transition: transform var(--motion-ui) var(--ease-out);
}

.btn-ghost-dark:hover::after {
    transform: translateX(4px);
}

/* Brand-moment surface (stats band, about band, testimonial card) */
.surface-gradient {
    background-image: var(--gradient-brand);
    color: var(--on-dark);
}

.surface-gradient h2, .surface-gradient h3 {
    color: var(--on-dark);
}


/* =====================================================================
   Buttons — square, hairline, arrow, wipe hover
   ===================================================================== */

.btn-fill,
.btn-line {
    display: inline-flex;
    align-items: center;
    gap: 16px;
    padding: 24px;
    border: 1px solid var(--brand);
    border-radius: 0;
    font-family: var(--font-sans);
    font-size: var(--text-ui);
    font-weight: 500;
    line-height: 1.2;
    text-decoration: none;
    cursor: pointer;
    position: relative;
    /* Own stacking context, so the fill layer's z-index:-1 resolves INSIDE the
       button: above its own background, below the label and the arrow. */
    isolation: isolate;
    /* Leave: snap the label back to red BEFORE the fill retreats past it. */
    transition: color 0s, border-color var(--motion-ui) var(--ease-out);
}

/* The bottom-up fill (2026-07-22, founder: "the effect flicks a bit").
   TWO things were wrong, and both are fixed here.

   1. MECHANISM. The fill used to be a gradient grown with background-size
      0% -> 100%. background-size is a PAINT property: it repaints the button
      every frame, on the main thread, directly over the hero film's composited
      video layer — which is what made it flicker on a real GPU (headless
      composites differently and never showed it). It is now a solid layer
      scaled on the Y axis, so the compositor animates it with no repaint at
      all. Geometry is unchanged: inset:0 resolves against the padding box,
      exactly where background-origin:padding-box used to paint, so the 1px
      border still reads as border-color.

   2. ORDER. The fill rises while the label crosses red -> white. Both used
      --ease-out, which is heavily front-loaded, so the label was already ~60%
      white while the fill had covered only half the button — pale pink glyphs
      on the still-WHITE upper half, then a snap back. The label is a
      consequence of the fill, so it now waits for it: on ENTER it holds full
      red until --wipe-cleared (the fill is past the cap height) and then ramps
      entirely over dark ground; on LEAVE it snaps back at once, before the
      fill retreats below the glyphs. Either way the label is never a mid-tone
      over a ground of the opposite value. */
.btn-fill::before,
.btn-line::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background-color: var(--brand-deep);
    transform: scaleY(0);
    transform-origin: bottom;
    transition: transform var(--motion-wipe) var(--ease-out);
}

.btn-fill:hover::before,
.btn-line:hover::before {
    transform: scaleY(1);
}

.btn-fill {
    background-color: var(--brand);
    color: var(--on-dark);
}

.btn-line {
    background-color: var(--surface);
    color: var(--brand-strong);
}

.btn-fill:hover,
.btn-line:hover {
    border-color: var(--brand-deep);
    color: var(--on-dark);
    /* Enter: hold red until the fill has cleared the glyphs. */
    transition: color var(--motion-color) var(--ease-out) var(--wipe-cleared), border-color var(--motion-ui) var(--ease-out);
}

/* Arrow glyph via mask so it inherits currentColor */
.btn-fill::after,
.btn-line::after,
.link-arrow::after {
    content: "";
    width: 16px;
    height: 16px;
    flex: none;
    background-color: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath d='M1 8h13M9 3l5 5-5 5' fill='none' stroke='black' stroke-width='1.6'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath d='M1 8h13M9 3l5 5-5 5' fill='none' stroke='black' stroke-width='1.6'/%3E%3C/svg%3E") center / contain no-repeat;
    transition: transform var(--motion-ui) var(--ease-out);
}

.btn-fill:hover::after,
.btn-line:hover::after,
.link-arrow:hover::after {
    transform: translateX(4px);
}

/* Header CTA: full-height brand block flush against the viewport's right edge */
/* Mistral-style cell header: every header element is a full-height cell
   separated by hairlines; the whole bar reads as one ruled row. */
.nav-cell {
    position: relative;
    display: inline-flex;
    align-items: center;
    height: 100%;
    padding: 0 22px;
    /* Borderless cells (founder, 2026-07-15): the bar carries only its bottom
       hairline; cell bounds appear through the hover wipe and the active tick. */
    color: var(--ink);
    font-family: var(--font-sans);
    font-size: var(--text-nav);
    font-weight: 400;
    text-decoration: none;
    transition: background-color var(--motion-color) var(--ease-out), color var(--motion-color) var(--ease-out);
}

/* Link cells: the "Lights On" hover — a warm amber glow rises from the cell's
   baseline (the hero's own metaphor), unified across the light and night bars
   (founder, 2026-07-20; superseded the full dark-red flood that read as pressed).
   Scoped to anchors so utility cells (language switcher span) stay quiet. */
a.nav-cell {
    transition: color var(--motion-ui) var(--ease-out);
}

a.nav-cell::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    opacity: 0;
    background: radial-gradient(120% 90% at 50% 118%, rgba(180, 83, 9, 0.30), rgba(180, 83, 9, 0.05) 60%, transparent 75%);
    transition: opacity 0.28s var(--ease-out);
}

a.nav-cell:hover::before {
    opacity: 1;
}

a.nav-cell:hover {
    color: var(--brand);
}

span.nav-cell:hover {
    background-color: var(--surface-alt);
}

.nav-cell.active {
    color: var(--brand);
    font-weight: 500;
}

a.nav-cell.active:hover {
    color: var(--brand);
}

/* The active page carries a 2px amber baseline tick (micro-accent, on-grid) */
.nav-cell.active::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: var(--brand-micro);
}

.nav-cell-logo {
    position: relative;
    display: inline-flex;
    align-items: center;
    height: 100%;
    /* Logo mark 24px inside grid line 0 (grid law inset) */
    padding: 0 24px;
    transition: opacity var(--motion-ui) var(--ease-out);
}

/* The logo cell cannot use the nav wipe: .nav-cell-logo::before is spoken for by the
   grid-line-0 hairline below, which overrides a.nav-cell's wipe pseudo-element. So it had
   no hover state at all, measured at 0px of change. A simple opacity step instead, which
   does not disturb the hairline. */
.nav-cell-logo:hover,
.nav-cell-logo:focus-visible {
    opacity: 0.72;
}

/* Grid line 0 carried up through the bar (founder, 2026-07-22): a full-height
   hairline on the logo cell's left edge. That edge IS grid line 0, so the line
   lands on the same x as every section's left vertical below and the page grid
   reads unbroken from the very top. Drawn as a pseudo-element, not a border, so
   the logo does not shift a pixel. */
.nav-cell-logo::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 1px;
    background: var(--hairline);
    pointer-events: none;
}

/* On the night bar (home, over the hero) the line takes the on-dark hairline */
:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-cell-logo::before {
    background: var(--hairline-on-dark);
}

/* Grid alignment (founder, 2026-07-15, revised): only the logo (line 0 + 24px)
   and the Contact block (exactly lines 3 -> 4) anchor to the page grid; the
   menu items pack naturally from the 25% line. The paddings kept the items
   narrower than the 25%-75% gap so they could never push the Contact block off
   its line.

   2026-07-27: the bar went from six cells to four, and the two compression
   steps here (14px at 1280-1439, 19px at 1440+) were what SEVEN items needed to
   clear that gap. Four items clear it at the natural 22px with room to spare
   even at 1024, which is the width the nav now appears at, so the steps are
   gone and every cell reads at one padding. If a fifth cell is ever added,
   re-measure the 25%-75% gap at 1024 FIRST; that is the tight width now, not
   1280. */

/* Header CTA: solid full-height cell flush right (Mistral "Contact sales") */
.nav-cta-block {
    gap: 12px;
    height: 100%;
    padding: 0 26px;
    background-color: var(--brand);
    color: var(--on-dark);
    font-family: var(--font-sans);
    font-size: 0.9375rem;
    font-weight: 500;
    text-decoration: none;
    background-image: linear-gradient(var(--brand-deep), var(--brand-deep));
    background-repeat: no-repeat;
    background-size: 100% 0%;
    background-position: left bottom;
    transition: background-size var(--motion-wipe) var(--ease-out);
}

.nav-cta-block::after {
    content: "";
    width: 16px;
    height: 16px;
    flex: none;
    background-color: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath d='M1 8h13M9 3l5 5-5 5' fill='none' stroke='black' stroke-width='1.6'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath d='M1 8h13M9 3l5 5-5 5' fill='none' stroke='black' stroke-width='1.6'/%3E%3C/svg%3E") center / contain no-repeat;
    transition: transform var(--motion-ui) var(--ease-out);
}

.nav-cta-block:hover {
    background-size: 100% 100%;
}

.nav-cta-block:hover::after {
    transform: translateX(4px);
}

/* Inline arrow link (e.g. "View all") */
.link-arrow {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    color: var(--brand);
    font-size: var(--text-nav);
    font-weight: 500;
    text-decoration: none;
    transition: color var(--motion-color) var(--ease-out);
}

.link-arrow:hover {
    color: var(--brand-deep);
}

/* Section link pair (2026-07-22): the section's own page as the primary
   .link-arrow, the contact CTA demoted beside it as .link-quiet. Added when
   the AI / FP&A / Apps home sections were found to link only to #contact,
   which left their pages reachable from the nav and footer alone. */
.sec-links {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px 28px;
}

.link-quiet {
    color: rgba(29, 29, 31, 0.62);
    font-size: var(--text-nav);
    font-weight: 400;
    text-decoration: none;
    padding-bottom: 2px;
    border-bottom: 1px solid rgba(29, 29, 31, 0.22);
    transition: color var(--motion-color) var(--ease-out), border-color var(--motion-color) var(--ease-out);
}

.link-quiet:hover {
    color: var(--ink);
    border-bottom-color: var(--ink);
}

/* These labels are sentences, so they wrap on narrow screens. The default
   .link-arrow is a flex row, which parks the arrow at the far right of the
   block, visibly detached from a wrapped label. Blockified here so the arrow
   is an inline mark that follows the last word instead. */
.sec-links .link-arrow,
.link-arrow-flow {
    display: block;
}

.sec-links .link-arrow::after,
.link-arrow-flow::after {
    display: inline-block;
    vertical-align: -2px;
    margin-left: 12px;
}

/* =====================================================================
   Footer — deep brand surface, hairline structure
   ===================================================================== */

.footer-v2 {
    background-color: var(--brand-deep);
    color: var(--on-dark);
}

.footer-action {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 28px 24px 28px 0;
    color: var(--on-dark);
    font-size: var(--text-ui);
    font-weight: 500;
    text-decoration: none;
    transition: color var(--motion-color) var(--ease-out);
}

.footer-action:hover {
    color: var(--brand-micro);
}

.footer-action::after {
    content: "";
    width: 16px;
    height: 16px;
    flex: none;
    background-color: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath d='M1 8h13M9 3l5 5-5 5' fill='none' stroke='black' stroke-width='1.6'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath d='M1 8h13M9 3l5 5-5 5' fill='none' stroke='black' stroke-width='1.6'/%3E%3C/svg%3E") center / contain no-repeat;
    transition: transform var(--motion-ui) var(--ease-out);
}

.footer-action:hover::after {
    transform: translateX(4px);
}

/* All action cells inset 24px, first included: the founder prefers the row
   reading as three like-padded cells over LinkedIn column-aligning with the
   flush-L0 sitemap below (decided 2026-07-12). */
@media (min-width: 768px) {
    .footer-action {
        padding-left: 24px;
    }
}

/* Every dark ground on the site flips the accent to its legible variant. Scoped rather than
   global because .tag-micro also appears on light grounds (the cookie banner, service pages),
   where #B45309 is correct and #E8A765 would be too pale. */
.surface-gradient,
.footer-v2,
.page-lines-dark,
#apps {
    --brand-micro-ground: var(--brand-micro-on-dark);
}

.footer-heading {
    color: var(--brand-micro-ground);
    font-size: 1rem;
    font-weight: 500;
    margin-bottom: 1.25rem;
}

.footer-link {
    color: var(--on-dark);
    font-size: 1rem;
    font-weight: 400;
    text-decoration: none;
    transition: color var(--motion-color) var(--ease-out);
}

.footer-link:hover {
    color: var(--brand-micro);
}

/* =====================================================================
   Micro-accents (amber) — text-sized only, never surfaces
   ===================================================================== */

.tag-micro {
    color: var(--brand-micro-ground);
    font-size: 0.875rem;
    font-weight: 500;
}

.stat-tick {
    border-left: 2px solid var(--brand-micro);
    padding-left: 24px;
}

.stat-number {
    font-size: var(--text-stat);
    font-weight: 500;
    line-height: 1.2;
    color: var(--on-dark);
}

.stat-label {
    font-size: var(--text-body);
    font-weight: 300;
    color: var(--on-dark-soft);
}

/* =====================================================================
   Wipe reveal for showcase imagery (pairs with existing
   IntersectionObserver: add .wipe-reveal, observer adds .is-visible)
   ===================================================================== */

/* Clip only once JS is confirmed loaded so imagery is never hidden without it.
   Pairs with the existing IntersectionObserver, which adds .revealed. */
.wipe-reveal {
    transition: clip-path calc(var(--motion-wipe) * 2) var(--ease-inout);
}

.js-loaded .wipe-reveal.reveal-on-scroll:not(.revealed),
.js-loaded .reveal-on-scroll:not(.revealed) .wipe-reveal {
    clip-path: inset(0 100% 0 0);
}

@media (prefers-reduced-motion: reduce) {
    .wipe-reveal {
        clip-path: none;
        transition: none;
    }

    /* The :hover variants are listed too: the wipe-order fix declares
       transition on .btn-*:hover, which would otherwise out-specify this. */
    .btn-fill, .btn-line, .btn-ghost-dark,
    .btn-fill:hover, .btn-line:hover, .btn-ghost-dark:hover,
    .btn-fill::before, .btn-line::before, .btn-ghost-dark::before,
    .btn-fill:hover::before, .btn-line:hover::before, .btn-ghost-dark:hover::before,
    .btn-fill::after, .btn-line::after, .link-arrow::after {
        transition: none;
    }
}

/* =====================================================================
   P1 "Ignite" — load entrance (motion-system preview, hero only)
   Keyed on body.app-ready so it starts exactly as the loading screen
   lifts. Without JS, app-ready never appears and content stays fully
   visible — there is no hidden-without-JS state.
   ===================================================================== */

@keyframes ignite {
    from {
        opacity: 0;
        transform: translateY(14px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

.app-ready .ignite {
    animation: ignite var(--motion-enter) var(--ease-out) both;
    animation-delay: var(--ignite-base);
}

.app-ready .ignite-2 {
    animation-delay: calc(var(--ignite-base) + var(--stagger));
}

.app-ready .ignite-3 {
    animation-delay: calc(var(--ignite-base) + var(--stagger) * 2);
}

.app-ready .ignite-4 {
    animation-delay: calc(var(--ignite-base) + var(--stagger) * 3);
}

/* Freeze after the entrance completes (motion-done set by app.js at 1.2s):
   a Blazor re-render that recreates hero DOM then shows the final state
   instead of replaying the entrance. */
html.motion-done .ignite {
    animation: none;
}

@media (prefers-reduced-motion: reduce) {
    .app-ready .ignite {
        animation: none;
    }
}

/* =====================================================================
   P3 "Count-up" support — stat cells (StatsBandSection)
   The amber top rule draws in left->right when the band reveals; the
   numbers are ticked up by app.js initStatCountUp(). Without JS the rule
   is fully drawn and numbers show their server-rendered final values.
   ===================================================================== */

.stat-cell {
    position: relative;
    padding-top: 1rem;
}

.stat-cell::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    background: var(--brand-micro);
    transform-origin: left;
    transition: transform 0.28s var(--ease-out);
}

/* In the gap-less stat grid the cells span page line to page line; the amber
   rule starts ON the line and stops 24px short of the next so the four ticks
   stay articulated instead of fusing into one band-wide bar. */
.stat-grid .stat-cell::before {
    right: 24px;
}

.js-loaded .stat-grid:not(.revealed) .stat-cell::before {
    transform: scaleX(0);
}

/* The grid carries .reveal-on-scroll only as the trigger for the tick draw;
   copy never waits for scroll (refs §4.2) — cancel the generic opacity fade. */
.js-loaded .stat-grid.reveal-on-scroll:not(.revealed) {
    opacity: 1;
}

.stat-grid .stat-cell:nth-child(2)::before { transition-delay: 90ms; }
.stat-grid .stat-cell:nth-child(3)::before { transition-delay: 180ms; }
.stat-grid .stat-cell:nth-child(4)::before { transition-delay: 270ms; }

.stat-number {
    font-variant-numeric: tabular-nums;
}

/* =====================================================================
   P6 "Ask" — the assistant exchange panel, the named-action ledger and
   the ask->answer rail (AI section). Amber-on-charcoal register: flat,
   hairline, square; amber stays text/micro-sized per the accent rule.
   ===================================================================== */

.works-with {
    font-size: 0.8125rem;
    font-weight: 300;
    color: var(--ink-soft);
}

.works-with span {
    font-weight: 500;
    color: rgba(29, 29, 31, 0.85);
}

/* The Claude skin (2026-07-15, founder call): the exchange panel looks and
   feels like claude.ai itself: cream surface, rounded product corners (a
   deliberate product-surface exception to the flat system, same status as
   photography), starburst avatar on Claude orange #D97757, tool chips.
   All [data-armed] typing machinery below is unchanged. */
.convo {
    background: #FAF9F5;
    border: 1px solid #E8E5DB;
    border-radius: 14px;
    color: #1F1E1D;
    font-size: 0.875rem;
    overflow: hidden;
}

.convo-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 11px 16px;
    border-bottom: 1px solid #EFEDE7;
    background: #FCFBF8;
}

.convo-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #DCD8CE;
    flex: none;
}

.convo-site {
    margin-left: 8px;
    font-size: 0.75rem;
    font-weight: 600;
    color: #55524B;
}

.convo-meta {
    margin-left: auto;
    font-size: 0.6875rem;
    font-weight: 300;
    color: #A5A196;
}

.convo-q {
    display: flex;
    justify-content: flex-end;
    padding: 20px 20px 0;
}

.convo-who {
    display: none;
}

.convo-qtext {
    margin: 0;
    font-weight: 400;
    color: #1F1E1D;
    min-height: 1.5em;
    background: #F0EEE6;
    border-radius: 12px;
    padding: 10px 16px;
    max-width: 85%;
}

.convo-caret {
    display: none;
}

.convo-a {
    display: grid;
    grid-template-columns: 30px 1fr;
    gap: 12px;
    padding: 18px 20px 4px;
}

.convo-av {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: #D97757;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-top: 1px;
}

.convo-av svg {
    width: 13px;
    height: 13px;
    fill: #FFFFFF;
}

.convo-src {
    margin: 0 0 8px;
    font-weight: 400;
    color: #1F1E1D;
}

.convo-row {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    padding: 9px 0;
    border-top: 1px solid #EDEBE2;
    font-weight: 300;
    color: #1F1E1D;
}

.convo-row span:first-child {
    color: #1F1E1D;
}

.convo-num {
    font-variant-numeric: tabular-nums;
    color: #55524B;
    margin-left: auto;
}

.convo-state {
    flex: none;
    width: 60px;
    text-align: right;
    color: #8F8B80;
}

.convo-risk {
    color: #A33D2B;
    font-weight: 500;
}

.convo-gate {
    margin: 14px 20px 0;
    border: 1px solid #E8E5DB;
    border-radius: 10px;
    background: #FFFFFF;
    padding: 12px 16px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px 16px;
    flex-wrap: wrap;
}

.convo-gtext {
    margin: 0;
    font-weight: 400;
    color: #1F1E1D;
}

.convo-actions {
    display: flex;
    align-items: center;
    gap: 10px;
}

/* The sign-off beat: on reveal the Approve button fills bottom-up (the
   brand wipe) and the audit line stamps after it. The static render is
   the committed state: filled button, audit visible. */
.convo-btn {
    border: 1px solid #1F1E1D;
    border-radius: 8px;
    padding: 7px 14px;
    font-size: 0.75rem;
    font-weight: 600;
    color: #FFFFFF;
    background-image: linear-gradient(#1F1E1D, #1F1E1D);
    background-repeat: no-repeat;
    background-position: 0 100%;
    background-size: 100% 100%;
    transition: background-size var(--motion-wipe) var(--ease-out) 1.05s, color var(--motion-ui) var(--ease-out) 1.12s;
}

.js-loaded .reveal-on-scroll:not(.revealed) .convo-btn {
    color: #1F1E1D;
    background-size: 100% 0;
}

.convo-dismiss {
    padding: 7px 6px;
    font-size: 0.75rem;
    font-weight: 400;
    color: #8F8B80;
}

.convo-foot {
    margin: 16px 0 0;
    padding: 12px 20px 14px;
    border-top: 1px solid #EFEDE7;
    font-size: 0.6875rem;
    font-weight: 300;
    color: #A5A196;
}

/* Typing choreography: armed by JS only (after reduced-motion and IO
   capability checks), so the server-rendered final state is never hidden
   without JS. The caret exists only while armed. */
@keyframes convo-caret {
    50% { opacity: 0; }
}

.js-loaded .convo[data-armed] .convo-caret {
    display: inline-block;
    width: 8px;
    height: 1em;
    margin-left: 3px;
    background: #D97757;
    vertical-align: text-bottom;
    animation: convo-caret 0.9s steps(1) infinite;
}

.js-loaded .convo[data-armed] .convo-a,
.js-loaded .convo[data-armed] .convo-tool,
.js-loaded .convo[data-armed] .convo-gate {
    opacity: 0;
    transform: translateY(6px);
    transition: opacity 0.5s var(--ease-out), transform 0.5s var(--ease-out);
}

.js-loaded .convo[data-armed].convo-tooled .convo-tool,
.js-loaded .convo[data-armed].convo-answered .convo-a,
.js-loaded .convo[data-armed].convo-gated .convo-gate {
    opacity: 1;
    transform: none;
}

/* Rows stream in one after another once the answer lands, like results
   coming back. Hidden only while armed, so the static render is whole. */
.js-loaded .convo[data-armed] .convo-a .convo-row {
    opacity: 0;
    transform: translateY(5px);
    transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-out);
}

.js-loaded .convo[data-armed].convo-answered .convo-a .convo-row {
    opacity: 1;
    transform: none;
}

.js-loaded .convo[data-armed].convo-answered .convo-a .convo-row:nth-child(2) { transition-delay: 0.12s; }
.js-loaded .convo[data-armed].convo-answered .convo-a .convo-row:nth-child(3) { transition-delay: 0.24s; }
.js-loaded .convo[data-armed].convo-answered .convo-a .convo-row:nth-child(4) { transition-delay: 0.36s; }

/* The named tool call: Claude shows which tool it runs before the answer
   lands. Mono like the ledger; amber mark; quiet meta. */
.convo-tool {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
    margin: 16px 20px 0;
    padding: 9px 13px;
    border: 1px solid #E8E5DB;
    border-radius: 9px;
    background: #FFFFFF;
    font-size: 0.75rem;
}

.tool-mark {
    flex: none;
    width: 6px;
    height: 6px;
    align-self: center;
    background: #D97757;
}

.tool-name {
    font-family: 'Cascadia Code', Consolas, ui-monospace, monospace;
    font-weight: 600;
    color: #1F1E1D;
}

.tool-meta {
    font-weight: 300;
    color: #8F8B80;
}

/* Story steps (Connect -> Ask -> Approve): numbered headers, captions,
   the wire diagram, and the approve panel. Native scroll; each step is a
   normal reveal-on-scroll block passing a sticky narrative column. */
.step-head {
    display: flex;
    align-items: baseline;
    gap: 24px;
    margin-bottom: 16px;
}

.step-cap {
    margin: 14px 0 0;
    font-size: 0.8125rem;
    font-weight: 300;
    line-height: 1.5;
    color: var(--ink-soft);
    max-width: 520px;
}

.wire {
    background: #16100C;
    border: 1px solid var(--hairline-on-dark);
    padding: 32px 24px 28px;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.wire-systems {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
    width: 100%;
}

.wire-systems span {
    border: 1px solid rgba(255, 255, 255, 0.18);
    padding: 14px 8px;
    text-align: center;
    font-size: 0.8125rem;
    font-weight: 400;
    color: rgba(255, 255, 255, 0.85);
}

.wire-v {
    position: relative;
    width: 1px;
    height: 28px;
    background: rgba(255, 255, 255, 0.25);
    transform-origin: top;
    transition: transform 0.45s var(--ease-out);
}

/* Signal pulse: a small amber packet travels the wire every 8s, the same
   ambient register as the ledger's grid lights. Scaled away with the
   undrawn wire, so it can never show before the draw-in. */
@keyframes wire-pulse-1 {
    0% { top: -8px; opacity: 0; }
    1.5% { opacity: 0.9; }
    6% { top: 100%; opacity: 0.9; }
    7.5% { top: 100%; opacity: 0; }
    100% { top: 100%; opacity: 0; }
}

@keyframes wire-pulse-2 {
    0%, 8.5% { top: -8px; opacity: 0; }
    10% { opacity: 0.9; }
    14.5% { top: 100%; opacity: 0.9; }
    16% { top: 100%; opacity: 0; }
    100% { top: 100%; opacity: 0; }
}

.wire-v::after {
    content: '';
    position: absolute;
    left: -1px;
    top: -8px;
    width: 3px;
    height: 8px;
    background: var(--brand-micro);
    opacity: 0;
}

.wire-v1::after {
    animation: wire-pulse-1 8s linear 1.8s infinite;
}

.wire-v2::after {
    animation: wire-pulse-2 8s linear 1.8s infinite;
}

.wire-node {
    border: 1px solid var(--brand-micro);
    color: var(--brand-micro);
    padding: 10px 22px;
    font-size: 0.8125rem;
    font-weight: 500;
    letter-spacing: 0.04em;
    transition: opacity 0.4s var(--ease-out) 0.35s;
}

.wire-assistants {
    font-size: 0.8125rem;
    font-weight: 400;
    color: rgba(255, 255, 255, 0.6);
    transition: opacity 0.4s var(--ease-out) 0.8s;
}

/* Draw-in when the step reveals (existing observer adds .revealed) */
.js-loaded .reveal-on-scroll:not(.revealed) .wire-v {
    transform: scaleY(0);
}

.js-loaded .reveal-on-scroll:not(.revealed) .wire-node,
.js-loaded .reveal-on-scroll:not(.revealed) .wire-assistants {
    opacity: 0;
}

.wire-v2 {
    transition-delay: 0.55s;
}

.js-loaded .reveal-on-scroll.revealed .wire-node {
    opacity: 1;
}

.js-loaded .reveal-on-scroll.revealed .wire-assistants {
    opacity: 1;
}

/* Approve panel: the gate plus the audit line that lands after it */
.convo-approve {
    padding: 22px 0 0;
}

.convo-approve .convo-gate {
    margin-top: 0;
}

.convo-audit {
    margin: 18px 0 0;
    padding: 12px 24px 16px;
    border-top: 1px solid var(--hairline-on-dark);
    font-size: 0.75rem;
    font-weight: 300;
    color: rgba(255, 255, 255, 0.55);
    transition: opacity 0.5s var(--ease-out) 1.5s;
}

.js-loaded .reveal-on-scroll:not(.revealed) .convo-audit {
    opacity: 0;
}

.audit-check {
    display: inline-block;
    width: 10px;
    height: 10px;
    margin-right: 8px;
    background: var(--brand-micro);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M1.5 5.5 4 8l4.5-6' fill='none' stroke='black' stroke-width='1.8'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M1.5 5.5 4 8l4.5-6' fill='none' stroke='black' stroke-width='1.8'/%3E%3C/svg%3E") center / contain no-repeat;
}

@media (prefers-reduced-motion: reduce) {
    .wire-v,
    .wire-node,
    .wire-assistants,
    .convo-audit,
    .convo-btn {
        transition: none;
    }

    .wire-v1::after,
    .wire-v2::after {
        animation: none;
    }

    .js-loaded .reveal-on-scroll:not(.revealed) .wire-v {
        transform: none;
    }

    .js-loaded .reveal-on-scroll:not(.revealed) .wire-node,
    .js-loaded .reveal-on-scroll:not(.revealed) .wire-assistants,
    .js-loaded .reveal-on-scroll:not(.revealed) .convo-audit {
        opacity: 1;
    }

    .js-loaded .reveal-on-scroll:not(.revealed) .convo-btn {
        color: #16100C;
        background-size: 100% 100%;
    }
}

/* =====================================================================
   Story-scroll v2 (measured spec: design/ai-scroll-teardown.md §5).
   The left step nav tracks the right panels. Server renders every step
   expanded and undimmed; JS arms [data-armed] on the nav only after
   reduced-motion / IO / min-width checks, so collapse and dimming exist
   only when the sync module runs. Active bar sits ON grid line L0; text
   indents 24px inside it (2px border + 22px padding, the gate motif).
   ===================================================================== */
.story-steps {
    list-style: none;
    margin-bottom: 0;
    padding: 0;
    max-width: 420px;
}

.story-steps li {
    border-left: 2px solid transparent;
    padding: 10px 0 10px 22px;
    transition: border-color var(--motion-color) var(--ease-out);
}

.story-steps a {
    display: block;
    font-size: 0.9375rem;
    font-weight: 500;
    color: #1D1D1F;
    text-decoration: none;
    transition: color var(--motion-color) var(--ease-out);
}

/* These are links and they read as links, but nothing happened on hover: the transition
   above was declared with no :hover rule to drive it. */
.story-steps a:hover,
.story-steps a:focus-visible {
    color: var(--brand);
}

.story-steps li:hover {
    border-color: var(--hairline);
}

.story-steps .step-num {
    display: inline-block;
    min-width: 34px;
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--brand-micro);
    transition: color var(--motion-color) var(--ease-out);
}

/* Description collapse: grid-rows 1fr <-> 0fr at equal duration both ways
   keeps the list's total height near-constant during a handoff (the
   Retool invariant: the sticky column never jumps). */
.story-steps .step-desc {
    display: grid;
    grid-template-rows: 1fr;
    transition: grid-template-rows 0.5s var(--ease-out), opacity 0.3s var(--ease-out);
}

.story-steps .step-desc p {
    overflow: hidden;
    min-height: 0;
    margin: 6px 0 0;
    font-size: 0.8125rem;
    font-weight: 300;
    line-height: 1.5;
    color: var(--ink-soft);
}

/* Armed: exactly one step lit, the rest collapsed and dimmed. */
/* Inactive steps were dimmed past legibility: 0.45 measured 2.84:1 and 0.35 measured 2.17:1
   against the 4.5 AA floor. These are real sentences a visitor reads, not decoration. Raised
   to the shallowest values that clear AA; the amber tick and the expanded description still
   carry the active state, so the hierarchy is unchanged. */
.js-loaded .story-steps[data-armed] li:not(.is-active) a {
    color: rgba(29, 29, 31, 0.72);
}

.js-loaded .story-steps[data-armed] li:not(.is-active) .step-num {
    color: rgba(29, 29, 31, 0.62);
}

.js-loaded .story-steps[data-armed] li:not(.is-active) .step-desc {
    grid-template-rows: 0fr;
    opacity: 0;
}

.js-loaded .story-steps[data-armed] li.is-active {
    border-color: var(--brand-micro);
}

/* Passive panels dim to 0.45 (Retool's 0.2 is a dark-page value; on our
   white page the warm-dark panels need to stay legible). Extra class
   beats the .revealed { opacity: 1 } rule on specificity. */
.js-loaded .reveal-on-scroll.revealed.is-passive {
    opacity: 0.45;
}

@media (prefers-reduced-motion: reduce) {
    .story-steps li,
    .story-steps a,
    .story-steps .step-num,
    .story-steps .step-desc,
    .convo-tool {
        transition: none;
    }
}

/* =====================================================================
   P6 step 04 "Delivered in your brand": the approved reminder as a
   finished letter, cycling three fictional client identities. Flat white
   document on the warm-dark panel, zero radius, no shadow; identity =
   logo mark + wordmark typeface + accent + footer strip, all per-layer
   CSS variables. Pure CSS cycle (10.5s, three 3.2s holds, 0.35s fades);
   reduced motion holds the first identity.
   ===================================================================== */
/* Claude-skin shell (2026-07-15): the letter preview reads as a claude.ai
   artifact window, so step 04 stops clashing with the cream register of
   steps 01-03. The chrome header comes from .convo-head. */
/* Step 04 scene (2026-07-16, the step-01/05 register): the artifact
   window floats on the warm field; a brand-kit card and a delivered
   toast overlap it as synced layers. The kit cards run the SAME
   brand-cycle timeline (10.5s, -7s/-3.5s) as the letter, so the active
   mark, palette, and typeface always match the letterhead on stage. */
.bc-scene {
    position: relative;
    padding: 34px 34px 78px;
    background:
        radial-gradient(90% 60% at 50% 6%, rgba(255, 255, 255, 0.9), transparent 60%),
        radial-gradient(70% 50% at 82% 92%, rgba(217, 119, 87, 0.16), transparent 70%),
        radial-gradient(60% 45% at 12% 78%, rgba(180, 83, 9, 0.10), transparent 70%),
        linear-gradient(175deg, #FBF7F1 0%, #F7EADF 55%, #F3DFD2 100%);
    border: 1px solid #ECECEC;
    overflow: hidden;
}

.bc-win {
    width: 82%;
    margin: 0 auto;
    background: #FAF9F5;
    border-radius: 14px;
    overflow: hidden;
    box-shadow: 0 18px 50px rgba(74, 36, 12, 0.13), 0 3px 12px rgba(74, 36, 12, 0.06);
}

/* Brand kit card: the identity swapping the letter, made explicit. */
.bc-kit {
    position: absolute;
    left: 3.5%;
    top: 40%;
    width: 176px;
    z-index: 2;
}

.bc-kit-cap {
    display: block;
    margin: 0 0 6px 2px;
    font-size: 0.5625rem;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: #8F8B80;
}

.bc-kit-stage {
    position: relative;
    height: 76px;
}

.bc-kit-card {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 10px;
    background: #FFFFFF;
    border: 1px solid #E8E5DB;
    border-radius: 12px;
    padding: 12px 14px;
    box-shadow: 0 20px 50px rgba(74, 36, 12, 0.18), 0 4px 12px rgba(74, 36, 12, 0.07);
    animation: brand-cycle 10.5s linear infinite;
}

.bc-kit-a { --doc-accent: #7F1D1D; }
.bc-kit-b { --doc-accent: #B45309; animation-delay: -7s; opacity: 0; }
.bc-kit-c { --doc-accent: #44403C; animation-delay: -3.5s; opacity: 0; }

.bc-kit-id {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

.bc-kit-mark {
    flex: none;
    width: 12px;
    height: 12px;
    background: var(--doc-accent);
}

.bc-kit-b .bc-kit-mark {
    width: 14px;
    height: 8px;
}

.bc-kit-c .bc-kit-mark {
    border-radius: 50%;
}

.bc-kit-id b {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: #1D1D1F;
}

.bc-kit-a .bc-kit-id b {
    font-family: 'Inter', sans-serif;
    font-weight: 700;
    letter-spacing: 0.10em;
    font-size: 0.625rem;
}

.bc-kit-b .bc-kit-id b {
    font-family: Georgia, 'Times New Roman', serif;
    font-weight: 400;
    font-size: 0.8125rem;
}

.bc-kit-c .bc-kit-id b {
    font-family: 'Sora', 'Inter', sans-serif;
    font-weight: 600;
    letter-spacing: 0.02em;
    font-size: 0.71875rem;
}

.bc-kit-row {
    display: flex;
    align-items: center;
    gap: 6px;
}

.bc-sw {
    width: 14px;
    height: 14px;
    border-radius: 4px;
    border: 1px solid rgba(29, 29, 31, 0.08);
}

.bc-sw-accent { background: var(--doc-accent); }
.bc-sw-ink { background: #1D1D1F; }
.bc-sw-paper { background: #F5F3EC; }

.bc-kit-row em {
    margin-left: auto;
    font-style: normal;
    font-size: 1rem;
    line-height: 1;
    color: var(--doc-accent);
}

.bc-kit-a .bc-kit-row em { font-family: 'Inter', sans-serif; font-weight: 700; }
.bc-kit-b .bc-kit-row em { font-family: Georgia, 'Times New Roman', serif; }
.bc-kit-c .bc-kit-row em { font-family: 'Sora', 'Inter', sans-serif; font-weight: 600; }

/* Delivered toast: the finished file, top layer. */
.bc-toast {
    position: absolute;
    right: 6%;
    bottom: 20px;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: 11px;
    width: min(300px, 82%);
    background: #FFFFFF;
    border: 1px solid #E8E5DB;
    border-radius: 12px;
    padding: 11px 14px;
    box-shadow: 0 24px 60px rgba(74, 36, 12, 0.20), 0 4px 14px rgba(74, 36, 12, 0.08);
}

.bc-file {
    position: relative;
    flex: none;
    width: 28px;
    height: 28px;
    border-radius: 8px;
    background: #FBF6E8;
    border: 1px solid #EFE5C8;
}

.bc-file::after {
    content: "";
    position: absolute;
    inset: 0;
    margin: auto;
    width: 12px;
    height: 14px;
    background: #B45309;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 14'%3E%3Cpath d='M1 0h7l3 3v11H1z'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 14'%3E%3Cpath d='M1 0h7l3 3v11H1z'/%3E%3C/svg%3E") center / contain no-repeat;
}

.bc-toast-tx {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.bc-toast-tx b {
    font-family: 'Cascadia Code', Consolas, ui-monospace, monospace;
    font-size: 0.6875rem;
    font-weight: 600;
    color: #1F1E1D;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    width: 0;
    min-width: 100%;
}

.bc-toast-tx span {
    font-size: 0.65625rem;
    font-weight: 300;
    color: #8F8B80;
}

.bc-done {
    position: relative;
    flex: none;
    margin-left: auto;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: #1F1E1D;
}

.bc-done::after {
    content: "";
    position: absolute;
    inset: 0;
    margin: auto;
    width: 10px;
    height: 10px;
    background: #FFFFFF;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.4 4.7 9 10 3.4' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.4 4.7 9 10 3.4' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* Scene beats: kit slides in from the left, the toast rises, then the
   check stamps. Static render is the final state. */
.bc-kit {
    transition: opacity 0.5s var(--ease-out) 0.45s, transform 0.5s var(--ease-out) 0.45s;
}

.bc-toast {
    transition: opacity 0.5s var(--ease-out) 0.8s, transform 0.5s var(--ease-out) 0.8s;
}

.js-loaded .reveal-on-scroll:not(.revealed) .bc-kit {
    opacity: 0;
    transform: translateX(-14px);
}

.js-loaded .reveal-on-scroll:not(.revealed) .bc-toast {
    opacity: 0;
    transform: translateY(12px) scale(0.97);
}

@keyframes bc-stamp {
    0% { transform: scale(0.4); opacity: 0; }
    100% { transform: scale(1); opacity: 1; }
}

.js-loaded .reveal-on-scroll.revealed .bc-done {
    animation: bc-stamp 0.4s var(--ease-out) 1.45s both;
}

@media (max-width: 639px) {
    .bc-scene {
        padding: 20px 14px 20px;
    }

    .bc-win {
        width: 100%;
    }

    .bc-kit {
        position: static;
        width: 200px;
        margin: -16px 0 0 10px;
    }

    .bc-toast {
        position: static;
        width: auto;
        max-width: 300px;
        margin: 10px 2px 0 auto;
    }
}

@media (prefers-reduced-motion: reduce) {
    .bc-kit-card {
        animation: none;
    }

    .bc-kit,
    .bc-toast {
        transition: none;
    }

    .js-loaded .reveal-on-scroll.revealed .bc-done {
        animation: none;
    }
}

/* Full width inside the panel: the letter's edges sit 20px inside the
   panel border (the grid rule), not on a floating centered cap. */
.brand-stage {
    position: relative;
    height: 252px;
    margin: 20px 20px 0;
}

@keyframes brand-cycle {
    0%, 30.5% { opacity: 1; }
    33.8%, 96.6% { opacity: 0; }
    100% { opacity: 1; }
}

.brand-doc {
    position: absolute;
    inset: 0;
    background: #FFFFFF;
    border: 1px solid #E8E5DB;
    padding: 24px;
    display: flex;
    flex-direction: column;
    animation: brand-cycle 10.5s linear infinite;
}

.brand-a { --doc-accent: #7F1D1D; }
.brand-b { --doc-accent: #B45309; animation-delay: -7s; opacity: 0; }
.brand-c { --doc-accent: #44403C; animation-delay: -3.5s; opacity: 0; }

.doc-head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 14px;
}

.doc-mark {
    flex: none;
    width: 16px;
    height: 16px;
    background: var(--doc-accent);
}

.brand-b .doc-mark {
    width: 18px;
    height: 10px;
}

.brand-c .doc-mark {
    border-radius: 50%;
}

.doc-name {
    font-size: 0.875rem;
    color: #1D1D1F;
}

/* Narrow screens: the letterhead keeps the mark + wordmark; the meta
   label yields (it would otherwise overflow the letter). */
@media (max-width: 479px) {
    .doc-meta {
        display: none;
    }
}

.brand-a .doc-name {
    font-family: 'Inter', sans-serif;
    font-weight: 700;
    letter-spacing: 0.10em;
    font-size: 0.8125rem;
}

.brand-b .doc-name {
    font-family: Georgia, 'Times New Roman', serif;
    font-weight: 400;
    font-size: 1rem;
}

.brand-c .doc-name {
    font-family: 'Sora', 'Inter', sans-serif;
    font-weight: 600;
    letter-spacing: 0.02em;
}

.doc-meta {
    margin-left: auto;
    font-size: 0.6875rem;
    font-weight: 300;
    color: rgba(29, 29, 31, 0.5);
    white-space: nowrap;
}

.doc-rule {
    display: block;
    height: 2px;
    background: var(--doc-accent);
    margin-bottom: 16px;
}

.doc-title {
    margin: 0 0 12px;
    font-size: 0.9375rem;
    font-weight: 500;
    color: #1D1D1F;
}

.brand-b .doc-title {
    font-family: Georgia, 'Times New Roman', serif;
    font-weight: 400;
}

.doc-bar {
    display: block;
    height: 7px;
    background: #ECECEC;
    margin-bottom: 8px;
}

.doc-w1 { width: 100%; }
.doc-w2 { width: 86%; }
.doc-w3 { width: 58%; }

.doc-row {
    display: flex;
    align-items: baseline;
    gap: 12px;
    margin-top: 14px;
    padding-top: 10px;
    border-top: 1px solid #ECECEC;
    font-size: 0.8125rem;
    color: #1D1D1F;
}

.doc-num {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    font-weight: 500;
}

.doc-badge {
    flex: none;
    font-size: 0.6875rem;
    font-weight: 500;
    color: var(--doc-accent);
}

.doc-foot {
    display: block;
    height: 6px;
    background: var(--doc-accent);
    margin-top: auto;
}

.brand-note {
    margin: 0;
    padding: 12px 20px 16px;
    font-size: 0.6875rem;
    font-weight: 300;
    color: #A5A196;
}

@media (prefers-reduced-motion: reduce) {
    .brand-doc {
        animation: none;
    }
}

/* Named-action ledger */
.ledger {
    position: relative;
    background: #16100C;
    border: 1px solid var(--hairline-on-dark);
}

.ledger-inner {
    padding: 40px 24px 76px;
}

@media (min-width: 768px) {
    .ledger-inner {
        padding: 48px 24px 88px;
    }
}

.ledger-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px 16px;
    flex-wrap: wrap;
    margin-bottom: 28px;
}

.ledger-note {
    font-size: 0.8125rem;
    font-weight: 300;
    color: rgba(255, 255, 255, 0.45);
}

.ledger-grid {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 10px 28px;
}

.ledger-grid li {
    font-family: 'Cascadia Code', Consolas, ui-monospace, monospace;
    font-size: 0.8125rem;
    font-weight: 400;
    color: rgba(255, 255, 255, 0.34);
}

.ledger-grid li.lit {
    color: var(--brand-micro);
}

.ledger-grid li.locked::after,
.ledger-lock {
    content: "";
    display: inline-block;
    width: 9px;
    height: 9px;
    margin-left: 6px;
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M3 4.5V3a2 2 0 0 1 4 0v1.5' fill='none' stroke='black' stroke-width='1.4'/%3E%3Crect x='1.8' y='4.5' width='6.4' height='4.5' fill='black'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M3 4.5V3a2 2 0 0 1 4 0v1.5' fill='none' stroke='black' stroke-width='1.4'/%3E%3Crect x='1.8' y='4.5' width='6.4' height='4.5' fill='black'/%3E%3C/svg%3E") center / contain no-repeat;
}

.ledger-lock {
    color: rgba(255, 255, 255, 0.6);
    margin: 0 2px;
}

.ledger-legend {
    margin: 26px 0 0;
    font-size: 0.75rem;
    font-weight: 300;
    color: rgba(255, 255, 255, 0.45);
    max-width: 640px;
}

@media (max-width: 640px) {
    .ledger-grid li:nth-child(n+25) {
        display: none;
    }
}

/* Ask->answer rail: one light asks at L1, a pulse travels the hairline,
   the light at L3 answers. Positioned on the band box itself, which is
   flush with the content column, so 25%/75% sit ON the page lines. */
.ask-rail {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 36px;
    height: 8px;
    pointer-events: none;
}

@keyframes ask-blink {
    0%, 3% { opacity: 0.15; }
    5%, 9% { opacity: 0.9; }
    11%, 14% { opacity: 0.15; }
    16%, 38% { opacity: 0.9; }
    40%, 100% { opacity: 0.15; }
}

@keyframes answer-on {
    0%, 34% { opacity: 0.15; }
    36%, 82% { opacity: 0.9; }
    84%, 100% { opacity: 0.15; }
}

@keyframes ask-travel {
    0%, 17% { left: 0; transform: translateX(0); opacity: 0; }
    19% { opacity: 1; }
    34% { left: 100%; transform: translateX(-100%); opacity: 1; }
    36%, 100% { left: 100%; transform: translateX(-100%); opacity: 0; }
}

.ask-dot,
.answer-dot {
    position: absolute;
    top: 50%;
    width: 8px;
    height: 8px;
    margin: -4px 0 0 -4px;
    background: var(--brand-micro);
    opacity: 0.15;
}

.ask-dot {
    left: 25%;
    animation: ask-blink 9s steps(1) infinite;
}

.answer-dot {
    left: 75%;
    animation: answer-on 9s steps(1) infinite;
}

.ask-path {
    position: absolute;
    left: 25%;
    right: 25%;
    top: 50%;
    height: 1px;
    margin-top: -0.5px;
    background: rgba(255, 255, 255, 0.10);
}

.ask-path::after {
    content: "";
    position: absolute;
    top: -0.5px;
    left: 0;
    width: 36px;
    height: 2px;
    background: linear-gradient(90deg, transparent, var(--brand-micro));
    opacity: 0;
    animation: ask-travel 9s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
    .ask-dot,
    .answer-dot,
    .ask-path::after,
    .js-loaded .convo[data-armed] .convo-caret {
        animation: none;
    }

    .js-loaded .convo[data-armed] .convo-a,
    .js-loaded .convo[data-armed] .convo-gate {
        opacity: 1;
        transform: none;
        transition: none;
    }
}

/* =====================================================================
   Polish + guardrails
   ===================================================================== */

/* FocusOnNavigate programmatically focuses the page h1; keep the focus for
   assistive tech but don't draw a ring around the headline. */
main h1:focus {
    outline: none;
}

@media (prefers-reduced-motion: reduce) {
    .carousel-track-right {
        animation: none;
    }

    .stat-cell::before,
    .js-loaded .stat-grid:not(.revealed) .stat-cell::before {
        transform: none;
        transition: none;
    }
}

/* =====================================================================
   Service artifact interiors — the miniature product surfaces (document
   extraction, forecast bars, queue rows) shared by the services bento v3
   (st-* kit, end of file) and the service pages.
   ===================================================================== */

/* 02 — document extraction */
.sv-doc {
    display: grid;
    grid-template-columns: 56px 1fr;
    gap: 0.875rem;
    align-items: start;
}

.sv-doc-page {
    height: 76px;
    border: 1px solid #DDDDDD;
    background: repeating-linear-gradient(var(--surface) 0 7px, var(--surface-alt) 7px 9px);
    position: relative;
}

.sv-doc-page::after {
    content: "";
    position: absolute;
    top: 5px;
    left: 5px;
    width: 22px;
    height: 4px;
    background: var(--brand);
}

.sv-doc-row {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.3rem 0;
    border-bottom: 1px solid #ECECEC;
    font-size: 0.75rem;
    font-weight: 300;
}

.sv-doc-row b {
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.sv-ok {
    color: var(--brand-micro);
}

/* 03 — actuals vs forecast bars */
.sv-bars {
    display: flex;
    align-items: flex-end;
    gap: 6px;
    height: 76px;
}

.sv-bars i {
    display: block;
    width: 16px;
    background: #D8D4CE;
}

.sv-bars i.sv-f {
    background: var(--brand-micro);
}

/* 04 — queue rows */
.sv-queue {
    border-top: 1px solid #ECECEC;
}

.sv-queue-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem;
    padding: 0.45rem 0;
    border-bottom: 1px solid #ECECEC;
    font-size: 0.75rem;
    font-weight: 300;
}

.sv-pill {
    padding: 0.1rem 0.5rem;
    border: 1px solid #DDDDDD;
    font-size: 0.625rem;
    letter-spacing: 0.04em;
}

.sv-pill-hot {
    background: var(--brand);
    border-color: var(--brand);
    color: var(--on-dark);
}

.sv-cap {
    margin: 0.25rem 0 0;
    font-size: 0.6875rem;
    font-weight: 300;
    color: rgba(29, 29, 31, 0.55);
}

/* =====================================================================
   Proof wall v2 — StatsBandSection (2026-07-21, /preview/proofwall
   direction A, founder-chosen). Outcomes are the hero: a designed
   before -> after delta with a collapse bar that shrinks to the after
   value on reveal; vanity stats demoted to the count-up rail below.
   Lives on the dark surface-gradient band; hairlines are white/14.
   The rail keeps .stat-number so initStatCountUp() ticks it; the bars
   ride the existing .reveal-on-scroll -> .revealed trigger.
   ===================================================================== */

/* Two-tone run-on statement (matches ServicesSection headline pattern) */
.proof-statement {
    font-family: var(--font-sans);
    font-size: clamp(1.5rem, 1rem + 1.9vw, 2.25rem);
    font-weight: 600;
    line-height: 1.18;
    letter-spacing: -0.01em;
    max-width: 52ch;
    margin: 0 0 3rem;
    color: var(--on-dark);
}

.proof-statement span {
    color: rgba(255, 255, 255, 0.42);
}

/* Outcome wall: equal-height grid, aligned bottoms (v1's masonry left a
   ragged bottom edge). Quarter columns so each edge sits on a page line.
   Each card spans FOUR shared row tracks (flag / delta / cut / attr)
   and re-uses them via subgrid, so those four horizontal lines are identical
   in all four cards no matter how many lines a flag or attribution wraps to.
   grid-auto-rows cycles the pattern, so the 2-col and 1-col stacks align too.
   Open on the left and right (2026-07-22, founder): only horizontal rules and
   the internal column dividers, no outer vertical frame. */
.proof-wall {
    display: grid;
    grid-template-columns: 1fr;
    grid-auto-rows: auto auto auto 1fr;
    gap: 0;
    border-top: 1px solid var(--hairline-on-dark);
}

@media (min-width: 640px) {
    .proof-wall { grid-template-columns: 1fr 1fr; }
}

@media (min-width: 1024px) {
    .proof-wall { grid-template-columns: repeat(4, 1fr); }
}

.proof-card {
    display: grid;
    grid-row: span 4;
    grid-template-rows: subgrid;
    padding: 1.75rem 1.5rem 1.5rem;
    border-bottom: 1px solid var(--hairline-on-dark);
    transition: background-color 0.3s var(--ease-out), transform 0.3s var(--ease-out);
}

/* Column dividers only between cards, never on the wall's outer edges. */
@media (min-width: 640px) {
    .proof-card { border-right: 1px solid var(--hairline-on-dark); }
    .proof-card:nth-child(2n) { border-right: 0; }
}

@media (min-width: 1024px) {
    .proof-card:nth-child(2n) { border-right: 1px solid var(--hairline-on-dark); }
    .proof-card:nth-child(4n) { border-right: 0; }
}

/* Fallback for engines without subgrid: flex column, bottoms still align. */
@supports not (grid-template-rows: subgrid) {
    .proof-card {
        display: flex;
        flex-direction: column;
    }

    .proof-attr { margin-top: auto; }
}

@media (hover: hover) {
    .proof-card:hover {
        background: rgba(255, 255, 255, 0.035);
        transform: translateY(-2px);
    }
}

.proof-flag {
    display: block;
    margin-bottom: 1.25rem;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #E8A765;
}

/* Delta row: before struck + muted, after big + warm. Single line, never
   wraps — the cut badge sits on its own row below so all four read alike. */
.proof-delta {
    display: flex;
    align-items: baseline;
    flex-wrap: nowrap;
    gap: 0.6rem;
    margin-bottom: 0.75rem;
}

.proof-before {
    font-size: 1rem;
    font-weight: 400;
    white-space: nowrap;
    /* The before/after delta is carried by SIZE (16px vs the 30px amber after), the
       strikethrough and the colour change, so this can meet AA without flattening the
       hierarchy. It was 0.5, which measured 3.79-4.42:1 across the gradient's warm shoulder. */
    color: var(--on-dark-soft);
    text-decoration: line-through;
    text-decoration-color: rgba(255, 255, 255, 0.3);
    text-decoration-thickness: 1px;
}

.proof-before em {
    font-style: normal;
    /* 0.75rem, not 0.8em: the em resolved against a 16px parent to 12.8px, a size that
       exists nowhere else in the scale. Snapping to the 12px step removes a scale leak
       with no visible change. */
    font-size: 0.75rem;
    color: var(--on-dark-soft);
}

.proof-arrow {
    font-size: 1.05rem;
    color: rgba(255, 255, 255, 0.45);
    transform: translateY(1px);
}

.proof-after {
    font-family: var(--font-sans);
    font-size: 1.9rem;
    font-weight: 600;
    line-height: 1;
    letter-spacing: -0.01em;
    white-space: nowrap;
    color: #F5B36B;
    font-variant-numeric: tabular-nums;
}

/* Own row, left-aligned: flag, delta, badge and attribution all start
   on the same left line, and the four badges share one baseline. */
.proof-cut {
    justify-self: start;
    align-self: start;
    margin-bottom: 1.25rem;
    padding: 0.2rem 0.45rem;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    white-space: nowrap;
    color: #F5B36B;
    border: 1px solid rgba(245, 179, 107, 0.4);
}

.proof-attr {
    align-self: start;
    margin: 0;
    font-size: 0.75rem;
    font-weight: 300;
    line-height: 1.5;
    color: var(--on-dark-soft);
}

/* Demoted vanity rail */
.proof-rail {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    margin-top: 2.5rem;
    border-top: 1px solid var(--hairline-on-dark);
}

@media (min-width: 640px) {
    .proof-rail { grid-template-columns: repeat(4, 1fr); }
}

.proof-stat {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    padding: 1rem 1.25rem 0;
    border-right: 1px solid var(--hairline-on-dark);
}

.proof-stat:last-child {
    border-right: 0;
}

.proof-rail .stat-number {
    font-family: var(--font-sans);
    /* 1.125rem (18px), not 1.15rem (18.4px) — same step, one fewer size in the scale. */
    font-size: 1.125rem;
    font-weight: 600;
    color: var(--on-dark);
    font-variant-numeric: tabular-nums;
}

.proof-stat-label {
    font-size: 0.75rem;
    font-weight: 300;
    color: var(--on-dark-soft);
}

@media (prefers-reduced-motion: reduce) {
    .proof-card {
        transition: none;
    }
}

/* =====================================================================
   MCP scene — AISection step 01 (2026-07-15, live-HTML version of the
   Retool-register composition, founder call: no rendered images, the
   panel IS the page). ERP window above, connector rail through the MCP
   node, Claude below in the connected-and-ready state. Rounded corners
   and soft shadows are the product-surface exception, scoped to .ms-*.
   ===================================================================== */

.ms-scene {
    position: relative;
    padding: 34px 34px 0;
    background:
        radial-gradient(90% 60% at 50% 6%, rgba(255, 255, 255, 0.9), transparent 60%),
        radial-gradient(70% 50% at 82% 92%, rgba(217, 119, 87, 0.16), transparent 70%),
        radial-gradient(60% 45% at 12% 78%, rgba(180, 83, 9, 0.10), transparent 70%),
        linear-gradient(175deg, #FBF7F1 0%, #F7EADF 55%, #F3DFD2 100%);
    border: 1px solid #ECECEC;
    overflow: hidden;
}

.ms-win {
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 18px 50px rgba(74, 36, 12, 0.13), 0 3px 12px rgba(74, 36, 12, 0.06);
}

.ms-erp {
    width: 88%;
    margin: 0 auto;
    background: #FFFFFF;
    font-size: 0.75rem;
}

.ms-erp-bar {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 9px 14px;
    border-bottom: 1px solid #EFEDE7;
}

.ms-erp-bar i {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #DCD8CE;
}

.ms-erp-bar span {
    margin-left: 7px;
    font-size: 0.6875rem;
    font-weight: 600;
    color: #6E6B63;
}

.ms-erp-bar em {
    margin-left: auto;
    font-style: normal;
    font-size: 0.625rem;
    color: #A5A196;
}

.ms-erp-table {
    width: 100%;
    border-collapse: collapse;
}

.ms-erp-table th {
    text-align: left;
    font-size: 0.5625rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #8F8B80;
    font-weight: 600;
    padding: 6px 14px;
    background: #FBFAF7;
    border-bottom: 1px solid #F1EFE9;
}

.ms-erp-table td {
    padding: 8px 14px;
    border-bottom: 1px solid #F4F2EC;
    color: #1F1E1D;
    font-variant-numeric: tabular-nums;
    font-weight: 400;
}

.ms-erp-table .num {
    text-align: right;
}

.ms-pill {
    font-size: 0.5625rem;
    font-weight: 600;
    border-radius: 20px;
    padding: 2px 8px;
    white-space: nowrap;
}

.ms-pill-over { color: #A33D2B; background: #FBEAE5; }
.ms-pill-due  { color: #A38942; background: #FBF4E0; }
.ms-pill-paid { color: #4E7D52; background: #E9F2E9; }

.ms-erp-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 14px;
    background: #FBFAF7;
    border-top: 1px solid #F1EFE9;
    font-size: 0.6875rem;
    color: #6E6B63;
}

.ms-conn {
    display: flex;
    align-items: center;
    gap: 6px;
}

.ms-conn i {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #5FA05F;
}

.ms-mono {
    font-family: 'Cascadia Code', Consolas, ui-monospace, monospace;
    font-size: 0.625rem;
    color: #8F8B80;
}

/* connector rail */
.ms-rail {
    position: relative;
    height: 120px;
}

.ms-rail-line {
    position: absolute;
    left: 50%;
    top: 0;
    bottom: 0;
    width: 1px;
    background: #CBB9A6;
}

@keyframes ms-pulse {
    0% { top: -6px; opacity: 0; }
    6% { opacity: 0.9; }
    46% { top: calc(100% - 2px); opacity: 0.9; }
    52%, 100% { top: calc(100% - 2px); opacity: 0; }
}

.ms-rail-pulse {
    position: absolute;
    left: calc(50% - 1px);
    top: -6px;
    width: 3px;
    height: 7px;
    background: #D97757;
    opacity: 0;
    animation: ms-pulse 5s var(--ease-out) infinite;
}

.ms-node {
    position: absolute;
    left: 50%;
    top: 42%;
    transform: translate(-50%, -50%) rotate(45deg);
    width: 52px;
    height: 52px;
    background: #FFFDFA;
    border: 1px solid #CBB9A6;
    border-radius: 12px;
    box-shadow: 0 6px 20px rgba(74, 36, 12, 0.10);
}

.ms-node i {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    transform: rotate(-45deg);
    font-style: normal;
    font-family: 'Cascadia Code', Consolas, ui-monospace, monospace;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    color: #7A766B;
}

/* Claude window, dark mode, connected-and-ready state */
.ms-claude {
    position: relative;
    background: #262624;
    border-radius: 14px 14px 0 0;
    box-shadow: 0 -14px 44px rgba(74, 36, 12, 0.10);
}

.ms-tile {
    position: absolute;
    top: -24px;
    left: 50%;
    transform: translateX(-50%);
    width: 48px;
    height: 48px;
    border-radius: 12px;
    background: #D97757;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 8px 24px rgba(160, 60, 20, 0.35), 0 0 0 5px rgba(255, 253, 250, 0.85);
}

.ms-tile svg {
    width: 24px;
    height: 24px;
    fill: #FFFFFF;
}

.ms-claude-inner {
    max-width: 480px;
    margin: 0 auto;
    padding: 40px 22px 24px;
}

.ms-status {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    font-size: 0.6875rem;
    color: #A6A29A;
    margin-bottom: 14px;
}

.ms-status b {
    color: #ECEAE4;
    font-weight: 600;
}

.ms-status i {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #8FBC8F;
    font-style: normal;
}

.ms-composer {
    border: 1px solid #45443F;
    border-radius: 12px;
    background: #30302E;
    padding: 12px 14px 10px;
}

.ms-composer-ph {
    color: #8A867D;
    font-size: 0.8125rem;
}

.ms-composer-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 12px;
}

.ms-composer-row .plus {
    color: #8A867D;
    font-size: 0.875rem;
    line-height: 1;
}

.ms-send {
    width: 26px;
    height: 26px;
    border-radius: 7px;
    background: #D97757;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #FFFFFF;
    font-size: 0.75rem;
    line-height: 1;
}

@media (prefers-reduced-motion: reduce) {
    .ms-rail-pulse {
        animation: none;
    }
}

/* Compact Claude panel — services bento cell 01 (static; the typed panel
   with [data-convo] lives in the AI section, one per page) */
.convo-mini {
    font-size: 0.8125rem;
}

.convo-mini .convo-q {
    padding: 14px 14px 0;
}

.convo-mini .convo-qtext {
    padding: 8px 12px;
    border-radius: 10px;
}

.convo-mini .convo-tool {
    margin: 12px 14px 0;
    padding: 7px 11px;
    font-size: 0.6875rem;
}

.convo-mini .convo-a {
    padding: 13px 14px 12px;
    grid-template-columns: 26px 1fr;
    gap: 9px;
}

.convo-mini .convo-av {
    width: 22px;
    height: 22px;
}

.convo-mini .convo-av svg {
    width: 11px;
    height: 11px;
}

.convo-mini .convo-row {
    padding: 6px 0;
    font-size: 0.75rem;
}

/* Held chip in the step-03 approval rows (Claude skin) */
.convo-held {
    flex: none;
    align-self: center;
    font-size: 0.5625rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #A38942;
    background: #FBF6E8;
    border: 1px solid #EFE5C8;
    border-radius: 5px;
    padding: 2px 7px;
}


/* =====================================================================
   Real marks (2026-07-15, founder call): the actual Claude spark (via
   simple-icons) as a shared mask; Copilot ships as the official favicon
   PNG (wwwroot/images/logo-copilot.png); MCP's official mark is inlined
   where used. The spark renders wherever .claude-spark appears.
   ===================================================================== */

.claude-spark::before {
    content: "";
    display: block;
    width: 100%;
    height: 100%;
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22m4.7144%2015.9555%204.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608%201.5179.1032%202.2767.1578%201.6514.0972%202.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973%209.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686%201.9064%201.4754%202.4893%201.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335%206.6997%200l.9957.1336.419.3642.6192%201.4147%201.0018%202.2282%201.5543%203.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853%201.8517-.5586%202.9021-.3643%201.9429h.2125l.2429-.2429.9835-1.3053%201.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759%201.1293-.34%201.1657-1.0625%201.3478-.8804%201.1414-1.2628%201.7-.7893%201.36.0729.1093.1882-.0183%202.8535-.607%201.5421-.2794%201.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607%201.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929%201.0686%202.0035%201.8092%202.5075%202.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496%202.3436%203.5214.1214%201.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38%2017.959l-1.1414-1.9428-.1397.079-.674%207.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328%201.9672-2.1796%202.9446-1.7243%201.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889%202.386-3.0357%201.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385%204.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429%201.9064-1.3114Z%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22m4.7144%2015.9555%204.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608%201.5179.1032%202.2767.1578%201.6514.0972%202.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973%209.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686%201.9064%201.4754%202.4893%201.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335%206.6997%200l.9957.1336.419.3642.6192%201.4147%201.0018%202.2282%201.5543%203.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853%201.8517-.5586%202.9021-.3643%201.9429h.2125l.2429-.2429.9835-1.3053%201.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759%201.1293-.34%201.1657-1.0625%201.3478-.8804%201.1414-1.2628%201.7-.7893%201.36.0729.1093.1882-.0183%202.8535-.607%201.5421-.2794%201.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607%201.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929%201.0686%202.0035%201.8092%202.5075%202.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496%202.3436%203.5214.1214%201.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38%2017.959l-1.1414-1.9428-.1397.079-.674%207.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328%201.9672-2.1796%202.9446-1.7243%201.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889%202.386-3.0357%201.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385%204.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429%201.9064-1.3114Z%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat;
}

.convo-av,
.ms-tile {
    color: #FFFFFF;
}

.convo-av.claude-spark::before {
    width: 13px;
    height: 13px;
    margin: auto;
}

.convo-mini .convo-av.claude-spark::before {
    width: 11px;
    height: 11px;
}

.ms-tile.claude-spark::before {
    width: 26px;
    height: 26px;
    margin: auto;
}

/* Assistant tile row on the Claude-window seam (Retool register):
   Claude center and lit, the other assistants your team already uses
   beside it. */
.ms-tile-row {
    position: absolute;
    top: -24px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    gap: 10px;
}

.ms-tile-side {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    background: #30302E;
    border: 1px solid #45443F;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 6px 18px rgba(20, 12, 6, 0.35);
}

.ms-tile-side svg {
    width: 19px;
    height: 19px;
    fill: #C9C5BC;
}

.ms-tile-side img {
    width: 19px;
    height: 19px;
    display: block;
}

.ms-node svg {
    position: absolute;
    inset: 0;
    margin: auto;
    width: 24px;
    height: 24px;
    transform: rotate(-45deg);
    fill: #7A766B;
}

/* =====================================================================
   Step 05 tool permissions (2026-07-16, v2 same day from the founder's
   reference screenshot): the REAL claude.ai screen — Settings >
   Connectors > a server's tool permissions. Absorbs the capability-card
   band into the story scroll as its closing beat. Human-readable tool
   names in interactive/read-only groups with count pills; each row
   carries the allow / ask-first / block triplet, the selected state
   dark. Real counts only in the panel footer (positioning-evidence
   E1.2); the sheet itself is the illustrative ERP.
   ===================================================================== */

/* The scene field (step-01 register: warm gradient, hairline frame, our
   flat edge) with the permissions window floating on it and the ask-first
   prompt card overlapping as the top layer. */
.tp-scene {
    position: relative;
    padding: 34px 34px 88px;
    background:
        radial-gradient(90% 60% at 50% 6%, rgba(255, 255, 255, 0.9), transparent 60%),
        radial-gradient(70% 50% at 82% 92%, rgba(217, 119, 87, 0.16), transparent 70%),
        radial-gradient(60% 45% at 12% 78%, rgba(180, 83, 9, 0.10), transparent 70%),
        linear-gradient(175deg, #FBF7F1 0%, #F7EADF 55%, #F3DFD2 100%);
    border: 1px solid #ECECEC;
    overflow: hidden;
}

.tp-win {
    width: 88%;
    margin: 0 auto;
    background: #FFFFFF;
    border-radius: 14px;
    overflow: hidden;
    box-shadow: 0 18px 50px rgba(74, 36, 12, 0.13), 0 3px 12px rgba(74, 36, 12, 0.06);
}

.tp-sheet {
    position: relative;
    padding: 16px 22px 0;
}

/* The consequence of "ask first": the real claude.ai permission prompt,
   overlapping the window as the top layer. */
.tp-prompt {
    position: absolute;
    right: 6%;
    bottom: 22px;
    width: min(330px, 82%);
    display: flex;
    flex-direction: column;
    gap: 10px;
    background: #FFFFFF;
    border: 1px solid #E8E5DB;
    border-radius: 12px;
    padding: 14px 16px 12px;
    box-shadow: 0 24px 60px rgba(74, 36, 12, 0.20), 0 4px 14px rgba(74, 36, 12, 0.08);
}

.tp-prompt-top {
    display: flex;
    align-items: flex-start;
    gap: 11px;
}

.tp-prompt-ic {
    position: relative;
    flex: none;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: #FBF6E8;
    border: 1px solid #EFE5C8;
}

.tp-prompt-ic::after {
    content: "";
    position: absolute;
    inset: 0;
    margin: auto;
    width: 13px;
    height: 13px;
    background: #B45309;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M6.4 10.6V4.8a1.15 1.15 0 0 1 2.3 0v4.6h.75V3.3a1.15 1.15 0 0 1 2.3 0v6.1h.75V4.4a1.15 1.15 0 0 1 2.3 0v7.4c0 3.5-2.2 5.6-5.4 5.6-2.8 0-4.1-1.5-5.2-3.9l-1.3-3c-.26-.57 0-1.25.57-1.5.57-.26 1.25 0 1.5.57z'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M6.4 10.6V4.8a1.15 1.15 0 0 1 2.3 0v4.6h.75V3.3a1.15 1.15 0 0 1 2.3 0v6.1h.75V4.4a1.15 1.15 0 0 1 2.3 0v7.4c0 3.5-2.2 5.6-5.4 5.6-2.8 0-4.1-1.5-5.2-3.9l-1.3-3c-.26-.57 0-1.25.57-1.5.57-.26 1.25 0 1.5.57z'/%3E%3C/svg%3E") center / contain no-repeat;
}

.tp-prompt-tx {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.tp-prompt-tx b {
    font-size: 0.75rem;
    font-weight: 600;
    color: #1F1E1D;
}

.tp-prompt-tx span {
    font-size: 0.6875rem;
    font-weight: 300;
    color: #8F8B80;
}

.tp-prompt-act {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 10px;
}

.tp-allow {
    border: 1px solid #1F1E1D;
    border-radius: 8px;
    background: #1F1E1D;
    color: #FFFFFF;
    padding: 6px 12px;
    font-size: 0.71875rem;
    font-weight: 600;
}

.tp-deny {
    padding: 6px 6px;
    font-size: 0.71875rem;
    font-weight: 400;
    color: #8F8B80;
}

.tp-crumb {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.75rem;
    font-weight: 500;
    color: #55524B;
}

.tp-back {
    font-size: 0.8125rem;
    color: #8F8B80;
}

.tp-server-row {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 16px 0 18px;
}

.tp-srv-mark {
    flex: none;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: #2C2B29;
    position: relative;
}

.tp-srv-mark::after {
    content: "";
    position: absolute;
    inset: 0;
    margin: auto;
    width: 12px;
    height: 12px;
    background: #E8E5DB;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Crect x='1' y='1' width='4.4' height='4.4'/%3E%3Crect x='6.6' y='1' width='4.4' height='4.4'/%3E%3Crect x='1' y='6.6' width='4.4' height='4.4'/%3E%3Crect x='6.6' y='6.6' width='4.4' height='4.4'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Crect x='1' y='1' width='4.4' height='4.4'/%3E%3Crect x='6.6' y='1' width='4.4' height='4.4'/%3E%3Crect x='1' y='6.6' width='4.4' height='4.4'/%3E%3Crect x='6.6' y='6.6' width='4.4' height='4.4'/%3E%3C/svg%3E") center / contain no-repeat;
}

.tp-srv-id {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.tp-srv-id b {
    font-size: 0.9375rem;
    font-weight: 600;
    color: #1F1E1D;
}

.tp-srv-id i {
    font-style: normal;
    font-size: 0.6875rem;
    font-weight: 300;
    color: #A5A196;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    /* zero intrinsic width: the nowrap URL must never set the column's
       min-content (it inflated the whole story grid on mobile) */
    width: 0;
    min-width: 100%;
}

.tp-disconnect {
    flex: none;
    margin-left: auto;
    border: 1px solid #DDDBD3;
    border-radius: 8px;
    padding: 5px 12px;
    font-size: 0.75rem;
    font-weight: 500;
    color: #3D3B36;
    background: #FFFFFF;
}

.tp-perm-h {
    margin: 0 0 2px;
    font-size: 0.8125rem;
    font-weight: 600;
    color: #1F1E1D;
}

.tp-perm-sub {
    margin: 0 0 10px;
    font-size: 0.75rem;
    font-weight: 300;
    color: #8F8B80;
}

.tp-ghead {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 0 10px;
}

.tp-chev {
    flex: none;
    width: 7px;
    height: 7px;
    border-right: 1.5px solid #8F8B80;
    border-bottom: 1.5px solid #8F8B80;
    transform: rotate(45deg) translateY(-2px);
}

.tp-gname {
    font-size: 0.8125rem;
    font-weight: 500;
    color: #1F1E1D;
}

.tp-count {
    border-radius: 6px;
    background: #F0EFEC;
    padding: 1px 7px;
    font-size: 0.6875rem;
    font-weight: 400;
    color: #6E6A61;
}

.tp-custom {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    border: 1px solid #DDDBD3;
    border-radius: 8px;
    padding: 4px 11px;
    font-size: 0.75rem;
    color: #3D3B36;
}

.tp-custom::before {
    content: "\00b7\00b7\00b7";
    letter-spacing: 1px;
    color: #8F8B80;
    line-height: 1;
}

.tp-custom::after {
    content: "";
    width: 6px;
    height: 6px;
    border-right: 1.4px solid #8F8B80;
    border-bottom: 1.4px solid #8F8B80;
    transform: rotate(45deg) translateY(-2px);
}

.tp-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 11px 0;
    border-top: 1px solid #F0EFEC;
}

.tp-name {
    min-width: 0;
    font-size: 0.8125rem;
    font-weight: 400;
    color: #1F1E1D;
}

.tp-tri {
    flex: none;
    display: flex;
    align-items: center;
    gap: 7px;
}

.tp-io {
    position: relative;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    border: 1px solid #E3E1DA;
}

.tp-io::after {
    content: "";
    position: absolute;
    inset: 0;
    margin: auto;
    width: 11px;
    height: 11px;
    background: #C6C3BA;
}

.tp-io.on {
    border-color: #55524B;
}

.tp-io.on::after {
    background: #1F1E1D;
}

.tp-io-allow::after {
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.4 4.7 9 10 3.4' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.4 4.7 9 10 3.4' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
}

.tp-io-ask::after {
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M6.4 10.6V4.8a1.15 1.15 0 0 1 2.3 0v4.6h.75V3.3a1.15 1.15 0 0 1 2.3 0v6.1h.75V4.4a1.15 1.15 0 0 1 2.3 0v7.4c0 3.5-2.2 5.6-5.4 5.6-2.8 0-4.1-1.5-5.2-3.9l-1.3-3c-.26-.57 0-1.25.57-1.5.57-.26 1.25 0 1.5.57z'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M6.4 10.6V4.8a1.15 1.15 0 0 1 2.3 0v4.6h.75V3.3a1.15 1.15 0 0 1 2.3 0v6.1h.75V4.4a1.15 1.15 0 0 1 2.3 0v7.4c0 3.5-2.2 5.6-5.4 5.6-2.8 0-4.1-1.5-5.2-3.9l-1.3-3c-.26-.57 0-1.25.57-1.5.57-.26 1.25 0 1.5.57z'/%3E%3C/svg%3E") center / contain no-repeat;
}

.tp-io-block::after {
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Ccircle cx='6' cy='6' r='4.6' fill='none' stroke='black' stroke-width='1.5'/%3E%3Cpath d='M2.9 2.9 9.1 9.1' stroke='black' stroke-width='1.5'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Ccircle cx='6' cy='6' r='4.6' fill='none' stroke='black' stroke-width='1.5'/%3E%3Cpath d='M2.9 2.9 9.1 9.1' stroke='black' stroke-width='1.5'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* The sheet scrolls in the real app: the last row is cut mid-height and
   a white fade closes the panel above the footer. */
.tp-row-cut {
    height: 24px;
    padding-bottom: 0;
    overflow: hidden;
    align-items: flex-start;
}

.tp-fade {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 34px;
    background: linear-gradient(rgba(255, 255, 255, 0), #FFFFFF);
    pointer-events: none;
}

/* Reveal beats: the groups land top to bottom, then the prompt card
   drops in as the top layer and its hand pings twice (the one ambient
   pulse). Static render is the final state; transitions run only off
   the reveal-on-scroll classes. */
.tp-sheet .tp-group {
    transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-out);
}

.tp-sheet .tp-group + .tp-group { transition-delay: 0.16s; }

.js-loaded .reveal-on-scroll:not(.revealed) .tp-sheet .tp-group {
    opacity: 0;
    transform: translateY(6px);
}

.tp-prompt {
    transition: opacity 0.5s var(--ease-out) 0.55s, transform 0.5s var(--ease-out) 0.55s;
}

.js-loaded .reveal-on-scroll:not(.revealed) .tp-prompt {
    opacity: 0;
    transform: translateY(12px) scale(0.97);
}

@keyframes tp-ping {
    0% { box-shadow: 0 0 0 0 rgba(180, 83, 9, 0.35); }
    100% { box-shadow: 0 0 0 12px rgba(180, 83, 9, 0); }
}

.js-loaded .reveal-on-scroll.revealed .tp-prompt-ic {
    animation: tp-ping 1.5s var(--ease-out) 1.3s 2;
}

@media (max-width: 639px) {
    .tp-scene {
        padding: 20px 14px 20px;
    }

    .tp-win {
        width: 100%;
    }

    .tp-prompt {
        position: static;
        width: auto;
        max-width: 330px;
        margin: -14px 2px 0 auto;
    }
}

@media (prefers-reduced-motion: reduce) {
    .tp-sheet .tp-group,
    .tp-prompt {
        transition: none;
    }

    .js-loaded .reveal-on-scroll.revealed .tp-prompt-ic {
        animation: none;
    }
}

/* Inside the tile row the center tile flows with its siblings; the
   absolute centering above applies only when it stands alone. */
.ms-tile-row .ms-tile {
    position: static;
    transform: none;
    box-shadow: 0 8px 24px rgba(160, 60, 20, 0.35);
}

/* =====================================================================
   Nav v2 (2026-07-15) — the nav joins the design system.
   Three pieces, from the nav proposal artifact:
     1. Night state: on the home page #navbar carries .night and starts
        transparent over the dark hero; app.js adds .scrolled after 50px
        and the bar resolves to the solid white ruled bar (input.css).
     2. Services mega panel: CSS-only (:has/:hover/:focus-within) ruled
        4-cell panel under the bar — the artifact bento, miniaturized.
     3. Switchboard mobile menu: the full-screen night panel that
        replaces the old white slide-down list.
   ===================================================================== */

/* ---- 1. Night state (home, before scroll) ---- */
:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled)::before {
    background: transparent;
    border-bottom-color: var(--hairline-on-dark);
}

/* Once hero content starts sliding under the bar (app.js adds .tinted past
   50px) the bar becomes a solid night surface so labels stay legible; the
   white morph still waits for the hero to slide off entirely. */
:is(#navbar.night, #navbar:has(.nav-night)).tinted:not(.scrolled)::before {
    background: rgba(10, 1, 1, 0.82);
}

/* With the switchboard open, the bar becomes a solid night surface so the
   hero (and its page-lines) cannot show through into the menu. */
html.nav-sb-lock :is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled)::before {
    background: #150505;
}

/* The hero's page-lines start below the transparent bar: the menu strip stays
   clean (founder, 2026-07-15: no grid lines through the menu) — and they now
   STOP above the client rail (founder, 2026-07-22: no grid verticals cutting
   through the moving logos, on either side). --rail-h is the band's own height,
   so the two edges cannot drift apart. */
.hero-v2 .hero-v2-lines::before,
.hero-v2 .hero-v2-lines::after {
    top: 64px;
    bottom: var(--rail-h);
}

/* ...but the overlay must NOT also draw its own top horizontal there. The bar
   already ends in a baseline hairline, which occupies the pixel row ABOVE 64px
   while the overlay's line starts AT 64px — two hairlines in adjacent rows, i.e.
   the doubled line under the logo (founder, 2026-07-22). The bar's border is the
   single line; the hero contributes only its verticals, which now rise to meet it. */
.hero-v2 .hero-v2-lines::after {
    background-image: none;
}

#navbar .nav-cell-logo img {
    transition: filter 0.32s var(--ease-out);
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-cell-logo img {
    /* White monochrome logo on the night bar (approved in the proposal
       mockups); swap for a real logo-text-light.webp when one is cut. */
    filter: brightness(0) invert(1);
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-cell {
    color: var(--on-dark-soft);
    font-weight: 300;
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-cell.active {
    color: var(--on-dark);
    font-weight: 500;
}

/* On the night bar the same glow burns brighter (lit amber on dark) and the
   text resolves to white instead of brand red — same metaphor, both bars. */
:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) a.nav-cell:hover {
    color: var(--on-dark);
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) a.nav-cell::before {
    background: radial-gradient(120% 90% at 50% 118%, rgba(217, 119, 6, 0.42), rgba(217, 119, 6, 0.07) 60%, transparent 75%);
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-cell.active::after {
    background: #D97706;
    box-shadow: 0 0 12px rgba(217, 119, 6, 0.55); /* light, not elevation */
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) [data-mobile-menu-btn] {
    color: var(--on-dark);
}

/* ---- 2. Services mega panel (desktop, CSS-only) ---- */
.nav-mega {
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    z-index: 5;
    background: var(--surface);
    border-bottom: 1px solid var(--hairline);
    clip-path: inset(0 0 100% 0);
    visibility: hidden;
    transition: clip-path 0.32s var(--ease-out), visibility 0s linear 0.32s;
}

#navbar:has(.nav-drop:hover) .nav-mega,
#navbar:has(.nav-drop:focus-visible) .nav-mega,
.nav-mega:hover,
.nav-mega:focus-within {
    clip-path: inset(0 0 0 0);
    visibility: visible;
    transition-delay: 0s;
}

.nav-mega-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
}

/* Mega-panel overview row (2026-07-27). Cells 01 and 02 are both AI offers, so
   the panel needs somewhere to send a visitor who is scanning for "AI" and does
   not yet know which. A quiet row under the grid, NOT a fifth cell: five cells
   would break the repeat(4, 1fr) the panel is built on. Content sits 24px
   inside the outer grid lines like every cell above it. */
.nav-mega-foot {
    border-top: 1px solid var(--hairline-faint);
    opacity: 0;
    transform: translateY(10px);
    transition: opacity 0.3s var(--ease-out), transform 0.3s var(--ease-out);
    /* The row reveals last, after the four cells have staggered in. */
    transition-delay: 0.16s;
}

/* The inner element carries .shell, so it inherits the shell's horizontal
   padding and the 24px below lands the links on the same inset as the cell
   content above. Never merge these two rules back into one element: a `padding`
   shorthand alongside .shell overrides the shell's inline padding and throws the
   row ~83px out of alignment at 1440. */
.nav-mega-foot-in {
    display: flex;
    align-items: center;
    gap: 28px;
    padding-top: 14px;
    padding-bottom: 16px;
}

.nav-mega-foot-in > * {
    margin-left: 24px;
}

.nav-mega-foot-in > * ~ * {
    margin-left: 0;
}

#navbar:has(.nav-drop:hover) .nav-mega-foot,
#navbar:has(.nav-drop:focus-visible) .nav-mega-foot,
.nav-mega:hover .nav-mega-foot,
.nav-mega:focus-within .nav-mega-foot {
    opacity: 1;
    transform: translateY(0);
}

.nav-mega-all {
    position: relative;
    font-family: var(--font-sans);
    font-size: 13px;
    font-weight: 400;
    line-height: 1;
    color: var(--ink);
    text-decoration: none;
    padding-bottom: 3px;
    transition: color var(--motion-color) var(--ease-out);
}

/* Same underline-grow as .nav-mega-t, so the row reads as part of the panel
   rather than as a link that wandered in from the page. */
.nav-mega-all::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    width: 0;
    height: 1px;
    background: var(--accent);
    transition: width var(--motion-ui) var(--ease-out);
}

.nav-mega-all:hover::after,
.nav-mega-all:focus-visible::after {
    width: 100%;
}

.nav-mega-all-quiet {
    color: color-mix(in srgb, var(--ink) 55%, transparent);
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-mega-foot {
    border-top-color: var(--hairline-on-dark);
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-mega-all {
    color: #fff;
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-mega-all-quiet {
    color: rgba(255, 255, 255, 0.55);
}

.nav-mega-item {
    display: block;
    /* 24px insets: panel cells sit on the quarter lines, content 24px inside */
    padding: 24px 24px 30px;
    border-right: 1px solid var(--hairline-faint);
    color: var(--ink);
    text-decoration: none;
    opacity: 0;
    transform: translateY(10px);
    transition: opacity 0.3s var(--ease-out), transform 0.3s var(--ease-out), background-color 0.2s var(--ease-out);
}

.nav-mega-item:last-child {
    border-right: 0;
}

#navbar:has(.nav-drop:hover) .nav-mega-item,
#navbar:has(.nav-drop:focus-visible) .nav-mega-item,
.nav-mega:hover .nav-mega-item,
.nav-mega:focus-within .nav-mega-item {
    opacity: 1;
    transform: none;
    transition-delay: calc(var(--i, 0) * 55ms + 60ms);
}

.nav-mega-item:hover {
    background-color: var(--surface-alt);
}

.nav-mega-item .nav-mega-no {
    display: block;
    font-family: ui-monospace, 'Cascadia Code', Consolas, monospace;
    font-size: 11px;
    color: var(--brand-micro);
    margin-bottom: 14px;
}

.nav-mega-item .nav-mega-t {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 17px;
    font-weight: 500;
    margin-bottom: 6px;
}

.nav-mega-item .nav-mega-t::after {
    content: "";
    width: 14px;
    height: 14px;
    flex: none;
    background-color: var(--brand);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath d='M1 8h13M9 3l5 5-5 5' fill='none' stroke='black' stroke-width='1.6'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath d='M1 8h13M9 3l5 5-5 5' fill='none' stroke='black' stroke-width='1.6'/%3E%3C/svg%3E") center / contain no-repeat;
    opacity: 0;
    transform: translateX(-4px);
    transition: opacity 0.2s var(--ease-out), transform 0.2s var(--ease-out);
}

.nav-mega-item:hover .nav-mega-t::after {
    opacity: 1;
    transform: none;
}

.nav-mega-item .nav-mega-d {
    margin: 0;
    font-size: 13px;
    font-weight: 300;
    color: rgba(29, 29, 31, 0.55);
    line-height: 1.5;
}

/* ---- Night variant (founder, 2026-07-20) ----------------------------------
   On dark-hero pages (home, /services and any page carrying .nav-night) the bar
   is night, and a WHITE panel dropping between the dark bar and the dark hero
   read as a slab of white on black. The panel now goes night WITH the bar, so
   the menu is the bar's own surface extending downward rather than a new
   surface. It is not a new dark section band: it is transient nav chrome, so
   the three-dark-surface register rhythm still holds. Once the bar resolves
   white (.scrolled) the panel is white again, so the two never disagree. */
:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-mega {
    background: #150505;
    border-bottom-color: var(--hairline-on-dark);
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-mega-item {
    border-right-color: var(--hairline-on-dark);
    color: var(--on-dark);
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-mega-item:hover {
    /* the same lit-window warmth as the cells above, not a grey wash */
    background-color: rgba(217, 119, 6, 0.10);
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-mega-item .nav-mega-no {
    color: #D97706; /* lit amber: the deep amber goes muddy on near-black */
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-mega-item .nav-mega-t::after {
    background-color: #D97706;
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-mega-item .nav-mega-d {
    color: rgba(245, 241, 236, 0.58);
}

@media (max-width: 767.98px) {
    .nav-mega {
        display: none;
    }
}

/* ---- 3. Switchboard mobile menu (full-screen night panel) ---- */
html.nav-sb-lock,
html.nav-sb-lock body {
    overflow: hidden;
}

.nav-sb {
    position: fixed;
    inset: 64px 0 0 0;
    z-index: 49;
    display: flex;
    flex-direction: column;
    background:
        radial-gradient(560px 320px at 86% 100%, rgba(217, 119, 6, 0.14), transparent 70%),
        linear-gradient(115deg, #150505 0%, #260707 60%, #2E0B06 100%);
    clip-path: inset(0 0 100% 0);
    visibility: hidden;
    transition: clip-path 0.45s var(--ease-out), visibility 0s linear 0.45s;
}

.nav-sb.open {
    clip-path: inset(0 0 0 0);
    visibility: visible;
    transition-delay: 0s;
}

.nav-sb-rows {
    position: relative;
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
}

.nav-sb-row {
    position: relative;
    flex: 1 1 auto;
    min-height: 56px;
    display: flex;
    align-items: center;
    gap: 18px;
    padding: 0 24px;
    color: var(--on-dark);
    text-decoration: none;
    border-bottom: 1px solid var(--hairline-on-dark);
    opacity: 0;
    transform: translateY(22px);
    transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-out);
}

.nav-sb.open .nav-sb-row {
    opacity: 1;
    transform: none;
    transition-delay: calc(var(--i, 0) * 60ms + 200ms);
}

.nav-sb-row::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    opacity: 0;
    background: linear-gradient(90deg, rgba(217, 119, 6, 0.16), rgba(217, 119, 6, 0.03) 55%, transparent);
    transition: opacity 0.25s var(--ease-out);
}

.nav-sb-row:hover::before,
.nav-sb-row:active::before {
    opacity: 1;
}

.nav-sb-row .nav-sb-no {
    flex: none;
    width: 26px;
    font-family: ui-monospace, 'Cascadia Code', Consolas, monospace;
    font-size: 12px;
    color: rgba(255, 255, 255, 0.4);
}

.nav-sb-row .nav-sb-t {
    font-size: 24px;
    font-weight: 600;
    letter-spacing: -0.01em;
    line-height: 1;
}

.nav-sb-row.active .nav-sb-no {
    color: #D97706;
}

.nav-sb-row.active::after {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 2px;
    background: #D97706;
}

.nav-sb-foot {
    position: relative;
    flex: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 16px 24px;
    border-top: 1px solid var(--hairline-on-dark);
    color: rgba(255, 255, 255, 0.55);
    font-size: 13px;
    font-weight: 300;
    opacity: 0;
    transition: opacity 0.4s var(--ease-out) 0.65s;
}

.nav-sb.open .nav-sb-foot {
    opacity: 1;
}

.nav-sb-foot a {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    color: var(--on-dark);
    font-weight: 500;
    text-decoration: none;
}

.nav-sb-foot a::after {
    content: "";
    width: 16px;
    height: 16px;
    flex: none;
    background-color: #D97706;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath d='M1 8h13M9 3l5 5-5 5' fill='none' stroke='black' stroke-width='1.6'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath d='M1 8h13M9 3l5 5-5 5' fill='none' stroke='black' stroke-width='1.6'/%3E%3C/svg%3E") center / contain no-repeat;
}

@media (prefers-reduced-motion: reduce) {
    .nav-sb,
    .nav-sb-row,
    .nav-sb-foot,
    .nav-mega,
    .nav-mega-item,
    a.nav-cell,
    #navbar::before {
        transition: none !important;
    }
}

/* =====================================================================
   Product window chrome (2026-07-15, product-surface exception: rounded
   windows + soft shadows inside artboards only). Used by the services
   bento v3 (st-* kit, end of file) and the AI section.
   ===================================================================== */

/* The floating product window */
.sv-win {
    width: 100%;
    background: #FFFFFF;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 14px 36px rgba(74, 36, 12, 0.12), 0 2px 8px rgba(74, 36, 12, 0.06);
    font-size: 0.75rem;
}

.sv-win-bar {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    border-bottom: 1px solid #EFEDE7;
}

.sv-win-bar i {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #DCD8CE;
    flex: none;
}

.sv-win-bar span {
    margin-left: 6px;
    /* keep the window title on one line: on narrow mobile windows it used to
       wrap and collide with the dots. Truncate like a real title bar instead. */
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-size: 0.6875rem;
    font-weight: 600;
    color: #6E6B63;
}

.sv-win-bar em {
    margin-left: auto;
    flex: none;
    padding-left: 8px;
    font-style: normal;
    font-size: 0.625rem;
    color: #A5A196;
}

.sv-win-body {
    padding: 12px 14px;
}

.sv-win-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 14px;
    border-top: 1px solid #F1EFE9;
    background: #FCFBF8;
    font-size: 0.6875rem;
    color: #6E6B63;
}

.sv-win-foot .sv-ok {
    font-weight: 600;
}

.convo-mini .convo-head {
    padding: 8px 12px;
}

.convo-mini .convo-dot {
    width: 7px;
    height: 7px;
}

/* The one ambient beat: the serving pill breathes */
@keyframes sv-serve {
    0%, 100% { box-shadow: 0 0 0 0 rgba(127, 29, 29, 0.30); }
    55% { box-shadow: 0 0 0 5px rgba(127, 29, 29, 0); }
}

.sv-pill-hot {
    animation: sv-serve 2.8s var(--ease-out) infinite;
}

@media (prefers-reduced-motion: reduce) {
    .sv-pill-hot {
        animation: none;
    }
}

/* Small screens: the scene's ERP table drops its Days column and the
   windows go full width, so the story column can never overflow the
   viewport (the table's min-content width was widening the grid). */
@media (max-width: 640px) {
    .ms-scene {
        padding: 28px 16px 0;
    }

    .ms-erp {
        width: 100%;
    }

    .ms-erp-table th,
    .ms-erp-table td {
        padding: 6px 10px;
    }

    .ms-erp-table th:nth-child(3),
    .ms-erp-table td:nth-child(3) {
        display: none;
    }

    .ms-erp-foot .ms-mono {
        display: none;
    }
}

/* =====================================================================
   Services bento v3 — "the product bento" (2026-07-16, direction F of
   the /preview/whatwebuild pass, founder-chosen; play-on-arrive concepts
   from direction S). Stripe's flexible-solutions anatomy on our laws:
   four framed cards (48px gaps = every edge 24px inside a page line),
   warm gradient stages scoped INSIDE the frames, floating product
   windows, one coherent receivables story in the lead card.
   ===================================================================== */

.st-grid {
    display: grid;
    gap: 48px;
}

/* 2026-07-16 (founder): the grid went from 2 to 4 columns so the FP&A
   card can take three quarters with the CapitalBridge tile beside it.
   Halves span 2, the lead/doc/apps rows span 4. Gaps stay 48px, so
   every card edge still sits 24px inside a page line (grid law). */
@media (min-width: 1024px) {
    .st-grid { grid-template-columns: repeat(4, 1fr); }
    .st-wide { grid-column: span 4; }
    .st-half { grid-column: span 2; }
    .st-w3 { grid-column: span 3; }
}

/* 1024-1439: the quarter column is only 180px (at 1024) to 244px (at 1280)
   here, because the shell's content width does not reach its 1276px cap until
   about 1440. At that size the CapitalBridge tile breaks: its title runs to
   five 2-word lines and its window is clipped by the stage (the taller wrapped
   head leaves the stage too short for the bottom-anchored window, so the title
   bar and KPI labels get cut off). The 3 + 1 pairing is a >=1440 design: it
   needs the 283px column it was drawn at. Below that, give the FP&A card and
   the CapitalBridge card the full row each instead. */
@media (min-width: 1024px) and (max-width: 1439.98px) {
    .st-w3 { grid-column: span 4; }
    .st-cb { grid-column: span 4; }
}

.st-card {
    position: relative;
    display: flex;
    flex-direction: column;
    background: #FFFFFF;
    text-decoration: none;
    color: #1D1D1F;
    overflow: hidden;
    min-height: 440px;
}

.st-wide { min-height: 400px; }

.st-head {
    position: relative;
    z-index: 4;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 18px;
    padding: 28px 28px 0;
}

.st-kick {
    display: block;
    font-size: 0.625rem;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: #7F1D1D;
    font-weight: 600;
    margin-bottom: 8px;
}

.st-title {
    font-family: 'Sora', sans-serif;
    font-weight: 600;
    font-size: 1.4375rem;
    line-height: 1.26;
    max-width: 19ch;
}

.st-wide .st-title { max-width: 34ch; }

/* side-by-side cards reserve two headline lines so their stages start on
   the same horizon regardless of how the titles wrap */
@media (min-width: 1024px) {
    .st-card:not(.st-wide) .st-title { min-height: 2.52em; }
}

.st-expand {
    flex: none;
    width: 34px;
    height: 34px;
    /* var(--hairline), not #DDDDDD: this is PAGE chrome, and #DDDDDD is off-palette and
       only 3 units from --hairline (#ECECEC), which does the same job 30 times over.
       The remaining #DDDDDD uses are scene interiors (doc paper, fpa cascade) that depict
       software chrome and keep their own palette deliberately. */
    border: 1px solid var(--hairline);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #1D1D1F;
    background: #FFFFFF;
    transition: background 0.16s, color 0.16s, border-color 0.16s;
}

.st-expand svg { width: 13px; height: 13px; }

.st-card:hover .st-expand {
    background: #7F1D1D;
    border-color: #7F1D1D;
    color: #FFFFFF;
}

.st-stage {
    position: relative;
    flex: 1;
    margin-top: 22px;
    min-height: 250px;
    overflow: hidden;
}

.st-s1 {
    background:
        radial-gradient(70% 80% at 82% 108%, rgba(232, 167, 101, 0.34), transparent 62%),
        radial-gradient(60% 70% at 16% 112%, rgba(127, 29, 29, 0.10), transparent 68%),
        linear-gradient(180deg, #FFFFFF 0%, #FCF5EC 46%, #F7E7D2 100%);
}

.st-s2 {
    background:
        radial-gradient(80% 88% at 20% 108%, rgba(217, 119, 87, 0.22), transparent 70%),
        linear-gradient(180deg, #FFFFFF 0%, #FCF4EC 50%, #F8E9DC 100%);
}

.st-s3 {
    background:
        radial-gradient(78% 82% at 82% 108%, rgba(180, 83, 9, 0.20), transparent 70%),
        linear-gradient(180deg, #FFFFFF 0%, #FBF5EA 48%, #F6EAD5 100%);
}

.st-s4 {
    background:
        radial-gradient(70% 80% at 50% 116%, rgba(127, 29, 29, 0.13), transparent 72%),
        radial-gradient(50% 60% at 90% 106%, rgba(232, 167, 101, 0.26), transparent 70%),
        linear-gradient(180deg, #FFFFFF 0%, #FAF1EC 50%, #F5E3DA 100%);
}

.st-stage .ms-erp,
.st-stage .sv-win,
.st-stage .convo-mini {
    position: absolute;
    z-index: 2;
    box-shadow: 0 18px 44px rgba(74, 36, 12, 0.15);
    border-radius: 10px;
    overflow: hidden;
}

.st-wide.st-lead .ms-erp {
    left: 28px;
    bottom: 18px;
    width: min(46%, 470px);
}

.st-wide.st-lead .convo-mini {
    right: 28px;
    bottom: 22px;
    width: min(40%, 420px);
    border-radius: 12px;
}

/* the wire physically runs from the ERP window into the Claude window:
   it sits UNDER both windows (z-index 1 vs their 2), so its ends
   disappear behind their edges and only the connected middle shows */
.st-wire {
    position: absolute;
    z-index: 1;
    left: 24%;
    right: 22%;
    top: 58%;
    height: 1px;
    pointer-events: none;
}

.st-wire .line {
    position: absolute;
    inset: 0;
    background-image: linear-gradient(to right, rgba(180, 83, 9, 0.55) 0 6px, transparent 6px 12px);
    background-size: 12px 1px;
    animation: st-dash 0.9s linear infinite;
}

@keyframes st-dash { to { background-position: -12px 0; } }

.st-wire .node {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%) rotate(45deg);
    width: 40px;
    height: 40px;
    background: #FFFDFA;
    border: 1px solid #CBB9A6;
    box-shadow: 0 8px 22px rgba(74, 36, 12, 0.14);
}

.st-wire .node b {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    transform: rotate(-45deg);
    font-family: 'Cascadia Code', Consolas, ui-monospace, monospace;
    font-size: 0.5625rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    color: #7A766B;
}

.st-wire .pulse {
    position: absolute;
    top: -2px;
    left: 0;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: #B45309;
    box-shadow: 0 0 8px 1px rgba(180, 83, 9, 0.6);
    animation: st-travel 3.2s ease-in-out infinite;
}

@keyframes st-travel {
    0% { left: 0; opacity: 0; }
    12% { opacity: 1; }
    44% { left: calc(50% - 20px); opacity: 1; }
    52% { left: calc(50% + 20px); opacity: 1; }
    88% { left: 100%; opacity: 1; }
    100% { left: 100%; opacity: 0; }
}

/* windows never crop their own payoff line */
.st-card:not(.st-wide) .sv-win {
    left: 28px;
    right: 28px;
    bottom: 20px;
    width: auto;
}

.st-wide.st-apps .sv-win {
    left: 28px;
    bottom: 18px;
    width: min(50%, 500px);
}

.st-wide.st-apps .convo-mini {
    right: 28px;
    bottom: 22px;
    width: min(38%, 400px);
    border-radius: 12px;
}

@keyframes st-float {
    from { transform: translateY(0); }
    to { transform: translateY(8px); }
}

.st-chip {
    position: absolute;
    z-index: 5;
    background: #FFFFFF;
    border: 1px solid #E4E1DA;
    border-left: 3px solid #B45309;
    padding: 9px 13px;
    font-size: 0.6875rem;
    line-height: 1.4;
    color: rgba(29, 29, 31, 0.65);
    box-shadow: 0 12px 30px rgba(74, 36, 12, 0.13);
    animation: st-float 4.6s ease-in-out infinite alternate;
    max-width: 230px;
}

.st-chip b {
    display: block;
    color: #1D1D1F;
    font-weight: 600;
    font-family: 'Cascadia Code', Consolas, ui-monospace, monospace;
    font-size: 0.6875rem;
    margin-bottom: 2px;
}

.st-chip .amt {
    color: #B45309;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.st-chip.c2 { right: 22px; top: 24px; animation-delay: 0.8s; }
.st-chip.c4 { left: 41%; top: 26%; animation-delay: 1.1s; }

/* small window-chrome labels were #A5A196 on white (~2.5:1); readable here */
.st-grid .ms-erp-bar em,
.st-grid .sv-win-bar em,
.st-grid .convo-meta { color: #6E6B63; }

/* ---- shared motion scaffolding (the hover-play beats live in the v3.2
   block at the end of this file; nothing here hides static content) ---- */
@media (prefers-reduced-motion: no-preference) {
    .st-stage .ms-erp,
    .st-stage .sv-win,
    .st-stage .convo-mini,
    .st-chip {
        transition: opacity 0.55s var(--ease-out), transform 0.55s var(--ease-out);
    }



    /* the wire draws itself left to right, then the pulse starts */
    .st-wire .line {
        transform-origin: left;
        transition: transform 0.7s var(--ease-out) 0.45s;
    }


    .st-wire .node { transition: opacity 0.4s var(--ease-out) 0.7s; }


    /* doc: a scan beam reads the page once, fields stream in, stamp lands */
    .sv-doc-page::before {
        content: "";
        position: absolute;
        left: 0;
        right: 0;
        top: -3px;
        height: 3px;
        background: linear-gradient(to right, transparent, rgba(180, 83, 9, 0.75), transparent);
        opacity: 0;
    }


    .st-card .sv-doc-row,
    .st-card .sv-win-foot {
        transition: opacity 0.45s var(--ease-out), transform 0.45s var(--ease-out);
    }



    /* fpa: bars grow left to right */
    .st-card .sv-bars i {
        transform-origin: bottom;
        transition: transform 0.6s var(--ease-out);
    }



    /* apps: queue tickets arrive */
    .st-card .sv-queue-row {
        transition: opacity 0.45s var(--ease-out), transform 0.45s var(--ease-out);
    }



    /* the answer traces back to its source: both Overdue pills flash once
       when the lead's typed answer lands (app.js adds .sv-traced) */
    .st-card.sv-traced .ms-pill-over {
        animation: sv-trace 1.4s var(--ease-out) 1;
    }
}

@keyframes sv-scan {
    0% { top: -3px; opacity: 0; }
    12% { opacity: 1; }
    88% { opacity: 1; }
    100% { top: calc(100% + 1px); opacity: 0; }
}

@keyframes sv-trace {
    0%, 100% { box-shadow: 0 0 0 0 rgba(180, 83, 9, 0); }
    30% { box-shadow: 0 0 0 4px rgba(180, 83, 9, 0.35); }
}

@media (max-width: 1023.98px) {
    .st-card { min-height: 380px; }
    .st-wire { display: none; }
    /* room for the floating chip above the window (they collided at 250px) */
    .st-card:not(.st-wide) .st-stage { min-height: 300px; }
    .st-wide.st-lead .ms-erp,
    .st-wide.st-lead .convo-mini,
    .st-wide.st-apps .sv-win,
    .st-wide.st-apps .convo-mini {
        position: static;
        width: auto;
        margin: 10px 20px 20px;
    }
    /* on mobile the lead keeps the Q&A (the story), not the ERP table */
    .st-wide.st-lead .ms-erp,
    .st-wide.st-apps .convo-mini { display: none; }
    .st-chip.c4 { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    .st-chip,
    .st-wire .line,
    .st-wire .pulse {
        animation: none;
    }
}

/* ---------------------------------------------------------------------
   Bento v3.1 — deeper play (2026-07-16, founder: the beats read dry and
   the cards need a sentence more). Each card now carries a short note
   under its title, and the choreography demonstrates the work instead of
   just fading it in:
     lead — after the question types, the ERP rows are visibly READ one
            by one (amber sweep), then the answer lands with a debtor
            breakdown streaming in, and the Overdue pills flash.
     doc  — the page thumbnail glows while the scan beam reads it, the
            field count on the chip counts up (app.js), each extracted
            value lands and then gets its validation tick.
     fpa  — two-phase commit: gray actuals grow first, amber forecast
            bars follow, glow once as they are written back, and only
            then does the "written back" chip pop.
     apps — the queue actually advances: ticket 4814 arrives, 4812
            completes (serving -> done), 4813 moves up to serving.
   --------------------------------------------------------------------- */

.st-note {
    margin: 10px 0 0;
    font-size: 0.875rem;
    font-weight: 300;
    line-height: 1.6;
    color: rgba(29, 29, 31, 0.66);
    max-width: 58ch;
}

.st-card:not(.st-wide) .st-note { max-width: 46ch; }

/* the lead convo grew a breakdown; give the card room */
.st-wide.st-lead { min-height: 500px; }

/* queue pill swap scaffold: the second pill overlays the first and is
   invisible until its beat (no-JS shows the sensible initial state) */
.sv-swap { position: relative; display: inline-flex; }

.sv-swap .sv-pill:last-child {
    position: absolute;
    inset: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
}

.sv-pill-done {
    border-color: rgba(180, 83, 9, 0.45);
    color: #B45309;
    font-weight: 600;
}

@media (prefers-reduced-motion: no-preference) {
    /* lead: the tool visibly reads the table, row by row, after the
       question is asked and before the answer lands */

    /* doc: the page glows while the beam reads it */

    /* doc: each value lands, then its validation tick stamps in */
    .st-card .sv-tick {
        display: inline-block;
        transition: opacity 0.3s var(--ease-out), transform 0.3s var(--ease-out);
    }



    /* fpa: two-phase commit — actuals first (odd bars), forecast after
       (even, amber), then the write-back glow, then the chip */


    /* apps: the queue advances — 4814 arrives, 4812 completes, 4813 up */

}

@keyframes sv-read {
    0%, 100% { background: transparent; }
    40% { background: rgba(232, 167, 101, 0.18); }
}

@keyframes sv-pageglow {
    0%, 100% { border-color: #DDDDDD; box-shadow: none; }
    50% { border-color: rgba(180, 83, 9, 0.55); box-shadow: 0 0 12px rgba(180, 83, 9, 0.25); }
}

@keyframes sv-commit {
    0%, 100% { box-shadow: none; }
    45% { box-shadow: 0 0 10px rgba(180, 83, 9, 0.45); }
}

@keyframes sv-fadeout { to { opacity: 0; } }
@keyframes sv-fadein { to { opacity: 1; } }

/* v3.1 follow-up: the lead card adopts the AI scene's window fidelity
   (Days column, mixed statuses, the Connected-via-MCP foot) and its MCP
   glyph node; the read sweep covers all four rows */
.st-wire .node { border-radius: 10px; }

.st-wire .node svg {
    position: absolute;
    inset: 0;
    margin: auto;
    width: 18px;
    height: 18px;
    transform: rotate(-45deg);
    fill: #B45309;
}

.st-wide.st-lead .ms-erp { width: min(48%, 500px); }

@media (prefers-reduced-motion: no-preference) {
}

/* ---------------------------------------------------------------------
   Bento v3.2 — serious + hover-to-work (2026-07-16, founder: the cards
   still read light next to the AI scene, and the motion should start on
   hover, not on scroll).

   Seriousness: the lead card's exchange moves into a DARK claude.ai
   panel (.convo-dark, the AI scene's #262624 register — the dark anchor
   that gives the scene its weight), the forecast chart fills its window,
   and the FP&A message lives in the window foot instead of a floating
   chip.

   Motion: cards render SETTLED and complete. app.js initServicesStages
   adds .sv-play on first hover (pointer devices) or on scroll-arrival
   (touch fallback); every beat is a keyframe with `both` fill, so the
   card resets and performs once: the question retypes, the ERP rows are
   read, the answer re-lands with its breakdown, the scan beam re-reads
   the page while the chip re-counts, the bars re-commit in two phases,
   the queue advances. Reduced motion: nothing ever plays.
   --------------------------------------------------------------------- */

/* --- the dark claude.ai panel (product-surface exception, AI-scene
       register: #262624 / #30302E / #45443F) --- */
.convo-dark {
    background: #262624;
    border: 1px solid #3A3833;
}

.convo-dark .convo-head {
    background: #21211F;
    border-bottom-color: #3A3833;
}

.convo-dark .convo-dot { background: #4A4843; }
.convo-dark .convo-site { color: #ECEAE4; }

.convo-dark .convo-meta { color: #A6A29A !important; }

.convo-dark .convo-meta::before {
    content: "";
    display: inline-block;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #8FBC8F;
    margin-right: 6px;
    vertical-align: 1px;
}

.convo-dark .convo-qtext {
    background: #30302E;
    color: #ECEAE4;
}

.convo-dark .convo-tool {
    background: #30302E;
    border-color: #45443F;
}

.convo-dark .tool-name { color: #ECEAE4; }
.convo-dark .tool-meta { color: #A6A29A; }

.convo-dark .convo-src { color: #ECEAE4; }

.convo-dark .convo-row { border-top-color: rgba(255, 255, 255, 0.09); }
.convo-dark .convo-row span:first-child { color: #C9C5BD; }
.convo-dark .convo-num { color: #ECEAE4; }

/* --- scale: the artifacts dominate their stages (desktop only; below
       1024px the lead scene stacks static/full-width, so this fixed width
       must not override the mobile width:auto and shrink the panel to a
       sliver) --- */
@media (min-width: 1024px) {
    .st-wide.st-lead .convo-mini { width: min(42%, 445px); }
}

/* 1024-1279: the two windows are still sized by percentage here (the 500px /
   445px caps only bite at 1280+), so at 48% + 42% they left only a 30-46px
   gap — narrower than the MCP node, whose 40px square is rotated 45deg and so
   needs 57px. The node was being clipped by both windows and read as a broken
   stub poking out from behind the ERP (founder, Nest Hub 1024x600).
   Narrowing the pair to 44% + 38% opens a ~100-145px gap across the band, and
   the wire is re-centred on it: the gap centre sits at (E + 1 - C) / 2 = 53%
   of the stage (the 28px side margins cancel, so this holds at every width in
   the band), and left:30%/right:24% puts the wire centre at (30 + 76) / 2 = 53%
   to match. The ends still tuck behind both windows. */
@media (min-width: 1024px) and (max-width: 1279.98px) {
    .st-wide.st-lead .ms-erp { width: 44%; }
    .st-wide.st-lead .convo-mini { width: 38%; }
    .st-wide.st-lead .st-wire { left: 30%; right: 24%; }
}

.st-s3 .sv-bars {
    height: 120px;
    gap: 0;
    justify-content: space-between;
}

.st-s3 .sv-bars i { width: 9%; }

.st-card:not(.st-wide) .sv-win {
    left: 24px;
    right: 24px;
}

/* --- hover-to-work choreography (.sv-play via app.js) --- */
@media (prefers-reduced-motion: no-preference) {
    /* lead: the question retypes (app.js), the rows are read while the
       tool runs, the answer lands (rows stream via the armed machinery) */
    .st-card.sv-play .ms-erp-table tr:nth-child(2) { animation: sv-read 0.55s var(--ease-out) 1.10s 1 both; }
    .st-card.sv-play .ms-erp-table tr:nth-child(3) { animation: sv-read 0.55s var(--ease-out) 1.32s 1 both; }
    .st-card.sv-play .ms-erp-table tr:nth-child(4) { animation: sv-read 0.55s var(--ease-out) 1.54s 1 both; }
    .st-card.sv-play .ms-erp-table tr:nth-child(5) { animation: sv-read 0.55s var(--ease-out) 1.76s 1 both; }

    /* doc: beam re-reads the page (glow), values re-land, ticks stamp,
       the filed foot returns last */
    .st-card.sv-play .sv-doc-page::before { animation: sv-scan 1.1s var(--ease-out) 0.15s 1; }
    .st-card.sv-play .sv-doc-page { animation: sv-pageglow 1.1s var(--ease-out) 0.15s 1; }

    .st-card.sv-play .sv-doc-row:nth-child(1) { animation: sv-rise 0.45s var(--ease-out) 0.40s 1 both; }
    .st-card.sv-play .sv-doc-row:nth-child(2) { animation: sv-rise 0.45s var(--ease-out) 0.60s 1 both; }
    .st-card.sv-play .sv-doc-row:nth-child(3) { animation: sv-rise 0.45s var(--ease-out) 0.80s 1 both; }

    .st-card.sv-play .sv-doc-row:nth-child(1) .sv-tick { animation: sv-pop 0.3s var(--ease-out) 0.95s 1 both; }
    .st-card.sv-play .sv-doc-row:nth-child(2) .sv-tick { animation: sv-pop 0.3s var(--ease-out) 1.15s 1 both; }
    .st-card.sv-play .sv-doc-row:nth-child(3) .sv-tick { animation: sv-pop 0.3s var(--ease-out) 1.35s 1 both; }

    .st-card.sv-play .st-s2 .sv-win-foot { animation: sv-rise 0.45s var(--ease-out) 1.60s 1 both; }

    /* fpa: two-phase commit — actuals, then forecast, then the write-back
       glow, then the committed foot */
    .st-card.sv-play .sv-bars i:nth-child(1) { animation: sv-grow 0.6s var(--ease-out) 0.05s 1 both; }
    .st-card.sv-play .sv-bars i:nth-child(3) { animation: sv-grow 0.6s var(--ease-out) 0.17s 1 both; }
    .st-card.sv-play .sv-bars i:nth-child(5) { animation: sv-grow 0.6s var(--ease-out) 0.29s 1 both; }
    .st-card.sv-play .sv-bars i:nth-child(7) { animation: sv-grow 0.6s var(--ease-out) 0.41s 1 both; }
    .st-card.sv-play .sv-bars i:nth-child(2) { animation: sv-grow 0.6s var(--ease-out) 0.85s 1 both, sv-commit 0.9s var(--ease-out) 1.75s 1; }
    .st-card.sv-play .sv-bars i:nth-child(4) { animation: sv-grow 0.6s var(--ease-out) 0.97s 1 both, sv-commit 0.9s var(--ease-out) 1.75s 1; }
    .st-card.sv-play .sv-bars i:nth-child(6) { animation: sv-grow 0.6s var(--ease-out) 1.09s 1 both, sv-commit 0.9s var(--ease-out) 1.75s 1; }
    .st-card.sv-play .sv-bars i:nth-child(8) { animation: sv-grow 0.6s var(--ease-out) 1.21s 1 both, sv-commit 0.9s var(--ease-out) 1.75s 1; }

    .st-card.sv-play .st-s3 .sv-win-foot { animation: sv-rise 0.45s var(--ease-out) 2.10s 1 both; }

    /* apps: the queue advances — 4814 re-arrives, 4812 completes, 4813
       moves up to serving */
    .st-card.sv-play .sv-queue-row:nth-child(3) { animation: sv-rise 0.45s var(--ease-out) 1.00s 1 both; }

    .st-card.sv-play .sv-q1 .sv-pill:first-child { animation: sv-fadeout 0.4s var(--ease-out) 1.80s 1 both; }
    .st-card.sv-play .sv-q1 .sv-pill:last-child { animation: sv-fadein 0.4s var(--ease-out) 1.80s 1 both; }
    .st-card.sv-play .sv-q2 .sv-pill:first-child { animation: sv-fadeout 0.4s var(--ease-out) 2.25s 1 both; }
    .st-card.sv-play .sv-q2 .sv-pill:last-child {
        animation:
            sv-fadein 0.4s var(--ease-out) 2.25s 1 both,
            sv-serve 2.8s var(--ease-out) 2.7s infinite;
    }

    /* capitalbridge: the covenant board loads. This card is .st-s4 and every beat
       above is scoped to .st-s2 / .st-s3, so it carried data-sv-stage and .sv-play
       but had no sequence at all: it measured 0.256% of movement over four seconds
       against 1.1-1.9% for its siblings. The only thing moving was the standing
       .sv-pill-hot pulse. Beats below follow the same register as the other three:
       portfolio KPIs land, each covenant resolves in turn, the MCP foot confirms
       last, and the eye finishes on the one covenant that needs a human. */
    .st-card.sv-play .st-s4 .fp-kpi:nth-child(1) { animation: sv-rise 0.45s var(--ease-out) 0.15s 1 both; }
    .st-card.sv-play .st-s4 .fp-kpi:nth-child(2) { animation: sv-rise 0.45s var(--ease-out) 0.28s 1 both; }
    .st-card.sv-play .st-s4 .fp-kpi:nth-child(3) { animation: sv-rise 0.45s var(--ease-out) 0.41s 1 both; }

    .st-card.sv-play .st-s4 .sv-queue-row:nth-child(1) { animation: sv-rise 0.45s var(--ease-out) 0.70s 1 both; }
    .st-card.sv-play .st-s4 .sv-queue-row:nth-child(2) { animation: sv-rise 0.45s var(--ease-out) 0.90s 1 both; }
    .st-card.sv-play .st-s4 .sv-queue-row:nth-child(3) { animation: sv-rise 0.45s var(--ease-out) 1.10s 1 both; }

    .st-card.sv-play .st-s4 .sv-queue-row:nth-child(1) .sv-ok { animation: sv-pop 0.3s var(--ease-out) 1.22s 1 both; }
    .st-card.sv-play .st-s4 .sv-queue-row:nth-child(3) .sv-ok { animation: sv-pop 0.3s var(--ease-out) 1.52s 1 both; }

    .st-card.sv-play .st-s4 .sv-win-foot { animation: sv-rise 0.45s var(--ease-out) 1.80s 1 both; }
}

@keyframes sv-rise {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: none; }
}

@keyframes sv-pop {
    from { opacity: 0; transform: scale(0.5); }
    to { opacity: 1; transform: none; }
}

@keyframes sv-grow {
    from { transform: scaleY(0); }
    to { transform: scaleY(1); }
}

/* ---------------------------------------------------------------------
   Bento v3.3 — scenes, not lone windows (2026-07-16 founder: grids out,
   no data shared with the AI section, cards 02-04 read boring).
   Stage grids removed everywhere; the lead tells an ORDERS story
   (get_open_orders — receivables belongs to the AI section); the other
   stages become two-layer scenes:
     doc  — a paper invoice (tilted sheet with a scan beam) feeding the
            extraction window: six fields, each validated.
     fpa  — a Power BI report with a KPI strip over the chart, and the
            write-back dialog stamped committed.
     apps — the physical warehouse gate display (dark board, big number)
            in front of the queue screen, plus webshop order #18240 (the
            same order that arrived in the lead card) confirming.
   --------------------------------------------------------------------- */

/* the two-layer scenes need taller stages than the lone windows did */
@media (min-width: 1024px) {
    .st-card:not(.st-wide) { min-height: 545px; }
    .st-wide.st-apps { min-height: 500px; }
}

/* --- 02 · the paper invoice --- */
.doc-paper {
    position: absolute;
    left: 24px;
    bottom: -14px;
    width: 34%;
    z-index: 1;
}

.doc-sheet-back {
    position: absolute;
    inset: 10px -8px -6px 8px;
    background: #F3EFE7;
    border: 1px solid #E4E1DA;
    transform: rotate(2deg);
}

.doc-sheet {
    position: relative;
    background: #FFFFFF;
    border: 1px solid #E4E1DA;
    box-shadow: 0 14px 36px rgba(74, 36, 12, 0.10);
    padding: 16px 16px 18px;
    transform: rotate(-2deg);
    overflow: hidden;
}

.doc-sheet-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    margin-bottom: 14px;
}

.doc-logo {
    width: 26px;
    height: 12px;
    background: #7F1D1D;
}

.doc-addr { display: grid; gap: 4px; justify-items: end; }
.doc-addr i { display: block; width: 54px; height: 4px; background: #E8E4DB; }
.doc-addr i:last-child { width: 38px; }

.doc-ln {
    display: block;
    height: 5px;
    background: #EAE6DD;
    margin: 7px 0;
}

.doc-ln.w70 { width: 70%; }
.doc-ln.w45 { width: 45%; }
.doc-ln.w35 { width: 35%; }

.doc-items {
    display: grid;
    gap: 6px;
    margin: 12px 0;
    padding: 9px 0;
    border-top: 1px solid #E4E1DA;
    border-bottom: 1px solid #E4E1DA;
}

.doc-items i { display: block; height: 5px; background: #EFEBE3; }
.doc-items i:nth-child(2) { width: 86%; }
.doc-items i:nth-child(3) { width: 62%; }

.doc-ln.doc-total {
    margin-left: auto;
    margin-top: 10px;
    background: #C9C2B4;
}

.doc-beam {
    position: absolute;
    left: 0;
    right: 0;
    top: -4px;
    height: 3px;
    background: linear-gradient(to right, transparent, rgba(180, 83, 9, 0.85), transparent);
    opacity: 0;
}

.st-stage .sv-win.doc-out {
    left: auto;
    right: 24px;
    width: 58%;
    bottom: 20px;
    z-index: 2;
}

/* --- 03 · the planning report — full-width since 2026-07-16 (founder);
   the wide composition lives with the fpw-* kit further down --- */

.fp-kpis {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
    margin-bottom: 12px;
}

.fp-kpi {
    border: 1px solid #F0EDE6;
    background: #FCFBF8;
    padding: 8px 10px;
}

.fp-kpi span {
    display: block;
    font-size: 0.625rem;
    color: #8F8B80;
    margin-bottom: 2px;
}

.fp-kpi b {
    font-size: 0.9375rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: #1D1D1F;
}

.fp-kpi em {
    display: block;
    font-style: normal;
    font-size: 0.625rem;
    color: #8F8B80;
}

.fp-kpi em.up { color: #B45309; font-weight: 600; }

.st-s3 .sv-bars { height: 104px; }

/* the write-back modal: a real dialog overlapping the report's edge,
   not a floating chip */
.fp-dialog {
    position: absolute;
    right: 18px;
    top: 38%;
    z-index: 3;
    width: 212px;
    background: #FFFFFF;
    border: 1px solid #E4E1DA;
    border-radius: 10px;
    box-shadow: 0 24px 60px rgba(74, 36, 12, 0.22);
    padding: 13px 15px 12px;
    font-size: 0.6875rem;
}

.fp-dialog b {
    display: block;
    font-weight: 600;
    font-size: 0.75rem;
    color: #1D1D1F;
    margin-bottom: 3px;
}

.fp-ver {
    display: block;
    font-family: 'Cascadia Code', Consolas, ui-monospace, monospace;
    font-size: 0.625rem;
    color: #8F8B80;
}

.fp-swap {
    display: block;
    position: relative;
    margin-top: 9px;
    padding-top: 9px;
    border-top: 1px solid #F0EDE6;
}

.fp-state { color: rgba(29, 29, 31, 0.6); white-space: nowrap; }
.fp-state.fp-ok { color: #B45309; font-weight: 600; }

.sv-swap .fp-state:last-child {
    position: absolute;
    inset: 0;
    display: inline-flex;
    align-items: center;
    opacity: 1;   /* static render shows the committed state */
}

.sv-swap .fp-state:first-child { opacity: 0; }

/* --- 04 · the dispatch console with the gate display docked inside --- */
.st-wide.st-apps .sv-win.app-win {
    left: 28px;
    bottom: 18px;
    width: min(52%, 560px);
}

.app-strip {
    display: grid;
    grid-template-columns: auto 1fr 1fr;
    gap: 10px;
    padding: 12px 14px 0;
}

.gate-inset {
    background: #211714;
    border: 1px solid rgba(232, 167, 101, 0.25);
    box-shadow: inset 0 0 30px rgba(232, 167, 101, 0.07);
    border-radius: 6px;
    padding: 9px 18px 8px;
    text-align: center;
}

.app-cell {
    border: 1px solid #F0EDE6;
    background: #FCFBF8;
    border-radius: 6px;
    padding: 9px 12px 8px;
}

.app-cell span {
    display: block;
    font-size: 0.625rem;
    color: #8F8B80;
    margin-bottom: 2px;
}

.app-cell b {
    font-size: 1rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: #1D1D1F;
}

.gate-label {
    display: block;
    font-size: 0.5625rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: rgba(232, 167, 101, 0.75);
    margin-bottom: 6px;
}

.gate-num {
    position: relative;
    display: block;
    font-family: 'Cascadia Code', Consolas, ui-monospace, monospace;
    font-size: 1.5rem;
    line-height: 1.1;
    font-weight: 600;
    color: #E8A765;
    text-shadow: 0 0 18px rgba(232, 167, 101, 0.55);
}

.gate-num b { font-weight: 600; }

.gate-swap b:last-child {
    position: absolute;
    inset: 0;
    opacity: 0;
}

.gate-sub {
    display: block;
    margin-top: 3px;
    font-size: 0.5625rem;
    color: rgba(255, 234, 210, 0.55);
}

.st-wide.st-apps .sv-win.ord-win {
    left: auto;
    right: 28px;
    bottom: 40px;
    width: min(28%, 300px);
}

/* the flow line: the console's confirmation travels to the order (plain
   dashed connector, no MCP node — that motif belongs to the lead) */
.st-wide.st-apps .flow-wire {
    left: 48%;
    right: 24%;
    top: 52%;
}

/* --- hover beats for the new scenes --- */
@media (prefers-reduced-motion: no-preference) {
    /* the answer's sources flash in the orders table */
    .st-card.sv-traced .sv-src .ms-pill { animation: sv-trace 1.4s var(--ease-out) 1; }

    /* doc: the beam reads the paper; its content lines flash as they are
       read; the fields land with ticks (six rows now) */
    .st-card.sv-play .doc-beam { animation: sv-scan 1.2s var(--ease-out) 0.15s 1; }

    .st-card.sv-play .doc-sheet { animation: sv-pageglow 1.2s var(--ease-out) 0.15s 1; }

    .st-card.sv-play .doc-ln,
    .st-card.sv-play .doc-items i { animation: sv-readln 0.5s var(--ease-out) 1 both; }

    .st-card.sv-play .doc-ln.w70 { animation-delay: 0.30s; }
    .st-card.sv-play .doc-ln.w45 { animation-delay: 0.45s; }
    .st-card.sv-play .doc-items i:nth-child(1) { animation-delay: 0.60s; }
    .st-card.sv-play .doc-items i:nth-child(2) { animation-delay: 0.72s; }
    .st-card.sv-play .doc-items i:nth-child(3) { animation-delay: 0.84s; }
    .st-card.sv-play .doc-ln.doc-total { animation-delay: 1.00s; }

    .st-card.sv-play .sv-doc-row:nth-child(4) { animation: sv-rise 0.45s var(--ease-out) 1.00s 1 both; }
    .st-card.sv-play .sv-doc-row:nth-child(5) { animation: sv-rise 0.45s var(--ease-out) 1.20s 1 both; }
    .st-card.sv-play .sv-doc-row:nth-child(6) { animation: sv-rise 0.45s var(--ease-out) 1.40s 1 both; }

    .st-card.sv-play .sv-doc-row:nth-child(4) .sv-tick { animation: sv-pop 0.3s var(--ease-out) 1.55s 1 both; }
    .st-card.sv-play .sv-doc-row:nth-child(5) .sv-tick { animation: sv-pop 0.3s var(--ease-out) 1.75s 1 both; }
    .st-card.sv-play .sv-doc-row:nth-child(6) .sv-tick { animation: sv-pop 0.3s var(--ease-out) 1.95s 1 both; }

    .st-card.sv-play .st-s2 .sv-win-foot { animation-delay: 2.2s; }

    /* fpa: the FY26 total and its quarters land, bars commit, dialog stamps */
    .st-card.sv-play .fpw-tree-fy { animation: sv-rise 0.4s var(--ease-out) 0.05s 1 both; }
    .st-card.sv-play .fpw-tree-q > span:nth-child(1) { animation: sv-rise 0.4s var(--ease-out) 0.14s 1 both; }
    .st-card.sv-play .fpw-tree-q > span:nth-child(2) { animation: sv-rise 0.4s var(--ease-out) 0.20s 1 both; }
    .st-card.sv-play .fpw-tree-q > span:nth-child(3) { animation: sv-rise 0.4s var(--ease-out) 0.26s 1 both; }
    .st-card.sv-play .fpw-tree-q > span:nth-child(4) { animation: sv-rise 0.4s var(--ease-out) 0.32s 1 both; }

    .st-card.sv-play .fp-swap .fp-state:first-child {
        animation: sv-fadein 0.2s var(--ease-out) 0.9s 1 both, sv-fadeout 0.22s var(--ease-out) 1.95s 1 both;
    }

    .st-card.sv-play .fp-swap .fp-state:last-child {
        animation: sv-fadeout 0.2s var(--ease-out) 0s 1 both, sv-fadein 0.3s var(--ease-out) 2.25s 1 both;
    }

    /* apps: the gate display flips with the queue */
    .st-card.sv-play .gate-swap b:first-child { animation: sv-fadeout 0.4s var(--ease-out) 2.25s 1 both; }
    .st-card.sv-play .gate-swap b:last-child { animation: sv-fadein 0.4s var(--ease-out) 2.25s 1 both; }

    .st-card.sv-play .ord-win .sv-doc-row:nth-child(1) { animation: sv-rise 0.45s var(--ease-out) 0.40s 1 both; }
    .st-card.sv-play .ord-win .sv-doc-row:nth-child(2) { animation: sv-rise 0.45s var(--ease-out) 0.60s 1 both; }
    .st-card.sv-play .ord-win .sv-doc-row:nth-child(3) { animation: sv-rise 0.45s var(--ease-out) 0.80s 1 both; }

    .st-card.sv-play .ord-win .sv-tick { animation: sv-pop 0.3s var(--ease-out) 1.1s 1 both; }
}

@keyframes sv-readln {
    0%, 100% { background-color: #EAE6DD; }
    45% { background-color: rgba(232, 167, 101, 0.85); }
}

/* mobile: the scenes simplify — paper and gate board step aside, the
   windows stack */
@media (max-width: 1023.98px) {
    .doc-paper { display: none; }
    .st-stage .sv-win.doc-out { left: 24px; right: 24px; width: auto; }
    .st-wide.st-apps .sv-win.app-win,
    .st-wide.st-apps .sv-win.ord-win {
        position: static;
        width: auto;
        margin: 10px 20px 20px;
    }
}

/* ---------------------------------------------------------------------
   Bento v3.5 — the write-back cell (2026-07-16, founder: prompt the
   visitor to enter something and show how it affects the other values
   and the chart; use the real Acterys write-back shortcuts; keep it
   simple; the write-back arrives in Acterys teal). The FP&A card
   carries it: the ink-and-amber fiscal year inside the report, one
   editable December cell that accepts a plain number or the shortcuts
   (i5 · a-150 · g3, tappable as chips), the KPIs and bars recompute,
   and every commit stamps the next version through the Acterys
   write-back dialog. The demo TYPES its own first entry and hits
   Enter (initFpWriteback), then the cell belongs to the visitor.
   Server-rendered state = the committed v08 baseline.
   --------------------------------------------------------------------- */

.st-card.st-fp { cursor: default; }

.st-card.st-fp .st-expand { cursor: pointer; }

/* the visual reads like a real report visual: a title, an actuals/forecast
   legend, and a plot area with a labelled value axis (0–600k scale) */
.fpw-vhead {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 8px;
}

.fpw-vtitle {
    font-size: 0.625rem;
    font-weight: 600;
    color: #6E6B63;
}

.fpw-legend {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.575rem;
    color: #8F8B80;
}

.fpw-legend s { text-decoration: none; width: 12px; height: 8px; display: inline-block; flex: none; }

.fpw-legend s.l-a { background: rgba(29, 29, 31, 0.72); }

.fpw-legend s.l-f {
    margin-left: 8px;
    background: repeating-linear-gradient(45deg, rgba(180, 83, 9, 0.5) 0 3px, transparent 3px 6px);
    box-shadow: inset 0 0 0 1px #B45309;
}

.fpw-chart { padding-left: 34px; }

.fpw-year {
    position: relative;
    display: flex;
    align-items: flex-end;
    gap: 5px;
    height: 96px;
    margin-bottom: 4px;
}

/* the value axis: hairline gridlines with € labels */
.fpw-gl {
    position: absolute;
    left: 0;
    right: 0;
    height: 1px;
    background: rgba(29, 29, 31, 0.08);
    pointer-events: none;
}

.fpw-gl em {
    position: absolute;
    left: -34px;
    top: -4px;
    width: 28px;
    text-align: right;
    font-style: normal;
    font-size: 0.5rem;
    color: #A5A196;
    font-variant-numeric: tabular-nums;
}

.fpw-year i { display: block; flex: 1; position: relative; z-index: 1; }

.fpw-year i.a { background: rgba(29, 29, 31, 0.72); }

.fpw-year i.f {
    background: repeating-linear-gradient(45deg, rgba(180, 83, 9, 0.5) 0 3px, transparent 3px 6px);
    box-shadow: inset 0 0 0 1px #B45309;
}

.fpw-year i.hot {
    background: repeating-linear-gradient(45deg, rgba(180, 83, 9, 0.85) 0 3px, rgba(180, 83, 9, 0.25) 3px 6px);
    box-shadow: inset 0 0 0 1px #7A4A07;
}

.fpw-today {
    position: absolute;
    top: -4px;
    bottom: -16px;
    left: 50%;
    width: 1px;
    background: rgba(127, 29, 29, 0.5);
}

.fpw-labs { display: flex; gap: 5px; margin-bottom: 12px; }

.fpw-labs span {
    flex: 1;
    text-align: center;
    font-size: 0.5rem;
    letter-spacing: 0.06em;
    color: #A5A196;
}

.fpw-labs span.hot { color: #7A4A07; font-weight: 600; }

/* the Acterys planning matrix: the forecast row as editable-looking cells,
   December is the one that really edits */
.fpw-matrix { display: flex; align-items: stretch; gap: 4px; margin-bottom: 10px; }

.fpw-mx-label {
    flex: none;
    width: 58px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    font-size: 0.55rem;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: #8F8B80;
    font-weight: 600;
    line-height: 1.35;
}

.fpw-mx-cell {
    flex: 1;
    min-width: 0;
    border: 1px solid #EFEDE7;
    background: #FCFBF8;
    padding: 3px 6px 4px;
}

.fpw-mx-cell em {
    display: block;
    font-style: normal;
    font-size: 0.5rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: #A5A196;
}

.fpw-mx-cell b {
    display: block;
    text-align: right;
    font-size: 0.6875rem;
    font-weight: 500;
    color: #1D1D1F;
    font-variant-numeric: tabular-nums;
}

.fpw-mx-edit { flex: 1.35; border: none; background: none; padding: 0; display: flex; flex-direction: column; }

.fpw-mx-edit em { padding: 0 0 1px 1px; color: #7A4A07; font-weight: 600; }

.fpw-input {
    flex: 1;
    width: 100%;
    min-width: 0;
    padding: 3px 6px;
    background: rgba(180, 83, 9, 0.10);
    box-shadow: inset 0 0 0 1px #B45309;
    border: none;
    border-radius: 0;
    color: #7A4A07;
    font-family: 'Cascadia Code', Consolas, ui-monospace, monospace;
    font-size: 0.6875rem;
    font-weight: 600;
    text-align: right;
    outline: none;
    font-variant-numeric: tabular-nums;
    transition: box-shadow 0.3s var(--ease-out), background 0.3s var(--ease-out), color 0.3s var(--ease-out);
}

.fpw-input:focus { box-shadow: inset 0 0 0 2px #B45309; }

/* the commit flash: Acterys teal takes the cell for a beat */
.fpw-input.fpw-committed {
    box-shadow: inset 0 0 0 2px #12807C;
    background: rgba(18, 128, 124, 0.08);
    color: #0E5F5C;
}

.fpw-key {
    flex: none;
    min-width: 30px;
    height: 28px;
    padding: 0 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid #DDDDDD;
    background: #FCFBF8;
    color: #6E6B63;
    font-size: 0.8125rem;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.1s;
}

.fpw-key:hover { border-color: #B45309; color: #7A4A07; }

.fpw-key.press { transform: translateY(1px) scale(0.96); border-color: #B45309; color: #7A4A07; }

.fpw-chips { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

.fpw-try {
    font-size: 0.575rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #8F8B80;
    font-weight: 600;
    margin-right: 2px;
}

.fpw-chips button {
    display: inline-flex;
    align-items: baseline;
    gap: 5px;
    padding: 3px 9px;
    border: 1px solid #DDDDDD;
    background: #FFFFFF;
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
}

.fpw-chips button b {
    font-family: 'Cascadia Code', Consolas, ui-monospace, monospace;
    font-size: 0.6875rem;
    font-weight: 600;
    color: #7A4A07;
}

.fpw-chips button em { font-style: normal; font-size: 0.575rem; color: #8F8B80; }

.fpw-chips button:hover { border-color: #12807C; background: rgba(18, 128, 124, 0.05); }

.fpw-more { margin: 7px 0 0; font-size: 0.575rem; color: #A5A196; }

/* the cascade tree (option C, 2026-07-20): one FY26 total sits above a
   dashed bracket that fans down to the four quarters. Q1/Q2 are settled
   actuals (dimmed); the two forecast quarters (Q3/Q4) light teal (.lit)
   and refill as the total splashes down. Flat system: square bracket, no
   radius. */
.fpw-tree { margin-bottom: 14px; }

.fpw-tree-fy { display: flex; gap: 6px; justify-content: center; margin-bottom: 8px; }

.fpw-fycell { max-width: 172px; flex: none; }

.fpw-fycell em { color: #7A4A07; font-weight: 600; }

.fpw-fycell .fpw-input { font-size: 0.8125rem; }

/* the ± stepper keys read as a matched pair flanking the total */
.fpw-step { min-width: 28px; padding: 0; font-size: 1.0625rem; font-weight: 500; }

.fpw-tree-rule {
    height: 12px;
    margin: 0 16%;
    border-left: 1px dashed #CBB9A6;
    border-right: 1px dashed #CBB9A6;
    border-bottom: 1px dashed #CBB9A6;
}

.fpw-tree-q { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin: 8px 0 2px; }

.fpw-q {
    border: 1px solid #EFEDE7;
    background: #FCFBF8;
    padding: 5px 8px;
    text-align: center;
    transition: box-shadow 0.3s var(--ease-out), background 0.3s var(--ease-out);
}

.fpw-q em {
    display: block;
    font-style: normal;
    font-size: 0.5rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: #A5A196;
}

.fpw-q b { font-size: 0.6875rem; font-variant-numeric: tabular-nums; }

.fpw-q.done { opacity: 0.5; }

.fpw-q.lit { box-shadow: inset 0 0 0 2px #12807C; background: rgba(18, 128, 124, 0.08); }

/* Acterys teal appears only where the write-back happens: the mark, the
   dialog's top rule, the committed check, the cell's commit flash */
.sv-win-foot .sv-ok.fpw-ok { color: #12807C; }

/* small screens: the cascade tree is this card's centrepiece, so the
   write-back dialog is anchored LOW — it stands over the matrix/foot while
   the FY26 total, the bracket, the quarters lighting, and the growing bars
   all stay visible above it. At desktop width (wide card) it stands on the
   field beside the window instead (override below). */
.fpw-dialog { border-top: 2px solid #12807C; left: 16px; right: auto; top: auto; bottom: 74px; }

.fpw-wire { display: none; }

@media (min-width: 1024px) {
    /* the three-quarter composition: report window left, the Acterys
       write-back dialog standing on the warm field to its right, the
       wire running between them under both (lead-card grammar) */
    .st-card.st-fp .st-stage { min-height: 465px; }

    .st-card.st-fp .sv-win.fp-win {
        left: 28px;
        right: auto;
        bottom: 20px;
        width: min(60%, 570px);
    }

    .st-card.st-fp .fpw-dialog {
        left: auto;
        right: 28px;
        top: auto;
        bottom: 116px;
        width: min(30%, 290px);
    }

    .st-card.st-fp .fpw-wire {
        display: block;
        position: absolute;
        z-index: 1;
        left: 52%;
        right: 16%;
        bottom: 176px;
        height: 1px;
    }

    .fpw-wire .line {
        position: absolute;
        inset: 0;
        background: linear-gradient(90deg, rgba(127, 29, 29, 0), rgba(127, 29, 29, 0.5) 15%, rgba(127, 29, 29, 0.5) 85%, rgba(127, 29, 29, 0));
    }

    /* the FP&A card and the CapitalBridge tile share a row on the 4-col
       grid; give the 3-span title the wide measure */
    .st-w3 .st-title { max-width: 34ch; }
}

/* ---------------------------------------------------------------------
   02c · the shop-to-warehouse card (2026-07-16, replacing the dispatch
   console the founder rejected). The visitor presses Place order in the
   webshop window and the order lands in the pick queue below: stock
   decrements, the confirmation stamps #7313, #7314, …, and when stock
   runs low the shop proposes a reorder. initAppOrder presses the button
   once on arrival, then it belongs to the visitor.
   --------------------------------------------------------------------- */

.st-card.st-shop { cursor: default; }

.st-card.st-shop .st-expand { cursor: pointer; }

.st-shop .st-stage { min-height: 345px; }

.st-shop .sv-win.shop-win { top: 24px; left: 24px; right: 24px; bottom: auto; width: auto; }

.st-shop .sv-win.wh-win { bottom: 20px; left: 24px; right: 24px; width: auto; }

.shop-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }

.shop-item b { display: block; font-size: 0.75rem; font-weight: 600; color: #1D1D1F; }

.shop-item span { font-size: 0.6875rem; color: #6E6B63; }

.shop-btn {
    flex: none;
    border: none;
    background: #1D1D1F;
    color: #FFFFFF;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    padding: 9px 16px;
    cursor: pointer;
    transition: background 0.15s, transform 0.1s, opacity 0.15s;
}

.shop-btn:hover { background: #7F1D1D; }

.shop-btn.press { transform: scale(0.95); background: #7F1D1D; }

.shop-btn:disabled { background: #A5A196; cursor: default; }

.shop-state { color: rgba(29, 29, 31, 0.6); white-space: nowrap; }

.shop-state.shop-ok { color: #B45309; font-weight: 600; }

.sv-swap .shop-state:last-child {
    position: absolute;
    inset: 0;
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    opacity: 1;
}

.sv-swap .shop-state:first-child { opacity: 0; }

.st-card.shop-live .shop-swap .shop-state {
    animation: none !important;
    transition: opacity 0.25s var(--ease-out);
}

.st-card.shop-live .shop-swap.shop-busy .shop-state:first-child { opacity: 1; }
.st-card.shop-live .shop-swap.shop-busy .shop-state:last-child { opacity: 0; }

.shop-low { color: #B45309; font-weight: 600; }

@keyframes shop-land {
    0% { background-color: rgba(180, 83, 9, 0.14); }
    100% { background-color: transparent; }
}

@media (prefers-reduced-motion: no-preference) {
    .sv-queue-row.land { animation: shop-land 0.9s var(--ease-out) 1; }
}

/* small screens: the two shop windows stack statically, no anchoring */
@media (max-width: 1023.98px) {
    .st-shop .st-stage { min-height: 0; }

    .st-shop .sv-win.shop-win,
    .st-shop .sv-win.wh-win {
        position: static;
        width: auto;
        margin: 10px 20px;
    }

    .st-shop .sv-win.wh-win { margin-bottom: 20px; }
}

/* 03b · the CapitalBridge tile: three published KPIs over a covenant board */
.st-cb-kpis { grid-template-columns: repeat(3, 1fr); gap: 6px; }

.st-cb .fp-kpi { padding: 8px 7px; }

@media (max-width: 1023.98px) {
    .st-card.st-fp .sv-win.fp-win {
        position: static;
        width: auto;
        margin: 10px 20px 20px;
    }
}

/* small phones: the six matrix cells wrap into two rows of three */
@media (max-width: 640px) {
    .fpw-matrix { flex-wrap: wrap; }

    .fpw-mx-label { width: 100%; flex-direction: row; gap: 4px; margin-bottom: 2px; }

    .fpw-mx-cell { flex: 1 1 27%; }

    .fpw-mx-edit { flex: 1 1 32%; }
}

.fpw-dialog .fp-state.fp-ok { color: #12807C; }

.fpw-mark { display: block; height: 21px; width: auto; margin-bottom: 8px; }

@keyframes fpw-glow {
    0% { box-shadow: 0 0 0 0 rgba(18, 128, 124, 0.38), 0 24px 60px rgba(74, 36, 12, 0.22); }
    100% { box-shadow: 0 0 0 10px rgba(18, 128, 124, 0), 0 24px 60px rgba(74, 36, 12, 0.22); }
}

@keyframes fpw-flash {
    0% { background-color: rgba(18, 128, 124, 0.16); }
    100% { background-color: #FCFBF8; }
}

.fp-kpi em.down { color: #7F1D1D; font-weight: 600; }

/* once the visitor drives the model, the dialog is state-driven: the
   hover-play keyframes release and the bars/KPIs move on live values */
.st-card.fp-live .fp-swap .fp-state {
    animation: none !important;
    transition: opacity 0.25s var(--ease-out);
}

.st-card.fp-live .fp-dialog.fp-busy .fp-state:first-child { opacity: 1; }
.st-card.fp-live .fp-dialog.fp-busy .fp-state:last-child { opacity: 0; }

@media (prefers-reduced-motion: no-preference) {
    .st-card .sv-bars i.sv-f { transition: transform 0.6s var(--ease-out), height 0.5s var(--ease-out); }

    .fpw-year i { transition: height 0.6s var(--ease-out); }

    .fpw-dialog.fpw-glowing { animation: fpw-glow 0.9s var(--ease-out) 1; }

    /* changed cells and KPI tiles flash teal as the write-back lands */
    .fpw-mx-cell.flash,
    .fp-kpi.flash { animation: fpw-flash 0.9s var(--ease-out) 1; }

    /* arrival: the year draws itself, actuals first, forecast after
       (nth-of-type: the axis gridline spans share the container) */
    .st-card.sv-play .fpw-year i { transform-origin: bottom; animation: fpw-draw 0.5s var(--ease-out) 1 both; }
    .st-card.sv-play .fpw-year i:nth-of-type(1) { animation-delay: 0.05s; }
    .st-card.sv-play .fpw-year i:nth-of-type(2) { animation-delay: 0.10s; }
    .st-card.sv-play .fpw-year i:nth-of-type(3) { animation-delay: 0.15s; }
    .st-card.sv-play .fpw-year i:nth-of-type(4) { animation-delay: 0.20s; }
    .st-card.sv-play .fpw-year i:nth-of-type(5) { animation-delay: 0.25s; }
    .st-card.sv-play .fpw-year i:nth-of-type(6) { animation-delay: 0.30s; }
    .st-card.sv-play .fpw-year i:nth-of-type(7) { animation-delay: 0.40s; }
    .st-card.sv-play .fpw-year i:nth-of-type(8) { animation-delay: 0.45s; }
    .st-card.sv-play .fpw-year i:nth-of-type(9) { animation-delay: 0.50s; }
    .st-card.sv-play .fpw-year i:nth-of-type(10) { animation-delay: 0.55s; }
    .st-card.sv-play .fpw-year i:nth-of-type(11) { animation-delay: 0.60s; }
    .st-card.sv-play .fpw-year i:nth-of-type(12) { animation-delay: 0.65s; }
}

@keyframes fpw-draw {
    0% { transform: scaleY(0); }
    100% { transform: scaleY(1); }
}

/* fpw polish (2026-07-17 founder): the Dec cell must read as the same box
   as its siblings — same padding rhythm, label inside the ring, the amber
   ring on the CELL (not the bare input); and the Acterys write-back toast
   steps up a size so it reads as the payoff, not a footnote. */
.fpw-mx-edit {
    padding: 3px 6px 4px;
    background: rgba(180, 83, 9, 0.10);
    box-shadow: inset 0 0 0 1px #B45309;
    transition: box-shadow 0.3s var(--ease-out), background 0.3s var(--ease-out);
}

.fpw-mx-edit em { padding: 0; }

.fpw-input,
.fpw-input:focus,
.fpw-input.fpw-committed {
    padding: 0;
    background: none;
    box-shadow: none;
}

.fpw-mx-edit:focus-within { box-shadow: inset 0 0 0 2px #B45309; }

.fpw-mx-edit:has(.fpw-committed) {
    box-shadow: inset 0 0 0 2px #12807C;
    background: rgba(18, 128, 124, 0.08);
}

.fp-dialog.fpw-dialog { width: 268px; padding: 16px 18px 14px; }

.fpw-dialog .fpw-mark { height: 27px; margin-bottom: 10px; }

.fpw-dialog b { font-size: 0.875rem; }

.fpw-dialog .fp-ver { font-size: 0.6875rem; }

.fpw-dialog .fp-state { font-size: 0.75rem; }

/* =====================================================================
   pst-* · the lawyer.ai "deadline save" product scene (2026-07-17,
   founder-chosen round-2/3 direction from /preview/apps-section).
   A ~6s hard-cut scene: judgment served → deadline engine computes
   (statute + court recess + holidays) → calendar pinned → task assigned
   → appeal drafted on letterhead, approved, filed early. Renders SETTLED
   without JS; plays when a .play class lands on .pst-stage.
   lt-* · the live-tile mechanic in the Apps grid: hovering the lawyer.ai
   tile expands the scene overlay across the grid (transform/opacity only,
   the grid never reflows), leave collapses it. Pointer-fine devices only;
   touch keeps the tile's normal click-to-modal behavior.
   ===================================================================== */

.pst-stage { position: relative; min-height: 540px; }

.pst-win { position: absolute; background: #FFFFFF; border-radius: 10px; overflow: hidden; box-shadow: 0 18px 44px rgba(0, 0, 0, 0.45); font-size: 0.71rem; color: #1D1D1F; }

.pst-bar { display: flex; gap: 6px; align-items: center; padding: 7px 11px; border-bottom: 1px solid #EFEDE7; font-size: 0.625rem; font-weight: 600; color: #6E6B63; }

.pst-bar i { width: 6px; height: 6px; border-radius: 50%; background: #DCD8CE; flex: none; }

.pst-bar em { margin-left: auto; font-style: normal; font-size: 0.575rem; color: #A5A196; font-weight: 400; }

.pst-row { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; padding: 6px 11px; border-bottom: 1px solid #F1EFE9; font-weight: 300; }

.pst-row b { font-weight: 500; font-variant-numeric: tabular-nums; white-space: nowrap; }

.pst-row .pin { display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 6px; }

.pst-row .pin.red { background: #7F1D1D; }

.pst-row .pin.amb { background: #B45309; }

.pst-row.final { background: linear-gradient(90deg, rgba(127, 29, 29, 0.10), transparent 70%); font-weight: 500; }

.pst-row.final2 { background: linear-gradient(90deg, rgba(180, 83, 9, 0.12), transparent 70%); font-weight: 500; }

.pst-foot { display: flex; justify-content: space-between; gap: 10px; padding: 7px 11px; background: #FCFBF8; font-size: 0.6rem; color: #6E6B63; }

.pst-foot .ok { color: #B45309; font-weight: 600; }

.pst-doc { position: absolute; left: 3%; top: 7%; width: 23%; background: #FDFCF9; border-radius: 2px; box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5); transform: rotate(-2.5deg); padding: 14px 14px 16px; }

.pst-doc .h { font-size: 0.575rem; letter-spacing: 0.08em; color: #6E6B63; font-weight: 600; text-transform: uppercase; }

.pst-doc .t { font-family: Georgia, 'Times New Roman', serif; font-size: 0.95rem; margin: 7px 0 10px; color: #1D1D1F; }

.pst-doc .l { height: 5px; background: #E5E2DA; margin: 7px 0; }

.pst-doc .l.w70 { width: 70%; }

.pst-doc .l.w50 { width: 50%; }

.pst-doc .s { font-size: 0.575rem; color: #A5A196; margin-top: 10px; }

.pst-stamp { position: absolute; right: -12px; top: -14px; transform: rotate(8deg); border: 2px solid #7F1D1D; color: #7F1D1D; font-weight: 700; font-size: 0.6rem; letter-spacing: 0.1em; padding: 4px 8px; background: rgba(255, 255, 255, 0.88); text-transform: uppercase; white-space: nowrap; }

.pst-engine { left: 30%; top: 5%; width: 37%; }

.pst-team { right: 2.5%; top: 9%; width: 26%; }

.pst-team .pst-row.new { background: rgba(224, 142, 43, 0.16); font-weight: 500; }

.pst-cal { position: absolute; left: 30%; top: 66%; width: 40%; }

.pst-cal .axis { position: relative; height: 1px; background: rgba(255, 255, 255, 0.35); margin-top: 30px; transform-origin: left center; }

.pst-cal .rec { position: absolute; left: 20%; width: 46%; top: -12px; height: 24px; background: repeating-linear-gradient(45deg, rgba(224, 142, 43, 0.28) 0 3px, transparent 3px 7px); border-left: 1px solid rgba(224, 142, 43, 0.5); border-right: 1px solid rgba(224, 142, 43, 0.5); }

.pst-cal .rec em { position: absolute; top: -18px; left: 50%; transform: translateX(-50%); font-style: normal; font-size: 0.575rem; color: rgba(255, 255, 255, 0.55); white-space: nowrap; }

.pst-cal .tick { position: absolute; top: -16px; width: 2px; height: 32px; }

.pst-cal .tick.amb { background: #E08E2B; }

.pst-cal .tick.red { background: #FF9C8F; }

.pst-cal .tick em { position: absolute; top: 36px; left: 1px; transform: translateX(-50%); font-style: normal; font-size: 0.575rem; white-space: nowrap; }

.pst-cal .tick.amb em { color: #E08E2B; top: -34px; }

.pst-cal .tick.red em { color: #FF9C8F; left: auto; right: 8px; transform: none; text-align: right; }

.pst-cal .mon { position: absolute; top: 60px; font-size: 0.575rem; letter-spacing: 0.12em; color: rgba(255, 255, 255, 0.35); }

.pst-chip { position: absolute; left: 61%; top: 32%; background: #B45309; color: #fff; font-size: 0.625rem; font-weight: 600; padding: 5px 11px; border-radius: 999px; box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4); white-space: nowrap; z-index: 3; opacity: 0; }

.pst-draft { right: 2.5%; top: 47%; width: 27%; }

.pst-draft .lh { font-family: Georgia, 'Times New Roman', serif; font-size: 0.75rem; color: #1D1D1F; padding: 9px 11px 0; }

.pst-draft .l { height: 5px; background: #E5E2DA; margin: 8px 11px; }

.pst-draft .l.w70 { width: 70%; }

.pst-draft .l.w55 { width: 55%; }

.pst-filed { position: absolute; right: 12px; bottom: 74px; transform: rotate(-7deg); border: 2px solid #B45309; color: #7A4A07; font-weight: 700; font-size: 0.625rem; letter-spacing: 0.08em; padding: 4px 9px; background: rgba(255, 255, 255, 0.9); text-transform: uppercase; white-space: nowrap; }

.pst-msg { position: absolute; left: 3%; bottom: 5%; width: 24%; color: #fff; font-size: 0.9375rem; font-weight: 400; line-height: 1.45; }

.pst-msg span { display: block; color: rgba(255, 255, 255, 0.5); font-size: 0.71rem; font-weight: 300; margin-top: 6px; line-height: 1.5; }

@media (prefers-reduced-motion: no-preference) {
    .pst-stage.play .pst-doc { animation: pst-slam 0.35s cubic-bezier(0.2, 0, 0, 1) 0s 1 both; }
    .pst-stage.play .pst-stamp { animation: pst-stampin 0.22s cubic-bezier(0.2, 0, 0, 1) 0.45s 1 both; }
    .pst-stage.play .pst-engine { animation: pst-pop 0.18s cubic-bezier(0.2, 0, 0, 1) 0.9s 1 both; }
    .pst-stage.play .pst-engine .pst-row:nth-child(2) { animation: pst-rowin 0.12s ease-out 1.15s 1 both; }
    .pst-stage.play .pst-engine .pst-row:nth-child(3) { animation: pst-rowin 0.12s ease-out 1.30s 1 both; }
    .pst-stage.play .pst-engine .pst-row:nth-child(4) { animation: pst-rowin 0.12s ease-out 1.45s 1 both; }
    .pst-stage.play .pst-engine .pst-row:nth-child(5) { animation: pst-rowin 0.12s ease-out 1.60s 1 both; }
    .pst-stage.play .pst-engine .pst-row.final { animation: pst-rowin 0.12s ease-out 1.85s 1 both, pst-flash 0.7s ease-out 1.97s 1; }
    .pst-stage.play .pst-engine .pst-row.final2 { animation: pst-rowin 0.12s ease-out 2.05s 1 both, pst-flash 0.7s ease-out 2.17s 1; }
    .pst-stage.play .pst-engine .pst-foot { animation: pst-rowin 0.15s ease-out 2.25s 1 both; }
    .pst-stage.play .pst-cal .axis { animation: pst-growx 0.3s cubic-bezier(0.2, 0, 0, 1) 2.5s 1 both; }
    .pst-stage.play .pst-cal .rec { animation: pst-fade 0.25s ease-out 2.75s 1 both; }
    .pst-stage.play .pst-cal .mon { animation: pst-fade 0.25s ease-out 2.75s 1 both; }
    .pst-stage.play .pst-cal .tick.amb { animation: pst-drop 0.2s cubic-bezier(0.2, 0, 0, 1) 3.0s 1 both; }
    .pst-stage.play .pst-cal .tick.red { animation: pst-drop 0.2s cubic-bezier(0.2, 0, 0, 1) 3.12s 1 both; }
    .pst-stage.play .pst-chip { animation: pst-fly 0.55s cubic-bezier(0.2, 0, 0, 1) 3.4s 1 both, pst-fade-out 0.25s ease-out 4.05s 1 forwards; }
    .pst-stage.play .pst-team { animation: pst-pop 0.18s cubic-bezier(0.2, 0, 0, 1) 3.75s 1 both; }
    .pst-stage.play .pst-team .pst-row.new { animation: pst-blink 0.5s ease-out 3.95s 1 both; }
    .pst-stage.play .pst-team .pst-row:not(.new) { animation: pst-rowin 0.12s ease-out 4.05s 1 both; }
    .pst-stage.play .pst-team .pst-foot { animation: pst-rowin 0.12s ease-out 4.15s 1 both; }
    .pst-stage.play .pst-draft { animation: pst-pop 0.18s cubic-bezier(0.2, 0, 0, 1) 4.4s 1 both; }
    .pst-stage.play .pst-draft .l, .pst-stage.play .pst-draft .lh { animation: pst-rowin 0.12s ease-out 4.6s 1 both; }
    .pst-stage.play .pst-draft .pst-row { animation: pst-rowin 0.12s ease-out 4.85s 1 both; }
    .pst-stage.play .pst-draft .pst-foot { animation: pst-rowin 0.12s ease-out 5.0s 1 both; }
    .pst-stage.play .pst-filed { animation: pst-stampin2 0.25s cubic-bezier(0.2, 0, 0, 1) 5.35s 1 both; }
    .pst-stage.play .pst-msg { animation: pst-fade 0.5s ease-out 5.8s 1 both; }
}

@keyframes pst-slam { 0% { opacity: 0; transform: rotate(-2.5deg) scale(1.18); } 60% { opacity: 1; transform: rotate(-2.5deg) scale(0.98); } 100% { opacity: 1; transform: rotate(-2.5deg) scale(1); } }

@keyframes pst-stampin { 0% { opacity: 0; transform: rotate(8deg) scale(1.7); } 100% { opacity: 1; transform: rotate(8deg) scale(1); } }

@keyframes pst-stampin2 { 0% { opacity: 0; transform: rotate(-7deg) scale(1.7); } 100% { opacity: 1; transform: rotate(-7deg) scale(1); } }

@keyframes pst-pop { 0% { opacity: 0; transform: translateY(12px) scale(0.96); } 100% { opacity: 1; transform: none; } }

@keyframes pst-rowin { 0% { opacity: 0; transform: translateX(-7px); } 100% { opacity: 1; transform: none; } }

@keyframes pst-flash { 0% { box-shadow: inset 0 0 0 100px rgba(180, 83, 9, 0.22); } 100% { box-shadow: none; } }

@keyframes pst-growx { 0% { transform: scaleX(0); } 100% { transform: scaleX(1); } }

@keyframes pst-fade { 0% { opacity: 0; } 100% { opacity: 1; } }

@keyframes pst-fade-out { 0% { opacity: 1; } 100% { opacity: 0; } }

@keyframes pst-drop { 0% { opacity: 0; transform: translateY(-12px) scaleY(0.4); } 100% { opacity: 1; transform: none; } }

@keyframes pst-fly { 0% { opacity: 0; transform: translate(0, 0) scale(0.8); } 25% { opacity: 1; } 100% { opacity: 1; transform: translate(115px, -78px) scale(1); } }

@keyframes pst-blink { 0% { opacity: 0; background: rgba(224, 142, 43, 0.45); } 100% { opacity: 1; background: rgba(224, 142, 43, 0.16); } }

/* --- lt-* · live tile in the Apps grid --- */

.lt-host { position: relative; }

.lt-host::after { content: ""; position: absolute; inset: 0; z-index: 4; background: rgba(18, 3, 3, 0.6); opacity: 0; pointer-events: none; transition: opacity 0.25s ease; }

.lt-host.lt-on::after { opacity: 1; }

.lt-live { box-shadow: inset 0 0 0 1px rgba(224, 142, 43, 0.45); }

.lt-live:hover { box-shadow: inset 0 0 0 1px rgba(224, 142, 43, 0.9); }

.lt-hint { display: block; font-size: 0.75rem; font-weight: 600; color: #FFB25E; margin-top: 10px; }

.lt-overlay { position: absolute; left: 0; top: 0; width: 100%; height: 570px; z-index: 5; background: #380808; border: 1px solid rgba(255, 255, 255, 0.28); box-shadow: 0 40px 110px rgba(0, 0, 0, 0.65); opacity: 0; pointer-events: none; transform: scale(0.25, 0.388); transform-origin: 100% 0; transition: transform 0.28s cubic-bezier(0.2, 0, 0, 1), opacity 0.18s ease; overflow: hidden; cursor: pointer; }

.lt-overlay.open { opacity: 1; transform: none; pointer-events: auto; }

.lt-overlay .pst-stage { height: 100%; min-height: 100%; }

/* The overlay exists only where the grid is 4 columns wide and a mouse
   exists; touch and small screens keep the plain tile (click → modal). */
@media (max-width: 1023px) {
    .lt-overlay { display: none; }
}

/* ── Services bento: lawyer.ai film INSIDE a card stage (2026-07-18, founder) ─
   The custom-applications card keeps its head and its WARM st-s4 field; the
   film is a floating cinematic "screen" on that field, matching the product
   windows of the other cards: rounded product-surface radius, the warm
   brand shadow, a hairline red edge, and a small amber live-tag. It never
   bleeds to the card edge, so it reads as a framed window, not a raw video. */
.st-videostage .lf-screen {
    position: absolute;
    left: 26px;
    right: 26px;
    top: 4px;
    aspect-ratio: 16 / 9;
    border-radius: 12px;
    overflow: hidden;
    background: #08090c;
    border: 1px solid rgba(127, 29, 29, 0.18);
    box-shadow: 0 18px 44px rgba(74, 36, 12, 0.18), 0 2px 8px rgba(74, 36, 12, 0.07);
}
.st-videostage .st-stage-video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
/* ── Services bento: the full-width lawyer.ai WORKFLOW film card (2026-07-20,
   founder "add another card"; ENLARGED same day after the film read too small).
   The 4:3 film FILLS the card width (a framed window with a thin warm margin)
   so the chat, workspace, and document all stay legible — the earlier 64%-wide
   16:9 downscaled the UI to nothing. span-4 keeps the 4-col grid clean.
   Complements the 02c NYC film (drama) with the mechanism end to end. */
.st-wide.st-lawfilm .st-stage { min-height: 0; padding: 0 24px 24px; }
.st-videostage-wide .lf-screen {
    position: relative;
    left: auto;
    right: auto;
    top: auto;
    width: 100%;
    aspect-ratio: 4 / 3;
    transform: none;
}

/* ── Services bento: the SQUARE justice loop centered on the warm field
   (2026-07-21, founder) — the recolored + animated "blind justice" loop fronts
   the custom-applications card. 1:1 so the figure is never cropped; the warm
   stage breathes on both sides so it reads as a framed cinematic window on the
   light field, not a full dark band. */
.st-videostage-sq {
    min-height: 0;
    padding: 0 26px 4px;
    display: flex;
    justify-content: center;
    align-items: flex-start;
}

/* ── Services bento: the ENTERPRISE-APPS PANTHEON card (2026-07-21, founder) ──
   ONE flush card, four god-figure cells edge to edge, NO padding, NO gaps
   (awards-strip layout). Each cell overlays its app kick + title + metric on the
   figure (lawyer.ai-card treatment) and reveals its own st-expand arrow on hover.
   Full-bleed dark band — a register deviation the founder has signed off on. */
.st-wide.st-pantheon { min-height: 0; }
.st-pn-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; }
.st-pn-cell {
    position: relative;
    display: block;
    aspect-ratio: 3 / 4.9;
    overflow: hidden;
    background: #0d0303;
    isolation: isolate;
}
/* TALLER cells with the figure anchored to the BOTTOM at its natural size
   (founder, 2026-07-22). The art is 3:4 and the cell is 3:4.9, so the figure
   fills the lower ~82% and leaves a clean ~18% band at the top for the
   kick/title/description — real space rather than a zoomed-in crop. The band is
   painted with that god's own flat field colour below, so the seam is invisible. */
.st-pn-cell img {
    position: absolute; left: 0; right: 0; bottom: -9%; top: auto;
    width: 100%; height: auto;
    transform-origin: center bottom;
    transition: transform 0.5s cubic-bezier(0.2, 0.7, 0.2, 1);
}
/* each cell painted with its figure's exact flat field colour (sampled from the
   art) so the clean top band reads as part of the image */
.st-pn-argus { background: #370C0C; }
.st-pn-athena { background: #263F4E; }
.st-pn-hermes { background: #8D5021; }
.st-pn-hephaestus { background: #231A16; }
/* text lives at the TOP now (lawyer.ai-card treatment), so the scrim darkens
   the top and grounds the very bottom, leaving the figure clear in between */
.st-pn-cell::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(8,5,4,.82) 0%, rgba(8,5,4,.52) 26%, rgba(8,5,4,0) 50%, rgba(8,5,4,0) 82%, rgba(8,5,4,.42) 100%);
}
/* hairline seam between the flush cells */
.st-pn-cell + .st-pn-cell { box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.4); }
@media (hover: hover) {
    .st-pn-cell:hover img { transform: scale(1.05); }
}
/* the top info block: kick + title + description, like the lawyer.ai card.
   Roomier than the first pass (founder, 2026-07-22): more inset, and more air
   between the kick, the title, and the description. */
.st-pn-head { position: absolute; top: 24px; left: 24px; right: 24px; z-index: 2; }
.st-pn-kick {
    display: block; margin-bottom: 13px;
    /* 0.625rem (10px), not 0.656rem (10.5px) — snapped to the existing 10px step. */
    font-size: 0.625rem; letter-spacing: .09em; text-transform: uppercase; font-weight: 600; color: #F3D8A6;
}
.st-pn-name {
    /* 1.25rem (20px), not 1.28rem (20.5px) — snapped to the existing 20px step. */
    display: block; font-family: 'Sora', sans-serif; font-weight: 600; font-size: 1.25rem; line-height: 1.2;
    color: #FBF7F1; letter-spacing: -.01em; margin-bottom: 14px;
}
.st-pn-desc { font-size: 0.8125rem; line-height: 1.62; font-weight: 300; color: #E7DCCF; margin: 0; }
/* per-cell expand arrow — hidden until hover, like the st-card st-expand */
.st-pn-exp {
    position: absolute; top: 12px; right: 12px; z-index: 3;
    width: 34px; height: 34px; display: flex; align-items: center; justify-content: center;
    border: 1px solid rgba(255,255,255,.34); color: #FBF7F1;
    background: rgba(20,17,14,.42); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
    opacity: 0; transform: translateY(-5px);
    transition: opacity 0.28s, transform 0.28s, background 0.16s, border-color 0.16s;
}
.st-pn-exp svg { width: 13px; height: 13px; }
@media (hover: hover) {
    .st-pn-cell:hover .st-pn-exp { opacity: 1; transform: none; background: #7F1D1D; border-color: #7F1D1D; }
}
/* touch devices: keep the arrow faintly visible so it is discoverable */
@media (hover: none) { .st-pn-exp { opacity: 0.85; } }
/* tablet 2x2, phone single column with a shorter cell so figure + text breathe */
/* 2x2 below desktop. The cell keeps its 3:4.9 ratio at every width — a landscape
   cell would push the bottom-anchored figure up out of frame and crop its head. */
@media (max-width: 1023px) { .st-pn-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px) {
    .st-pn-head { top: 16px; left: 16px; right: 16px; }
    .st-pn-name { font-size: 1.05rem; margin-bottom: 10px; }
    .st-pn-kick { margin-bottom: 9px; }
    .st-pn-desc { font-size: 0.75rem; line-height: 1.5; }
}
.st-videostage-sq .lf-screen {
    position: relative;
    left: auto;
    right: auto;
    top: auto;
    width: auto;
    height: min(360px, 82vw);
    max-width: 100%;
    aspect-ratio: 1 / 1;
    margin: 0 auto;
}

/* ── Services bento: the lawyer.ai card as a FULL-BLEED film (2026-07-21,
   founder "without the white box; video is the box, text white on it";
   same day: Watch-it-work footer + lf-tag pill removed for the normal
   st-expand arrow, copy now names lawyer.ai). The recolored justice loop
   fills the whole cell edge to edge (flat rectangle, no inner window
   frame), the copy sits white over a top scrim, and the whole card opens
   the lawyer.ai detail panel (same [data-app-open] target as the Apps
   live-tile). This card deliberately departs from the framed-white
   register of its bento siblings — the art carries it. */
.st-videocard {
    background: #120303;
    color: #FFFFFF;
    cursor: pointer;
}
.st-videocard .st-fill-video {
    position: absolute;
    inset: 0;
    z-index: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
/* top scrim carries the headline; a softer bottom scrim seats the footer row */
.st-videocard .vc-scrim {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background:
        linear-gradient(180deg, rgba(10, 2, 2, 0.86) 0%, rgba(10, 2, 2, 0.5) 34%, rgba(10, 2, 2, 0) 58%),
        linear-gradient(0deg, rgba(10, 2, 2, 0.74) 0%, rgba(10, 2, 2, 0) 34%);
}
/* text-shadow keeps the copy legible on any looped frame (the gold armor can
   drift under a lower line, especially on the taller mobile card) */
.st-videocard .st-head { padding: 26px 26px 0; }
.st-videocard .st-kick {
    color: #F0B27A;
    text-shadow: 0 1px 10px rgba(10, 2, 2, 0.5);
}
.st-videocard .st-title {
    color: #FFFFFF;
    text-shadow: 0 1px 14px rgba(10, 2, 2, 0.6);
}
.st-videocard .st-note {
    margin-top: 10px;
    color: rgba(255, 255, 255, 0.85);
    text-shadow: 0 1px 12px rgba(10, 2, 2, 0.6);
}

/* ── Hero client rail ──────────────────────────────────────────────────────
   Every named client moving on the hero's lowest line (founder, 2026-07-22),
   replacing the five static logos in the trust strip. Pure CSS, no app.js:
   the track carries the roster TWICE and slides exactly -50%, so the loop
   has no seam. It is deliberately quiet — ~45px/s, 55% opacity, a single
   hairline above it — because the hero film plays once and HOLDS, and a rail
   that shouts would compete with the headline. Hover pauses the whole rail
   and lifts the mark under the pointer; reduced motion renders it static. */
.hero-rail {
    position: relative;
    overflow: hidden;
    /* Fixed band height, not content height: --rail-h is also what the hero's
       vertical grid lines stop at (see .hero-v2-lines below), and the two must
       agree to the pixel. Marks up to the 30px cap ceiling sit inside it. */
    height: var(--rail-h);
    border-top: 1px solid var(--hairline-on-dark);
    background-image: linear-gradient(to top, rgba(6, 2, 2, 0.55), rgba(6, 2, 2, 0));
    /* logos dissolve at the viewport edges instead of being cut by them */
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 4%, #000 96%, transparent 100%);
    mask-image: linear-gradient(90deg, transparent 0, #000 4%, #000 96%, transparent 100%);
}

.hero-rail-track {
    display: flex;
    height: 100%;
    width: max-content;
    /* --rail-secs is set per render from the roster width, so adding a client
       lengthens the loop instead of speeding the rail up (see HeroSection) */
    animation: hero-rail-slide var(--rail-secs, 55s) linear infinite;
    will-change: transform;
}

/* Each set carries its own trailing gap, so both halves are exactly the same
   width and -50% lands the clone precisely where the original started. */
.hero-rail-set {
    display: flex;
    align-items: center;
    height: 100%;
    gap: 4.5rem;
    padding-right: 4.5rem;
}

.hero-rail img {
    flex: none;
    width: auto;
    filter: brightness(0) invert(1);
    opacity: 0.55;
    transition: opacity 0.25s ease;
}

.hero-rail:hover .hero-rail-track {
    animation-play-state: paused;
}

.hero-rail img:hover {
    opacity: 1;
}

@keyframes hero-rail-slide {
    from { transform: translate3d(0, 0, 0); }
    to { transform: translate3d(-50%, 0, 0); }
}

@media (max-width: 768px) {
    .hero-rail-set {
        gap: 3rem;
        padding-right: 3rem;
    }
    .hero-rail-track {
        animation-duration: calc(var(--rail-secs, 55s) * 0.7);
    }
    /* a 4% fade is only ~15px on a phone, which still reads as a hard cut */
    .hero-rail {
        -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 9%, #000 91%, transparent 100%);
        mask-image: linear-gradient(90deg, transparent 0, #000 9%, #000 91%, transparent 100%);
    }
}

@media (prefers-reduced-motion: reduce) {
    .hero-rail-track {
        animation: none;
    }
}

/* ── #apps artefact tiles: "lights coming on" (2026-07-22, founder chose option C
   of /preview/apps-display) ────────────────────────────────────────────────────
   Every tile carries the object its app produces. The grid rests dark; when it
   enters the viewport the artefacts fade up one after another to a low 22%, so
   the abyss field stays dark and the grid reads as a constellation of lit
   windows. Hover only ever ADDS: artefact to full, wash eased back, the app's
   key feature slides in. Riding the existing .reveal-on-scroll → .revealed
   observer in app.js, so no new JS; the no-JS fallback marks everything
   .revealed and the tiles simply render lit. */
.app-tile .app-art {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Rests LIT. The zero state is gated on .js-loaded below, matching every other reveal in
       this file. Unconditional `opacity: 0` here meant all 16 tile artworks stayed invisible
       with JS disabled and the grid rendered as flat maroon boxes, contradicting the comment
       above and the repo's no-JS rule. */
    opacity: 0.22;
    z-index: 0;
    transition: opacity 0.4s ease;
}
.js-loaded .app-tile .app-art {
    opacity: 0;
}
.app-grid.revealed .app-tile .app-art {
    animation: appArtLightUp 0.85s ease forwards;
    animation-delay: calc(var(--art-i, 0) * 85ms);
}
@keyframes appArtLightUp {
    from { opacity: 0; }
    to { opacity: 0.22; }
}
.app-tile .app-art-wash {
    position: absolute;
    inset: 0;
    z-index: 1;
    background: rgba(69, 10, 10, 0.55);
    transition: opacity 0.4s ease;
}
/* the app's key feature, revealed on hover so the hover earns itself */
.app-art-proof {
    position: relative;
    z-index: 2;
    margin-top: 8px;
    max-width: 32ch;
    font-size: 0.72rem;
    line-height: 1.45;
    font-weight: 300;
    color: #E9C48A;
    opacity: 0;
    transform: translateY(6px);
    transition: opacity 0.3s ease, transform 0.3s ease;
}
/* the reveal animation is `forwards`, so its filled value outranks a plain
   opacity declaration — the hover rules must clear the animation AND match the
   .lt-host.revealed specificity to win */
@media (hover: hover) {
    .app-grid .app-tile:hover .app-art,
    .app-grid.revealed .app-tile:hover .app-art { opacity: 1; animation: none; }
    .app-tile:hover .app-art-wash { opacity: 0.35; }
    .app-tile:hover .app-art-proof { opacity: 1; transform: none; }
}
/* touch has no hover: the artefacts still light up, but the proof line would
   never be reachable, so it is dropped rather than left dead on screen */
@media (hover: none) {
    .app-art-proof { display: none; }
}
@media (prefers-reduced-motion: reduce) {
    .app-grid.revealed .app-tile .app-art { animation: none; opacity: 0.22; }
}

/* =====================================================================
   Detail-page kit — first built for /fpa (2026-07-23)
   ---------------------------------------------------------------------
   The service detail pages used to render the HOME PAGE section verbatim
   (<FPSection IsRevealed="true" />), so /fpa and the homepage's #fpa block
   were the same thing. These pages now carry their own deeper content in
   the same vocabulary: page-lines grid, hairline ink, Sora display type,
   tag-micro labels, red/amber micro-accents.

   Detail-page register (the per-page equivalent of the home page's
   three-dark-surfaces law): a detail page carries exactly TWO dark
   surfaces, and they bookend it — the PageHero at the top and the proof/
   CTA band at the bottom. Everything between them stays light. Do not add
   a third without a founder sign-off.
   ===================================================================== */

/* Numbered step rows — the workflow list. Hairline-ruled, number in the
   left column ON the grid line, copy inset 24px like every other cell. */
.dp-steps {
    border-top: 1px solid var(--hairline, #ECECEC);
}

/* Mobile: number in a narrow first column, title AND copy stacked in the
   second. Both children must be pinned to column 2 or the copy falls back
   into the 3.5rem number column and sets one word per line. */
.dp-step {
    display: grid;
    grid-template-columns: 2.75rem minmax(0, 1fr);
    gap: 0 1rem;
    padding: 1.75rem 1.5rem 1.75rem 0;
    border-bottom: 1px solid var(--hairline, #ECECEC);
}

.dp-step-no { grid-column: 1; grid-row: 1; }
.dp-step-t { grid-column: 2; grid-row: 1; }
.dp-step-d { grid-column: 2; grid-row: 2; }

@media (min-width: 768px) {
    .dp-step {
        grid-template-columns: 5rem minmax(0, 22rem) minmax(0, 1fr);
        gap: 0 1.5rem;
        align-items: baseline;
        padding-block: 2rem;
    }

    .dp-step-t { grid-column: 2; grid-row: 1; }
    .dp-step-d { grid-column: 3; grid-row: 1; }
}

.dp-step-no {
    font-family: var(--font-sans);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--brand-micro, #B45309);
}

.dp-step-t {
    margin: 0 0 0.5rem;
    font-size: 1.125rem;
    font-weight: 500;
    line-height: 1.35;
    color: var(--ink, #1D1D1F);
}

@media (min-width: 768px) {
    .dp-step-t { margin-bottom: 0; padding-right: 1.5rem; }
}

.dp-step-d {
    margin: 0;
    font-size: 0.875rem;
    font-weight: 300;
    line-height: 1.7;
    color: rgba(29, 29, 31, 0.8);
}

/* The planner's-eye figure: a small Acterys Matrix drawn in ink. Static by
   design — the ANIMATED write-back demo belongs to the home page's bento
   (the fpw-* cascade tree). This one explains the same mechanic without
   competing with it, and needs no JS. */
.dp-mx {
    border: 1px solid var(--hairline, #ECECEC);
    background: #FFFFFF;
}

.dp-mx-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.625rem 1rem;
    border-bottom: 1px solid var(--hairline, #ECECEC);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: rgba(29, 29, 31, 0.55);
}

.dp-mx-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) repeat(4, minmax(0, 1fr));
    font-size: 0.8125rem;
    font-weight: 400;
}

.dp-mx-grid > span {
    padding: 0.6rem 0.75rem;
    border-bottom: 1px solid #F2F2F2;
    text-align: right;
    font-variant-numeric: tabular-nums;
    color: rgba(29, 29, 31, 0.82);
}

.dp-mx-grid > span:nth-child(5n + 1) {
    text-align: left;
    color: rgba(29, 29, 31, 0.6);
}

.dp-mx-head > span,
.dp-mx-grid > span.dp-mx-h {
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: rgba(29, 29, 31, 0.45);
}

/* The cell the planner types into, and the cells that move because of it. */
.dp-mx-edit {
    background: rgba(180, 83, 9, 0.09);
    /* outline, not an inset box-shadow: the flat system bans shadows outright
       and an audit flags any box-shadow, even one standing in for a border. */
    outline: 1px solid var(--brand-micro, #B45309);
    outline-offset: -1px;
    color: var(--brand-micro, #B45309) !important;
    font-weight: 600;
}

.dp-mx-lit {
    background: rgba(180, 83, 9, 0.05);
    color: rgba(29, 29, 31, 0.95) !important;
}

.dp-mx-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.625rem 1rem;
    border-top: 1px solid var(--hairline, #ECECEC);
    font-size: 0.75rem;
    font-weight: 300;
    color: rgba(29, 29, 31, 0.6);
}

.dp-mx-commit {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-weight: 500;
    color: #15803D;
}

/* Connector cells and FAQ rows: hairline boxes ON the grid lines, 24px in. */
.dp-cell {
    padding: 1.5rem;
    border-top: 1px solid var(--hairline, #ECECEC);
}

@media (min-width: 768px) {
    .dp-cell { border-right: 1px solid var(--hairline, #ECECEC); }
    .dp-cell:last-child { border-right: 0; }
}

.dp-cell-t {
    margin: 0 0 0.4rem;
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--ink, #1D1D1F);
}

.dp-cell-d {
    margin: 0;
    font-size: 0.8125rem;
    font-weight: 300;
    line-height: 1.65;
    color: rgba(29, 29, 31, 0.7);
}

.dp-faq {
    border-top: 1px solid var(--hairline, #ECECEC);
}

.dp-faq-row {
    display: grid;
    gap: 0.5rem 1.5rem;
    padding: 1.75rem 1.5rem 1.75rem 0;
    border-bottom: 1px solid var(--hairline, #ECECEC);
}

@media (min-width: 768px) {
    .dp-faq-row {
        /* 1:1, not 1:1.4 (2026-07-30). The row is 1276px wide inside the content
           column, so a 1.4 answer column started at x=617.7 — off every page
           line (82/401/720/1039/1358) and off the 24px inset, which breaks the
           grid law for the one element on these pages that reads as a table.
           Equal columns put the answer edge exactly ON line 2 at every viewport,
           because the split is a column fraction rather than a ratio tuned to a
           width. It also narrows the answer measure from 716px to 614px, which
           was over-long for 14px body copy. Verified on all seven pages that
           use this kit. */
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        padding-block: 2rem;
    }
}

.dp-faq-q {
    margin: 0;
    font-size: 1.0625rem;
    font-weight: 500;
    line-height: 1.4;
    color: var(--ink, #1D1D1F);
    padding-right: 1.5rem;
}

.dp-faq-a {
    margin: 0;
    font-size: 0.875rem;
    font-weight: 300;
    line-height: 1.75;
    color: rgba(29, 29, 31, 0.8);
}

/* Page-level proof block. The proof-* kit is sized for a card in the home
   page's four-across wall; on a detail page a single result carries half the
   band, so it is scaled up here instead of reading as a stray card. Same
   semantics, same colours, different scale. */
.dp-proof {
    border-top: 1px solid var(--hairline-on-dark);
    padding-top: 2.5rem;
}

.dp-proof .proof-flag { margin-bottom: 1.75rem; }

.dp-proof .proof-delta {
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.dp-proof .proof-before { font-size: 1.375rem; }
.dp-proof .proof-arrow { font-size: 1.5rem; }
.dp-proof .proof-after { font-size: clamp(3rem, 5vw, 4.25rem); }

.dp-proof .proof-cut {
    display: inline-block;
    margin-bottom: 1.75rem;
    padding: 0.35rem 0.6rem;
    font-size: 0.75rem;
}

.dp-proof .proof-attr {
    font-size: 0.875rem;
    line-height: 1.65;
    max-width: 26rem;
}

/* Step rows inside a HALF-WIDTH column. The default .dp-step goes three across
   at md+ (number | title | copy), which is right when the list owns the full
   content width, as on /fpa. Dropped into one side of a two-column section it
   leaves the copy a ~150px column and sets one word per line. This modifier
   keeps the stacked layout at every width. Higher specificity than the md
   rules, so source order does not matter. */
.dp-steps-stacked .dp-step {
    grid-template-columns: 2.75rem minmax(0, 1fr);
    gap: 0 1rem;
    align-items: start;
}

.dp-steps-stacked .dp-step-t {
    grid-column: 2;
    grid-row: 1;
    margin-bottom: 0.5rem;
    padding-right: 0;
}

.dp-steps-stacked .dp-step-d {
    grid-column: 2;
    grid-row: 2;
}

/* =====================================================================
   PageHero background imagery (2026-07-23)
   ---------------------------------------------------------------------
   The rebuilt detail pages read thin next to the home page, which earns its
   weight from imagery and built product scenes. First fix: put the Lights On
   photography behind each hero, the way the home hero carries its film.

   Layering inside the section's stacking context (.page-lines sets z-index:0),
   THREE distinct levels, bottom to top: photo (-3), scrim (-2), page-lines grid
   (-1), copy on top.

   The scrim and the grid used to SHARE z-index -1 (founder, 2026-07-30: "the
   rails are almost not visible on some pages on hero, especially on the left
   hand side"). At equal z-index paint order falls back to DOM order, and
   .ph-scrim is a later sibling than the section's own ::before, so the scrim
   painted OVER the grid and subtracted its own alpha from the hairline. The
   scrim is left-heavy by design (0.90 black at 0%, 0.06 at 100%), so it erased
   ~90% of the left rail and only ~6% of the right one: measured at 1440 on
   /mcp the left rail lifted 3.8 luminance off its ground against the right
   rail's 8.3, i.e. below the threshold of perception on the left while the
   right stayed legible. Same on /fpa (3.8 vs 16.2) and /apps (3.9 vs 9.9).
   Dropping the photo and the scrim one level each puts the grid above both,
   which is the layering the home hero already had (.hero-v2-lines at z-index 2
   over .hero-v2-grade at 1) and why home never showed the fault.
   Keep the three levels distinct: any new hero layer needs its own number.
   ===================================================================== */

.ph-has-bg {
    /* Fills the first screen the way the home hero does (founder, 2026-07-23).
       FULL 100svh, not minus the nav: the bar is position:fixed, so the hero
       starts at the top of the viewport underneath it and the section's own
       top padding clears the copy. Subtracting 64px left a white band exactly
       one nav-height tall at the bottom of the first screen.
       svh, not vh, so mobile browser chrome does not push the CTAs under. */
    min-height: 100svh;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

/* The section is a flex container, which makes .shell a flex ITEM: in a row
   it shrinks to its content and its margin-inline:auto then centres that
   narrow block, so the copy pulled away from the grid's left line. Column
   direction plus an explicit full width keeps .shell spanning the content
   column exactly as it does everywhere else. */
.ph-has-bg > .shell {
    width: 100%;
}

@supports not (height: 100svh) {
    .ph-has-bg { min-height: 100vh; }
}

/* The hero's grid verticals START BELOW THE BAR, exactly as the home hero's do
   (see `.hero-v2 .hero-v2-lines::before`, and the founder rule from 2026-07-15:
   no grid lines through the menu strip).

   A dark hero puts the bar in its transparent night state, so a vertical drawn
   to y=0 shows THROUGH the bar and composites with the bar's own grid-line-0,
   which sits on the same x=82 by design. Two 14% hairlines on one pixel column
   read as one heavy line: measured at 1440 on /mcp the line inside the bar
   lifted +64.3 luminance against +34.1 in the hero body below, i.e. nearly
   twice as heavy inside the menu strip (founder, 2026-07-30: "the rail goes
   into header and duplicates it"). The bar owns the line above 64px, the hero
   owns it below, and the grid still reads unbroken from the very top.

   Scoped to the DARK hero because that is the whole affected set: the default
   bar is solid white (`#navbar::before`), which hides anything drawn under it,
   and every dark PageHero carries a background image. `.page-lines` is in the
   selector purely to outrank the base `.page-lines::before { top: 0 }` on
   specificity rather than on source order. 64px is the bar height from
   input.css — if that ever changes, both this and .hero-v2 move with it. */
.page-lines[data-hero-dark="true"]::before {
    top: 64px;
}

.ph-bg {
    position: absolute;
    inset: 0;
    /* -3, below the scrim, which is below the grid (see the layering note above) */
    z-index: -3;
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* The Lights On photographs are night shots and already very dark; at less
       than full opacity, under a scrim, they turned to mud and read as noise
       rather than as imagery. Full opacity, lifted slightly. */
    opacity: 1;
    filter: brightness(1.18) saturate(1.05);
}

/* Left-heavy so the copy column keeps full contrast and the picture stays
   legible on the right, where the text runs out. The vertical pass darkens
   the top under the floating nav and the bottom into the next section. */
.ph-scrim {
    position: absolute;
    inset: 0;
    /* -2, ABOVE the photo but BELOW the page-lines grid. Never move this back to
       -1: it ties with .page-lines::before and the scrim wins on DOM order,
       which is exactly what wiped the left rail out. */
    z-index: -2;
    pointer-events: none;
    background:
        linear-gradient(90deg,
            rgba(10, 1, 1, 0.90) 0%,
            rgba(10, 1, 1, 0.74) 36%,
            rgba(10, 1, 1, 0.30) 68%,
            rgba(10, 1, 1, 0.06) 100%),
        linear-gradient(to bottom,
            rgba(10, 1, 1, 0.45) 0%,
            rgba(10, 1, 1, 0) 22%,
            rgba(10, 1, 1, 0) 66%,
            rgba(10, 1, 1, 0.72) 100%);
}

/* On narrow screens the copy spans the full width, so the horizontal pass
   would leave the headline sitting on the bright part of the picture. */
@media (max-width: 767px) {
    .ph-scrim {
        background: linear-gradient(to bottom,
            rgba(10, 1, 1, 0.72) 0%,
            rgba(10, 1, 1, 0.68) 55%,
            rgba(10, 1, 1, 0.88) 100%);
    }

}


/* The language switcher paints in ink for the white bar; on the night bar it
   was dark-on-dark and effectively invisible (caught 2026-07-23 when the
   detail-page heroes went night). */
:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-lang a {
    color: rgba(255, 255, 255, 0.6);
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-lang a[aria-current="true"] {
    color: #FFFFFF;
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-lang a:hover {
    color: #FFFFFF;
}

:is(#navbar.night, #navbar:has(.nav-night)):not(.scrolled) .nav-lang span[aria-hidden] {
    color: rgba(255, 255, 255, 0.28);
}

/* =====================================================================
   Touch-target floor (2026-07-23, audit goal L7).
   WCAG 2.5.5 asks for 44x44 on touch. The audit measured 24 controls
   below it at 390: 12 footer links at 21px tall, 4 .link-arrow, 3
   .fpw-key at 28x28 and .st-expand at 34x34. Scoped to coarse pointers
   so the desktop rhythm and the tight scene chrome are untouched, and
   expressed as a min-height plus centring rather than padding so no
   drawn edge moves off the grid.
   ===================================================================== */
@media (pointer: coarse) {

    .footer-link,
    .link-arrow,
    .link-quiet {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
    }

    /* The FY26 cell is a real input the visitor types into, not scene decoration. */
    .fpw-input {
        min-height: 44px;
    }

    /* Micro-controls inside the depicted scenes are still real controls a
       thumb has to hit. Grown from the centre so the scene's layout,
       which is tuned to the mock UI's proportions, does not reflow. */
    .fpw-key,
    .fpw-chips button,
    .st-expand {
        min-width: 44px;
        min-height: 44px;
    }
}

/* =====================================================================
   Narrow-viewport containment (2026-07-23, audit goal L6).
   At 320 the page scrolled 33px horizontally. Two causes, both the same
   CSS default: a grid item's min-width is `auto`, so it refuses to
   shrink below its content and pushes the whole document wider instead.
   ===================================================================== */

/* #ai: the depicted product surfaces are designed at a fixed width and
   were forcing a 328.8px track into a 272px column. The scenes keep
   their proportions and scroll inside their own box; the page does not. */
@media (max-width: 1023px) {

    #ai > .shell > .grid > * {
        min-width: 0;
    }

    #ai .ms-scene,
    #ai .bc-scene,
    #ai .tp-scene,
    #ai .convo {
        max-width: 100%;
        overflow-x: auto;
    }
}

/* .proof-stat is a non-wrapping flex row (number + label) in a 2-col grid.
   Below 360 the pair cannot fit, so the cell overflowed by 14.2px. Let the
   label drop under the number rather than widen the page. */
@media (max-width: 400px) {

    .proof-stat {
        flex-wrap: wrap;
        min-width: 0;
    }
}

/* ── #apps wall: inner hairlines only (2026-07-23, founder) ──────────────────
   The grid draws border-t on the container and border-b/border-r on each cell.
   That put a rule down the far LEFT edge (container border-l, now removed) and
   down the far RIGHT edge (the last column's border-r). This kills the right
   one. The 2x2 header cube changes which children land in the last column, so
   the selector differs per breakpoint:
     1 col  — every child is the right edge
     2 cols — the cube spans both, so it and every odd child after it
     4 cols — the cube sits in cols 1-2, so children 3, 5, 9, 13, 17 */
   NOTE the 2-col rule is bounded at BOTH ends. `min-width: 640px` alone stays
   true at desktop, and :nth-child(odd) (0,2,0) outranks the 4-col reset (0,1,0),
   so it silently stripped the right hairline from every odd cell at 1440 —
   column-2 cells 7, 11 and 15 — not just the ones on the edge. */
.app-grid > * { border-right-width: 0; }
@media (min-width: 640px) and (max-width: 1023.98px) {
    .app-grid > * { border-right-width: 1px; }
    .app-grid > :nth-child(odd) { border-right-width: 0; }
}
@media (min-width: 1024px) {
    .app-grid > * { border-right-width: 1px; }
    .app-grid > :nth-child(3),
    .app-grid > :nth-child(4n + 5) { border-right-width: 0; }
}

/* ============================================================
   FP&A section (#fpa) — the story-scroll kit, shipped 2026-07-23.
   Five numbered steps in five DELIBERATELY different registers:
   convergence diagram, Excel workbook, Power BI report, a bare audit
   ledger with no window chrome, and a closing outcome at poster scale.
   Structure and step chrome are shared with AISection (story-steps,
   data-story-nav, step-head, step-cap). Deck history and the rejected
   directions: design/fpa-section-directions.md.
   ============================================================ */

/* ---------- shared light window chrome ---------- */
        .fpa-win { background: #FFF; border: 1px solid #E4E0DA; }
.fpa-bar { display: flex; align-items: center; gap: 8px; padding: 9px 13px; border-bottom: 1px solid #EFECE6; background: #FBFAF8; }
.fpa-bar i { width: 7px; height: 7px; border-radius: 50%; background: #DCD7CF; display: block; }
.fpa-bar b { font-size: 11.5px; font-weight: 600; color: #1D1D1F; margin-left: 5px; }
.fpa-bar em { margin-left: auto; font-style: normal; font-size: 10.5px; color: #94908A; }
.fpa-foot { display: flex; align-items: center; gap: 8px; padding: 9px 13px; border-top: 1px solid #EFECE6; background: #FBFAF8; font-size: 10.5px; color: #94908A; }
.fpa-foot .ok { margin-left: auto; color: #12807C; font-weight: 600; }
/* ---------- 01 · convergence ---------- */
/* The step-01 stage (2026-07-23, founder): the warm cream radial wash used elsewhere on
   the site, taken GREEN. The green is Acterys teal (#12807C), which this section already
   earned as its vendor colour in the bento write-back card, so the stage is anchored to
   the vendor rather than tinted at random. Scoped to this ONE stage — the section field
   stays #F4F4F4. */
.fpa-conv { display: grid; grid-template-columns: 1fr auto 1.05fr; align-items: center; gap: 0;
    padding: 30px 26px; border: 1px solid #E3EDE8;
    background:
        radial-gradient(90% 60% at 50% 6%, rgba(255, 255, 255, 0.90), transparent 60%),
        radial-gradient(70% 50% at 82% 92%, rgba(18, 128, 124, 0.16), transparent 70%),
        radial-gradient(60% 45% at 12% 78%, rgba(21, 94, 89, 0.10), transparent 70%),
        linear-gradient(175deg, #FAFCFA 0%, #EDF5F1 55%, #DFEDE6 100%); }
.fpa-src { display: flex; flex-direction: column; gap: 8px; }
.fpa-src div { display: flex; align-items: center; gap: 9px; background: #FFF; border: 1px solid #E4E0DA; padding: 9px 12px; font-size: 12px; color: #1D1D1F; }
.fpa-src div img.t { width: 20px; height: 20px; display: block; flex: none; object-fit: contain; }
.fpa-src div em { margin-left: auto; font-style: normal; font-size: 10px; color: #B0ABA3; }
.fpa-wire { width: 96px; height: 190px; position: relative; }
.fpa-wire svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.fpa-node { position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); background: #FFF; border: 1px solid #E4E0DA; padding: 7px 9px; z-index: 2; }
.fpa-node img { height: 15px; width: auto; display: block; }
.fpa-model .big { font-family: 'Sora',sans-serif; font-size: 34px; font-weight: 600; color: #1D1D1F; line-height: 1; letter-spacing: -.02em; }
.fpa-k { font-size: 9.5px; letter-spacing: .13em; text-transform: uppercase; color: #B0ABA3; font-weight: 700; display: block; margin-bottom: 7px; }
.fpa-mrows { margin-top: 13px; }
.fpa-mrows div { display: flex; gap: 9px; align-items: baseline; padding: 6px 0; border-bottom: 1px solid #F2EFEA; font-size: 11.5px; }
.fpa-mrows div:last-child { border-bottom: 0; }
.fpa-mrows .vr { font-family: 'Cascadia Code',Consolas,monospace; font-size: 10.5px; color: #B45309; font-weight: 700; }
.fpa-mrows .tx { flex: 1; color: rgba(29,29,31,.8); }
.fpa-mrows .wh { color: #B0ABA3; font-size: 10.5px; }
/* ---------- 02 · Excel ---------- */
        .fpa-xl { border: 1px solid #D9D5CE; background: #FFF; }
.fpa-xl-bar { display: flex; align-items: center; gap: 9px; padding: 9px 13px; background: #217346; }
.fpa-xl-bar img { width: 18px; height: 18px; display: block; flex: none; }
.fpa-xl-bar b { color: #FFF; font-size: 12px; font-weight: 500; }
.fpa-xl-bar em { margin-left: auto; font-style: normal; color: rgba(255,255,255,.75); font-size: 10.5px; }
.fpa-rib { display: flex; border-bottom: 1px solid #E4E0DA; background: #F7F6F4; }
.fpa-rib span { font-size: 11px; color: #6B6864; padding: 8px 14px; }
.fpa-rib span.on { color: #12807C; font-weight: 600; border-bottom: 2px solid #12807C; background: #FFF; }
.fpa-fx { display: flex; align-items: center; gap: 11px; padding: 7px 11px; border-bottom: 1px solid #E4E0DA; }
.fpa-fx .cell { font-family: 'Cascadia Code',Consolas,monospace; font-size: 11px; color: #6B6864; border: 1px solid #E4E0DA; padding: 4px 12px; }
.fpa-fx .fx { font-family: 'Cascadia Code',Consolas,monospace; font-size: 11.5px; color: #1D1D1F; }
.fpa-grid { width: 100%; border-collapse: collapse; font-size: 12px; }
.fpa-grid th, .fpa-grid td { border: 1px solid #E8E5E0; padding: 8px 11px; text-align: right; color: rgba(29,29,31,.86); font-weight: 400; }
.fpa-grid thead th { background: #F7F6F4; color: #94908A; font-size: 10px; font-weight: 700; text-align: center; }
.fpa-grid tbody th { background: #F7F6F4; color: #94908A; font-size: 10px; font-weight: 700; text-align: center; width: 28px; }
.fpa-grid td.lbl { text-align: left; color: #1D1D1F; font-weight: 500; }
.fpa-grid td.act { color: #A9A49C; }
.fpa-grid td.sel { outline: 3px solid #217346; outline-offset: -3px; background: #F0F8F3; font-weight: 700; color: #1D1D1F; }
.fpa-tabs { display: flex; border-top: 1px solid #E4E0DA; background: #F7F6F4; }
.fpa-tabs span { font-size: 10.5px; color: #94908A; padding: 7px 14px; }
.fpa-tabs span.on { background: #FFF; color: #1D1D1F; font-weight: 600; border-top: 2px solid #217346; margin-top: -1px; }
/* ---------- 03 · Power BI report ---------- */
        .fpa-bi { border: 1px solid #E4E0DA; background: #FFF; }
.fpa-bi-bar { display: flex; align-items: center; gap: 9px; padding: 9px 13px; border-bottom: 1px solid #EFECE6; background: #FBFAF8; }
.fpa-bi-bar img.mk { width: 18px; height: 18px; display: block; flex: none; }
.fpa-bi-bar b { font-size: 11.5px; font-weight: 600; color: #1D1D1F; }
.fpa-bi-bar span { font-size: 11px; color: #94908A; }
.fpa-bi-bar em { margin-left: auto; font-style: normal; font-size: 10.5px; color: #4E7D52; }
.fpa-kpis { display: grid; grid-template-columns: repeat(3,1fr); border-bottom: 1px solid #EFECE6; }
.fpa-kpi { padding: 13px 16px; border-right: 1px solid #EFECE6; }
.fpa-kpi:last-child { border-right: 0; }
.fpa-kpi .v { font-family: 'Sora',sans-serif; font-size: 24px; font-weight: 600; color: #1D1D1F; line-height: 1; }
.fpa-kpi .d { font-size: 10.5px; color: #94908A; margin-top: 5px; display: block; }
.fpa-kpi .d.up { color: #B45309; font-weight: 600; }
.fpa-chart { position: relative; height: 190px; padding: 20px 16px 0; }
.fpa-bars { display: grid; grid-template-columns: repeat(12,1fr); align-items: end; height: 140px; gap: 5px; }
.fpa-bars span { display: block; background: #1D1D1F; }
.fpa-bars span.f { background: repeating-linear-gradient(135deg,#B45309 0 4px,rgba(180,83,9,.26) 4px 8px); }
.fpa-x { display: grid; grid-template-columns: repeat(12,1fr); gap: 5px; margin-top: 7px; }
.fpa-x span { font-size: 9.5px; color: #B0ABA3; text-align: center; }
.fpa-split { position: absolute; left: 50%; top: 20px; bottom: 34px; width: 1px; background: #7F1D1D; }
.fpa-split em { position: absolute; top: -2px; left: 7px; font-style: normal; font-size: 9px; letter-spacing: .13em; text-transform: uppercase; color: #7F1D1D; font-weight: 700; white-space: nowrap; }
/* ---------- 04 · audit ledger, no window chrome ---------- */
        .fpa-aud { border-top: 2px solid #1D1D1F; }
.fpa-arow { display: grid; grid-template-columns: 92px 1fr auto; gap: 18px; align-items: baseline; padding: 15px 0; border-bottom: 1px solid #E4E0DA; }
.fpa-arow .vr { font-family: 'Cascadia Code',Consolas,monospace; font-size: 12px; font-weight: 700; color: #B45309; }
.fpa-arow .vr.now { color: #12807C; }
.fpa-arow .tx { font-size: 13.5px; color: #1D1D1F; line-height: 1.5; }
.fpa-arow .tx b { font-weight: 600; }
.fpa-arow .tx s { color: #B0ABA3; text-decoration-thickness: 1px; }
.fpa-arow .tx .note { display: block; font-size: 11.5px; color: #94908A; margin-top: 3px; font-weight: 300; }
.fpa-arow .wh { font-size: 11px; color: #94908A; white-space: nowrap; text-align: right; }
.fpa-arow .wh b { display: block; color: #1D1D1F; font-weight: 600; font-size: 12px; }
/* ---------- 05 · the outcome, at poster scale ---------- */
        .fpa-out { border-top: 1px solid #DDD; padding-top: 26px; }
.fpa-big { font-family: 'Sora',sans-serif; font-weight: 600; line-height: .84; letter-spacing: -.045em; margin: 0; }
.fpa-was { font-size: clamp(54px, 8.6vw, 104px); color: #1D1D1F; position: relative; display: inline-block; }
.fpa-was::after { content: ""; position: absolute; left: -2%; right: -2%; top: 52%; height: 7px; background: #7F1D1D; }
.fpa-now { font-size: clamp(54px, 8.6vw, 104px); color: #B45309; display: block; margin-top: 4px; }
.fpa-rule { display: flex; align-items: center; gap: 16px; margin: 16px 0 14px; }
.fpa-rule .ln { flex: 1; height: 1px; background: #C9C4BC; }
.fpa-rule .tx { font-size: 10px; letter-spacing: .17em; text-transform: uppercase; color: #94908A; font-weight: 700; white-space: nowrap; }
.fpa-scale { display: flex; align-items: center; margin-top: 26px; }
.fpa-scale .amb { height: 34px; width: 5%; min-width: 22px; background: #B45309; }
.fpa-scale .rest { flex: 1; height: 34px; border: 1px dashed #DCD7CF; border-left: 0; background: repeating-linear-gradient(135deg, rgba(180,83,9,.05) 0 6px, transparent 6px 12px); display: flex; align-items: center; padding-left: 14px; font-size: 11.5px; color: #6B6864; }
.fpa-scale .rest b { color: #1D1D1F; font-weight: 600; }

@media (max-width: 1023px) {
    /* Grid children default to min-width:auto, so a wide min-content child (here
       .sec-links, a nowrap flex row carrying two labels longer than the AI
       section's) drags the whole narrative column past the viewport at 390. */
    #fpa .grid > div { min-width: 0; }
    #fpa .sec-links { flex-wrap: wrap; gap: 10px 22px; }
    .fpa-conv { grid-template-columns: 1fr; gap: 20px; }
    .fpa-wire { width: 100%; height: 60px; }
    /* Drop Sep AND Oct (both settled actuals) so Nov, the SELECTED Dec cell and Q4
       survive. Hiding only one column still left the table 420px wide in a 342px
       column, and the selected cell is the whole point of the step. */
    .fpa-grid th:nth-child(3), .fpa-grid td:nth-child(3),
    .fpa-grid th:nth-child(4), .fpa-grid td:nth-child(4) { display: none; }
    .fpa-grid th, .fpa-grid td { padding: 7px 8px; font-size: 11px; }
    .fpa-arow { grid-template-columns: 62px 1fr; }
    .fpa-arow .wh { grid-column: 2; text-align: left; }
}

/* =========================================================================
   Contact CTA panel (2026-07-24). Matches the FOOTER treatment exactly: a
   FULL-WIDTH red band carrying .page-lines, so the page's two vertical grid
   lines are drawn INSIDE the red at the content edges (322/1598) as clean
   hairlines, lining up with the footer's grid beneath it (no white-gutter edge
   that reads as a stray line). Content sits in a content-max shell so the copy
   and the cream sculpture align to those same grid columns.
   ========================================================================= */
.contact-section {
    position: relative;
    /* Draws OVER the footer's dark band, which now starts above this section's
       bottom edge (see --contact-footer-overlap below). */
    z-index: 2;
}

/* The panel SITS INTO the footer (founder, 2026-07-27, against the cyber64 reference).
   Ours used to STACK: the red panel's bottom edge landed exactly on the footer's top
   edge, so the white gutters ran the full height of the panel and the two read as two
   blocks touching. On cyber64 the full-width dark band starts ABOVE the teal panel's
   bottom edge (measured ~83px up on a ~448px panel, about 18%), so the panel's lower
   portion overlaps it, the white gutters stop early, and the panel reads as set INTO
   the footer rather than sitting on top of it.

   The footer is pulled up by the overlap and given matching padding-top, so its dark
   BACKGROUND extends upward while its content (the social row, the sitemap) stays
   exactly where it was. Since 2026-07-30 the contact panel ships from MainLayout on
   every page, but keep the :has() scoping: PlainLayout pages (and any future page
   without the panel) must keep a flush footer top edge. */
:root {
    --contact-footer-overlap: 80px;
}

body:has(.contact-section) .footer-v2 {
    margin-top: calc(-1 * var(--contact-footer-overlap));
    padding-top: var(--contact-footer-overlap);
}

@media (max-width: 1023px) {
    :root {
        --contact-footer-overlap: 48px;
    }
}

/* CONTAINED red panel (white gutters on wide screens, edges on the content-column
   grid lines) — the cyber64 footer treatment. Full-width darker footer sits beneath it.

   NO BACKGROUND ART (founder, 2026-07-29). The panel is the brand gradient and nothing
   else; the only thing on it is the knocked-out procept.io lockup. Every generated
   subject was rejected — cream marble P marks, geometric solids, interlocking modules,
   a lit-window wall, a quarry block. Do not keep proposing new subjects for this panel
   without an explicit ask.

   This also DISSOLVES the problem that ate several rounds: a knocked-out logo washes out
   to cream-on-white whenever something bright sits behind it. With a flat gradient behind
   the box, the letterforms are always solid oxblood at every width, with no art offset to
   tune and no scrim to maintain. Simpler and strictly more robust.

   Removed with the art, ALL of it dead weight once the image went (recoverable in git):
     - the five-way art switchboard and `contact-objects-{1..5}.webp`
     - `background-size` / `background-position` / `background-repeat`, incl. the measured
       `right -250px` desktop offset and the `-300px` 1024–1279 override
     - `.contact-panel::before`, the horizontal desktop scrim and vertical mobile scrim.
       They existed ONLY to keep copy legible over the art. Against a plain gradient they
       would just dull the brand red, so they must NOT be left behind. */
.contact-panel {
    position: relative;
    background-image: var(--gradient-brand);
    color: var(--on-dark);
    margin-inline: calc(max((100% - var(--content-max)) / 2, 0px) + var(--gutter));
    overflow: hidden;
}

.contact-panel h2 {
    color: var(--on-dark);
    font-size: clamp(2rem, 3.2vw, 3rem);
    line-height: 1.05;
    margin-bottom: 1.5rem;
}

.contact-inner {
    position: relative;
    z-index: 2;
    padding: 2.75rem 1.75rem;
}

@media (min-width: 1024px) {
    .contact-inner {
        padding: 4.5rem 3.5rem;
    }

    .contact-copy {
        max-width: 50%;
    }
}

/* Mobile: the lockup flows in below the copy. */
.contact-art {
    position: relative;
    z-index: 2;
    display: flex;
    justify-content: center;
    padding: 0 1.75rem 2.75rem;
}

.contact-lockup {
    width: 100%;
    max-width: 300px;
    height: auto;
    pointer-events: none;
    user-select: none;
}

/* Desktop: the lockup is CENTRED in the panel's right half, the way cyber64 centres its
   mark over the chess. It is NOT bled off an edge — a knocked-out box only reads if the
   whole rectangle is visible, so unlike the sculpture it replaced, this must sit fully
   inside the panel. 80% of the right half works out at ~40% of the panel's width, which
   is the proportion the reference uses.

   IMPORTANT: whatever sits behind this box has to be DARK, or the knocked-out logo turns
   pale-on-white and disappears. That is why the scene is graded down and the scrim exists.
   If the scene is ever swapped, re-check the luminance behind the box before shipping. */
@media (min-width: 1024px) {
    .contact-art {
        position: absolute;
        inset: 0 0 0 50%;
        padding: 0;
        align-items: center;
    }

    .contact-lockup {
        /* Percentage is of .contact-art, which is the panel's RIGHT HALF — so 60% here
           is 30% of the panel's full width. */
        width: 60%;
        max-width: 560px;
    }
}

/* =========================================================================
   Mid-page seam band (2026-07-27). A ~320px night beat between the AI and
   FP&A story-scrolls, breaking a measured 6,795px light run (47% of the page)
   that had no tonal change in it. Rationale and the "beat, not a section"
   constraint live in Components/Sections/SeamBand.razor.
   ========================================================================= */
/* --brand-deep, NOT a near-black. #0A0101 (the hero film's own base) was tried here
   on 2026-07-27 and the founder rejected it on sight: the hero gets away with that
   value because a lit film plays over it, but as a flat 286px slab between two light
   sections it reads as a hole punched in the page rather than a dark surface. The
   site's darks are warm red-blacks; the seam uses the same one as the apps abyss. */
.seam-band {
    background-color: var(--brand-deep);
    color: var(--on-dark);
}

.seam-band .shell {
    padding-block: 6rem;
}

/* Same two-tone run-on register as .proof-statement, one step larger because
   this line is the whole content of its band and has no wall beneath it. */
.seam-line {
    font-family: var(--font-sans);
    font-size: clamp(1.625rem, 1rem + 2.1vw, 2.5rem);
    font-weight: 600;
    line-height: 1.16;
    letter-spacing: -0.01em;
    /* Tuned by measurement, not by ch. At 46ch the line ran to x=1307 and stopped
       51px short of the right page line (1358), reading as text that ran out of
       room. At 900px it broke to THREE lines and left "half." as a widow, which
       also put two thirds of the statement in the muted tone. 1040px is the width
       that holds it to two even lines, ending near the three-quarter column. */
    max-width: 1040px;
    margin: 0;
    color: var(--on-dark);
}

.seam-line span {
    color: rgba(255, 255, 255, 0.42);
}

@media (max-width: 767px) {
    .seam-band .shell {
        padding-block: 3.5rem;
    }
}

/* =========================================================================
   Partner featured band (2026-07-27). Went from the brand gradient to a light
   surface on founder instruction, so the contact CTA is the only saturated red
   left in the page's tail (which dropped from 85% red to 72%, and from four red
   masses to three). It is FULL-BLEED like .hero-rail — the markup, not a
   negative margin, does that: the band sits outside #partners' .shell and
   carries its own .shell inside. Full rationale in PartnersSection.razor.
   ========================================================================= */
.partner-card {
    background-color: var(--surface-alt);
    color: var(--ink);
}

.partner-card h3 {
    color: var(--ink-heading);
}

/* --ink-soft is the ONE muted step on light (4.74:1 on white). The dark card had
   invented text-white/80 and text-white/70 for the same job; both collapse here. */
.partner-desc,
.partner-meta {
    color: var(--ink-soft);
}

.partner-meta strong {
    color: var(--ink);
    font-weight: 500;
}

/* The tile needs an edge on the light card. On the old gradient ground the white
   square was a bright anchor; on #F4F4F4 an unbordered white square reads as a hole
   punched in the card, especially for a wide wordmark like Acterys (404x125 inside a
   220px square, ~19% filled). Why the tile cannot simply be dropped: see the razor. */
.partner-logo-tile {
    border: 1px solid var(--hairline);
}

/* ===========================================================================
   MCP demo page (/mcp/demo), 2026-07-27.
   Two small additions only: a copyable endpoint block and an inline tool-name
   token. Everything else on that page reuses the existing dp-* / proof-* kits,
   deliberately, so a new page did not become a new visual language.
   Flat system: zero radius, zero shadow, hairline borders, mono for machine
   text so an endpoint URL never reads as prose.
   ======================================================================== */

.mcpd-endpoint {
    display: block;
    max-width: 480px;
    padding: 14px 16px;
    border: 1px solid var(--hairline);
    background: #FAFAFA;
}

/* Label and copy button share a row so the button never pushes the URL down
   and never overlays it. */
.mcpd-endpoint-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 6px;
}

.mcpd-copy {
    flex-shrink: 0;
    padding: 4px 12px;
    border: 1px solid var(--hairline);
    background: #fff;
    font-family: var(--font-sans);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.04em;
    color: var(--ink);
    cursor: pointer;
    /* Flat system: no radius, no shadow. */
    transition: background-color var(--motion-color) var(--ease-out),
                border-color var(--motion-color) var(--ease-out),
                color var(--motion-color) var(--ease-out);
}

.mcpd-copy:hover {
    background: #7F1D1D;
    border-color: #7F1D1D;
    color: #fff;
}

.mcpd-copy.is-copied {
    background: #7F1D1D;
    border-color: #7F1D1D;
    color: #fff;
}

.mcpd-copy:focus-visible {
    outline: 2px solid #B45309;
    outline-offset: 2px;
}

/* Jump row: the button that opens the connector settings, plus the health link */
.mcpd-jump {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 16px 24px;
    max-width: 480px;
}

.mcpd-endpoint-label {
    display: block;
    font-family: var(--font-mono, ui-monospace, "Cascadia Code", Consolas, monospace);
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--accent);
}

/* overflow-wrap, not a scroller: the endpoint must stay fully selectable with
   one drag on a phone, and a horizontally scrolling URL defeats copy-paste,
   which is the single action this whole page exists to enable. */
.mcpd-endpoint-url {
    display: block;
    font-family: var(--font-mono, ui-monospace, "Cascadia Code", Consolas, monospace);
    font-size: 13px;
    line-height: 1.5;
    color: var(--ink);
    overflow-wrap: anywhere;
    -webkit-user-select: all;
    user-select: all;
}

.mcpd-tool {
    font-family: var(--font-mono, ui-monospace, "Cascadia Code", Consolas, monospace);
    font-size: 0.88em;
    padding: 1px 5px;
    background: rgba(127, 29, 29, 0.06);
    color: #7F1D1D;
    overflow-wrap: anywhere;
}

/* The live-demo link in the mega-panel foot (2026-07-27). An amber dot marks it
   as the one thing in the panel you can actually USE right now, rather than a
   third page to read. Kept to a dot rather than a pill or badge: the flat system
   has no radius and no filled chips, and a badge here would read as a foreign
   element borrowed from a SaaS nav. */
.nav-mega-all-live {
    font-weight: 500;
}

.nav-mega-all-live::before {
    content: "";
    display: inline-block;
    width: 6px;
    height: 6px;
    margin-right: 8px;
    background: var(--accent);
    vertical-align: middle;
}

@media (prefers-reduced-motion: no-preference) {
    .nav-mega-all-live::before {
        animation: navLivePulse 2.4s var(--ease-out) infinite;
    }
}

@keyframes navLivePulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.35; }
}

/* =====================================================================
   About page kit (ab-*) — 2026-07-30
   ---------------------------------------------------------------------
   The /about rebuild's designed moments, drawn from the site's own
   vocabulary only: hairline ink, the warm stage field (ms-scene register,
   calmed), square live-dots (nav-mega-all-live precedent), Sora display
   scale, amber micro-accents. Everything animates by riding the existing
   .reveal-on-scroll -> .revealed trigger and hides its start state behind
   .js-loaded, so no-JS and reduced-motion render the settled final state.
   ===================================================================== */

/* The flywheel stage: products plate | two labeled wires | services plate.
   One framed composition that says "each side feeds the other". */
.ab-loop {
    display: grid;
    gap: 28px;
    padding: 32px 24px;
    border: 1px solid var(--hairline, #ECECEC);
    background:
        radial-gradient(90% 60% at 50% 4%, rgba(255, 255, 255, 0.92), transparent 60%),
        radial-gradient(55% 45% at 88% 96%, rgba(180, 83, 9, 0.07), transparent 70%),
        linear-gradient(175deg, #FBF8F3 0%, #F7EEE3 100%);
}

@media (min-width: 1024px) {
    .ab-loop {
        grid-template-columns: minmax(0, 1fr) minmax(0, 15rem) minmax(0, 1fr);
        align-items: center;
        gap: 0 32px;
        padding: 44px 40px;
    }
}

.ab-plate {
    background: #FFFFFF;
    border: 1px solid var(--hairline, #ECECEC);
}

.ab-plate-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 16px;
    border-bottom: 1px solid var(--hairline, #ECECEC);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgba(29, 29, 31, 0.55);
}

.ab-plate-bar em {
    font-style: normal;
    color: var(--brand-micro, #B45309);
}

/* Below sm the right-aligned sub wraps into a ragged column beside a long
   name, so the row stacks: name above, sub below, both left-set. */
.ab-plate-row {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 11px 16px;
    border-bottom: 1px solid #F2F2F2;
}

@media (min-width: 640px) {
    .ab-plate-row {
        flex-direction: row;
        align-items: baseline;
        justify-content: space-between;
        gap: 12px;
    }
}

.ab-plate-row:last-child { border-bottom: 0; }

.ab-plate-name {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--ink, #1D1D1F);
    white-space: nowrap;
}

.ab-plate-sub {
    font-size: 0.75rem;
    font-weight: 300;
    line-height: 1.5;
    color: rgba(29, 29, 31, 0.6);
}

@media (min-width: 640px) {
    .ab-plate-sub { text-align: right; }
}

/* Square live-dot, the nav-mega-all-live vocabulary. Green = in production. */
.ab-live::before {
    content: "";
    display: inline-block;
    width: 6px;
    height: 6px;
    margin-right: 8px;
    background: #15803D;
    vertical-align: 1px;
}

/* The two wires between the plates. Desktop: horizontal hairlines with an
   arrow glyph at the pointed end and the claim above each line. Mobile: the
   lines are hidden and the labels stack with up/down glyph arrows. */
.ab-wires {
    display: flex;
    flex-direction: column;
    gap: 26px;
    justify-content: center;
}

.ab-wire {
    text-align: center;
}

.ab-wire-label {
    display: block;
    margin-bottom: 8px;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--brand-micro, #B45309);
}

.ab-wire-line {
    display: none;
}

@media (min-width: 1024px) {
    .ab-wire-line {
        display: block;
        position: relative;
        height: 1px;
        background: rgba(29, 29, 31, 0.28);
        transition: transform 0.7s var(--ease-out, ease-out);
    }

    .ab-wire-fwd .ab-wire-line { transform-origin: left center; }
    .ab-wire-back .ab-wire-line { transform-origin: right center; }

    .ab-wire-line::after {
        position: absolute;
        top: -0.68em;
        font-size: 0.8125rem;
        line-height: 1;
        color: rgba(29, 29, 31, 0.55);
    }

    .ab-wire-fwd .ab-wire-line::after { content: "\25B8"; right: -3px; }
    .ab-wire-back .ab-wire-line::after { content: "\25C2"; left: -3px; }
}

/* Mobile stand-in for the lines: a single glyph under each label. */
.ab-wire-glyph {
    display: block;
    font-size: 0.9375rem;
    line-height: 1;
    color: rgba(29, 29, 31, 0.45);
}

@media (min-width: 1024px) {
    .ab-wire-glyph { display: none; }
}

.ab-note {
    margin-top: 14px;
    font-size: 0.8125rem;
    font-weight: 300;
    line-height: 1.6;
    color: rgba(29, 29, 31, 0.6);
}

/* Reveal choreography: plates rise, then the wires draw toward the side they
   feed. Start states exist only under .js-loaded (no-JS = settled). The stage
   itself carries .reveal-on-scroll purely as the trigger, so the generic
   whole-block fade is cancelled here the way .stat-grid cancels it. */
.js-loaded .ab-loop.reveal-on-scroll:not(.revealed) {
    opacity: 1;
}

.ab-plate,
.ab-wire-label {
    transition: opacity 0.6s var(--ease-out, ease-out), transform 0.6s var(--ease-out, ease-out);
}

.js-loaded .reveal-on-scroll:not(.revealed) .ab-plate {
    opacity: 0;
    transform: translateY(12px);
}

.js-loaded .reveal-on-scroll:not(.revealed) .ab-wire-label {
    opacity: 0;
}

.js-loaded .reveal-on-scroll:not(.revealed) .ab-wire-line {
    transform: scaleX(0);
}

.ab-loop .ab-plate:last-child { transition-delay: 0.12s; }
.ab-wire-fwd .ab-wire-line { transition-delay: 0.45s; }
.ab-wire-fwd .ab-wire-label { transition-delay: 0.6s; }
.ab-wire-back .ab-wire-line { transition-delay: 0.95s; }
.ab-wire-back .ab-wire-label { transition-delay: 1.1s; }

@media (prefers-reduced-motion: reduce) {
    .ab-plate, .ab-wire-label, .ab-wire-line { transition: none; }
}

/* The studio plate (restructured 2026-07-30). The founders were display-scale
   posters here, and two large portraits read as "the company is two people"
   however the copy was worded (founder). So the pair is now two ROWS inside a
   framed plate whose bar states the studio, in the same plate language as the
   flywheel above: the section names its founders without implying they are the
   whole team. Keep the row and portrait scale BELOW the section headline —
   the moment a portrait competes with the h2, the two-person read is back.
   Portraits are pre-graded (B&W, shared #E8E8E6 ground, matched face
   scale) in wwwroot/images/founders/ — never drop raw photos in here,
   the two sources have opposite grounds (black studio vs blown white). */
.ab-team {
    background: #FFFFFF;
    border: 1px solid var(--hairline, #ECECEC);
}

.ab-founder {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    padding: 1.25rem;
    border-top: 1px solid var(--hairline, #ECECEC);
}

.ab-team > .ab-founder:first-of-type {
    border-top: 0;
}

.ab-founder-img {
    flex: none;
    width: 84px;
    height: 105px;
    object-fit: cover;
    border: 1px solid var(--hairline, #ECECEC);
}

@media (max-width: 640px) {
    .ab-founder { gap: 1rem; padding: 1.125rem 1rem; }
    .ab-founder-img { width: 68px; height: 85px; }
}

.ab-founder-no {
    display: block;
    margin-bottom: 0.4rem;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--brand-micro, #B45309);
}

.ab-founder-name {
    margin: 0 0 0.4rem;
    font-family: var(--font-sans);
    font-size: 1.375rem;
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: -0.01em;
    color: var(--ink, #1D1D1F);
}

.ab-founder-role {
    margin: 0;
    font-size: 0.875rem;
    font-weight: 300;
    line-height: 1.65;
    color: rgba(29, 29, 31, 0.7);
}

/* Client roster cells: name + quiet category line, hairline-ruled. */
.ab-org {
    padding: 0.875rem 1.5rem 0.875rem 0;
    border-bottom: 1px solid var(--hairline, #ECECEC);
}

.ab-org-name {
    display: block;
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--ink, #1D1D1F);
}

.ab-org-cat {
    display: block;
    margin-top: 2px;
    font-size: 0.75rem;
    font-weight: 300;
    color: rgba(29, 29, 31, 0.55);
}

/* ---------------------------------------------------------------------
   03 the certified stack. The partnerships section was two paragraphs in
   boxes (founder, 2026-07-30: "the rest of the page is boring"), which is
   the weakest way to say the strongest thing here: the certifications sit
   on the layers we actually build on. So it is drawn as strata — read
   downward and you go deeper into the platform. The tint deepens with
   depth; it is the only thing making this read as a stack rather than a
   list, so do not flatten it back to plain rows.
   --------------------------------------------------------------------- */
.ab-stack {
    background: #FFFFFF;
    border: 1px solid var(--hairline, #ECECEC);
}

.ab-stack-row {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    padding: 0.875rem 1rem;
    border-top: 1px solid #F2F2F2;
}

.ab-stack > .ab-stack-row:first-of-type { border-top: 0; }

/* Strata: four steps of the same ink, deepest at the platform layer. */
.ab-stack-row:nth-child(3) { background: rgba(29, 29, 31, 0.014); }
.ab-stack-row:nth-child(4) { background: rgba(29, 29, 31, 0.028); }
.ab-stack-row:nth-child(5) { background: rgba(29, 29, 31, 0.042); }

.ab-stack-mark {
    flex: none;
    width: 20px;
    height: 20px;
    object-fit: contain;
}

/* Placeholder mark for a layer with no vendor file (our own work): a square
   amber tick, the site's live-dot vocabulary rather than an invented glyph. */
.ab-stack-ours {
    flex: none;
    width: 8px;
    height: 8px;
    margin: 0 6px;
    background: var(--brand-micro, #B45309);
}

.ab-stack-t {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--ink, #1D1D1F);
}

.ab-stack-d {
    display: block;
    margin-top: 1px;
    font-size: 0.75rem;
    font-weight: 300;
    line-height: 1.45;
    color: var(--ink-soft, rgba(29, 29, 31, 0.62));
}

.ab-stack-cert {
    margin-left: auto;
    padding-left: 0.75rem;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--brand-micro, #B45309);
    white-space: nowrap;
}

/* Rollout speed, drawn to scale. Same device as the FPSection outcome step:
   the comparison only means something if the bars are actually proportional,
   so both are measured against the same 39-week span (9 months) and the
   width percentages are computed from weeks, never eyeballed. */
.ab-speed-row + .ab-speed-row { margin-top: 1.5rem; }

.ab-speed-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.5rem;
}

.ab-speed-k {
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--ink, #1D1D1F);
}

.ab-speed-v {
    font-size: 0.8125rem;
    font-weight: 300;
    color: var(--ink-soft, rgba(29, 29, 31, 0.62));
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.ab-speed-bar {
    height: 10px;
    background: rgba(29, 29, 31, 0.06);
}

.ab-speed-fill {
    height: 100%;
    background: rgba(29, 29, 31, 0.22);
    transform-origin: left center;
    transition: transform 0.8s var(--ease-out, ease-out);
}

.ab-speed-ours .ab-speed-fill { background: var(--brand-micro, #B45309); }

.js-loaded .reveal-on-scroll:not(.revealed) .ab-speed-fill { transform: scaleX(0); }
.ab-speed-ours .ab-speed-fill { transition-delay: 0.15s; }

.ab-speed-scale {
    margin-top: 0.75rem;
    font-size: 0.6875rem;
    font-weight: 300;
    color: var(--ink-soft, rgba(29, 29, 31, 0.62));
}

@media (prefers-reduced-motion: reduce) {
    .ab-speed-fill { transition: none; }
}

/* ---------------------------------------------------------------------
   04 the client wall. Was a column of plain names. The site already owns
   every one of these marks, so the roster is drawn with them: one white
   tile per client, hairline-ruled onto the grid. The tile stays PURE
   WHITE and keeps its hairline for the reason documented on
   .partner-logo-tile — five assets carry a baked white canvas and two are
   coloured tiles, so a transparent tile would float white rectangles on
   the grey field. Names stay under the marks: a logo wall alone makes a
   visitor squint at unfamiliar marks to learn nothing.
   --------------------------------------------------------------------- */
.ab-wall {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    border-top: 1px solid var(--hairline, #ECECEC);
    border-left: 1px solid var(--hairline, #ECECEC);
}

@media (min-width: 640px) { .ab-wall { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .ab-wall { grid-template-columns: repeat(5, minmax(0, 1fr)); } }

.ab-wall-cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
    padding: 1.25rem 1rem;
    border-right: 1px solid var(--hairline, #ECECEC);
    border-bottom: 1px solid var(--hairline, #ECECEC);
}

.ab-wall-tile {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    aspect-ratio: 3 / 2;
    padding: 0.75rem;
    background: #FFFFFF;
    border: 1px solid var(--hairline, #ECECEC);
}

.ab-wall-tile img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.ab-wall-name {
    font-size: 0.8125rem;
    font-weight: 500;
    line-height: 1.3;
    text-align: center;
    color: var(--ink, #1D1D1F);
}

.ab-wall-cat {
    margin-top: -0.5rem;
    font-size: 0.6875rem;
    font-weight: 300;
    text-align: center;
    color: var(--ink-soft, rgba(29, 29, 31, 0.62));
}

/* ---------------------------------------------------------------------
   05 the company record. The practical details were a definition list,
   which is the correct semantics and the dullest possible rendering. Same
   content, set as an on-the-record document: mono keys (the /mcp/demo
   endpoint-label register), hairline rows, values in the body ink.
   --------------------------------------------------------------------- */
.ab-rec {
    background: #FFFFFF;
    border: 1px solid var(--hairline, #ECECEC);
}

.ab-rec-row {
    display: grid;
    gap: 0.25rem 1.5rem;
    padding: 1rem 1.25rem;
    border-top: 1px solid #F2F2F2;
}

.ab-rec > .ab-rec-row:first-of-type { border-top: 0; }

@media (min-width: 768px) {
    .ab-rec-row {
        grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
        align-items: baseline;
    }
}

.ab-rec-k {
    margin: 0;
    font-family: var(--font-mono, ui-monospace, "Cascadia Code", Consolas, monospace);
    font-size: 0.625rem;
    font-weight: 500;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--brand-micro, #B45309);
}

.ab-rec-v {
    margin: 0;
    font-size: 0.875rem;
    font-weight: 300;
    line-height: 1.6;
    color: rgba(29, 29, 31, 0.85);
}

/* Dark-close poster figure: the decade, at the FPSection step-05 scale. */
.ab-poster-num {
    display: block;
    font-family: var(--font-sans);
    font-size: clamp(3.25rem, 6vw, 5.25rem);
    font-weight: 600;
    line-height: 1;
    letter-spacing: -0.01em;
    color: var(--brand-micro, #B45309);
}

.ab-poster-sub {
    display: block;
    margin-top: 0.875rem;
    font-size: 1.0625rem;
    font-weight: 300;
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.82);
    max-width: 24rem;
}

/* =====================================================================
   Products index — feature scenes (pfx-*), 2026-07-30 /products rebuild.
   Founder: the first text-only pass was "nowhere near the level set on the
   main page" — the home bento gives every product a drawn scene, so the
   four feature products get one too. This kit adds NO new visual language:
   it reuses the bento's scene grammar verbatim (st-s1..s4 warm grounds,
   ms-win/ms-erp table windows, sv-win field windows, the st-wire dashed
   line + node + travelling pulse, convo-mini convo-dark for the one dark
   claude.ai anchor) and only contributes placement inside the index cells.
   Scenes render SETTLED (v3.2 doctrine): no play states, no JS hooks —
   the wire dash/pulse are the bento's own always-on CSS animations and
   reduced-motion inherits the bento's resets.
   ===================================================================== */

.pfx-scene {
    position: relative;
    height: 300px;
    overflow: hidden;
    margin: 2px 0 26px;
}

/* st-stage brings flex:1 + margin-top for bento cards; neutralize both so
   every cell's scene is the same height and sits tight under the name. */
.pfx-scene.st-stage {
    flex: 0 0 auto;
    margin-top: 2px;
    min-height: 0;
}

/* Same licensed floating-window treatment the bento stages apply. */
.pfx-scene .ms-win,
.pfx-scene .sv-win,
.pfx-scene .convo-mini {
    position: absolute;
    z-index: 2;
    box-shadow: 0 18px 44px rgba(74, 36, 12, 0.15);
    border-radius: 10px;
    overflow: hidden;
}

.pfx-scene .convo-mini { z-index: 3; }
.pfx-scene .sv-win { font-size: 0.75rem; }
.pfx-scene .sv-win-body { padding: 10px 12px; }

/* ---- 01 NetSuite Sync: NetSuite ledger → SYNC node → Power BI model ----
   Windows narrowed so the wire's middle gap stays open: left ends ~43%,
   right starts ~59%, node centred at ~50% inside the gap. */
.pfx-nss .ms-erp { left: 14px; bottom: 20px; width: 45%; margin: 0; }
.pfx-nss .sv-win { right: 14px; top: 30px; width: 36%; }
.pfx-nss .st-wire { left: 42%; right: 38%; top: 52%; }

/* ---- 02 CapitalBridge: covenant board → MCP node → claude.ai answer ----
   The convo panel is ~230px tall, so the 300px stage leaves its head
   visible; gap 41–50%, node centred ~45%. */
.pfx-cb .sv-win { left: 14px; top: 26px; width: 34%; }
.pfx-cb .convo-mini { right: 14px; bottom: 14px; width: 54%; }
.pfx-cb .st-wire { left: 32%; right: 52%; top: 54%; }

/* ---- 03 lawyer.ai: the deadline engine window, computed not guessed ---- */
.pfx-law .sv-win { left: 50%; top: 26px; transform: translateX(-50%); width: min(76%, 400px); }
.pfx-law .pfx-tag { position: absolute; right: 14px; bottom: 12px; z-index: 3; }

/* ---- 04 Proceptio.BI: four ERP sources → SYNC node → one live window ---- */
.pfx-bi .pfx-srcs {
    position: absolute;
    left: 16px;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.pfx-bi .ms-erp { right: 14px; bottom: 22px; width: 56%; margin: 0; }
.pfx-bi .st-wire { left: 27%; right: 52%; top: 50%; }

/* Small ink chips (ERP sources, reminder tag) in the window register. */
.pfx-chip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 6px 10px;
    background: #FFFDFA;
    border: 1px solid #E3DACD;
    border-radius: 7px;
    box-shadow: 0 6px 16px rgba(74, 36, 12, 0.08);
    font-family: 'Cascadia Code', Consolas, ui-monospace, monospace;
    font-size: 0.5625rem;
    letter-spacing: 0.04em;
    color: #6E6B63;
    white-space: nowrap;
}
.pfx-chip i {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #B45309;
    opacity: 0.65;
    flex: none;
}

/* Amber caution line inside a window (the recess warning). */
.pfx-warn {
    margin: 8px 12px 12px;
    padding: 7px 10px;
    background: #FBF4E0;
    border-radius: 7px;
    font-size: 0.6875rem;
    line-height: 1.45;
    color: #8A6D2B;
}

/* Mobile: the cells narrow to ~340px, so paired windows widen and layer
   (the z-order keeps the reply/destination window on top), matching how
   the bento's lead stage reads on a phone. */
@media (max-width: 767px) {
    .pfx-nss .ms-erp { width: 60%; left: 10px; bottom: 12px; }
    .pfx-nss .sv-win { width: 56%; right: 10px; top: 14px; }
    /* At phone width the paired composition can't breathe: the claude.ai
       panel owns the CapitalBridge stage alone, full-width, head visible.
       The stage grows to hold the panel's full height (cells are stacked
       here, so per-row height uniformity no longer applies). */
    .pfx-cb { height: 348px; }
    .pfx-cb .sv-win { display: none; }
    .pfx-cb .st-wire { display: none; }
    .pfx-cb .convo-mini { width: calc(100% - 20px); right: 10px; bottom: 12px; }
    .pfx-law .sv-win { width: 88%; }
    .pfx-bi .ms-erp { width: 66%; }
    .pfx-bi .pfx-srcs { gap: 6px; }
}

/* ---------------------------------------------------------------------
   Ledger miniatures (pfm-*): one small ink drawing per operations row,
   because seven identical text rows read as one product repeated
   (founder note, 2026-07-30: "the list of products all looks the same").
   Same micro-vocabulary as the pfx scenes — chips, a short dashed wire,
   hairline mini windows, and one dark now-serving display — sized to sit
   quietly at the right edge of a ledger row on the white field.
   --------------------------------------------------------------------- */

.pfm {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 9px;
    min-height: 84px;
}

.pfm-col {
    display: flex;
    flex-direction: column;
    gap: 5px;
    min-width: 0;
}

.pfm-wire {
    flex: none;
    width: 22px;
    height: 1px;
    background-image: linear-gradient(to right, rgba(180, 83, 9, 0.55) 0 4px, transparent 4px 8px);
    background-size: 8px 1px;
}

.pfm .pfx-chip {
    padding: 4px 8px;
    box-shadow: none;
}

.pfm-win {
    display: flex;
    flex-direction: column;
    gap: 5px;
    min-width: 0;
    overflow: hidden;
    padding: 9px 11px;
    background: #FFFFFF;
    border: 1px solid #E9E4DA;
    border-radius: 8px;
    box-shadow: 0 6px 16px rgba(74, 36, 12, 0.07);
    font-size: 0.6875rem;
    line-height: 1.3;
    color: #3A3831;
}

.pfm-win b { font-weight: 600; }

.pfm-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    white-space: nowrap;
}

.pfm-mono {
    font-family: 'Cascadia Code', Consolas, ui-monospace, monospace;
    font-size: 0.5625rem;
    color: #8A867C;
    white-space: nowrap;
}

/* The queue product's register: the dark now-serving display. */
.pfm-disp {
    flex: none;
    padding: 9px 14px 10px;
    background: #16130F;
    border-radius: 8px;
    box-shadow: 0 6px 16px rgba(74, 36, 12, 0.12);
}

.pfm-disp .lbl {
    display: block;
    margin-bottom: 2px;
    font-family: 'Cascadia Code', Consolas, ui-monospace, monospace;
    font-size: 0.5rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: #A6A29A;
}

.pfm-disp .num {
    display: block;
    font-family: 'Cascadia Code', Consolas, ui-monospace, monospace;
    font-size: 1.25rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    color: #E8A765;
}

/* PowerCRM's register: a tiny embedded report. */
.pfm-bars {
    display: flex;
    align-items: flex-end;
    gap: 3px;
    height: 30px;
}

.pfm-bars i { width: 8px; background: #E3DACD; }
.pfm-bars i.a { background: #B45309; }

@media (max-width: 767px) {
    .pfm {
        width: auto;
        justify-content: flex-start;
        min-height: 0;
        margin-top: 14px;
    }
}

/* ---------------------------------------------------------------------------
   bl-* — the BUILD LOG on /custom-software (2026-07-30).

   The page's spine: eight built-to-order systems, each a hairline cell in a
   2-col grid. Deliberately NOT the /products idiom — that page uses scene cards
   (pfx-*) and a compact row ledger, and the whole point of the re-architecture
   (design/what-we-built-architecture.md) is that the two pages stop looking like
   each other. This is a denser, quieter register: kicker, title, who it runs
   for, what it is, and one proof line set off by an amber rule.

   Grid law: 1.5rem (24px) inset so content sits 24px inside the column line,
   inner hairlines only, no rule on the outer edges.
   --------------------------------------------------------------------------- */
/* The wall. grid-auto-rows names the five tracks every cell subscribes to, so
   kicker / title / who / description / proof land on identical horizontal lines
   across a row no matter how a description wraps. The 1fr on the last track is
   what pushes every proof rule to a shared baseline. Alignment is STRUCTURAL
   here, exactly as on the home page's proof wall — never re-tune it with
   margins. */
.bl-wall {
    display: grid;
    grid-auto-rows: auto auto auto auto 1fr;
}

@media (min-width: 768px) {
    .bl-wall { grid-template-columns: 1fr 1fr; }
}

.bl-cell {
    display: grid;
    grid-row: span 5;
    grid-template-rows: subgrid;
    padding: 2rem 1.5rem 2.25rem;
    border-top: 1px solid var(--hairline, #ECECEC);
}

@media (min-width: 768px) {
    /* Inner hairline only: odd children carry the rule, so nothing draws on the
       wall's right edge. Cells 1-8 only — the hand-off block is outside. */
    .bl-cell:nth-child(odd) { border-right: 1px solid var(--hairline, #ECECEC); }
}

.bl-t {
    margin: 0.75rem 0 0.35rem;
    font-size: 1.125rem;
    font-weight: 500;
    line-height: 1.35;
    color: var(--ink, #1D1D1F);
}

/* Who it runs for. Quiet, and never a claim — the client is named here only
   where that name is already public (messaging rule 5). */
.bl-who {
    margin: 0 0 1rem;
    font-size: 0.8125rem;
    font-weight: 300;
    line-height: 1.5;
    color: rgba(29, 29, 31, 0.5);
}

.bl-d {
    margin: 0 0 1.5rem;
    font-size: 0.9375rem;
    font-weight: 300;
    line-height: 1.7;
    color: rgba(29, 29, 31, 0.8);
    max-width: 34rem;
}

/* The proof line: the one fact that makes the cell real. It rides the wall's
   fifth (1fr) track, so its rule starts on the same line as every other proof
   in the row. Marked with the amber rule rather than a badge — this page has no
   scenes, so the accent does the work of drawing the eye. */
.bl-proof {
    margin: 0;
    align-self: start;
    padding-left: 1rem;
    border-left: 2px solid var(--brand-micro, #B45309);
    font-size: 0.875rem;
    font-weight: 400;
    line-height: 1.6;
    color: rgba(29, 29, 31, 0.9);
    max-width: 34rem;
}

/* The products hand-off. A plain full-width block after the wall, not a ninth
   cell: it is a different kind of thing (a route out, not a system) and a
   spanning member of a pair-cycling subgrid fights the row rhythm. No right
   rule — grid law: nothing draws on an outer edge. */
/* The block itself carries NO horizontal padding — its two children do, exactly
   like .bl-cell. Padding the block and then splitting it 1fr/1fr would move the
   column line off the wall's own line above and leave the right column 48px
   inside instead of 24px. Grid law: content sits ON a line or 24px inside it. */
.bl-handoff {
    padding: 0;
    border-top: 1px solid var(--hairline, #ECECEC);
}

.bl-handoff > * { padding: 2rem 1.5rem 2.25rem; }

@media (min-width: 768px) {
    .bl-handoff {
        display: grid;
        grid-template-columns: 1fr 1fr;
        align-items: start;
    }
}

.bl-handoff-out {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.5rem 2rem;
}

@media (min-width: 768px) {
    .bl-handoff-out {
        flex-direction: column;
        align-items: flex-start;
        gap: 1rem;
    }
}

@media (max-width: 767px) {
    .bl-cell { padding: 1.75rem 1.5rem 2rem; }
    /* Stacked: the statement keeps its full padding, the routes tuck under it
       without a second full block of space between them. */
    .bl-handoff > * { padding: 1.75rem 1.5rem 0.5rem; }
    .bl-handoff > *:last-child { padding-bottom: 2rem; }
    .bl-d { margin-bottom: 1.25rem; }
}

/* =====================================================================
   psc-* — the product-page SCENE kit (2026-07-30)

   Promoted verbatim out of the lawyer.ai product page (founder, same day:
   "reuse the ui and the idea of lawyer images"). Every product page now
   runs the home page's story-scroll, so the stage furniture that page
   invented had to stop being page-local: eleven pages hand-rolling the
   same window chrome would have been eleven drifting copies of it.

   What belongs here: FURNITURE only — the framed stage, the floating
   window and its title bar, label/value rows, the verification checks,
   the poster-scale outcome. What must stay page-local is the product's own
   surface (a covenant board, a tyre catalogue, a queue display), because
   the whole point is that no two product pages look alike. Twelve pages
   on one mechanic is the risk this kit carries: the mechanic is shared,
   the SCENES must not be.

   The flatness law still holds on the OUTSIDE: .psc-stage is a hairline
   frame at zero radius over an st-s* wash. The rounded, softly shadowed
   .psc-win inside it is the scoped product-surface exception the AI
   section already licensed — a depicted real product, never a treatment
   for site chrome.

   Everything renders its complete final state server-side. Scenes never
   hide content: a visitor scrolling past always meets a finished card,
   and the reduced-motion block at the end is the single kill switch.
   ===================================================================== */
.psc {
    --psc-ink: #1c1917;
    --psc-sub: #78716c;
    --psc-faint: #a8a29e;
    --psc-line: #e7e5e4;
    --psc-warn: #b45309;
    --psc-warn-bg: #fef3c7;
    font-family: Inter, ui-sans-serif, system-ui, sans-serif;
    font-variant-numeric: tabular-nums;
    -webkit-font-smoothing: antialiased;
    /* Decorative mockups: the loops run, but nothing here is clickable,
       selectable or copyable — it is a picture drawn in DOM. */
    pointer-events: none;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
}

.psc,
.psc * { box-sizing: border-box; }

/* ---------- The stage: hairline frame outside, warm wash inside ---------- */
.psc-stage {
    position: relative;
    overflow: hidden;
    border: 1px solid #EDE7DC;
    padding: 34px 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 320px;
}

/* A stage that hosts a single tall window wants to breathe less. */
.psc-stage.psc-tight { padding: 24px 20px; min-height: 260px; }

/* ---------- The floating product window ---------- */
.psc-win {
    position: relative;
    z-index: 1;
    width: 100%;
    background: #fff;
    border-radius: 10px;
    overflow: hidden;
    box-shadow: 0 18px 44px rgba(74, 36, 12, 0.15);
    font-size: 0.75rem;
}

.psc-bar {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    border-bottom: 1px solid #EFEDE7;
}

.psc-bar i {
    flex: none;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #DCD8CE;
}

.psc-bar span {
    margin-left: 6px;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-size: 0.6875rem;
    font-weight: 600;
    color: #6E6B63;
}

.psc-bar em {
    margin-left: auto;
    flex: none;
    padding-left: 8px;
    font-style: normal;
    font-size: 0.625rem;
    color: #A5A196;
}

.psc-pad { padding: 14px 16px 16px; }

/* The window foot: the one line that makes the mockup a real system
   (what it is connected to, how often, under whose authority). */
.psc-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: 13px;
    padding-top: 10px;
    border-top: 1px solid #F5F5F4;
    font-size: 10.5px;
    color: var(--psc-sub);
}

.psc-foot b { color: var(--psc-ink); }

/* ---------- Label / value furniture ---------- */
/* The 3-up field header: what went in, before anything was computed. */
.psc-fields {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
}

.psc-fields.psc-fields-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.psc-field {
    border: 1px solid var(--psc-line);
    border-radius: 8px;
    padding: 8px 10px;
    min-width: 0;
}

.psc-field em,
.psc-sect {
    display: block;
    font-style: normal;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--psc-faint);
    margin-bottom: 3px;
}

.psc-field b {
    display: block;
    font-size: 12px;
    color: var(--psc-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.psc-sect { letter-spacing: 0.08em; margin: 12px 0 4px; }

/* The stacked key/value row (a record being read out, one line each). */
.psc-row {
    display: flex;
    gap: 8px;
    align-items: baseline;
    padding: 5px 0;
    border-bottom: 1px solid #F5F5F4;
    font-size: 11.5px;
}

.psc-row:last-child { border-bottom: 0; }

.psc-row em {
    flex: none;
    width: 52px;
    font-style: normal;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--psc-faint);
}

.psc-row b {
    min-width: 0;
    font-weight: 600;
    color: var(--psc-ink);
}

/* Value pushed to the right edge instead of sitting beside the label. */
.psc-row.psc-row-split { justify-content: space-between; }
.psc-row.psc-row-split em { width: auto; }

/* ---------- Chips, warnings, verification ---------- */
.psc-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 9px;
    border-radius: 999px;
    background: #F5F5F4;
    font-size: 10.5px;
    font-weight: 700;
    color: var(--psc-sub);
    white-space: nowrap;
}

.psc-chip i {
    flex: none;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--ps-accent, #B45309);
}

.psc-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.psc-arrow { font-size: 12px; color: var(--psc-faint); }

/* The amber strip: the thing the system will NOT decide for you. Every
   product has one, and putting it on the scene is the trust story. */
.psc-warn {
    display: flex;
    gap: 7px;
    margin-top: 11px;
    padding: 8px 10px;
    border-radius: 8px;
    background: var(--psc-warn-bg);
    font-size: 11px;
    font-weight: 600;
    line-height: 1.45;
    color: var(--psc-warn);
}

.psc-check {
    display: flex;
    gap: 7px;
    align-items: flex-start;
    padding: 5px 0;
    font-size: 11px;
    line-height: 1.45;
    color: var(--psc-ink);
}

.psc-check .ok {
    flex: none;
    font-weight: 800;
    color: var(--psc-ink);
}

.psc-check--bad {
    padding: 7px 10px;
    border-radius: 8px;
    background: var(--psc-warn-bg);
    font-weight: 600;
    color: var(--psc-warn);
}

.psc-check--bad .bad { flex: none; font-weight: 800; }

/* ---------- The headline figure inside a window ---------- */
.psc-due {
    display: flex;
    align-items: baseline;
    gap: 10px;
}

.psc-due em {
    font-style: normal;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--psc-faint);
}

.psc-due b {
    font-size: 20px;
    font-weight: 800;
    letter-spacing: -0.02em;
    color: var(--psc-ink);
}

/* ---------- The compute track (a value being derived, not typed) ---------- */
.psc-track {
    position: relative;
    height: 8px;
    margin: 16px 0 12px;
    border-radius: 999px;
    background: #F0EFEC;
    overflow: hidden;
}

.psc-fill {
    position: absolute;
    inset: 0;
    transform-origin: left;
    border-radius: 999px;
    background: linear-gradient(90deg, var(--ps-accent-2, #B45309), var(--ps-accent, #7F1D1D));
}

/* ---------- Small bar chart (a trend, drawn in ink) ---------- */
.psc-bars {
    display: flex;
    align-items: flex-end;
    gap: 5px;
    height: 46px;
}

.psc-bars i {
    flex: 1;
    min-width: 0;
    display: block;
    background: #DDD7CB;
}

.psc-bars i.a { background: var(--ps-accent, #B45309); }

/* ---------- Two-up composition (a draft beside its finished output) ---------- */
.psc-duo {
    display: grid;
    grid-template-columns: 1fr 1.08fr;
    gap: 18px;
    align-items: center;
    width: 100%;
    max-width: 560px;
}

/* ---------- The dark inset display (a screen inside the scene) ---------- */
.psc-disp {
    border-radius: 8px;
    background: #17110D;
    padding: 12px 14px;
    color: #F5EFE6;
    text-align: center;
}

.psc-disp .lbl {
    display: block;
    font-size: 8.5px;
    font-weight: 700;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: rgba(245, 239, 230, 0.5);
}

.psc-disp .num {
    display: block;
    margin-top: 2px;
    font-family: Sora, Inter, ui-sans-serif, sans-serif;
    font-size: 30px;
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1;
}

/* ---------- Step 05: the outcome at poster scale ----------
   The FP&A section's step-05 register, and the one panel every product
   page ends on: the before struck through, the after huge, and a bar
   DRAWN TO SCALE so the claim is checkable rather than asserted. */
.psc-poster { width: 100%; max-width: 520px; }

.psc-kick {
    display: block;
    margin-bottom: 16px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: #8B867B;
}

.psc-before {
    margin-bottom: 2px;
    font-size: clamp(22px, 2.4vw, 30px);
    font-weight: 600;
    color: #A8A29E;
    text-decoration: line-through;
    text-decoration-thickness: 2px;
}

.psc-after {
    margin-bottom: 26px;
    font-family: Sora, Inter, ui-sans-serif, sans-serif;
    font-size: clamp(46px, 5vw, 68px);
    font-weight: 700;
    letter-spacing: -0.03em;
    line-height: 1.05;
    color: #1D1D1F;
}

.psc-bar-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 12px;
    margin-bottom: 9px;
}

.psc-bar-row i {
    display: block;
    height: 10px;
    background: #DDD7CB;
}

.psc-bar-row em {
    font-style: normal;
    font-size: 10.5px;
    color: #78716C;
    white-space: nowrap;
}

.psc-poster-foot {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    margin-top: 22px;
    padding-top: 12px;
    border-top: 1px solid #EDE7DC;
    font-size: 11px;
    color: #78716C;
}

.psc-poster-foot b { color: #1D1D1F; }

/* ---------- Motion ----------
   One kill switch. The loops are embellishment on a card that is already
   complete, so switching them off costs the visitor nothing. */
@media (prefers-reduced-motion: reduce) {
    .psc *,
    .psc *::before,
    .psc *::after {
        animation: none !important;
        transition: none !important;
    }
}

@media (max-width: 640px) {
    .psc-stage { padding: 18px 14px; min-height: 0; }
    .psc-fields { grid-template-columns: 1fr; }
    .psc-field b { white-space: normal; }
    .psc-duo { grid-template-columns: 1fr; }
    .psc-bars { height: 38px; }
}

/* ---------------------------------------------------------------------------
   cs-* — /case-studies outcomes (2026-07-30).

   The page's job under design/what-we-built-architecture.md is OUTCOMES: what
   the software did for a named client, with numbers. /custom-software carries
   the systems, /products carries what you can buy. If this kit ever starts
   describing platforms, the page has drifted.

   It borrows the home proof wall's GRAMMAR (struck-through before, big amber
   after) but not its CSS: proof-* is tuned for the dark stats band — white
   strikethrough, #F5B36B amber picked against a dark gradient — and is unusable
   on white. Same idea, light-surface values.
   --------------------------------------------------------------------------- */
.cs-outs {
    display: grid;
    grid-auto-rows: auto auto auto;
}

@media (min-width: 640px) {
    .cs-outs { grid-template-columns: 1fr 1fr; }
}

@media (min-width: 1024px) {
    .cs-outs { grid-template-columns: repeat(4, 1fr); }
}

/* Subgrid again: label / delta / note land on identical lines across all four,
   however the labels wrap. Structural, not eyeballed. */
.cs-out {
    display: grid;
    grid-row: span 3;
    grid-template-rows: subgrid;
    row-gap: 0.6rem;
    padding: 1.75rem 1.5rem 2rem;
    border-top: 1px solid var(--hairline, #ECECEC);
}

@media (min-width: 640px) {
    .cs-out:nth-child(odd) { border-right: 1px solid var(--hairline, #ECECEC); }
}

@media (min-width: 1024px) {
    /* At 4-up the rule pattern changes: every cell but the last carries it, so
       nothing draws on the wall's right edge. */
    .cs-out:nth-child(odd) { border-right: 0; }
    .cs-out:not(:last-child) { border-right: 1px solid var(--hairline, #ECECEC); }
}

.cs-out-before {
    font-size: 0.9375rem;
    font-weight: 400;
    color: rgba(29, 29, 31, 0.45);
    text-decoration: line-through;
    text-decoration-color: rgba(29, 29, 31, 0.3);
    text-decoration-thickness: 1px;
    align-self: end;
}

.cs-out-after {
    font-family: var(--font-sans);
    font-size: 1.9rem;
    font-weight: 600;
    line-height: 1;
    letter-spacing: -0.01em;
    color: var(--brand-micro, #B45309);
    font-variant-numeric: tabular-nums;
    align-self: start;
}

.cs-out-label {
    font-size: 0.8125rem;
    font-weight: 300;
    line-height: 1.5;
    color: rgba(29, 29, 31, 0.7);
    align-self: start;
}

/* The named-customer ledger. Outcome-first: client, what they run, what changed.
   Rows, not cards — the rounded bg-gray-50 card grid this replaced was the last
   pre-rebrand surface on the site. */
.cs-ledger { border-bottom: 1px solid var(--hairline, #ECECEC); }

.cs-row {
    padding: 1.75rem 1.5rem;
    border-top: 1px solid var(--hairline, #ECECEC);
}

@media (min-width: 768px) {
    .cs-row {
        display: grid;
        grid-template-columns: minmax(0, 14rem) minmax(0, 16rem) minmax(0, 1fr);
        column-gap: 1.5rem;
        align-items: baseline;
        padding-left: 1.5rem;
        padding-right: 1.5rem;
    }
}

.cs-row-name {
    margin: 0;
    font-size: 1.0625rem;
    font-weight: 500;
    line-height: 1.35;
    color: var(--ink, #1D1D1F);
}

.cs-row-what {
    margin: 0.35rem 0 0;
    font-size: 0.8125rem;
    font-weight: 300;
    line-height: 1.6;
    color: rgba(29, 29, 31, 0.55);
}

.cs-row-outcome {
    margin: 0.5rem 0 0;
    font-size: 0.9375rem;
    font-weight: 300;
    line-height: 1.65;
    color: rgba(29, 29, 31, 0.85);
}

@media (min-width: 768px) {
    .cs-row-what,
    .cs-row-outcome { margin-top: 0; }
}

/* The pull quote. Amber rule, not a border-l-4 red block: the flat system has
   one accent language and this page is on white. */
.cs-quote {
    margin: 0;
    padding-left: 1.5rem;
    border-left: 2px solid var(--brand-micro, #B45309);
    font-size: 1.25rem;
    font-weight: 300;
    line-height: 1.6;
    color: var(--ink, #1D1D1F);
    max-width: 44rem;
}

@media (min-width: 768px) {
    .cs-quote { font-size: 1.4rem; }
}
