/* GENERATED by `php artisan site:css-bundle`. Do not edit.
 * Edit the source sheets in public/css and re-run the command.
 * Sources, in load order, are config('site_css.core').
 */

/* ===== css/loading-ui.css ===== */
/* Loading UI: global navigation + submit feedback.
 *
 * Hand-written rather than Tailwind on purpose: resources/css/app.css is a
 * prebuilt bundle whose @source glob does not scan public/js, so any utility
 * class injected by public/js/loading-ui.js would never be compiled. Everything
 * this file styles is applied from that script.
 *
 * Loaded by every layout (portal, admin, site, frontend) and by the standalone
 * r/{token} signup embed, so it must not assume Tailwind, Alpine or Font Awesome
 * beyond the fa-* icon classes the app already ships everywhere.
 */

/* ── Top progress bar ─────────────────────────────────────────────────────── */

/* Fixed to the viewport, not to a topbar. Both panels have a sticky header that
 * shifts down by 40px while impersonating; anchoring to the viewport means the
 * bar never has to know about that offset. z-index clears the portal sidebar
 * (z-30), the admin topbar (z-20) and every modal overlay in the app. */
#loading-bar {
    position: fixed;
    top: 0;
    left: 0;
    height: 3px;
    width: 0;
    z-index: 99999;
    pointer-events: none;
    opacity: 0;
    border-radius: 0 3px 3px 0;
    /* The r/{token} embed defines --brand only, with no 50-950 ramp, so each
     * stop falls back through --brand before reaching a literal. */
    background: linear-gradient(90deg,
        var(--brand-600, var(--brand, #b45309)) 0%,
        var(--brand, #d97706) 55%,
        var(--brand-400, var(--brand, #fbbf24)) 100%);
    box-shadow: 0 0 10px rgba(0, 0, 0, .18);
    transition: width .28s cubic-bezier(.16, 1, .3, 1), opacity .25s ease;
}

#loading-bar.is-active {
    opacity: 1;
}

/* The leading glow that sells the "still working" impression while the width
 * sits parked at 90% waiting on the server. */
#loading-bar::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    height: 100%;
    width: 90px;
    border-radius: inherit;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .85));
    animation: loading-bar-pulse 1.1s ease-in-out infinite;
}

@keyframes loading-bar-pulse {
    0%, 100% { opacity: .25; }
    50%      { opacity: .9; }
}

/* ── Element loading state ────────────────────────────────────────────────── */

/* Applied to a submit button or a navigating link. pointer-events rather than
 * the disabled property on purpose: a disabled submitter is dropped from the
 * form entry list, which would silently stop admin/service-orders/show.blade.php
 * from posting its silent=1 value. */
.is-loading-el {
    pointer-events: none;
    cursor: progress;
    opacity: .82;
}

/* The swapped-in spinner. Font Awesome's fa-spin is not assumed to be present on
 * every surface, so the rotation is defined here and the glyph is whatever
 * fa-circle-notch resolves to. */
.loading-ui-spinner {
    animation: loading-ui-spin .7s linear infinite;
    transform-origin: 50% 50%;
}

@keyframes loading-ui-spin {
    to { transform: rotate(360deg); }
}

/* Fallback ring for surfaces where Font Awesome has not painted yet, so a click
 * during the CDN fetch still shows something turning. */
.loading-ui-ring {
    display: inline-block;
    width: 1em;
    height: 1em;
    vertical-align: -.125em;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: loading-ui-spin .7s linear infinite;
}

/* Keeps the swapped label on one line inside w-full flex buttons so the button
 * never changes height mid-submit. */
.loading-ui-label {
    white-space: nowrap;
}

/* ── Dark mode ────────────────────────────────────────────────────────────── */

/* Both panels toggle the dark class on <html>; the site and the r/* embed are
 * light-only, so this simply never matches there. */
html.dark #loading-bar {
    box-shadow: 0 0 12px rgba(0, 0, 0, .55);
}

html.dark .is-loading-el {
    opacity: .75;
}

/* ── Reduced motion ───────────────────────────────────────────────────────── */

/* The spin is the information, so it stays, just slower and calmer. The purely
 * decorative pulse on the bar's leading edge goes away entirely. */
@media (prefers-reduced-motion: reduce) {
    #loading-bar {
        transition: width .01s linear, opacity .01s linear;
    }

    #loading-bar::after {
        animation: none;
        opacity: .5;
    }

    .loading-ui-spinner,
    .loading-ui-ring {
        animation-duration: 1.6s;
    }
}

/* ===== css/brand-lockup.css ===== */
/* The tagline lockup: a brand mark, not a caption.
 *
 * Written as plain CSS on purpose. The public site loads
 * public/assets/css/app.css, a minified Tailwind build that nothing in this
 * repo regenerates (CI builds public/build for the portal only), so a new
 * arbitrary utility written into a site view silently resolves to nothing.
 * max-w-[7rem] on the old lockup is exactly that: written, never generated.
 *
 * --brand comes from partials/brand-vars, which every layout includes.
 */

.brand-lockup {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    line-height: 1;
}

/* The figure is the claim, so it carries the size, the display face and the
   brand colour. Optical letter-spacing: a 7 leaves a hole on its right. */
.brand-lockup__figure {
    font-family: 'Space Grotesk', 'Manrope', ui-sans-serif, system-ui, sans-serif;
    font-size: 2.4rem;
    font-weight: 700;
    line-height: 0.78;
    letter-spacing: -0.05em;
    color: var(--brand, #2563eb);
    flex-shrink: 0;
}

.brand-lockup__words {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

/* Both lines stay on one line each, always. */
.brand-lockup__line {
    white-space: nowrap;
    text-transform: uppercase;
    font-size: 10px;
    line-height: 1;
}

.brand-lockup__line--lead {
    font-weight: 700;
    letter-spacing: 0.22em;
    /* 4.76:1 on the white navbar. #94a3b8 measured 2.66 and this is text,
       small and tracked out, which is the hardest kind to read. The dark
       lockup below keeps the lighter value, where it clears 6.9. */
    color: #64748b;
}

/* The payload word carries the weight; that contrast is the lockup. */
.brand-lockup__line--key {
    font-weight: 900;
    letter-spacing: 0.13em;
    color: #0b1220;
}

/* Seven ticks, one per day. The mark says what the product does. */
.brand-lockup__ticks {
    display: flex;
    gap: 2.5px;
    margin-top: 2px;
}

.brand-lockup__ticks i {
    display: block;
    width: 7px;
    height: 3px;
    border-radius: 1px;
    background: var(--brand, #2563eb);
    transform-origin: bottom;
    transition: transform 0.28s cubic-bezier(0.2, 0.8, 0.3, 1);
}

/* Ripple left to right off the brand link's own hover. Transform only, so
   nothing around it moves. */
.group:hover .brand-lockup__ticks i { transform: scaleY(2.3); }
.brand-lockup__ticks i:nth-child(1) { transition-delay: 0ms; }
.brand-lockup__ticks i:nth-child(2) { transition-delay: 30ms; }
.brand-lockup__ticks i:nth-child(3) { transition-delay: 60ms; }
.brand-lockup__ticks i:nth-child(4) { transition-delay: 90ms; }
.brand-lockup__ticks i:nth-child(5) { transition-delay: 120ms; }
.brand-lockup__ticks i:nth-child(6) { transition-delay: 150ms; }
.brand-lockup__ticks i:nth-child(7) { transition-delay: 180ms; }

@media (prefers-reduced-motion: reduce) {
    .brand-lockup__ticks i { transition: none; }
    .group:hover .brand-lockup__ticks i { transform: none; }
}

/* On the dark footer the key line is the white one. */
.brand-lockup--dark .brand-lockup__line--lead { color: #94a3b8; }
.brand-lockup--dark .brand-lockup__line--key { color: #ffffff; }

/* The header lockup shows on a phone too. It used to be hidden below 640px,
 * which left opvii.com on mobile as a bare wordmark with no tagline at all.
 * It tightens rather than disappears: the mark shrinks, the rule goes, and the
 * words step down so the whole lockup clears the menu button. */
.brand-lockup--header { display: inline-flex; }

@media (max-width: 639px) {
    .brand-lockup--header { gap: 0.3rem; }
    .brand-lockup--header .brand-lockup__figure { font-size: 1.5rem; }
    .brand-lockup--header .brand-lockup__line { font-size: 8px; }
    .brand-lockup--header .brand-lockup__line--lead { letter-spacing: 0.14em; }
    .brand-lockup--header .brand-lockup__line--key { letter-spacing: 0.08em; }
    .brand-lockup--header .brand-lockup__ticks { gap: 2px; }
    .brand-lockup--header .brand-lockup__ticks i { width: 4px; height: 2px; }
}

/* Under about 360px the wordmark and the menu button leave no room for words. */
@media (max-width: 359px) {
    .brand-lockup--header { display: none; }
}

/* Rule between the mark and the lockup. Plain rgba, not a Tailwind opacity
   utility: v4 emits those through color-mix, and the no-color-mix fallback is
   the colour at FULL strength, which on the dark footer is a hard white bar. */
.brand-rule {
    width: 1px;
    height: 2.5rem;
    flex-shrink: 0;
    align-self: center;
    background: linear-gradient(to bottom, transparent, rgba(15, 23, 42, 0.22), transparent);
}

.brand-rule--dark {
    background: linear-gradient(to bottom, transparent, rgba(255, 255, 255, 0.22), transparent);
}

.brand-rule--header { display: none; }
@media (min-width: 640px) {
    .brand-rule--header { display: block; }
}

/* The footer is dark, so the mark goes white. Not a white chip behind it. */
.brand-logo-invert { filter: brightness(0) invert(1); }

/* Compact: the portal sidebar is w-64, and after px-4, a 72px mark, the gap
 * and the pr-9 kept clear for the collapse toggle, the lockup has about 99px
 * to live in. Measured, not guessed. */
.brand-lockup--compact { gap: 0.4rem; }
.brand-lockup--compact .brand-lockup__figure { font-size: 1.6rem; line-height: 0.8; }
.brand-lockup--compact .brand-lockup__words { gap: 2px; }
.brand-lockup--compact .brand-lockup__line { font-size: 9px; }
.brand-lockup--compact .brand-lockup__line--lead { letter-spacing: 0.18em; }
.brand-lockup--compact .brand-lockup__line--key { letter-spacing: 0.1em; }
.brand-lockup--compact .brand-lockup__ticks { gap: 2px; margin-top: 1px; }
.brand-lockup--compact .brand-lockup__ticks i { width: 5px; height: 2.5px; }
.brand-rule--compact { height: 1.75rem; }

/* ===== css/site-forms.css ===== */
/* Site-page form widgets.
 *
 * public/assets/css/app.css is a frozen Tailwind build that nothing
 * regenerates, so a utility the portal uses may simply not exist out here. The
 * searchable dropdown needs one that does not, and its trigger has to match the
 * metrics of the inputs beside it rather than the portal's shorter control.
 *
 * Loaded AFTER app.css, so these win on equal specificity.
 */

/* Used by the teleported dropdown panel; absent from the site build. */
.max-w-\[calc\(100vw-1rem\)\] { max-width: calc(100vw - 1rem); }

/* The register form's inputs are px-4 py-2.5 on brand-sand. The portal trigger
   is h-10 on white, which sat a few pixels short of the fields either side of
   it and in the wrong ground. */
.site-select-trigger {
    height: auto;
    padding: 0.625rem 1rem;
    background-color: #f8fafc;
    font-weight: 400;
    font-size: 1rem;
}

.site-select-trigger:hover { background-color: #f1f5f9; }

.site-select-trigger:focus {
    border-color: var(--brand, #2563eb);
    background-color: #fff;
    box-shadow: 0 0 0 2px rgba(var(--brand-rgb), 0.3);
}

/* Invalid field. A semantic class rather than !border-red-400: the bang
 * variants are not in the frozen site build, so they render as nothing, and
 * without !important the red loses to whichever border colour the stylesheet
 * happens to emit last. */
.field-invalid {
    border-color: #f87171 !important;
    background-color: #fef2f2 !important;
}

.field-invalid:focus {
    border-color: #ef4444 !important;
    box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.25) !important;
}

/* Pick A Time: a 3-column grid leaves a hole whenever the count is not a
 * multiple of three. Flex with a percentage basis lets the last row's tiles
 * stretch across the gap instead. The basis classes are not in the frozen
 * build, so they live here. */
.time-grid { display: flex; flex-wrap: wrap; gap: 0.5rem; }

.time-grid > button {
    flex: 1 1 30%;
    min-width: 8.5rem;
}

/* NO INNER SCROLL. This was capped at 8rem so the panel finished level with
 * the order summary beside it, and the cap cost twice over: the list scrolled
 * when a day's dozen slots would have fitted in three rows, AND it left the
 * panel with a band of white underneath that the slots were being hidden to
 * create. The whole day shows; what is left over below is the footer's. */
.time-grid { align-content: flex-start; }

/* Kept as a no-op hook. The checkout still measures the list and still sets
 * this class, and if a day ever brings enough slots to need a box again this
 * is where that box goes. Nothing is capped, so it never fires today. */
.time-grid--scrolls { }

/* ===== css/site-chrome.css ===== */
/* Marketing-site chrome that Tailwind cannot express.
 *
 * The scrollbars are the portal's, moved out here so the public pages match the
 * product instead of wearing whatever the operating system paints. Same 6px
 * thin bar, transparent track and brand-tinted thumb as .portal-sidebar in
 * portal.css.
 *
 * Applied to the page itself and to anything that scrolls inside it, since a
 * code sample box with a default grey scrollbar sitting next to a styled page
 * is more obvious than no styling at all.
 */
html {
    scrollbar-width: thin;
    scrollbar-color: rgba(var(--brand-rgb), 0.4) transparent;
}

html::-webkit-scrollbar,
.site-scroll::-webkit-scrollbar,
pre::-webkit-scrollbar,
.overflow-x-auto::-webkit-scrollbar,
.overflow-y-auto::-webkit-scrollbar {
    width: 6px;
    height: 6px;
}

html::-webkit-scrollbar-track,
.site-scroll::-webkit-scrollbar-track,
pre::-webkit-scrollbar-track,
.overflow-x-auto::-webkit-scrollbar-track,
.overflow-y-auto::-webkit-scrollbar-track {
    background: transparent;
}

html::-webkit-scrollbar-thumb,
.site-scroll::-webkit-scrollbar-thumb,
pre::-webkit-scrollbar-thumb,
.overflow-x-auto::-webkit-scrollbar-thumb,
.overflow-y-auto::-webkit-scrollbar-thumb {
    background: rgba(var(--brand-rgb), 0.4);
    border-radius: 6px;
}

html::-webkit-scrollbar-thumb:hover,
.site-scroll::-webkit-scrollbar-thumb:hover,
pre::-webkit-scrollbar-thumb:hover,
.overflow-x-auto::-webkit-scrollbar-thumb:hover,
.overflow-y-auto::-webkit-scrollbar-thumb:hover {
    background: rgba(var(--brand-rgb), 0.7);
}

/* A dark panel needs a light thumb or the bar disappears into it. */
.site-scroll-dark {
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, 0.28) transparent;
}

.site-scroll-dark::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.28);
}

.site-scroll-dark::-webkit-scrollbar-thumb:hover {
    background: rgba(255, 255, 255, 0.45);
}

/* Card elevation the public pages ask for but never got.
 *
 * shadow-soft-xl and shadow-panel are used across the marketing site and
 * neither has a rule in assets/css/app.css, so every card wearing them has
 * been rendering perfectly flat. These are the values the portal uses for the
 * same job, so the two halves of the product finally match.
 */
.shadow-soft-xl {
    box-shadow: 0 1px 2px rgba(15, 23, 42, .04),
                0 8px 24px -16px rgba(15, 23, 42, .18);
}

.shadow-panel {
    box-shadow: 0 1px 2px rgba(15, 23, 42, .04),
                0 24px 60px -30px rgba(15, 23, 42, .35);
}

/* ---------------------------------------------------------------------------
 * The Solutions mega menu, with some life in it.
 *
 * The panel was correct but flat: a plain gradient rail, six cards that only
 * changed background on hover, and a footer row of borderless links. These
 * three touches give it the same language as the marketing bands without
 * changing what it says or how tall it is.
 */

/* The rail's dot field - the pitch used on the proof band and the contact
   section. rgba(), not the slash form: --brand-rgb is comma separated and the
   slash syntax silently drops the whole declaration. */
.mega-dots {
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-image: radial-gradient(rgba(147, 197, 253, 0.18) 1px, transparent 1px);
    background-size: 18px 18px;
}

/* One figure in the rail, so the panel opens with a reason rather than a
   description. Same number the front page leads with. */
.mega-stat {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 1px;
    margin-top: 14px;
    border-top: 1px solid rgb(255 255 255 / 0.12);
    padding-top: 12px;
}
.mega-stat__v {
    font-size: 20px;
    font-weight: 800;
    letter-spacing: -0.02em;
    line-height: 1.1;
    background: linear-gradient(90deg, #bfdbfe, #60a5fa);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}
.mega-stat__l {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: rgb(191 219 254 / 0.75);
}

/* A brand spine that wipes in from the top on hover, and a small lift. The
   spine is drawn inside the card's own radius so nothing pokes out. */
.mega-card { position: relative; overflow: hidden; }
.mega-card::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 3px;
    border-radius: 3px;
    background: linear-gradient(180deg, var(--brand-400), var(--brand-700));
    transform: scaleY(0);
    transform-origin: top;
    transition: transform .25s ease;
}
.mega-card:hover::before,
.mega-card:focus-visible::before,
.mega-card.is-on::before { transform: scaleY(1); }
.mega-card:hover { transform: translateY(-1px); }

@media (prefers-reduced-motion: reduce) {
    .mega-card::before { transition: none; }
    .mega-card:hover { transform: none; }
}

/* ---------------------------------------------------------------------------
 * The 1024px overflow.
 *
 * The header switches from the mobile button to the full desktop bar at `lg`
 * (1024px), but the nav capsule plus Login and Get Started need about 1057px.
 * Every marketing page therefore scrolled sideways by ~33px in the narrow band
 * between 1024 and the next breakpoint - R3, on every page at once.
 *
 * The breakpoint itself is left alone (moving it to xl would put the mobile
 * menu on 1024-1279 laptops). Instead the bar is tightened just inside that
 * band, and goes back to its normal metrics at 1280.
 */
@media (min-width: 1024px) and (max-width: 1279px) {
    .site-nav { gap: 0; padding: 3px; }
    .site-nav > a,
    .site-nav > div > a,
    .site-nav > div > button {
        padding-left: 7px;
        padding-right: 7px;
        font-size: 13px;
        gap: 5px;
    }
    /* The nav icons are decoration beside their labels; the labels are the
       thing being clicked, so the icons give up the space first. */
    .site-nav i { display: none; }

    .site-cta { gap: 6px; }
    .site-cta > a { padding-left: 11px; padding-right: 11px; font-size: 13px; }
}

/* The card grid fills the panel.
 *
 * It carried `content-start`, so its three rows sat at the top while the dark
 * rail beside it set a taller panel — leaving a block of white under the last
 * pair of solutions. The rows share the height instead, which also makes the
 * six cards the same size as each other. */

/* The panel hangs BELOW the navbar rather than butting into it, and every
   corner carries the same radius - including the two at the top, where the
   dark rail meets the shell and the join was reading square. */
/* THE PANEL SPANS THE NAVBAR.
 *
 * `left-1/2 -translate-x-1/2` centered a 56rem box on the Solutions BUTTON.
 * The button is not the middle of the page and 56rem is not its width, so the
 * panel hung in the middle of the bar with the wordmark outside it on one side
 * and Get Started outside it on the other.
 *
 * Two parts. First the containing block: the nav item carries `relative`, so
 * an absolute child could only ever be positioned against a 90px button. Made
 * static, the panel resolves against <header>, which is `sticky` and therefore
 * positioned, and spans the full bar. Second the insets, which reproduce the
 * header container's own centering: max-w-6xl is 72rem and px-4 is 1rem, so
 * the content box starts at max(1rem, (100% - 72rem) / 2 + 1rem) from each
 * edge. The panel lines up with the wordmark and the Get Started button at
 * every width, with no measuring in JavaScript.
 */
.site-nav .group\/nav:has(> .mega-panel) { position: static; }

.mega-panel {
    left: max(1rem, calc((100% - 72rem) / 2 + 1rem));
    right: max(1rem, calc((100% - 72rem) / 2 + 1rem));
    width: auto;
    max-width: none;
}

/* The panel's TOP EDGE lands on the navbar's BOTTOM EDGE, with nothing
   between them, and there is exactly ONE line where they meet.
   The bar carries two: a `border-b` AND a decorative gradient hairline
   absolutely placed at its bottom. Sitting under both of them stacked the
   panel's own border into a 2px seam. Three things were tried and two were
   wrong: moving the panel OVER the bar's lines works but leaves it sitting on
   top of the bar, and painting them out under the panel stops the bar's edge
   dead where the panel starts and restarts after it.
   What was actually doubled is the bar itself, which carried a border AND a
   decorative gradient hairline on the same edge. The hairline is gone, the
   border is the one line, and the panel hangs off it with no border of its
   own. Measured at 1440 with the menu open: bar border 120-121, panel 121. */
.mega-panel {
    top: calc(100% + 1px);
    padding-top: 0;
}

/* The strip between the trigger and the panel belongs to neither of them.
   Crossing it fired mouseleave on the nav item, which closed the menu, and
   landing on the panel opened it again: the dropdown blinked on the way down,
   worse diagonally, where the pointer spends longer in the strip. While the
   menu is open the panel grows a transparent bridge over it, so the pointer
   never leaves the item it is hovering. It exists only while the panel does,
   so nothing below the bar is clickable-through when the menu is shut.
   Measured at 1440: trigger bottom 96, panel top 119. */
.mega-panel::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: 100%;
    /* Exactly the strip, and not a pixel into the other nav items: taller, it
       would sit over the bottom edge of their buttons and eat the click. */
    height: 25px;
}

/* Square along the top, round along the bottom. The panel hangs off the
   navbar rather than floating under it, so a radius at the top cut two
   notches out of a join that is meant to be continuous. The rail follows the
   shell: square at the top left, square at the bottom left where the footer
   strip runs under it. */
/* ONE line where the panel meets the bar. Flush, the navbar's own bottom
   hairline and the shell's top border stacked into a 2px seam that read as a
   mistake. The shell drops its top border, and the box-shadow is written out
   in full so Tailwind's `ring-1` cannot put the same line back as a ring. */
.mega-shell {
    border-radius: 0 0 20px 20px;
    /* No border on the edge that meets the bar, and the box-shadow is written
       out in full so Tailwind's `ring-1` cannot redraw one as a ring. */
    border-top: 0;
    box-shadow: 0 44px 90px -34px rgba(15, 23, 42, .45);
    isolation: isolate;
}
.mega-shell > .flex > div:first-child {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
}

/* The grid fills whatever height the rail sets, so there is never white under
   the last pair of cards - with or without the pointer on them. */
.mega-shell > .flex { align-items: stretch; }

/* The grid fills the panel, and the cards are big enough that filling it does
 * not show.
 *
 * Stretching alone was the bug, not the fix: the rail was ~70px taller than
 * three rows of cards needed, the rows absorbed all of it, and six cards each
 * carrying 36px of content inside an 89px box read as exactly what Allen
 * called it, white space. The rail gave a line back (see header.blade.php) and
 * the cards got real padding, so the rows now want nearly the height they are
 * given and the leftover is a few pixels rather than a hole. */
.mega-grid {
    align-content: stretch;
    grid-template-rows: repeat(3, minmax(0, 1fr));
}

/* Full bar width means room for three across, and six solutions over two rows
   leaves no half-empty row. Below that it stays two across over three. */
@media (min-width: 1024px) {
    .mega-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
        grid-template-rows: repeat(2, minmax(0, 1fr));
    }
}
.mega-grid > a { height: 100%; align-items: center; padding-top: 20px; padding-bottom: 20px; }

/* At three across the panel is 1120px wide and the rail no longer sets the
   height by much, so the cards get their own presence instead of being
   stretched into it: a bigger medallion and real padding, which leaves about
   ten pixels of slack per row rather than forty. */
@media (min-width: 1024px) {
    .mega-card > span:first-child {
        width: 44px;
        height: 44px;
        flex: 0 0 44px;
    }
}

/* A RESTING BORDER on every card (R15). Without one an 89px box with 36px of
 * content inside it is indistinguishable from empty panel; with one it reads
 * as a row, and hover has something to change rather than something to add. */
.mega-card {
    border: 1px solid #eef2f7;
    background: #fff;
}
.mega-card:hover { border-color: #cbd5e1; background: #f8fafc; }
.mega-card.is-on { border-color: rgba(var(--brand-rgb), 0.3); background: rgba(var(--brand-rgb), 0.05); }

/* The mega menu's footer strip.
 *
 * `items-center` centers the BOXES, and the sentence on the left is a 19px
 * line box while the three buttons beside it are 31px tall - so the two were
 * centered against different heights and the sentence rode high. Giving the
 * sentence the buttons' own height makes the one centering do both. */
.mega-footrow > p {
    min-height: 31px;
    line-height: 31px;
    margin: 0;
}

/* ===== css/site-headers.css ===== */
/* Page hero bands and full-width section heads.
 *
 * Plain CSS on purpose. public/assets/css/app.css is a FROZEN marketing
 * Tailwind build that nothing in this repo rebuilds, so a utility with no rule
 * already in it renders as nothing at all, silently (lg:col-span-7 is one).
 * Layout that has to be right every time lives here instead, where it is
 * served straight off disk and asset_v() busts the cache on filemtime.
 *
 * Two rules drive both components:
 *   - Content spans the SAME width as the header and the sections. No inner
 *     max-width on a headline or a lead, ever. A readable measure is for body
 *     prose; a hero inset inside its own band reads as a narrower page.
 *   - Nothing is a lone centered block floating in an empty band. The hero is
 *     two columns, the section head is a title against its lead.
 */

/* ── Page hero ───────────────────────────────────────────────────────────── */

/* ONE band height for every hero on the site, in one place.

   The history matters, because this is the third position. It was a 40rem
   floor, which left a secondary page's title, lead and three cards floating in
   a slab of empty blue. Then it was content sized, which removed the slab and
   left eight heroes between 428px and 619px. Neither is what was wanted.

   What makes both work at once is R2's own answer: even the CONTENT, never the
   box. The band is one number; the copy column centers in it, the right column
   STRETCHES so its cards grow rather than leaving air, and a long headline
   steps down a size (x-site.hero-title) instead of spending a fourth line.

   33rem is not a guess. It is what /contact and /pricing already measured at
   when they were content sized, and those two were the ones signed off. */
:root {
    --hero-band: 33rem;
}

.page-hero {
    position: relative;
    isolation: isolate;
    display: flex;
    align-items: center;
    overflow: hidden;
    min-height: 0;
    border-bottom: 2px solid rgba(var(--brand-rgb), 0.4);
    background: linear-gradient(150deg, #0b1220 0%, #101c34 60%, #16284d 120%);
    color: #fff;
}

.page-hero__decor {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
}

.page-hero__glow {
    position: absolute;
    border-radius: 9999px;
    filter: blur(48px);
}

.page-hero__glow--one {
    top: -8rem;
    left: 33%;
    height: 34rem;
    width: 34rem;
    background: radial-gradient(circle, rgba(var(--brand-rgb), 0.22), transparent 60%);
}

.page-hero__glow--two {
    right: 0;
    bottom: -10rem;
    height: 30rem;
    width: 30rem;
    background: radial-gradient(circle, rgba(99, 102, 241, 0.18), transparent 60%);
}

.page-hero__grid-tile {
    position: absolute;
    inset: 0;
    background-image:
        linear-gradient(rgba(96, 165, 250, 0.06) 1px, transparent 1px),
        linear-gradient(90deg, rgba(96, 165, 250, 0.06) 1px, transparent 1px);
    background-size: 50px 50px;
    -webkit-mask-image: radial-gradient(ellipse at top, #000 30%, transparent 80%);
    mask-image: radial-gradient(ellipse at top, #000 30%, transparent 80%);
}

.page-hero__rule {
    position: absolute;
    top: 0;
    right: 0;
    left: 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgb(var(--brand-400-rgb) / 0.4), transparent);
}

.page-hero__inner {
    position: relative;
    width: 100%;
    margin-inline: auto;
    padding: 2.75rem 1rem;
}

.page-hero__layout {
    display: grid;
    gap: 2.5rem;
    align-items: center;
}

.page-hero__copy {
    min-width: 0;
}

.page-hero__eyebrow {
    /* The copy column is a flex column now, so an inline-flex child stretches
       to its full width unless it says otherwise. Without this the chip ran
       the whole 554px. */
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    border: 1px solid rgb(var(--brand-400-rgb) / 0.3);
    border-radius: 9999px;
    background: rgb(var(--brand-400-rgb) / 0.1);
    padding: 0.375rem 1rem;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: #bfdbfe;
    backdrop-filter: blur(4px);
}

.page-hero__eyebrow i {
    color: var(--brand-300);
}

/* No max-width. The headline is as wide as the band, which is as wide as the
   header. This is the exact thing that was wrong before.

   text-wrap: balance because the alternative is a full first line and a
   two-word second one: /contact read "Support Straight From" over "Our Team",
   which is the ragged shape that made two heroes of identical height look like
   they disagreed. Balance evens the lines without touching the copy, and it
   degrades to normal wrapping where it is unsupported. */
.page-hero__title {
    margin-top: 1.125rem;
    text-wrap: balance;
    font-size: 1.875rem;
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -0.02em;
    color: #fff;
}

.page-hero__title .page-hero__accent {
    background: linear-gradient(90deg, var(--brand-300), var(--brand-400) 45%, var(--brand-600));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

/* Chosen from the string length by x-site.hero-title, never by hand per page.
   /features ran to four lines at the base size and was 92px taller than every
   other hero on its own. */
.page-hero__title--long { font-size: 1.75rem; }
.page-hero__title--xlong { font-size: 1.625rem; }

.page-hero__lead {
    margin-top: 0.875rem;
    font-size: 1.0625rem;
    line-height: 1.7;
    color: #cbd5e1;
}

.page-hero__actions {
    margin-top: 1.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.page-hero__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    white-space: nowrap;
    border: 1px solid transparent;
    border-radius: 0.75rem;
    padding: 0.875rem 1.75rem;
    font-size: 1rem;
    font-weight: 700;
    transition: border-color .18s ease, background-color .18s ease, transform .18s ease;
}

.page-hero__btn--primary {
    background: linear-gradient(135deg, var(--brand-600) 0%, var(--brand-700) 100%);
    border-color: rgb(var(--brand-400-rgb) / 0.45);
    color: #fff;
    box-shadow: 0 18px 40px -18px rgba(var(--brand-rgb), 0.95);
}

.page-hero__btn--primary:hover {
    border-color: var(--brand-300);
    transform: translateY(-1px);
}

.page-hero__btn--ghost {
    border-color: rgba(255, 255, 255, 0.2);
    background: rgba(255, 255, 255, 0.05);
    color: #fff;
    font-weight: 600;
    backdrop-filter: blur(4px);
}

.page-hero__btn--ghost:hover {
    border-color: var(--brand-300);
    background: rgba(255, 255, 255, 0.1);
}

.page-hero__proof {
    margin-top: 1.125rem;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem 0.5rem;
    font-size: 0.875rem;
    color: #94a3b8;
}

.page-hero__proof span {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
}

.page-hero__proof i {
    color: #34d399;
}

.page-hero__proof .page-hero__dot {
    color: #475569;
}

/* Right column. Three cards, so the band is never a title beside nothing. */
.page-hero__cards {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    min-width: 0;
}

.page-hero__card {
    display: flex;
    align-items: center;
    gap: 1rem;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 1rem;
    background: rgba(255, 255, 255, 0.05);
    padding: 1.25rem;
    backdrop-filter: blur(12px);
    box-shadow: 0 24px 60px -32px rgba(2, 6, 23, 0.9);
    transition: border-color .18s ease, background-color .18s ease;
}

.page-hero__card:hover {
    border-color: rgb(var(--brand-400-rgb) / 0.4);
    background: rgba(255, 255, 255, 0.08);
}

.page-hero__card-icon {
    display: flex;
    height: 3rem;
    width: 3rem;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 0.75rem;
    background: linear-gradient(135deg, var(--brand-600), var(--brand-700));
    color: #fff;
    box-shadow: 0 10px 24px -10px rgba(var(--brand-rgb), 0.9);
}

.page-hero__card-body {
    min-width: 0;
}

.page-hero__card-title {
    font-size: 1rem;
    font-weight: 700;
    color: #fff;
}

.page-hero__card-desc {
    margin-top: 0.25rem;
    font-size: 0.875rem;
    line-height: 1.45;
    color: #94a3b8;
}

@media (min-width: 640px) {
    .page-hero__title { font-size: 2.25rem; }
    .page-hero__actions { flex-direction: row; flex-wrap: wrap; }
}

@media (min-width: 1024px) {
    .page-hero,
    .site-hero-band { min-height: var(--hero-band); }

    .page-hero__inner { padding: 3.25rem 1rem; }

    /* stretch, not center: the right column has to be able to fill the band,
       which is the only way the slack lands inside a card instead of under it. */
    .page-hero__layout {
        grid-template-columns: 1.05fr 0.95fr;
        gap: 4rem;
        align-items: stretch;
    }

    /* The copy centers in the band it no longer fills. */
    .page-hero__copy {
        display: flex;
        flex-direction: column;
        justify-content: center;
    }

    .page-hero__cards { justify-content: stretch; }
    .page-hero__card { flex: 1 1 0; }

    .page-hero__tiles {
        align-content: stretch;
        grid-auto-rows: 1fr;
    }

    .page-hero__title { font-size: 2.5rem; }
    .page-hero__title--long { font-size: 2.125rem; }
    .page-hero__title--xlong { font-size: 1.875rem; }
    .page-hero__lead { font-size: 1.125rem; }
}

/* Four cards stacked are taller than the band. Two columns of two are not, and
   the four steps of a solution flow read as a sequence either way.

   Half the column width means every description wraps further, so the grid
   variant is a size down on padding, medallion and copy. Without that the two
   rows came to 440px against the 416px the band leaves for content. */
.page-hero__cards--grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem;
}

.page-hero__cards--grid .page-hero__card {
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.875rem;
}

.page-hero__cards--grid .page-hero__card-icon {
    height: 2.25rem;
    width: 2.25rem;
    border-radius: 0.625rem;
    font-size: 0.8125rem;
}

.page-hero__cards--grid .page-hero__card-title { font-size: 0.875rem; }

.page-hero__cards--grid .page-hero__card-desc {
    font-size: 0.8125rem;
    line-height: 1.4;
}

@media (min-width: 1024px) {
    .page-hero__cards--grid { gap: 0.875rem; grid-auto-rows: 1fr; }
}

/* ── Section head ────────────────────────────────────────────────────────── */

/* Title left, lead right, a hairline under both. Spans the whole band, so a
   section never opens with a narrow centered column in the middle of nothing. */
.section-head {
    display: grid;
    gap: 1rem;
    padding-bottom: 1.5rem;
    border-bottom: 1px solid var(--section-head-line, rgba(15, 23, 42, 0.12));
}

/* The squared tab with a thick brand left edge, copied from the "Event
   Automation Simplified" chip on the home page, which is the one Allen picked.
   It replaced a pill whose border was written rgba(var(--brand-rgb), 0.2):
   --brand-rgb is COMMA separated, so that was invalid and the chip shipped with
   no border at all. */
.section-head__eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    border: 1px solid var(--section-head-chip-border, rgba(var(--brand-rgb), 0.3));
    border-left: 4px solid var(--section-head-chip-accent, var(--brand));
    border-radius: 0.25rem;
    background: var(--section-head-chip-bg, #fff);
    padding: 0.375rem 1rem 0.375rem 0.75rem;
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.35;
    color: var(--section-head-chip-text, var(--color-brand-ink, #0b1220));
}

.section-head__eyebrow i {
    color: var(--section-head-chip-icon, var(--brand));
}

.section-head__title {
    margin-top: 0.875rem;
    text-wrap: balance;
    font-size: 1.75rem;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: -0.02em;
    color: var(--section-head-title, #0b1220);
}

.section-head__lead {
    font-size: 1rem;
    line-height: 1.7;
    color: var(--section-head-lead, #1e293b);
}

.section-head__copy {
    min-width: 0;
}

@media (min-width: 1024px) {
    .section-head {
        grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
        align-items: end;
        column-gap: 4rem;
        padding-bottom: 1.75rem;
    }
    .section-head__title { font-size: 2.125rem; }
    .section-head__lead { padding-bottom: 0.25rem; }
}

.section-head--dark {
    --section-head-line: rgba(255, 255, 255, 0.12);
    --section-head-chip-border: rgba(255, 255, 255, 0.18);
    --section-head-chip-accent: var(--brand-400);
    --section-head-chip-bg: rgba(255, 255, 255, 0.08);
    --section-head-chip-text: #ffffff;
    --section-head-chip-icon: var(--brand-300);
    --section-head-title: #ffffff;
    --section-head-lead: #cbd5e1;
}

.section-head--dark .section-head__eyebrow {
    backdrop-filter: blur(4px);
}

/* Right column variant: a 2x2 of glass tiles, for the pages whose hero already
   carried four stat cards in a narrow centered strip below the copy. Same job
   as .page-hero__cards, different content shape. */
.page-hero__tiles {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem;
    min-width: 0;
}

.page-hero__tile {
    display: flex;
    flex-direction: column;
    justify-content: center;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 1rem;
    background: rgba(255, 255, 255, 0.06);
    padding: 1.125rem 1rem;
    text-align: center;
    backdrop-filter: blur(12px);
    transition: border-color .18s ease, background-color .18s ease;
}

.page-hero__tile:hover {
    border-color: rgb(var(--brand-400-rgb) / 0.4);
    background: rgba(255, 255, 255, 0.09);
}

.page-hero__tile i {
    margin-bottom: 0.5rem;
    font-size: 1.125rem;
    color: var(--brand-300);
}

.page-hero__tile-value {
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1.2;
    color: #fff;
    white-space: nowrap;
}

.page-hero__tile-label {
    margin-top: 0.25rem;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: #bfdbfe;
}

@media (min-width: 1024px) {
    .page-hero__tiles { gap: 1rem; }
    .page-hero__tile { padding: 1.5rem 1rem; }
    .page-hero__tile-value { font-size: 1.5rem; }
}

/* Floor for the shared blue hero band (x-site.blue-hero).
 *
 * It used to be min-h-[26rem] / sm:30rem / lg:40rem. On /features the content
 * is taller than that anyway, so the floor did nothing; on /pricing and
 * /contact it forced ~110px of empty blue above and below a hero that had
 * finished. The floor is now low enough that the content sets the height on
 * every page and high enough that a one-line hero is still a band.
 *
 * Plain CSS because the frozen marketing Tailwind build has no rule for any
 * min-h-[...] value other than the three above.
 */

/* Safety net. A section head is dark-on-dark the moment somebody forgets
   tone="dark", and it is invisible rather than merely wrong: on
   /solutions/classes the "From Registration To Attendance" head rendered
   near-black on a near-black band. Any dark section on this site sets
   text-white on the <section>, so inherit the dark tokens from that. The
   explicit modifier is still the right thing to write; this only stops the
   omission from shipping unreadable. */
.text-white .section-head {
    --section-head-line: rgba(255, 255, 255, 0.12);
    --section-head-chip-border: rgba(255, 255, 255, 0.18);
    --section-head-chip-accent: var(--brand-400);
    --section-head-chip-bg: rgba(255, 255, 255, 0.08);
    --section-head-chip-text: #ffffff;
    --section-head-chip-icon: var(--brand-300);
    --section-head-title: #ffffff;
    --section-head-lead: #cbd5e1;
}

/* ── /status service board ───────────────────────────────────────────────── */

/* TWO services per row, each one half the width. Eight services used to be
 * eight full-width rows and 1192px of board; two-up makes it four rows, which
 * is the point: less scrolling.
 *
 * The tracks are literal 50% percentages and the gutter is carved OUT of them
 * with a half-rem margin on each card, rather than a grid gap. Same pixels
 * either way, but this way each service really does own half the width and the
 * outer edges stay flush with the section instead of each card being
 * (half minus half a gutter).
 *
 * Plain CSS, not utilities, for the reason at the top of this file:
 * public/assets/css/app.css is a frozen marketing Tailwind build, so a
 * grid-template-columns value that is not already in it renders as nothing at
 * all, silently.
 *
 * Inside a card the identity sits ABOVE the health rather than beside it. Half
 * a page split in half again leaves about 230px for ninety bars, which is a
 * smear, not a chart. */
.svc-grid {
    display: grid;
    grid-template-columns: 100%;
    align-items: stretch;
    row-gap: 1rem;
}

@media (min-width: 768px) {
    .svc-grid {
        grid-template-columns: 50% 50%;
    }

    .svc-grid > .svc-card:nth-child(odd)  { margin-right: 0.5rem; }
    .svc-grid > .svc-card:nth-child(even) { margin-left: 0.5rem; }
}

/* A column flex so the two cards in a row end level: the identity block grows
 * to take the slack from a neighbor with a longer description, which bounds it
 * in the tinted panel and its border rather than leaving a white gap under the
 * shorter one (R2). */
.svc-card {
    display: flex;
    min-width: 0;
    flex-direction: column;
}

.svc-card__id {
    display: flex;
    min-width: 0;
    flex: 1 1 auto;
    align-items: center;
    gap: 0.875rem;
    border-bottom: 1px solid rgba(var(--brand-rgb), 0.12);
    background: rgba(var(--brand-rgb), 0.04);
    padding: 0.9375rem 1.125rem;
}

.svc-card__medallion {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    border: 1px solid rgba(var(--brand-rgb), 0.22);
    border-radius: 0.75rem;
    background: #ffffff;
    color: var(--brand);
    font-size: 0.9375rem;
    transition: border-color .18s ease, color .18s ease;
}

.svc-card:hover .svc-card__medallion {
    border-color: rgba(var(--brand-rgb), 0.45);
}

.svc-card__text {
    min-width: 0;
}

.svc-card__text p + p {
    margin-top: 0.125rem;
}

/* ── the health half of a card ── */

.svc-card__health {
    display: flex;
    min-width: 0;
    flex-direction: column;
    flex: 0 0 auto;
    gap: 0.4375rem;
    padding: 0.9375rem 1.125rem;
}

.svc-card__state {
    display: flex;
    min-width: 0;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
}

.svc-card__pill {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 0.5rem;
    border-radius: 9999px;
    padding: 0.25rem 0.75rem;
    font-size: 0.75rem;
    font-weight: 700;
    white-space: nowrap;
}

.svc-card__dot {
    position: relative;
    display: inline-flex;
    flex: 0 0 auto;
    width: 0.5rem;
    height: 0.5rem;
}

.svc-card__ping {
    position: absolute;
    inset: 0;
    border-radius: 9999px;
    opacity: 0.6;
}

@media (prefers-reduced-motion: no-preference) {
    .svc-card__ping {
        animation: svccardping 1.6s cubic-bezier(0, 0, 0.2, 1) infinite;
    }
}

@keyframes svccardping {
    75%, 100% { transform: scale(2.2); opacity: 0; }
}

.svc-card__dot-core {
    position: relative;
    display: inline-flex;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 9999px;
}

.svc-card__pct {
    min-width: 0;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    white-space: nowrap;
}

/* The strip clips the shimmer only. It holds nothing that overlays. */
.svc-card__bars {
    position: relative;
    overflow: hidden;
    border-radius: 0.125rem;
}

/* Ninety bars in half a page is about 4.5px each once the gaps are paid for,
 * so the gap stays at 1px at every width: at 2px the gutters outweigh the
 * bars and the strip reads as a hatch rather than a chart. */
.svc-card__track {
    display: flex;
    align-items: stretch;
    gap: 1px;
    height: 1.75rem;
}

.svc-card__bar {
    flex: 1 1 0;
    min-width: 0;
    height: 100%;
    border-radius: 1px;
    transition: transform .2s ease, opacity .2s ease;
}

.svc-card__bar:hover {
    transform: scaleY(1.12);
    opacity: 1;
}

.svc-card__shimmer {
    position: absolute;
    top: 0;
    bottom: 0;
    left: -33.333333%;
    width: 33.333333%;
    pointer-events: none;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.45), transparent);
}

@media (prefers-reduced-motion: no-preference) {
    .svc-card__shimmer {
        animation: uptimeshimmer 3.2s ease-in-out infinite;
    }
}

@keyframes uptimeshimmer {
    0%   { transform: translateX(0); }
    100% { transform: translateX(450%); }
}

.svc-card__scale {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    font-size: 0.625rem;
    font-weight: 500;
    white-space: nowrap;
    color: rgba(30, 41, 59, 0.55);
}

.svc-card__scale-mid {
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

@media (min-width: 1024px) {
    .svc-card__id,
    .svc-card__health { padding: 1rem 1.25rem; }
    .svc-card__track { height: 2.25rem; }
}

/* The eyebrow runs as a ruled line, matching x-site.hero. */
.page-hero__eyebrow-row { display: flex; align-items: center; gap: 14px; }
.page-hero__eyebrow-rule {
    flex: 1;
    height: 1px;
    background: linear-gradient(90deg, rgb(var(--brand-400-rgb) / 0.5), transparent);
}

/* ---------------------------------------------------------------- /status */

/* The board's incident banner. It only renders when a probe has actually
   found something, so it is never decoration: if it is on the page, a check
   failed. Bordered medallion floated left, like every other one. */
.svc-alert {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    margin-bottom: 24px;
    padding: 16px 18px;
    border: 1px solid #fcd34d;
    border-left-width: 4px;
    border-radius: 16px;
    background: #fffbeb;
}

.svc-alert__medallion {
    display: inline-flex;
    flex: 0 0 38px;
    width: 38px;
    height: 38px;
    align-items: center;
    justify-content: center;
    border: 1px solid #fcd34d;
    border-radius: 11px;
    background: #fef3c7;
    color: #b45309;
    font-size: 15px;
}

.svc-alert__head {
    font-weight: 800;
    font-size: 14px;
    color: #78350f;
}

.svc-alert__body {
    margin-top: 3px;
    font-size: 13px;
    line-height: 1.6;
    color: #92400e;
}

/* Why a service is not green, in the probe's own words. Shown only when there
   is a reason to show, so the card does not grow a permanent empty line. */
.svc-card__why {
    margin-top: 8px;
    padding: 7px 10px;
    border: 1px solid #e2e8f0;
    border-radius: 9px;
    background: #f8fafc;
    font-size: 12px;
    line-height: 1.5;
    color: #475569;
}

/* A day with no checks. Not green, not red: a hairline, because painting an
   unmeasured day either colour is the thing this whole page exists to stop. */
.svc-card__bar--none {
    background: #e2e8f0;
    opacity: 0.55;
}

/* A day from BEFORE automated monitoring. Green, because no incident was
   recorded on it, but visibly lighter than a measured day and never counted
   in the percentage: "we know of no outage" and "we ran 288 checks and they
   all passed" are different claims and the strip has to show which is which. */
.svc-card__bar--past {
    background: #6ee7b7;
    opacity: 0.42;
}

/* A bar is focusable so a keyboard can reach its tooltip. The ring sits
   outside the 3px bar rather than inside it, where it would be invisible. */
.svc-card__bar:focus-visible {
    outline: 2px solid rgba(var(--brand-rgb), 0.9);
    outline-offset: 2px;
    border-radius: 2px;
}

/* ===== css/site-heroes.css ===== */


.fx { min-height: 26rem; }
@media (min-width: 640px) { .fx { min-height: 30rem; } }
@media (min-width: 1024px) { .fx { min-height: 33rem; } }
.fx-wrap { position: relative; width: 100%; padding-top: 36px; padding-bottom: 36px; }
@media (min-width: 1024px) { .fx-wrap { padding-top: 40px; padding-bottom: 40px; } }
.fx-eyebrow { display: flex; align-items: center; gap: 14px; }
.fx-chip { display: inline-flex; align-items: center; gap: 8px; border: 1px solid rgb(var(--brand-400-rgb) / .3); border-radius: 999px; background: rgb(var(--brand-400-rgb) / .1); padding: 6px 14px; font-size: 12px; font-weight: 600; color: #bfdbfe; white-space: nowrap; }
.fx-chip i { color: #93c5fd; }
.fx-rule { flex: 1; height: 1px; background: linear-gradient(90deg, rgb(var(--brand-400-rgb) / .5), transparent); }
.fx-h { margin: 16px 0 0; font-size: 26px; font-weight: 700; line-height: 1.22; letter-spacing: -.02em; color: #fff; }
@media (min-width: 1024px) { .fx-h { font-size: 38px; } }
.fx-accent { background: linear-gradient(90deg, var(--brand-300), var(--brand-400), var(--brand-600)); -webkit-background-clip: text; background-clip: text; color: transparent; }
.fx-lead { margin: 14px 0 0; font-size: 16px; line-height: 1.6; color: #cbd5e1; }
.fx-ctas { display: flex; flex-wrap: wrap; gap: 10px; }
.fx-go { display: inline-flex; align-items: center; gap: 9px; border-radius: 12px; background: linear-gradient(135deg, var(--brand-600), var(--brand-700)); padding: 12px 24px; font-size: 15px; font-weight: 700; color: #fff; text-decoration: none; transition: transform .2s; }
.fx-go:hover { transform: scale(1.03); }
.fx-go i { font-size: 12px; }
.fx-alt { display: inline-flex; align-items: center; gap: 9px; border: 1px solid rgb(255 255 255 / .2); border-radius: 12px; background: rgb(255 255 255 / .05); padding: 12px 24px; font-size: 15px; font-weight: 600; color: #fff; text-decoration: none; transition: border-color .2s, background .2s; }
.fx-alt:hover { border-color: rgb(255 255 255 / .35); background: rgb(255 255 255 / .1); }
.fx-alt i { font-size: 13px; color: #93c5fd; }
.fx-proof { display: flex; flex-wrap: wrap; gap: 8px 16px; margin: 0; font-size: 12.5px; color: #94a3b8; }
.fx-proof span { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; }
.fx-proof i { color: #34d399; font-size: 11px; }
.fx-tv { font-size: 16px; font-weight: 700; color: #fff; white-space: nowrap; }
.fx-tl { margin-top: 2px; font-size: 11.5px; color: #94a3b8; }
.fx-tb { min-width: 0; }
.fx-tic { display: inline-flex; width: 38px; height: 38px; flex: 0 0 38px; align-items: center; justify-content: center; border: 1px solid rgb(255 255 255 / .14); border-radius: 11px; background: rgb(var(--brand-400-rgb) / .14); color: #93c5fd; font-size: 14px; }

/* The proof words move OUT of the copy and run as a full width rail under
   both columns, which lets the headline and the tiles each have their own
   space instead of the left column carrying five stacked blocks. */
.fx-grid { display: grid; align-items: center; gap: 28px; }
@media (min-width: 1024px) { .fx-grid { grid-template-columns: 1.05fr 0.95fr; gap: 44px; } }
.fx-bar { margin-top: 14px; }
.fx-tiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.fx-tile { display: flex; align-items: center; gap: 11px; border: 1px solid rgb(255 255 255 / .14); border-radius: 14px; background: rgb(255 255 255 / .05); padding: 12px 13px; }
.fx-rail { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 22px; margin-top: 22px; padding-top: 14px; border-top: 1px solid rgb(255 255 255 / .12); }
.fx-rail .fx-proof { justify-content: center; }

/* The right column fills by having FOUR ROWS, not by inflating two.
 *
 * Stretching a 2x2 grid to 448px made four 190px boxes with a line of text
 * floating in the middle of each - taller boxes, same content, more emptiness.
 * Four stacked rows at ~105px fill the same height with the same words and
 * no hollow middles.
 */
.fx-tiles { align-self: stretch; grid-template-columns: minmax(0, 1fr); grid-template-rows: repeat(4, minmax(0, 1fr)); gap: 10px; }
.fx-tile { align-items: center; padding: 14px 16px; }
.fx-tic { width: 42px; height: 42px; flex-basis: 42px; font-size: 15px; }
.fx-tv { font-size: 17px; }
.fx-tl { font-size: 12px; }

/* The band fills with content instead of centring a short block in it.
 *
 * 528px of band was holding 310px of content, so 218px sat as air above and
 * below it. The wrap now stretches to the band and the grid takes the free
 * height; the tiles stretch with it, so the height is spent on the content
 * rather than around it. The band's own height does not change.
 */
.fx { align-items: stretch; }
.fx-wrap { display: flex; flex-direction: column; }
.fx-grid { flex: 1; align-items: center; }
.fx-tiles { align-self: stretch; }


/* Same here: the copy centres in its column instead of the action bar being
   pinned to the floor. */
/* Natural flow, centred. space-between threw the eyebrow, title and lead
   apart with holes between them - worse than the air it replaced. */
.fx-copy { display: flex; flex-direction: column; justify-content: center; }
.fx-grid { align-items: stretch; }

/* The features hero uses its own prefix for the same bar. */
.fx-bar .fx-ctas { display: flex; gap: 10px; }
.fx-bar .fx-ctas > a { flex: 1 1 0; min-width: 0; justify-content: center; }
@media (max-width: 639px) { .fx-bar .fx-ctas { flex-direction: column; } }


/* The rail is a closing line, not a section: tight to the columns above it. */
.fx-rail { margin-top: 14px; padding-top: 12px; }
.fx-rail .fx-proof { justify-content: center; margin: 0; }

/* ===========================================================================
 * The front page hero is the default; every other marketing hero adopts its
 * treatment and keeps its own content and colours.
 *
 * Two moves only, both CSS, both safe for every page that ships this markup:
 *   1. the lead sits against a brand spine, the way the front page sets it
 *   2. the buttons and the proof line read as ONE bordered bar
 *
 * The tile grid is deliberately NOT touched: site-headers.css notes that four
 * cards stacked are taller than the band, and changing it to one column is
 * what pushed /pricing, /contact and /integrations from 528px to 738px.
 * =========================================================================== */
.page-hero__lead {
    border-left: 2px solid rgb(var(--brand-400-rgb) / 0.45);
    padding-left: 16px;
}

.page-hero__actions {
    border: 1px solid rgb(255 255 255 / 0.12);
    border-bottom: 0;
    border-radius: 14px 14px 0 0;
    background: rgb(255 255 255 / 0.05);
    padding: 12px 14px 10px;
}
.page-hero__proof {
    margin-top: 0;
    border: 1px solid rgb(255 255 255 / 0.12);
    border-top-color: rgb(255 255 255 / 0.1);
    border-radius: 0 0 14px 14px;
    background: rgb(255 255 255 / 0.05);
    padding: 10px 14px 12px;
}

/* ---------------------------------------------------------------------------
 * The features band fills edge to edge.
 *
 * Three separate pockets of air, all from the same cause - the content was
 * inset inside a fixed 528px band and then centred inside that inset:
 *   1. above the eyebrow: 40px wrap padding + the copy centring in its column
 *   2. under the buttons: the copy ending early while the tiles ran on
 *   3. under the proof rail: the wrap's bottom padding
 * The wrap is tight to the band now, the copy starts on the same line as the
 * first tile, and the grid takes whatever is left so the tiles end with it.
 */
.fx-wrap { padding-top: 22px; padding-bottom: 22px; }
@media (min-width: 1024px) { .fx-wrap { padding-top: 24px; padding-bottom: 24px; } }
.fx-copy { justify-content: flex-start; }
.fx-rail { margin-top: 12px; padding-top: 10px; }

/* ===== css/site-home.css ===== */
/* The home page proof band.
 *
 * ONE plate cut into three cells by hairlines, rather than three separate
 * cards: three boxes made three objects out of a single claim.
 *
 * Plain CSS, not Tailwind: the marketing build in public/assets/css/app.css is
 * frozen, so a new arbitrary utility in this view would render as nothing.
 */

.st { position: relative; overflow: hidden; border-bottom: 2px solid rgba(var(--brand-rgb), .4); background: linear-gradient(180deg, #fff 0%, var(--brand-50) 100%); }
.st-glow { position: absolute; left: 50%; top: 0; width: 40rem; height: 10rem; transform: translateX(-50%); border-radius: 999px; background: rgb(var(--brand-400-rgb) / .10); filter: blur(90px); pointer-events: none; }
.st-wrap { position: relative; padding-top: 40px; padding-bottom: 40px; }
.st-eyebrow { display: flex; align-items: center; justify-content: center; gap: 7px; margin: 0; font-size: 12px; font-weight: 700; letter-spacing: .22em; text-transform: uppercase; color: var(--brand); text-align: center; }
.st-eyebrow i { font-size: 10px; }
.st-star { color: var(--brand); font-weight: 800; }
.st-note { max-width: 42rem; margin: 22px auto 0; font-size: 12px; line-height: 1.7; color: #475569; text-align: center; }
.st-l { margin-top: 6px; font-size: 11.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: #475569; white-space: nowrap; }
.st-vt { background: linear-gradient(120deg, var(--brand-700), var(--brand-500)); -webkit-background-clip: text; background-clip: text; color: transparent; }
.st-b { min-width: 0; }

/* ONE plate, cut into three cells by hairlines, with the eyebrow notched
   into its top edge. Three separate cards for three numbers made three
   objects out of one claim. */
.st-row { position: relative; margin-top: 30px; display: grid; grid-template-columns: minmax(0, 1fr); border: 1px solid #e2e8f0; border-radius: 20px; background: #fff; box-shadow: 0 20px 44px -34px rgb(15 23 42 / .5); }
@media (min-width: 640px) { .st-row { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.st-cell { display: flex; align-items: center; gap: 16px; border-top: 1px solid #eef2f7; padding: 22px 24px; }
.st-cell:first-child { border-top: 0; }
@media (min-width: 640px) {
    .st-cell { border-top: 0; border-left: 1px solid #eef2f7; }
    .st-cell:first-child { border-left: 0; }
}
.st-ic { display: inline-flex; width: 46px; height: 46px; flex: 0 0 46px; align-items: center; justify-content: center; border: 1px solid var(--brand-100, #dbeafe); border-radius: 14px; background: var(--brand-50, #eff6ff); font-size: 17px; color: var(--brand); transition: background .2s, color .2s, border-color .2s; }
.st-cell:hover .st-ic { border-color: var(--brand); background: var(--brand); color: #fff; }
.st-v { font-family: inherit; font-size: 27px; font-weight: 800; line-height: 1; letter-spacing: -.02em; }

/* The dots.
 *
 * NO mask-image on this layer. A radial fade was used once to soften a dot
 * field on the pricing FAQ and it erased every dot past the first few rows;
 * the fade is done with the dot colour instead, which cannot delete anything.
 * The grid is 22px, the same pitch used elsewhere on the site.
 */
.st-dots {
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-image: radial-gradient(rgba(var(--brand-rgb), 0.22) 1.2px, transparent 1.2px);
    background-size: 22px 22px;
    background-position: 0 0;
}

/* The plate sits above the dots, not in them. */
.st-wrap { position: relative; z-index: 1; }


/* Same band, less of it: the vertical padding and the gap under the head
   are where the height was, not the content. */
.hw { padding-top: 40px; padding-bottom: 40px; }
@media (min-width: 1024px) { .hw { padding-top: 48px; padding-bottom: 48px; } }
.hw-ic { display: inline-flex; width: 38px; height: 38px; flex: 0 0 38px; align-items: center; justify-content: center; border: 1px solid rgb(255 255 255 / .12); border-radius: 11px; background: rgb(var(--brand-400-rgb) / .12); color: #93c5fd; font-size: 14px; transition: background .2s, color .2s, border-color .2s; }
.hw-step:hover .hw-ic { border-color: rgb(var(--brand-400-rgb) / .5); background: var(--brand); color: #fff; }
.hw-n { font-family: inherit; font-size: 20px; font-weight: 700; line-height: 1; color: rgb(255 255 255 / .16); }
.hw-t { margin: 0; font-size: 15.5px; font-weight: 700; color: #fff; white-space: nowrap; }
.hw-d { margin: 4px 0 0; font-size: 13.5px; line-height: 1.55; color: #94a3b8; }
.hw-b { min-width: 0; }
/* The house head is built for a full band; inside a compacted one its own
   margins are most of what we are trying to remove. */
.section-head { margin-bottom: 0; padding-bottom: 14px; }

/* One strip, four cells, hairlines between - the same plate the proof band
   above it now uses, so the two read as one family. Four separate cards
   carried four sets of padding and four borders. */
.hw-steps { margin-top: 18px; display: grid; grid-template-columns: minmax(0, 1fr); border: 1px solid rgb(255 255 255 / .12); border-radius: 18px; background: rgb(255 255 255 / .04); overflow: hidden; }
@media (min-width: 640px) { .hw-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .hw-steps { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.hw-step { display: flex; align-items: flex-start; gap: 12px; border-top: 1px solid rgb(255 255 255 / .08); padding: 16px 18px; transition: background .2s; }
.hw-step:first-child { border-top: 0; }
@media (min-width: 1024px) {
    .hw-step { border-top: 0; border-left: 1px solid rgb(255 255 255 / .08); }
    .hw-step:first-child { border-left: 0; }
}
.hw-step:hover { background: rgb(255 255 255 / .06); }
.hw-n { position: absolute; opacity: 0; pointer-events: none; }
.hw-step { position: relative; }


.ft { padding-top: 40px; padding-bottom: 40px; }
@media (min-width: 1024px) { .ft { padding-top: 48px; padding-bottom: 48px; } }
.section-head { margin-bottom: 0; padding-bottom: 14px; }
.ft-t { margin: 0; font-size: 16px; font-weight: 700; color: #0b1220; }
.ft-d { margin: 5px 0 0; font-size: 13.5px; line-height: 1.6; color: #475569; }
/* Visible at rest. It used to appear only under the pointer, which hides a
   link from anybody not already hovering the card it is in. */
.ft-more { display: inline-flex; align-items: center; gap: 6px; margin-top: 9px; font-size: 12.5px; font-weight: 700; color: var(--brand); text-decoration: none; white-space: nowrap; transition: gap .2s, color .2s; }
.ft-more i { font-size: 10px; }
.ft-card:hover .ft-more { gap: 10px; color: var(--brand-700, #1d4ed8); }
.ft-ic { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 44px; width: 44px; height: 44px; border: 1px solid var(--brand-200, #bfdbfe); border-radius: 13px; background: linear-gradient(135deg, var(--brand-500), var(--brand-700)); color: #fff; font-size: 17px; }
.ft-b { min-width: 0; }
.ft-foot { margin-top: 18px; text-align: center; }
.ft-all { display: inline-flex; align-items: center; gap: 8px; border: 1px solid #e2e8f0; border-radius: 11px; background: #fff; padding: 9px 16px; font-size: 13px; font-weight: 700; color: var(--brand); text-decoration: none; white-space: nowrap; transition: border-color .2s, background .2s; }
.ft-all:hover { border-color: var(--brand); background: #f8fafc; }
.ft-all i { font-size: 10px; }

/* Head on the left, the three features stacked beside it. The full-width
   header plus a 56px gap was the tallest thing in the section and none of
   it needed the whole band. */
.ft-wrap { display: grid; gap: 24px; align-items: start; }
@media (min-width: 1024px) { .ft-wrap { grid-template-columns: 330px minmax(0, 1fr); gap: 40px; } }
.ft-grid { display: grid; gap: 10px; grid-template-columns: minmax(0, 1fr); }
.ft-card { display: flex; align-items: flex-start; gap: 14px; border: 1px solid #e2e8f0; border-radius: 14px; background: #fff; padding: 14px 16px; transition: border-color .2s, box-shadow .2s; }
.ft-card:hover { border-color: rgba(var(--brand-rgb), .4); box-shadow: 0 14px 30px -24px rgb(15 23 42 / .5); }
/* .section-head is a GRID, not a flex row, so flex-direction did nothing to
   it and the title kept sharing its row with the lead - 155px wide and
   seven lines tall inside this column. One column is the fix. */
.section-head { grid-template-columns: minmax(0, 1fr); padding-bottom: 0; }
.ft-foot { text-align: left; margin-top: 14px; }


.hfq { padding-top: 40px; padding-bottom: 40px; }
@media (min-width: 1024px) { .hfq { padding-top: 48px; padding-bottom: 48px; } }
.section-head { margin-bottom: 0; padding-bottom: 14px; }
.hfq-ic { display: inline-flex; width: 28px; height: 28px; flex: 0 0 28px; align-items: center; justify-content: center; border: 1px solid rgb(255 255 255 / .12); border-radius: 9px; background: rgb(var(--brand-400-rgb) / .12); color: #93c5fd; font-size: 11px; }
.hfq-a { margin: 0; font-size: 13.5px; line-height: 1.65; color: #94a3b8; }

/* One plate, four cells - the shape the rest of the page now uses. */
.hfq-list { margin-top: 16px; display: grid; grid-template-columns: minmax(0, 1fr); overflow: hidden; border: 1px solid rgb(255 255 255 / .12); border-radius: 16px; background: rgb(255 255 255 / .04); }
@media (min-width: 768px) { .hfq-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.hfq-row { border-top: 1px solid rgb(255 255 255 / .08); padding: 16px 20px; }
.hfq-row:first-child { border-top: 0; }
@media (min-width: 768px) {
    .hfq-list > .hfq-row:nth-child(-n+2) { border-top: 0; }
    .hfq-list > .hfq-row:nth-child(2n) { border-left: 1px solid rgb(255 255 255 / .08); }
}
.hfq-q { display: flex; align-items: center; gap: 11px; margin: 0 0 6px; font-size: 14.5px; font-weight: 700; color: #fff; }


/* 80px top and bottom (112 at lg) was most of this section. */
.cta { padding-top: 40px; padding-bottom: 40px; }
@media (min-width: 1024px) { .cta { padding-top: 48px; padding-bottom: 48px; } }
.cta-chip { display: inline-flex; align-items: center; gap: 8px; border: 1px solid rgba(var(--brand-rgb), .3); border-left: 4px solid var(--brand); border-radius: 3px; background: #f8fafc; padding: 6px 14px 6px 12px; font-size: 13px; font-weight: 600; color: #0b1220; white-space: nowrap; }
.cta-h { margin: 12px 0 0; font-size: 30px; font-weight: 700; line-height: 1.15; letter-spacing: -.02em; color: #0b1220; }
@media (min-width: 1024px) { .cta-h { font-size: 34px; } }
.cta-lead { margin: 10px 0 0; font-size: 15px; line-height: 1.6; color: #475569; }
.cta-bullets { margin-top: 16px; display: grid; gap: 9px 22px; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 640px) { .cta-bullets { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.cta-b { display: inline-flex; align-items: center; gap: 9px; font-size: 13.5px; color: #475569; }
.cta-b i { color: var(--brand); font-size: 13px; }
.cta-b--sky { color: #0ea5e9 !important; }
.cta-b--amber { color: #f59e0b !important; }
.cta-b--emerald { color: #10b981 !important; }
.cta-go { display: inline-flex; align-items: center; justify-content: center; gap: 8px; border-radius: 11px; background: linear-gradient(135deg, var(--brand-600), var(--brand-700)); padding: 11px 20px; font-size: 14px; font-weight: 700; color: #fff; text-decoration: none; white-space: nowrap; transition: opacity .2s; }
.cta-go:hover { opacity: .9; }
.cta-go i { font-size: 11px; }
.cta-alt { display: inline-flex; align-items: center; justify-content: center; border: 1px solid #e2e8f0; border-radius: 11px; background: #f8fafc; padding: 11px 20px; font-size: 14px; font-weight: 700; color: #0b1220; text-decoration: none; white-space: nowrap; transition: background .2s, border-color .2s; }
.cta-alt:hover { border-color: var(--brand); background: #f1f5f9; }
.cta-ic { display: inline-flex; width: 44px; height: 44px; align-items: center; justify-content: center; border-radius: 13px; background: linear-gradient(135deg, var(--brand-500), var(--brand-700)); color: #fff; font-size: 16px; }
.cta-ct { margin: 10px 0 0; font-size: 17px; font-weight: 700; color: #0b1220; }
.cta-cp { margin: 5px 0 0; font-size: 13px; color: #475569; }
.cta-note { margin: 12px 0 0; font-size: 11.5px; color: #94a3b8; }
.cta-btns { display: grid; gap: 9px; margin-top: 14px; }

/* No card. The pitch and the two buttons sit on one band, which is what a
   closing CTA is - a line and a door, not a panel inside a panel. */
.cta-grid { display: grid; gap: 22px; align-items: center; }
@media (min-width: 1024px) { .cta-grid { grid-template-columns: minmax(0, 1fr) auto; gap: 44px; } }
.cta-card { display: flex; flex-direction: column; gap: 4px; align-items: stretch; min-width: 250px; }
.cta-ic, .cta-ct, .cta-cp { display: none; }
.cta-btns { margin-top: 0; }
.cta-note { text-align: center; }


.hx-wrap { position: relative; width: 100%; padding-top: 64px; padding-bottom: 64px; }
@media (min-width: 1024px) { .hx-wrap { padding-top: 80px; padding-bottom: 80px; } }
.hx-chip { display: inline-flex; align-items: center; gap: 8px; border: 1px solid rgb(var(--brand-400-rgb) / .3); border-radius: 999px; background: rgb(var(--brand-400-rgb) / .1); padding: 6px 15px; font-size: 12px; font-weight: 600; color: #bfdbfe; white-space: nowrap; }
.hx-chip i { color: var(--brand-300, #93c5fd); }
/* No nowrap. It was harmless when the accent was "On Autopilot.", but the
   features accent is a whole sentence: an unbreakable 819px word forces the
   grid's first track to 819px, which is why that hero's columns could not be
   equal no matter what grid-template-columns said. */
.hx-grad { background: linear-gradient(90deg, var(--brand-300), var(--brand-400), var(--brand-600)); -webkit-background-clip: text; background-clip: text; color: transparent; }
.hx-go { display: inline-flex; align-items: center; justify-content: center; gap: 9px; border-radius: 12px; background: linear-gradient(135deg, var(--brand-600), var(--brand-700)); padding: 14px 28px; font-size: 16px; font-weight: 700; color: #fff; text-decoration: none; box-shadow: 0 18px 40px -18px rgba(var(--brand-rgb), .95); transition: transform .2s; }
.hx-go:hover { transform: scale(1.03); }
.hx-go i { font-size: 12px; }
.hx-alt { display: inline-flex; align-items: center; justify-content: center; gap: 9px; border: 1px solid rgb(255 255 255 / .2); border-radius: 12px; background: rgb(255 255 255 / .05); padding: 14px 28px; font-size: 16px; font-weight: 600; color: #fff; text-decoration: none; transition: border-color .2s, background .2s; }
.hx-alt:hover { border-color: rgb(255 255 255 / .35); background: rgb(255 255 255 / .1); }
.hx-alt i { font-size: 13px; color: #93c5fd; }
.hx-ct { margin: 0; font-size: 15px; font-weight: 700; color: #fff; }
.hx-cd { margin: 4px 0 0; font-size: 13px; line-height: 1.5; color: #94a3b8; }
.hx-cb { min-width: 0; }
.hx-ic { display: inline-flex; width: 42px; height: 42px; flex: 0 0 42px; align-items: center; justify-content: center; border-radius: 12px; background: linear-gradient(135deg, var(--brand-600), var(--brand-700)); color: #fff; font-size: 15px; }
.hx-ic--green { background: linear-gradient(135deg, #34d399, #059669); }
.hx-trust span { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; }
.hx-trust i { color: #34d399; font-size: 12px; }

/* PROOF FIRST. The number is the strongest thing on the page, so it is set
   at display size and given the right half outright; the other two claims
   sit beneath it as quiet rows, and the left column is reset around a
   stacked CTA with the trust items as chips. */
.hx-grid { display: grid; align-items: center; gap: 36px; }
/* Equal columns. 1fr/0.9fr made the right side visibly narrower than the
   left, which showed up as the two halves not matching. */
@media (min-width: 1024px) { .hx-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 48px; } }
.hx-h { margin: 14px 0 0; font-size: 26px; font-weight: 700; line-height: 1.2; letter-spacing: -.02em; color: #fff; }
@media (min-width: 1024px) { .hx-h { font-size: 36px; } }
.hx-lead { margin: 12px 0 0; font-size: 15px; line-height: 1.5; color: #cbd5e1; }
.hx-ctas { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 20px; }
.hx-trust { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0 0; font-size: 12px; }
.hx-trust span { border: 1px solid rgb(255 255 255 / .14); border-radius: 999px; background: rgb(255 255 255 / .05); padding: 5px 12px; color: #cbd5e1; }
.hx-cards { display: grid; gap: 10px; }
.hx-card { display: flex; align-items: center; gap: 12px; border: 1px solid rgb(255 255 255 / .12); border-radius: 14px; background: rgb(255 255 255 / .05); padding: 13px 15px; }
/* R25: the medallion floats LEFT of the copy it labels, on this card as on
   every other one. Stacking it above the figure made it a decoration sitting
   on top of a number instead of the icon for it. */
.hx-card--stat { flex-direction: row; align-items: center; gap: 14px; border-color: rgb(52 211 153 / .4); background: linear-gradient(150deg, rgb(52 211 153 / .16), rgb(255 255 255 / .05) 62%); padding: 18px; }
.hx-card--stat .hx-ic { width: 48px; height: 48px; flex-basis: 48px; font-size: 18px; }
.hx-card--stat .hx-ct { font-size: 24px; letter-spacing: -.02em; line-height: 1.15; }
.hx-card--stat .hx-cd { font-size: 13px; }

/* R35: every hero band is the same size on every page.
 *
 * /pricing, /features and /contact all render their hero at 528px (33rem).
 * The home hero was 698 - 170px taller than the rest of the site - and
 * pinning it there after the redesign is what turned the difference into
 * whitespace. It matches the others now, and the content was tightened to FIT
 * 528 rather than being padded out to it: a band is only the same size as its
 * neighbours if its contents agree, otherwise the floor just hides the
 * overflow somewhere else.
 */
.hx { min-height: 26rem; }
@media (min-width: 640px) { .hx { min-height: 30rem; } }
@media (min-width: 1024px) { .hx { min-height: 33rem; } }   /* 528px, as every other hero */

/* The band's own padding, trimmed so the copy column fits inside 528. */
.hx-wrap { padding-top: 40px; padding-bottom: 40px; }
@media (min-width: 1024px) { .hx-wrap { padding-top: 40px; padding-bottom: 40px; } }

/* ---------------------------------------------------------------------------
 * The hero's LEFT column, restructured.
 *
 * Changing only the right half left the pitch in the same chip / headline /
 * paragraph / buttons / trust stack it always had. These three moves change
 * what the column IS, not how it is painted:
 *   - the eyebrow becomes a ruled line across the column
 *   - the lead sits against a brand spine, which is what a pull quote wants
 *   - the buttons and the three promises share ONE bordered action bar rather
 *     than floating as separate blocks with gaps between them
 */
.hx-eyebrow { display: flex; align-items: center; gap: 14px; }
.hx-rule { flex: 1; height: 1px; background: linear-gradient(90deg, rgb(var(--brand-400-rgb) / .5), transparent); }

.hx-lead { border-left: 2px solid rgb(var(--brand-400-rgb) / .45); padding-left: 16px; }

.hx-bar { margin-top: 14px; border: 1px solid rgb(255 255 255 / .12); border-radius: 16px; background: rgb(255 255 255 / .05); padding: 11px 14px; backdrop-filter: blur(10px); }
.hx-bar .hx-ctas { margin-top: 0; }
.hx-bar .hx-trust { margin-top: 10px; padding-top: 10px; border-top: 1px solid rgb(255 255 255 / .1); }

/* Same on the front page: 84px of air around the content, and the three
   claims were 316px inside a 443px column. Both are spent on the content now. */
.hx { align-items: stretch; }
.hx-wrap { display: flex; flex-direction: column; }
.hx-grid { flex: 1; align-items: center; }
.hx-cards { align-self: stretch; grid-auto-rows: minmax(0, 1fr); }

/* The two columns start and end on the same lines, and the copy CENTRES in
   its column rather than having its action bar pinned to the floor. Pinning
   it put every spare pixel into one gap between the paragraph and the
   buttons, which is a worse hole than the air it was meant to remove. */
.hx-grid { align-items: stretch; }
.hx-copy { display: flex; flex-direction: column; justify-content: space-between; height: 100%; }

/* The action bar had the two buttons bunched left with the rest of the bar
   empty. They share its width now, and the three promises spread across the
   same line, so the bar is filled by what it contains. */
.hx-bar .hx-ctas { display: flex; gap: 10px; }
.hx-bar .hx-ctas > a { flex: 1 1 0; min-width: 0; }
.hx-bar .hx-trust { display: flex; justify-content: space-between; gap: 8px; }
@media (max-width: 639px) {
    .hx-bar .hx-ctas { flex-direction: column; }
    .hx-bar .hx-trust { flex-wrap: wrap; justify-content: flex-start; }
}

/* Both columns start and end on the same lines: the copy distributes over its
   column instead of centring, so its first line sits with the first card and
   its action bar ends with the last one. The spread is small (the content is
   close to the column height), which is why this reads as alignment rather
   than as gaps. */
.hx-copy > * + * { margin-top: 0; }
.hx-copy .hx-h { margin-top: 12px; }
.hx-copy .hx-lead { margin-top: 10px; }

/* The cards fill their rows with CONTENT, not with empty box.
 *
 * Four rows in a 446px column make ~100px rows; an icon and two short lines
 * left ~40px of nothing inside each one. A larger medallion and a step up in
 * type spends that on the card instead of leaving it hollow.
 */
.hx-ic { width: 52px; height: 52px; flex: 0 0 52px; border-radius: 15px; font-size: 19px; }
.hx-card { gap: 16px; padding: 16px 18px; }
.hx-ct { font-size: 16px; }
.hx-cd { font-size: 13.5px; line-height: 1.5; }

/* One more step up, to cut the leftover inside each card. The stretch itself
   has to stay: it is what makes the two columns start and end on the same
   lines, which was the requirement. */
.hx-ic { width: 58px; height: 58px; flex: 0 0 58px; border-radius: 16px; font-size: 21px; }
.hx-ct { font-size: 17px; }
.hx-cd { font-size: 14px; }

/* The copy sits together and centres in its column.
 *
 * Two attempts at forcing it to FILL the column both looked worse than the
 * air they removed: space-between pushed 50px gaps between the chip, the
 * headline and the lead, and growing the action bar turned it into a large
 * empty panel with the buttons floating in the middle. The copy is its
 * natural size now, centred, which is what a hero column normally does.
 */
.hx-copy { justify-content: center; }

/* The copy distributes over its column so its first line sits with the first
   card and its action bar ends with the last one - which is the alignment
   that was asked for. The type scale that was here is gone: it closed the
   gaps but pushed the band from 528 to 652, and the band height is fixed. */
.hx-copy { justify-content: space-between; }

/* Band padding stays at 40px.
 *
 * Raising it to 60 left the copy taller than the column it had to fit, and
 * space-between then drove the blocks apart until the headline and the lead
 * overlapped. Whatever the padding is, the copy has to FIT inside what is
 * left, or distributing it collides. */
.hx-wrap { padding-top: 40px; padding-bottom: 40px; }
@media (min-width: 1024px) { .hx-wrap { padding-top: 40px; padding-bottom: 40px; } }

/* The card's right-hand detail. The cards are wide and the icon plus two
   short lines left most of that width empty; this puts a checkable fact in
   it rather than padding. It floats right and never wraps. */
.hx-meta {
    margin-left: auto;
    flex: 0 0 auto;
    border: 1px solid rgb(255 255 255 / 0.14);
    border-radius: 999px;
    background: rgb(255 255 255 / 0.06);
    padding: 5px 12px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: #93c5fd;
    white-space: nowrap;
}

/* The help centre's search box, inside the hero copy column. It is the thing
   people came to the page to use, so it keeps its place in the column rather
   than being demoted to a card. */
.hx-search { margin-top: 2px; width: 100%; }
.hx-search-label { display: block; margin-bottom: 6px; font-size: 13px; font-weight: 600; color: #bfdbfe; }
.hx-search-field { position: relative; }
.hx-search-icon { position: absolute; left: 16px; top: 50%; transform: translateY(-50%); color: #94a3b8; font-size: 13px; pointer-events: none; }
.hx-search-input { width: 100%; border: 1px solid rgb(255 255 255 / 0.1); border-radius: 14px; background: rgb(255 255 255 / 0.95); padding: 13px 108px 13px 40px; font-size: 14px; color: #0b1220; }
.hx-search-input::placeholder { color: #94a3b8; }
.hx-search-input:focus { border-color: #60a5fa; outline: none; box-shadow: 0 0 0 3px rgba(var(--brand-rgb), 0.35); }
.hx-search-go { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); border: 0; border-radius: 10px; background: linear-gradient(135deg, var(--brand-600), var(--brand-700)); padding: 9px 16px; font-size: 13px; font-weight: 700; color: #fff; cursor: pointer; white-space: nowrap; }
.hx-search-go:hover { opacity: .92; }

/* "Popular:" plus its three links, set on the trust row's rhythm. */
.hx-popular a { color: #bfdbfe; text-decoration: none; font-weight: 600; }
.hx-popular a:hover { text-decoration: underline; text-underline-offset: 4px; }

/* "Popular:" and its three links sit on one baseline. The row is a flex line
   but only its <span> children were being centred, so the anchors rode high
   against the label. */
.hx-popular { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; }
.hx-popular > * { display: inline-flex; align-items: center; line-height: 1; }
.hx-popular > span:first-child { color: #94a3b8; }

/* ---------------------------------------------------------------------------
 * The help centre's bands alternate in PATTERN as well as colour.
 *
 * White and slate-100 alternated already, but a 1-2% step between two pale
 * greys barely reads as a change. The tinted bands now carry the dot field the
 * marketing sections use, so the rhythm is visible rather than theoretical.
 * Comma form on --brand-rgb: the slash syntax is invalid for it and the whole
 * declaration gets dropped.
 */
.sup-band { position: relative; overflow: hidden; }
.sup-band > * { position: relative; }
.sup-dots {
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-image: radial-gradient(rgba(var(--brand-rgb), 0.16) 1.2px, transparent 1.2px);
    background-size: 22px 22px;
}

/* The knowledge base search. The filtering already existed in the Alpine
   component; this is the control that was missing. */
.kb-search { position: relative; display: inline-flex; align-items: center; min-width: 260px; }
.kb-search__icon { position: absolute; left: 14px; font-size: 12px; color: #94a3b8; pointer-events: none; }
.kb-search__input {
    width: 100%;
    border: 1px solid var(--color-brand-stone, #e2e8f0);
    border-radius: 999px;
    background: #fff;
    padding: 9px 36px 9px 36px;
    font-size: 14px;
    color: #0b1220;
    box-shadow: 0 1px 2px rgb(15 23 42 / .06);
    transition: border-color .2s, box-shadow .2s;
}
.kb-search__input::placeholder { color: #94a3b8; }
.kb-search__input:focus {
    border-color: var(--brand);
    outline: none;
    box-shadow: 0 0 0 3px rgba(var(--brand-rgb), 0.25);
}
.kb-search__clear {
    position: absolute; right: 10px;
    display: inline-flex; align-items: center; justify-content: center;
    width: 20px; height: 20px;
    border: 0; border-radius: 999px; background: #e2e8f0;
    font-size: 10px; color: #475569; cursor: pointer;
}
.kb-search__clear:hover { background: #cbd5e1; color: #0b1220; }

/* The knowledge base search, in the card that was already named for it. */
.kb-hero-search { position: relative; display: flex; flex-wrap: wrap; align-items: center; margin-top: 18px; }
.kb-hero-search__icon { position: absolute; left: 18px; top: 23px; font-size: 14px; color: #94a3b8; pointer-events: none; }
.kb-hero-search__input {
    width: 100%;
    border: 1px solid var(--color-brand-stone, #e2e8f0);
    border-radius: 14px;
    background: #f8fafc;
    padding: 14px 44px 14px 44px;
    font-size: 15px;
    color: #0b1220;
    transition: border-color .2s, background .2s, box-shadow .2s;
}
.kb-hero-search__input::placeholder { color: #94a3b8; }
.kb-hero-search__input:focus {
    border-color: var(--brand);
    background: #fff;
    outline: none;
    box-shadow: 0 0 0 3px rgba(var(--brand-rgb), 0.25);
}
.kb-hero-search__clear {
    position: absolute; right: 14px; top: 16px;
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px;
    border: 0; border-radius: 999px; background: #e2e8f0;
    font-size: 11px; color: #475569; cursor: pointer;
}
.kb-hero-search__clear:hover { background: #cbd5e1; color: #0b1220; }
.kb-hero-search__hint { width: 100%; margin: 10px 0 0; font-size: 13px; color: #475569; }
.kb-hero-search__jump { margin-left: 8px; font-weight: 700; color: var(--brand); text-decoration: none; }
.kb-hero-search__jump:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ===== css/site-tooltip.css ===== */
/* The tooltip node the engine in public/js/tooltip.js anchors to <body>.
   Same rules the admin carries, so the two never drift apart visually. */
.js-tooltip {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 2147483000;          /* above modals, drawers, sticky headers */
    max-width: 320px;
    padding: 6px 10px;
    border-radius: 7px;
    background: #111827;
    color: #fff;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.35;
    white-space: normal;          /* long text wraps instead of running off */
    word-break: break-word;
    box-shadow: 0 8px 20px -6px rgba(0, 0, 0, 0.5);
    pointer-events: none;         /* never eats a click meant for the button */
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.12s ease, visibility 0.12s ease;
}

.js-tooltip.is-visible {
    opacity: 1;
    visibility: visible;
}
