/* =============================================================================
   Workflow Corporation - corporate design system
   =============================================================================

   The group wears the family green, the same green as Radio Workflow and
   every Buddy mark's head: #109875, with #33CFA7 for type and rings on the
   dark ground and the lime #80FF44 at the bright end of the one gradient.
   The owner asked for it on 2026-09-27 ("make it green like everything
   else"), after the violet-to-pink this site used was removed at his
   repeated instruction. Never bring purple, violet or pink back.

   What still keeps the parent from reading as a Radio Workflow page:

     - a cooler, deeper ground (#08090B, not #0A0A0A)
     - squared geometry (8px), not pills and not glass panels
     - colour reserved for meaning: apart from the group green, the only
       colour on a page belongs to an operating company, arriving per-card
       through --co-accent

   Tailwind (CDN) does layout and spacing. This file holds the type scale, the
   surfaces, the accent behaviour and the motion, which utilities express badly.
   Everything is namespaced or semantic so it cannot collide with product CSS.
   ========================================================================== */

/* ---------- Base ---------------------------------------------------------- */

html {
    scroll-behavior: smooth;
    -webkit-text-size-adjust: 100%;
    background-color: #08090B;
    /* The header is sticky and 72px tall (nav.php pins it with h-[72px]), so
       an in-page anchor or a focus move would otherwise park its target under
       the header where it cannot be read. 72px plus a little air. */
    scroll-padding-top: 5.5rem;
}

/* Muted type. The same three values the Tailwind config in partials/head.php
   gives ink-700 / ink-500 / ink-400: the measured contrast ratios, and the
   floor nothing here may go under, are documented there. They live as custom
   properties so this file has one place to change rather than the five
   hard-coded copies of #8B929B it used to carry. If you change one of these,
   change head.php in the same commit or the page will use two ramps. */
:root {
    --ink-700: #C7CBD2;
    --ink-500: #9AA1AC;
    --ink-400: #868D98;
}

body {
    background-color: #08090B;
    color: #FFFFFF;
    font-family: Geist, system-ui, -apple-system, "Segoe UI", sans-serif;
    font-size: 16px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
}

::selection {
    background: #33CFA7;
    color: #08090B;
}

:focus-visible {
    outline: 2px solid #33CFA7;
    outline-offset: 3px;
    border-radius: 4px;
}

.corp-content-start {
    outline: none;
}

/* Fixed, not absolute. Absolute pins the link to the top of the DOCUMENT, so
   reaching it part-way down a page threw the viewport back to the top before
   the reader had even seen the link, and whatever they were on went with it.
   That is reachable: it is the first focusable element, so a Shift+Tab back
   past the wordmark lands on it from anywhere in a scrolled page. Fixed pins it
   to the VIEWPORT instead, so it appears over what is already on screen and
   nothing scrolls until the link is actually followed.
   Off-screen is left: -9999px rather than display:none or visibility:hidden,
   which would take it out of the tab order and there would be no skip link at
   all. Negative left cannot produce a scrollbar in a left-to-right page, so
   parking it there is safe on a fixed element as well as an absolute one.
   z-index 100 has to stay above .corp-header (50) or the focused link would
   slide under the sticky bar. */
.skip-link {
    position: fixed;
    left: -9999px;
    top: 0;
    z-index: 100;
    padding: 0.75rem 1.25rem;
    background: #FFFFFF;
    color: #08090B;
    font-weight: 600;
    border-radius: 0 0 6px 0;
}
.skip-link:focus { left: 0; top: 0; }
/* The link sits flush in the corner of the viewport, so the site-wide ring,
   drawn 3px outside the element, fell off the top and left edges: measured,
   5px of it was cut away. Drawn inside instead, and in the deep green
   #0D7A5E, about 5.3:1 on this white fill, where the site-wide #33CFA7 is
   under the 3:1 a focus indicator needs. */
.skip-link:focus-visible { outline-offset: -5px; outline-color: #0D7A5E; }

/* ---------- Ambient background -------------------------------------------
   One radial wash behind the hero and a very faint grid over the whole page.
   Both are fixed and pointer-events-none so nothing below has to account for
   them, and both are cheap: no blur filters, no animation. */

.corp-ambient {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background:
        radial-gradient(60rem 34rem at 12% -8%, rgba(16, 152, 117, 0.20), transparent 62%),
        radial-gradient(44rem 26rem at 92% 2%, rgba(128, 255, 68, 0.06), transparent 60%);
}

.corp-grid {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background-image:
        linear-gradient(rgba(255, 255, 255, 0.028) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, 0.028) 1px, transparent 1px);
    background-size: 76px 76px;
    /* Fade the grid out down the page so it reads as texture, not as a table. */
    -webkit-mask-image: linear-gradient(180deg, #000 0%, transparent 78%);
            mask-image: linear-gradient(180deg, #000 0%, transparent 78%);
}

/* Cursor light. --mx/--my are written by corp.js on pointer move (rAF-throttled,
   fine pointers only); until they are, the fallback keeps it parked off-screen
   so nothing moves on touch devices or with JS off. */
.corp-spotlight {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.6s ease;
    background: radial-gradient(
        22rem 22rem at var(--mx, -50%) var(--my, -50%),
        rgba(51, 207, 167, 0.10),
        transparent 68%);
}
.corp-spotlight.is-live { opacity: 1; }

/* Everything real sits above the ambient layers. */
.corp-header,
main,
.corp-footer { position: relative; z-index: 1; }

/* ---------- The hero product mark ----------------------------------------
   The hero's payoff, beside the headline: ONE large product mark that swaps
   in step with the rotating word, so the sentence and the picture always name
   the same Buddy. These are the real product marks from
   assets/images/products, used unaltered, because on a site whose whole claim
   is "this is where Buddy lives" the marks ARE the argument.

   Before changing anything here, open one of those files. They are drawn FOR
   a dark page: near-black headphones inside a white badge ring. A previous
   comment in this file had that exactly backwards, said the marks were "light
   headphones, dark badge ring", and used it to argue for a pale plate behind
   each one. There is no plate, no disc and no ring of our own here, and there
   must not be: the white badge ring is already the mark's own edge, and a
   second circle behind it reads as a sticker. That treatment was proposed,
   built and rejected once already.

   The only thing behind the mark is a soft radial glow in the current
   product's colour, which arrives on --co-accent from corp.js.

   The markup contract, which index.php emits and corp.js drives:
     .hero-mark holds one .hero-mark-img per rotator entry, in rotator order,
     each carrying data-mark-index, with .is-active on the first only. An
     entry whose product has no mark file simply has no <img>, so that beat
     shows the glow alone.
   ---------------------------------------------------------------------- */

.hero-mark {
    position: relative;
    /* A fixed square: every mark is 1:1, and a box that resized per image
       would drag the headline column around on each swap. */
    width: clamp(11rem, 30vw, 17rem);
    height: clamp(11rem, 30vw, 17rem);
    margin: 0 auto;
    /* The glow sits at z-index -1. Without a stacking context of its own it
       would slide behind the page background instead of behind the mark. */
    isolation: isolate;
}

/* The glow. The colour lives in background-color behind a radial mask rather
   than in a gradient colour stop, because a gradient cannot interpolate
   between two custom-property colours: as a flat colour it transitions with
   the mark instead of snapping to the next product mid cross-fade. */
.hero-mark::before {
    content: "";
    position: absolute;
    inset: -14%;
    z-index: -1;
    background-color: var(--co-accent, #33CFA7);
    opacity: 0.2;
    -webkit-mask-image: radial-gradient(closest-side, #000 0%, rgba(0, 0, 0, 0.45) 46%, transparent 74%);
            mask-image: radial-gradient(closest-side, #000 0%, rgba(0, 0, 0, 0.45) 46%, transparent 74%);
    transition: background-color 0.34s ease;
    pointer-events: none;
}

.hero-mark-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    /* 340ms, matching .rotator-word exactly. The word and the mark are one
       change: move one of these durations without the other and the pair
       visibly falls out of step. */
    transition: opacity 0.34s ease;
    filter: drop-shadow(0 16px 34px rgba(0, 0, 0, 0.55));
}
.hero-mark-img.is-active { opacity: 1; }
/* The one-face hero (index.php): the SVG fills the box and carries the shadow;
   inside it only the badges cross-fade. A badge is an SVG <g>, so the box
   rules above (position, size, filter) do not apply to it. */
.hero-mark-svg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    filter: drop-shadow(0 16px 34px rgba(0, 0, 0, 0.55));
}
.hero-mark-svg .hero-badge { filter: none; }
/* The hero's right column (mark, product row, caption) sits 15px higher than
   the centred grid puts it (owner, 2026-10-10). top, not transform: the
   scroll reveal animates transform on this same element. Side by side only. */
@media (min-width: 768px) {
    .hero-side { position: relative; top: -15px; }
}

/* The hero's row of product marks (index.php). Quiet until hovered, focused
   or named by the headline (.is-current, set by corp.js), so the row reads as
   one family rather than twelve competing logos. */
/* A fixed grid, so the row never wraps into an orphan pair: six across where
   the column has room (a phone, and from 1024px), four across in the
   768-1023px column and below 360px. */
.hero-family-marks {
    display: grid;
    grid-template-columns: repeat(4, 2.75rem);
    justify-content: center;
    gap: 0.5rem;
}
@media (min-width: 360px) and (max-width: 767.98px), (min-width: 1024px) {
    .hero-family-marks { grid-template-columns: repeat(6, 2.75rem); }
}
.hero-family-caption {
    min-height: 1.25rem;
    margin-top: 0.75rem;
    font-size: 0.8125rem;
    line-height: 1.25rem;
    color: var(--ink-500, #9AA1AC);
    text-align: center;
}
.hero-family-mark {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: 999px;
    opacity: 0.55;
    transition: opacity 0.3s ease, border-color 0.3s ease, transform 0.3s ease;
}
.hero-family-mark img {
    width: 2rem;
    height: 2rem;
}
.hero-family-dot {
    width: 0.625rem;
    height: 0.625rem;
    border-radius: 999px;
    background: #33CFA7;
}
a.hero-family-mark:hover,
a.hero-family-mark:focus-visible,
.hero-family-mark.is-current {
    opacity: 1;
    border-color: rgba(51, 207, 167, 0.55);
}
.hero-family-mark.is-current { transform: translateY(-2px); }
.hero-family-mark.is-soon {
    opacity: 0.3;
    border-style: dashed;
}
.hero-family-mark.is-soon.is-current { opacity: 1; }
@media print {
    .hero-family-marks,
    .hero-family-caption { display: none; }
}
@media (prefers-reduced-motion: reduce) {
    .hero-family-mark { transition: none; }
    .hero-family-mark.is-current { transform: none; }
}

/* ---------- Rotating headline word ---------------------------------------
   The word in front of "Buddy" cycles through the family. corp.js measures
   every word in the real rendered font and animates this element's width from
   one to the next, so "Buddy." travels with the change and the line below the
   headline never moves. (An earlier version pinned the box to the widest word;
   the comment here still described that long after it stopped being true.) */

.rotator {
    display: inline-block;
    position: relative;
    vertical-align: bottom;
    text-align: left;
    white-space: nowrap;
    /* The word slides vertically, so the box has to clip or the outgoing word
       shows over the line above. Clipping tight to the text box, which is what
       a bare overflow:hidden does at this line-height (1.03), cut the
       descender off "Design" and "Spin". The window is grown with padding and
       pulled straight back with an equal negative margin, so the clip gains
       headroom while the line box and the text position stay exactly where
       they were. Keep the pair identical or the headline moves.

       0.18em is measured, not guessed. Below the baseline the clip natively
       allows 0.160em in Geist and 0.103em in the system fallback, while the
       deepest ink in the word set is "Design" at 0.171em and 0.242em in those
       same two faces: 0.011em short in Geist, 0.138em short in the fallback,
       which is what renders until the webfont arrives and permanently if
       Google Fonts is blocked. So the fallback sets the number, and 0.18em
       clears it with about 0.04em to spare.

       There is no top padding for the same reason: the tallest ink in the set
       is 0.739em and the clip already allows 0.870em, so nothing is being cut
       up there and any padding added would only widen the window for the
       0.32em slide to show through. */
    overflow: hidden;
    padding: 0 0 0.18em;
    margin: 0 0 -0.18em;
    /* Width is set per word by corp.js and animated, so "Buddy." slides along
       with the change instead of a fixed gap sitting after the short words. */
    transition: width 0.34s cubic-bezier(0.22, 1, 0.36, 1);
}
.rotator-word {
    display: inline-block;
    transition: opacity 0.34s ease, transform 0.34s cubic-bezier(0.22, 1, 0.36, 1);
}
.rotator-word.is-out {
    opacity: 0;
    transform: translateY(-0.32em);
}
.rotator-word.is-in {
    opacity: 0;
    transform: translateY(0.32em);
    /* Snap here, do not animate here. With the transition left on, adding
       is-in started a move from wherever the exit ended (0.32em ABOVE), and
       dropping the class a moment later re-aimed that move at 0: the word fell
       in from above. Replayed in the browser: entry started at 0em before this
       line, +0.32em after it, which is the roll up from below the design is. */
    transition: none;
}

/* The rotating line ("a Voice Buddy.") stays on one line once corp.js has
   sized that line for the longest word (it adds .is-fitted to the h1). Before that, or
   with no script, it wraps as ordinary text, so it can never overflow a phone.
   Without this, "a Compliance Buddy." broke "Buddy." onto a third line and
   the whole page below the hero jumped on every long word. */
/* inline-block gives the scaled line its own line box. Left inline, it sat in
   the h1's full-size line box, and .rotator (vertical-align: bottom) dropped
   the product word below "a" and "Buddy.". */
.is-fitted .hero-line {
    display: inline-block;
    white-space: nowrap;
    /* The size is set by corp.js and must land at once: the reduced-motion
       rule gives every property a short transition, which turned the fit into
       a loop (see measure() in corp.js). */
    transition: none !important;
}

/* The article sits outside .rotator on purpose. It carries no transition, so
   it changes on the same tick as the word without rolling: there are only two
   values it can ever hold, and animating them reads as a glitch. */
.rotator-article {
    display: inline-block;
    transition: none;
}

/* ---------- Display type -------------------------------------------------- */

.display-xl,
.display-lg,
.display-md {
    font-weight: 600;
    letter-spacing: -0.035em;
    line-height: 1.03;
    color: #FFFFFF;
}

.display-xl { font-size: clamp(2.6rem, 6.4vw, 5.25rem); }
.display-lg { font-size: clamp(2rem, 4vw, 3.25rem); line-height: 1.06; letter-spacing: -0.03em; }
.display-md { font-size: clamp(1.35rem, 2.1vw, 1.75rem); line-height: 1.18; letter-spacing: -0.02em; }

/* The one phrase per heading that carries the accent: the family green,
   teal to lime, the way radioworkflow.com sets its emphasis. Gradient rather
   than a flat colour so it reads as deliberate emphasis instead of a link. */
.display-em {
    background: linear-gradient(100deg, #33CFA7 0%, #80FF44 100%);
    -webkit-background-clip: text;
            background-clip: text;
    -webkit-text-fill-color: transparent;
    color: #33CFA7; /* fallback where background-clip:text is unsupported */
}

/* ---------- Editorial furniture ------------------------------------------ */

/* 11px, uppercase and tracked out, which is small enough that it needs the
   same 4.5:1 as body copy rather than the large-text allowance. It was
   #6B7280, 4.12:1 on this ground, which is under AA on every page it appears
   on. --ink-400 measures 5.95:1 and is still the quietest step in the ramp,
   so the hierarchy reads the same. */
.eyebrow {
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-400, #868D98);
}

.lede {
    font-size: clamp(1.0625rem, 1.35vw, 1.25rem);
    line-height: 1.6;
    color: var(--ink-500, #9AA1AC);
}

/* The rules sit between sections whose content is inset by the page gutter
   (px-5, then sm:px-8 from 640px up). An <hr> cannot borrow that inset from a
   border: a border is drawn on the element's own edge, so padding would not
   move it and the line overhung the content column by 20px, then 32px. The
   line is therefore a background painted into the content box, which the
   gutter padding does inset. Top and bottom margins are set individually so
   the `mx-auto` utility that centres the rule is left alone. */
.rule {
    border: 0;
    height: 1px;
    margin-top: 0;
    margin-bottom: 0;
    padding: 0 1.25rem;
    background-color: rgba(255, 255, 255, 0.07);
    background-clip: content-box;
}
@media (min-width: 640px) {
    .rule { padding: 0 2rem; }
}

.section-index {
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: #33CFA7;
}

/* ---------- Links --------------------------------------------------------- */

.link-quiet {
    color: #FFFFFF;
    text-decoration: none;
    background-image: linear-gradient(currentColor, currentColor);
    background-position: 0 100%;
    background-repeat: no-repeat;
    background-size: 0% 1px;
    transition: background-size 0.3s cubic-bezier(0.22, 1, 0.36, 1);
    /* 19px of ink + 3 + 2 clears the 24px target floor. The padding goes on TOP
       because background-position is 0 100%: growing the bottom would push the
       underline away from the text. Standalone quiet links (the contact cards)
       are not covered by the inline exemption, so they need this. */
    padding-top: 3px;
    padding-bottom: 2px;
}
.link-quiet:hover,
.link-quiet:focus-visible { background-size: 100% 1px; }

/* Target size, WCAG 2.2 SC 2.5.8 (AA): a pointer target must be at least 24 by
   24 CSS pixels. Measured at 375px wide, three things on this site missed it, and
   all three are the same mistake, which is letting the ink decide the hit area:

     footer social links   20x20, the icon and nothing else
     .link-arrow CTAs      23px tall, one pixel under, from line-height alone
     the tel: link         19px tall

   SC 2.5.8 exempts targets that sit inline in a sentence, which covers the phone
   number inside its <address> block, so that one is left alone. The other two are
   standalone controls and are not exempt. Both are fixed by padding the target
   rather than growing the glyph, so nothing moves visually. */
.link-arrow {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    font-weight: 500;
    color: #FFFFFF;
    text-decoration: none;
    /* 23px of ink plus this clears 24 without shifting the baseline. */
    padding-block: 2px;
}

.social-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* 20px icon in a 44px target: comfortably past the 24px floor, and the
       negative margin keeps the row's visual spacing exactly as it was. */
    width: 44px;
    height: 44px;
    margin: -12px;
    color: inherit;
}
.link-arrow svg { transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1); }
.link-arrow:hover svg,
.link-arrow:focus-visible svg { transform: translateX(4px); }

/* ---------- Buttons ------------------------------------------------------- */

.btn-ink,
.btn-outline {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.8125rem 1.5rem;
    border-radius: 8px;
    font-size: 0.9375rem;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    transition: background-color 0.22s ease, color 0.22s ease,
                border-color 0.22s ease, transform 0.22s ease,
                box-shadow 0.22s ease;
}

/* Primary is white on black: the parent does not need a gradient to be loud. */
.btn-ink {
    background: #FFFFFF;
    color: #08090B;
    border: 1px solid #FFFFFF;
}
.btn-ink:hover {
    transform: translateY(-1px);
    box-shadow: 0 10px 30px -12px rgba(255, 255, 255, 0.45);
}

.btn-outline {
    background: transparent;
    color: #FFFFFF;
    border: 1px solid rgba(255, 255, 255, 0.18);
}

/* The button for the page you are already on. partials/nav.php renders Contact
   as a .btn-outline and marks the current page with aria-current="page" and
   nothing else, so the attribute is the styling hook as well as the
   accessibility one.
   Two things about this rule are load-bearing. It sits ABOVE .btn-outline:hover
   and the two selectors weigh the same (one class plus one attribute against
   one class plus one pseudo-class), so source order is what lets hover win, and
   the button on its own page still answers the pointer. And its values sit
   BETWEEN resting and hover on both axes: border 0.18 -> 0.32 -> 0.45,
   background transparent -> 0.03 -> 0.04. So the current page reads as lit
   while hover still has somewhere brighter to go.
   This replaced an inline style in nav.php that set those same two properties.
   An inline declaration outranks every rule in this file, so on
   /pages/contact.php border-color and background were frozen and the only thing
   hover could still do to that button was the one-pixel lift, which under
   prefers-reduced-motion is removed as well. Be careful reinstating any inline
   style on a control that also has a :hover: it does not merely add a state, it
   deletes the properties it names from every state below it. */
.btn-outline[aria-current="page"] {
    border-color: rgba(255, 255, 255, 0.32);
    background: rgba(255, 255, 255, 0.03);
}

.btn-outline:hover {
    border-color: rgba(255, 255, 255, 0.45);
    background: rgba(255, 255, 255, 0.04);
    transform: translateY(-1px);
}

/* ---------- Company cards ------------------------------------------------- */

/* --co-accent is set inline from config.php, so a new company needs no CSS. */

.co-card {
    position: relative;
    display: block;
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.018));
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    padding: 1.75rem;
    text-decoration: none;
    color: inherit;
    overflow: hidden;
    isolation: isolate;
    transition: border-color 0.3s ease, transform 0.35s cubic-bezier(0.22, 1, 0.36, 1),
                box-shadow 0.35s ease;
}

/* Accent wash that fades up from the card floor on hover. Behind content. */
.co-card::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: radial-gradient(28rem 14rem at 12% 118%, var(--co-accent, #33CFA7), transparent 70%);
    opacity: 0;
    transition: opacity 0.4s ease;
}

/* Accent rule along the top edge, drawn across on hover. */
.co-card::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    height: 2px;
    width: 3.25rem;
    background: var(--co-accent, #33CFA7);
    transition: width 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

.co-card:hover,
.co-card:focus-visible {
    border-color: rgba(255, 255, 255, 0.16);
    transform: translateY(-4px);
    box-shadow: 0 22px 50px -28px rgba(0, 0, 0, 0.9);
}
.co-card:hover::before,
.co-card:focus-visible::before { width: 100%; }
.co-card:hover::after,
.co-card:focus-visible::after { opacity: 0.16; }

.co-dot {
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 8px;
    background: var(--co-accent, #33CFA7);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--co-accent, #33CFA7) 18%, transparent);
    flex: none;
}

/* Accent-coloured TEXT, which is a different problem from an accent-coloured
   dot or rule: it has to be read. The raw badge colours do not survive that.
   Measured on the page ground (#08090B): the API Console's #2563EB is 3.85:1
   and Table Buddy's #DC2626 is 4.12:1, both under the 4.5:1 AA floor, and it
   gets worse on a .co-card, whose hover wash lifts the ground underneath the
   CTA the text sits in.

   Mixing 70% of the accent into white fixes every one of them without
   laundering the colour: 70% blue still reads blue, 70% red still reads red.
   Measured worst case across every accent in config.php (2026-09-27, after
   Voice Buddy's violet became emerald) is Table Buddy's, at 6.17:1 on the
   page; the violet was the old worst case, at 6.06:1 and 5.31:1 over its own
   hover wash.

   The flat colour first is the fallback for anything without color-mix:
   legible everywhere, just not coloured. Do NOT collapse these two lines
   back into var(--co-accent) on its own. */
.co-accent-text {
    color: #EDEDED;
    color: color-mix(in srgb, var(--co-accent, #33CFA7) 70%, #FFFFFF);
}

/* Leadership: the founders sit side by side, one .co-card each, with a
   "Founder" badge and then the title on one row under the name, the way the
   founders appear on website/pages/about.php. The badge takes the person's
   accent from --co-accent, with the same flat fallbacks and the same 70% text
   mix as .co-accent-text above, for the same reason. */
.founder-grid {
    max-width: 56rem;
    margin-left: auto;
    margin-right: auto;
}
.founder-card {
    text-align: center;
}
.founder-avatar {
    margin-left: auto;
    margin-right: auto;
}
/* The badge on one line, the title on the next (owner, 2026-10-10). */
.founder-meta {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
}
.founder-badge {
    display: inline-block;
    padding: 0.25rem 0.75rem;
    border-radius: 9999px;
    font-size: 0.75rem;
    font-weight: 500;
    line-height: 1.2;
    background: rgba(255, 255, 255, 0.06);
    background: color-mix(in srgb, var(--co-accent, #33CFA7) 20%, transparent);
    color: #EDEDED;
    color: color-mix(in srgb, var(--co-accent, #33CFA7) 70%, #FFFFFF);
}

/* Unlaunched entries read as placeholders, not products. */
.co-card--soon {
    background: transparent;
    border-style: dashed;
    border-color: rgba(255, 255, 255, 0.12);
    cursor: default;
}
.co-card--soon:hover {
    transform: none;
    box-shadow: none;
    border-color: rgba(255, 255, 255, 0.12);
}
.co-card--soon:hover::before { width: 3.25rem; }
.co-card--soon:hover::after { opacity: 0; }

/* Corporate teasers keep the product in the family while the preview stays
   obscured. Only the readable overlay is interactive or exposed to readers. */
.corp-teaser {
    position: relative;
    overflow: hidden;
    isolation: isolate;
}
.corp-teaser-content {
    filter: blur(8px);
    opacity: 0.42;
    pointer-events: none;
    user-select: none;
}
.corp-teaser-overlay {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    padding: 1.5rem;
    background: rgba(8, 9, 11, 0.32);
    color: #FFFFFF;
    text-align: center;
    text-decoration: none;
}
.corp-teaser-name {
    font-family: var(--font-display, inherit);
    font-size: clamp(1.25rem, 3vw, 2rem);
    font-weight: 600;
    line-height: 1.15;
}
.corp-teaser-status {
    display: inline-block;
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 9999px;
    padding: 0.4rem 0.9rem;
    background: #17231F;
    color: #D6FCEB;
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.3;
}
.corp-teaser-note {
    display: block;
    margin-top: 0.25rem;
    color: #D6FCEB;
    font-size: 0.75rem;
    line-height: 1.3;
}
.corp-teaser-overlay:focus-visible {
    outline: 2px solid #D6FCEB;
    outline-offset: -4px;
}
.corp-teaser-placeholder {
    min-height: 18rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1.5rem;
}
.product-shot.corp-teaser { min-height: 14rem; }
@media print {
    .corp-teaser-content { visibility: hidden; }
    .corp-teaser-overlay { color: #111111; background: transparent; }
    .corp-teaser-status { color: #111111; background: transparent; border-color: #555555; }
}

/* ---------- Stats --------------------------------------------------------- */

.stat-value {
    font-size: clamp(2.5rem, 4.4vw, 3.5rem);
    font-weight: 600;
    line-height: 1;
    letter-spacing: -0.04em;
    background: linear-gradient(160deg, #FFFFFF 30%, rgba(255, 255, 255, 0.55) 100%);
    -webkit-background-clip: text;
            background-clip: text;
    -webkit-text-fill-color: transparent;
    color: #FFFFFF;
}

/* ---------- Accent band --------------------------------------------------
   The one full-bleed statement block per page. Lighter than the page, not
   darker, so it lifts rather than disappears. */

.band {
    position: relative;
    background:
        radial-gradient(48rem 26rem at 18% 0%, rgba(16, 152, 117, 0.16), transparent 64%),
        #0C0D11;
    border-top: 1px solid rgba(255, 255, 255, 0.07);
    border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}

/* ---------- Reveal on scroll ---------------------------------------------- */

/* The hidden state is armed only by assets/js/corp.js, which stamps
   .js-reveal on <html> first. With JS off or failed, nothing is ever hidden. */

.js-reveal .reveal {
    opacity: 0;
    transform: translateY(16px);
}
.js-reveal .reveal.is-visible {
    opacity: 1;
    transform: none;
    transition: opacity 0.75s cubic-bezier(0.22, 1, 0.36, 1),
                transform 0.75s cubic-bezier(0.22, 1, 0.36, 1);
}

/* A link inside a block that has not revealed yet is focusable while it is
   invisible, for up to 1.3s with the stagger on. Tabbing into it looked like
   nothing happened. Focus reveals its block at once, without the transition,
   because the scroll that would otherwise have revealed it may be the very
   thing focus is trying to cause. Must stay after .is-visible: same
   specificity, so source order is what makes it win. */
.js-reveal .reveal:focus-within {
    opacity: 1;
    transform: none;
    transition: none;
}

@media (prefers-reduced-motion: reduce) {

    /* Everything, deliberately. This block used to name the animated rules one
       by one and it kept falling behind: the rotator width and the hero mark
       were both added later and neither was listed, so both still moved for
       someone who had asked the browser for less motion. Stopping every
       transition and animation at the root means a new rule is covered the day
       it is written, and the handful of end states that still have to be
       reached are restated underneath. */
    *,
    *::before,
    *::after {
        animation-duration: 1ms !important;
        animation-delay: 0ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 1ms !important;
        transition-delay: 0ms !important;
    }

    html { scroll-behavior: auto; }

    /* corp.js never stamps .js-reveal under reduced motion, so this is only a
       backstop: if the class survives a back/forward restore, content must not
       be left sitting at opacity 0 with nothing left to reveal it. */
    .js-reveal .reveal,
    .js-reveal .reveal.is-visible {
        opacity: 1;
        transform: none;
    }

    /* Decoration that moves rather than fades. Making these instant is not the
       point: the lift on a card or a button and the nudge on an arrow are
       motion for its own sake, so they come out entirely. */
    .co-card:hover, .co-card:focus-visible,
    .btn-ink:hover, .btn-outline:hover { transform: none; }
    .link-arrow:hover svg,
    .link-arrow:focus-visible svg { transform: none; }

    .corp-spotlight { display: none; }

    /* The hero holds on the first mark and never swaps: corp.js returns before
       starting the rotator, and these two rules pin it there anyway so a stale
       .is-active restored from bfcache cannot leave the box empty or show two
       marks at once. Specificity ties .hero-mark-img.is-active on purpose and
       wins on source order. */
    .hero-mark .hero-mark-img { opacity: 0; }
    .hero-mark .hero-mark-img:first-of-type { opacity: 1; }
}

/* ---------- Header -------------------------------------------------------- */

.corp-header {
    position: sticky;
    top: 0;
    z-index: 50;
    background: rgba(8, 9, 11, 0.72);
    backdrop-filter: saturate(160%) blur(14px);
    -webkit-backdrop-filter: saturate(160%) blur(14px);
    border-bottom: 1px solid transparent;
    transition: border-color 0.25s ease, background-color 0.25s ease;
}
.corp-header.is-scrolled {
    background: rgba(8, 9, 11, 0.92);
    border-bottom-color: rgba(255, 255, 255, 0.07);
}

/* The Workflow app switcher in the header (partials/nav.php). Its button draws in
   currentColor, so the colour set here is the icon's. The size repeats the
   component's own 36px so the header does not shift when the deferred script
   upgrades the element. A browser without the popover API gets no button: the
   component hides itself with an inline style, which wins over this rule. */
.corp-app-switcher {
    display: inline-flex;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    color: var(--ink-700, #C7CBD2);
}

.corp-wordmark {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 1.0625rem;
    font-weight: 600;
    letter-spacing: -0.02em;
    color: #FFFFFF;
    text-decoration: none;
    white-space: nowrap;
}

/* The mark: a small square holding the W, drawn in CSS so there is no image
   request in the header and it stays crisp at any density. */
.corp-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 6px;
    background: linear-gradient(140deg, #109875, #33CFA7 55%, #80FF44);
    color: #08090B;
    font-size: 0.8125rem;
    font-weight: 700;
    letter-spacing: -0.03em;
    flex: none;
}

.nav-link {
    font-size: 0.9375rem;
    color: var(--ink-500, #9AA1AC);
    text-decoration: none;
    transition: color 0.2s ease;
    /* SC 2.5.8 again: the line box alone was 23px, one pixel under the 24px
       floor, on every page in the site. The header is a fixed 72px and centres
       its row, so padding the target changes nothing visually. */
    display: inline-block;
    padding-block: 4px;
}
.nav-link:hover { color: #FFFFFF; }
.nav-link.is-active { color: #FFFFFF; font-weight: 500; }
/* A nav item flagged 'wide' in partials/nav.php joins the desktop bar only
   from 1024px. At the md breakpoint (768px) the wordmark and the other links
   already fill the row edge to edge, and one more link pushed every page into
   horizontal scroll up to about 870px. The item is still in the phone menu
   below 768px and in the footer at every width, so it is never unreachable. */
.nav-link.nav-link-wide { display: none; }
.nav-link.nav-link-library { display: none; }
@media (min-width: 1024px) {
    .nav-link.nav-link-wide { display: inline-block; }
    .corp-header .corp-nav { column-gap: 20px; }
}
/* The library also lives in the mobile menu and footer. It joins the desktop
   bar once there is room for its longer label beside Docs and the switcher. */
@media (min-width: 1280px) {
    .nav-link.nav-link-library { display: inline-block; }
}

/* The desktop bar switches on at 768px, and at 768px it did not fit: the
   wordmark, six links and the Contact button needed 768px of a window whose
   scrollbar leaves 751 to 753. The bar ran under the scrollbar, the page
   scrolled sideways, and the wordmark touched "Companies" with no gap at all.
   Until 1024px the links sit 18px apart instead of 32px. Measured at 768px
   with a 17px scrollbar: no sideways scroll, and 21px between the wordmark and
   "Companies", just above the gap between the links themselves. 20px left the
   wordmark 11px from the first link, tighter than the links were to each
   other, which reads as a collision rather than a layout.

   Two classes deep on purpose: tailwind-utilities.css loads after this file,
   so a single-class rule loses to gap-8 at equal specificity. And it is a rule
   here rather than gap-5 lg:gap-8 in the markup because the utilities are
   compiled ahead of time, and a class that is not in that build does nothing. */
@media (min-width: 768px) and (max-width: 1023.98px) {
    .corp-header .corp-nav { column-gap: 18px; }
}

/* The Workflow app switcher joined the header on 2026-09-27 and needs 52px (its
   36px plus the 16px gap), which is more than the 21px the note above left spare
   at 768px: the wordmark touched the first link again, and at 320px it met the
   switcher. So " Corporation" drops out of the wordmark between 768 and 1023px
   and below 360px, leaving the W mark and "Workflow". The link's aria-label
   still names the company in full, and every width outside those two bands
   keeps the whole wordmark. */
@media (min-width: 768px) and (max-width: 1023.98px), (max-width: 359.98px) {
    .corp-wordmark-suffix { display: none; }
}

/* Section heading beside section content, the 4-of-12 / 8-of-12 split most
   sections use, switches on at 768px. Between 768 and 1023px the 4-column
   side is about 220px, and the intro text under each section heading ran 25
   to 30 characters a line on the home page, Leadership, Careers and Contact:
   measured, not eyeballed, by a line-length sweep across every page. Below
   768px those sections already stack, and that layout is the designed one, so
   it simply holds until 1024px, where the side column is wide enough.

   Only grids that open with a 4-column child: the hero and the other splits
   read fine at this width and are left alone. That set also takes in each
   product block on the Products page and each founder row on Leadership,
   which stack the way they do on a phone; checked, and nothing in them
   depends on sitting side by side. :has() is current in every
   evergreen browser; one without it keeps the side-by-side layout, which is
   where the page was before. The margins restore each child's own mobile
   spacing, which its md:mt-0 cancels at this width. Two classes and an
   element deep, because tailwind-utilities.css loads after this file. */
@media (min-width: 768px) and (max-width: 1023.98px) {
    main .md\:grid-cols-12:has(> .md\:col-span-4:first-child) { display: block; }
    main .md\:grid-cols-12:has(> .md\:col-span-4:first-child) > .mt-4.md\:mt-0  { margin-top: 1rem; }
    main .md\:grid-cols-12:has(> .md\:col-span-4:first-child) > .mt-6.md\:mt-0  { margin-top: 1.5rem; }
    main .md\:grid-cols-12:has(> .md\:col-span-4:first-child) > .mt-8.md\:mt-0  { margin-top: 2rem; }
    main .md\:grid-cols-12:has(> .md\:col-span-4:first-child) > .mt-10.md\:mt-0 { margin-top: 2.5rem; }
}

/* Windows high contrast (forced colours). Checked in Edge with
   --force-high-contrast: headings, the gradient words, buttons, cards and
   links all survive, because the browser overrides the transparent text fill
   and redraws borders in system colours. The one casualty was the feature-list
   bullet, which is a background, and forced colours remove backgrounds: every
   list lost its marker. Drawn in the user's own text colour instead, and only
   that element opts out of the override. */
@media (forced-colors: active) {
    .co-dot {
        forced-color-adjust: none;
        background: CanvasText;
        box-shadow: none;
    }
}

/* Meet Buddy's launcher scales up on hover through an inline style its loader
   sets. Under reduced motion it stays put, like every other button here. */
@media (prefers-reduced-motion: reduce) {
    #meetbuddy-launcher { transform: none !important; }
}

/* ---------- Footer -------------------------------------------------------- */

/* Clearance for Meet Buddy's chat launcher (partials/footer.php), which is
   fixed 20px from the bottom right and 52px tall, so its top is 72px up from
   the bottom when the page is scrolled to the end. The footer's last row
   (Privacy, Terms, the support address) needs 80px under it at every width.
   From Tailwind's sm breakpoint up, the inner py-20 (5rem) gives that on its
   own; below it, py-16 (4rem) gives 64px and at 375px the address runs under
   the launcher's left edge, so phones get 1rem more.
   The launcher is sized in px and the Tailwind padding in rem, so a browser
   whose default font is smaller than 16px shrinks the padding but not the
   launcher. The calc() floors top the total back up to 80px in that case
   and add nothing at 16px or larger.
   This was 2.5rem at every width until 2026-09-28, which stacked 40px on the
   80px and left a 120px empty band under the bottom row on desktop that read
   as a bug (the owner's report). Measured on www.workflowcorp.com at 320 to
   1273px before and after changing it. */
.corp-footer {
    background: #050608;
    border-top: 1px solid rgba(255, 255, 255, 0.07);
    color: var(--ink-500, #9AA1AC);
    padding-bottom: max(0px, calc(80px - 5rem));
}
@media (max-width: 639.98px) {
    .corp-footer { padding-bottom: max(1rem, calc(80px - 4rem)); }
}
.corp-footer a {
    color: var(--ink-500, #9AA1AC);
    text-decoration: none;
    transition: color 0.2s ease;
}
.corp-footer a:hover { color: #FFFFFF; }

/* Target size again, SC 2.5.8. Measured at 375px, EVERY link in the footer's
   three columns and its bottom bar was 19 to 20 pixels tall: the line box and
   nothing else. They are standalone navigation, so the inline exemption does not
   apply to them, and the footer is where a phone user does most of their tapping.
   Padding the line box clears 24 and costs 6px of column height per item.
   The wordmark and .social-link are already sized and are excluded so this does
   not stack on top of their own geometry. */
.corp-footer a:not(.corp-wordmark):not(.social-link) {
    display: inline-block;
    padding-block: 3px;
}
.corp-footer .footer-heading {
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: #FFFFFF;
}

/* ---------- Print --------------------------------------------------------- */

@media print {
    .corp-header, .corp-footer, .corp-ambient, .corp-grid,
    .btn-ink, .btn-outline { display: none; }
    /* Meet Buddy's chat (partials/footer.php): its launcher and an open panel
       are fixed elements that would print over the page. */
    #meetbuddy-launcher, #meetbuddy-panel { display: none !important; }
    body { background: #FFFFFF; color: #000000; font-size: 12pt; }

    /* Scroll-reveal holds everything below the first screen at opacity 0
       until it is scrolled into view, and printing is not scrolling. Printed
       from the top, the About page came out as four pages carrying 384
       characters: four of its five section headings were blank. */
    .js-reveal .reveal {
        opacity: 1 !important;
        transform: none !important;
        transition: none !important;
    }

    /* The headline's product word is the same trap in a different place: it
       sits at opacity 0 for part of every beat, so a print that lands on that
       moment drops it, and its box is a pixel width measured for the screen
       font rather than the print one, so a longer word can be clipped. Freeze
       it visible and let the box size to the word. */
    .rotator { width: auto !important; overflow: visible !important; }
    .is-fitted .hero-line { white-space: normal; }
    .is-fitted .hero-line { font-size: inherit !important; }
    .rotator-word {
        opacity: 1 !important;
        transform: none !important;
        transition: none !important;
    }

    /* Black ink on everything, including the gradient words. .display-em and
       .stat-value are background-clip:text with a transparent fill, and a
       browser drops backgrounds when it prints unless told otherwise, so
       "Buddy." printed as nothing. Forcing only the parent headings black did
       not reach them: the span sets its own fill. The theme's pale greys are
       tuned for a near-black page and fade out on paper, so they go too. */
    *, *::before, *::after {
        color: #000000 !important;
        -webkit-text-fill-color: #000000 !important;
        background: transparent !important;
        box-shadow: none !important;
        text-shadow: none !important;
    }

    /* Put back the few things that are drawn WITH a background and would
       otherwise vanish under the rule above: the feature-list bullets (the
       only marker on those lists), the section dividers, and the card edges,
       which are 8% white and so invisible on paper. A class beats the
       universal selector when both are !important. */
    .co-dot { background: #000000 !important; }
    .rule   { background-color: #BBBBBB !important; }
    .co-card { border-color: #CCCCCC !important; }
}

/* A small product mark, used where a card needs identifying but not selling.
   Nothing behind it: see the note above .hero-mark for why the marks are left
   to sit on the page on their own. */
/* 44px, up from 36. Each mark is a face with a product badge on its
   shoulder, and the badge carries the only thing that tells one product from
   another: a waveform, a note, a picture, a dollar sign. At 36px that glyph
   was a few pixels across and every mark read as the same green face with a
   coloured speck. 44px is the smallest size, compared side by side at 1:1,
   where each badge says which product it is. */
.buddy-mark-sm {
    width: 2.75rem;
    height: 2.75rem;
    flex: none;
    filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.5));
}

/* ---------- Product pages (pages/product.php) -----------------------------
   One page per listed product. <main class="product-page"> carries the
   product's --co-accent, so every accent on the page (the tagline, the section
   kickers, the step numbers, the band's wash) is that product's colour rather
   than the group's green. Accent TEXT goes through the same 70% mix as
   .co-accent-text, for the contrast reason given there. */

/* Vertical padding only, so the px-5 / sm:px-8 gutter utilities on the same
   element still apply. Semantic rather than utilities because pt-12, sm:pt-16
   and pb-20 are not in the compiled tailwind-utilities.css. */
.product-hero    { padding-top: 2rem; }
.product-closing { padding-top: 1rem; padding-bottom: 5rem; }
@media (min-width: 640px) {
    .product-hero    { padding-top: 2.5rem; }
    .product-closing { padding-bottom: 7rem; }
}

.product-crumb {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.875rem;
    color: var(--ink-400, #868D98);
}
.product-crumb a {
    color: var(--ink-500, #9AA1AC);
    text-decoration: none;
    padding-block: 3px;
    transition: color 0.2s ease;
}
.product-crumb a:hover { color: #FFFFFF; }
.product-crumb [aria-current="page"] { color: var(--ink-700, #C7CBD2); }

.product-tagline {
    font-size: clamp(1.25rem, 2.1vw, 1.625rem);
    font-weight: 500;
    line-height: 1.25;
    letter-spacing: -0.02em;
}

.product-host {
    font-size: 0.8125rem;
    color: var(--ink-400, #868D98);
}

.product-page .section-index.product-index {
    color: #EDEDED;
    color: color-mix(in srgb, var(--co-accent, #33CFA7) 70%, #FFFFFF);
}

/* The facts band: hairline cells drawn by a 1px gap over a lighter ground,
   so the separators stay one pixel whichever way the grid wraps. */
.product-facts {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1px;
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    overflow: hidden;
}
@media (min-width: 640px) {
    .product-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
    .product-facts { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.product-fact {
    background: #0D0E12;
    padding: 1.5rem;
}

.product-points {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.75rem;
}
@media (min-width: 640px) {
    .product-points { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.product-point {
    display: flex;
    gap: 0.75rem;
    padding: 1.125rem 1.25rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.025);
    font-size: 0.9375rem;
    line-height: 1.45;
    color: var(--ink-700, #C7CBD2);
}
.product-point .co-dot { margin-top: 0.4rem; }

/* The shared .band, washed in the product's colour instead of the group's. The
   first background is the fallback for a browser without color-mix. */
.band.product-band {
    background:
        radial-gradient(48rem 26rem at 18% 0%, rgba(16, 152, 117, 0.16), transparent 64%),
        #0C0D11;
    background:
        radial-gradient(48rem 26rem at 18% 0%, color-mix(in srgb, var(--co-accent, #33CFA7) 12%, transparent), transparent 64%),
        #0C0D11;
}

.product-steps {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: 1rem;
}
.product-step {
    position: relative;
    padding: 1.75rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.018));
}
.product-step-num {
    display: block;
    font-size: 2.25rem;
    font-weight: 600;
    line-height: 1;
    letter-spacing: -0.04em;
    color: #EDEDED;
    color: color-mix(in srgb, var(--co-accent, #33CFA7) 70%, #FFFFFF);
}
.product-step-title {
    margin-top: 1.25rem;
    font-size: 1.125rem;
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: -0.015em;
    color: #FFFFFF;
}

.product-fit {
    max-width: 36em;
    font-size: clamp(1.1875rem, 1.9vw, 1.5rem);
    font-weight: 500;
    line-height: 1.45;
    letter-spacing: -0.015em;
    color: #FFFFFF;
}

/* Studio Buddy's core products need room for their distinct jobs. */
.product-suite { margin-bottom: 4rem; }
.product-suite-grid { display: grid; grid-template-columns: 1fr; gap: 1.25rem; }
.product-suite-card {
    display: flex;
    flex-direction: column;
    min-width: 0;
    padding: 1.75rem;
    border: 1px solid rgba(51, 207, 167, 0.22);
    border-top: 3px solid #33CFA7;
    border-radius: 8px;
    background: #101715;
}
.product-suite-role { color: #6EE7B7; font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase; }
.product-suite-name { margin-top: 1rem; color: #FFFFFF; font-size: 2rem; font-weight: 600; letter-spacing: -0.04em; }
.product-suite-headline { margin-top: 1rem; color: #EDEDED; font-size: 1.125rem; line-height: 1.5; font-weight: 500; }
.product-suite-body { margin-top: 1rem; color: #AFB5BE; font-size: 0.9375rem; line-height: 1.7; }
.product-suite-points { margin: 1.5rem 0 2rem; padding-left: 1.1rem; list-style: disc; color: #C7CBD2; font-size: 0.875rem; line-height: 1.7; }
.product-suite-points li + li { margin-top: 0.75rem; }
.product-suite-link { margin-top: auto; font-size: 0.9375rem; }
.product-suite-extra { margin-top: 2rem; max-width: 52rem; color: #AFB5BE; font-size: 1rem; line-height: 1.7; }
@media (min-width: 960px) {
    .product-suite-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media print {
    .product-suite-card { background: #FFFFFF; border-color: #777777; break-inside: avoid; }
    .product-suite-role, .product-suite-name, .product-suite-headline,
    .product-suite-body, .product-suite-points, .product-suite-extra { color: #000000; }
}

.product-more {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: 0.75rem;
}
.product-chip {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    height: 100%;
    padding: 0.875rem 1rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.025);
    color: inherit;
    text-decoration: none;
    transition: border-color 0.25s ease, background-color 0.25s ease, transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}
.product-chip:hover,
.product-chip:focus-visible {
    border-color: rgba(255, 255, 255, 0.22);
    border-color: color-mix(in srgb, var(--co-accent, #33CFA7) 55%, transparent);
    background: rgba(255, 255, 255, 0.045);
    transform: translateY(-2px);
}
.product-chip-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}
.product-chip-name {
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.3;
    color: #FFFFFF;
}
.product-chip-cat {
    margin-top: 2px;
    font-size: 0.75rem;
    line-height: 1.4;
    color: var(--ink-400, #868D98);
}

@media (prefers-reduced-motion: reduce) {
    .product-chip:hover,
    .product-chip:focus-visible { transform: none; }
}

@media print {
    .product-fact { border: 1px solid #CCCCCC !important; }
    .product-point, .product-step, .product-chip { border-color: #CCCCCC !important; }
    .product-step-num { color: #000000 !important; }
}

/* ---------- Privacy and terms (privacy/index.php, terms/index.php) ---------
   The product rows reuse .product-chip from the product pages. Only products
   that publish the document are listed (partials/policy-list.php). */

.policy-list {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.75rem;
}
@media (min-width: 640px) {
    .policy-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.policy-facts {
    display: grid;
    gap: 1.25rem;
}
.policy-facts li {
    display: flex;
    gap: 0.875rem;
    font-size: 1rem;
    line-height: 1.6;
    color: var(--ink-500, #9AA1AC);
}
.policy-facts li strong {
    color: #FFFFFF;
    font-weight: 600;
}
.policy-facts .co-dot { margin-top: 0.55rem; }

/* ---------- Newsroom (pages/news.php) and its feed (feed/index.php) --------
   Each announcement is an anchor, #<id> from $aNewsItems, and its date links to
   it. No scroll-margin here: html's scroll-padding-top (top of this file)
   already keeps a jumped-to item below the sticky header, and the two add up. */

.news-permalink {
    width: fit-content;
    text-decoration: none;
}
.news-permalink:hover time { color: #FFFFFF; text-decoration: underline; text-underline-offset: 3px; }
.news-feed {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;
    font-size: 0.9375rem;
    color: var(--ink-500, #9AA1AC);
}
.news-feed-icon { color: #33CFA7; flex: none; }
/* The feed's address as text, on the newsroom and the press kit. */
.feed-url {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.875rem;
    overflow-wrap: anywhere;
}
.news-item:target h2 { color: #33CFA7; }

/* ---------- Products page: "Which one do I need?" (pages/products.php) -----
   One row per job ($aProductChooser in config.php): the visitor's need on the
   left, the product that does it on the right, the whole row one link to that
   product's page. On hover the row's edge and arrow take the product's accent,
   as .product-chip's edge does; nothing lifts. The mark is .buddy-mark-sm, the
   44px floor at which the badges can be told apart. Stacked on a phone, the
   product under the need. */

.chooser {
    display: grid;
    gap: 0.5rem;
}
.chooser-row {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.75rem;
    align-items: center;
    padding: 1rem 1.25rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.025);
    color: inherit;
    text-decoration: none;
    transition: border-color 0.25s ease, background-color 0.25s ease;
}
@media (min-width: 640px) {
    .chooser-row {
        grid-template-columns: minmax(0, 1fr) 13.5rem;
        gap: 1.5rem;
    }
}
.chooser-row:hover,
.chooser-row:focus-visible {
    border-color: rgba(255, 255, 255, 0.22);
    border-color: color-mix(in srgb, var(--co-accent, #33CFA7) 55%, transparent);
    background: rgba(255, 255, 255, 0.045);
}
.chooser-need {
    font-size: 0.9375rem;
    line-height: 1.5;
    color: var(--ink-700, #C7CBD2);
}
.chooser-product {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    min-width: 0;
}
.chooser-name {
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.3;
    color: #FFFFFF;
}
.chooser-arrow {
    width: 1rem;
    height: 1rem;
    flex: none;
    margin-left: auto;
    color: var(--ink-400, #868D98);
    transition: color 0.25s ease, transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}
.chooser-row:hover .chooser-arrow,
.chooser-row:focus-visible .chooser-arrow {
    color: #EDEDED;
    color: color-mix(in srgb, var(--co-accent, #33CFA7) 70%, #FFFFFF);
    transform: translateX(3px);
}
@media (prefers-reduced-motion: reduce) {
    .chooser-row:hover .chooser-arrow,
    .chooser-row:focus-visible .chooser-arrow { transform: none; }
}
@media print {
    .chooser-row { border-color: #CCCCCC !important; }
    .chooser-arrow { display: none; }
}

/* ---------- Press kit (press/index.php) ------------------------------------
   The facts band reuses .product-facts from the product pages. Everything
   else is here: the description with its copy button, the mark on a dark and
   a light tile, its greens, and a row per product. */

.press-copy {
    padding: 1.5rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.025);
}
.press-copy-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    min-height: 2rem;
}
.press-copy-text {
    margin-top: 0.75rem;
    max-width: 40em;
    font-size: 1.0625rem;
    line-height: 1.6;
    color: #FFFFFF;
}
.press-copy-btn {
    flex: none;
    padding: 0.3125rem 0.875rem;
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-radius: 999px;
    background: transparent;
    color: var(--ink-700, #C7CBD2);
    font: inherit;
    font-size: 0.8125rem;
    font-weight: 500;
    line-height: 1.4;
    cursor: pointer;
    transition: border-color 0.2s ease, color 0.2s ease;
}
.press-copy-btn:hover {
    border-color: #33CFA7;
    color: #FFFFFF;
}
.press-copy-btn[data-copied] {
    border-color: #33CFA7;
    color: #33CFA7;
}
.press-copy-btn[hidden] { display: none; }

.press-fact-note {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.8125rem;
    color: var(--ink-400, #868D98);
}

.press-mark-tiles {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem;
}
.press-mark-tile {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 16 / 10;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    background: #08090B;
}
.press-mark-tile--light {
    border-color: #FFFFFF;
    background: #FFFFFF;
}
.press-mark-tile img {
    width: clamp(3.5rem, 12vw, 6rem);
    height: auto;
}

.press-swatches {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem 1.5rem;
}
.press-swatch {
    display: flex;
    align-items: center;
    gap: 0.625rem;
}
.press-swatch-chip {
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 6px;
    background: var(--swatch, #33CFA7);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
}
.press-swatch-hex {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.875rem;
    color: var(--ink-700, #C7CBD2);
    user-select: all;
}

.press-products {
    display: grid;
    gap: 0.75rem;
}
/* Mark and name side by side, the line under both on a phone, where a mark
   column the height of the row left the sentence four words wide. From 640px
   the mark sits in its own column beside both. */
.press-product {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    gap: 0.75rem 1rem;
    padding: 1.25rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.025);
}
.press-product .co-dot { margin: 0 0.25rem; }
.press-product-line { grid-column: 1 / -1; }
@media (min-width: 640px) {
    .press-product { align-items: start; row-gap: 0.375rem; }
    .press-product > .buddy-mark-sm,
    .press-product > .co-dot { grid-row: span 2; }
    .press-product > .co-dot { margin-top: 0.5rem; }
    .press-product-line { grid-column: 2; }
}
.press-product-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.25rem 0.75rem;
}
.press-product-name {
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.3;
    color: #FFFFFF;
    text-decoration: none;
}
a.press-product-name:hover { color: #33CFA7; }
.press-product-cat {
    font-size: 0.75rem;
    color: var(--ink-400, #868D98);
}
.press-product-host {
    font-size: 0.8125rem;
    color: #33CFA7;
    text-decoration: none;
    overflow-wrap: break-word;
}
.press-product-host:hover { text-decoration: underline; }
.press-product-line {
    font-size: 0.9375rem;
    line-height: 1.55;
    color: var(--ink-500, #9AA1AC);
}

/* Recent announcements: a date and tag over a headline that links to the
   item's anchor on the newsroom. */
.press-news {
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.press-news-item {
    padding: 1.125rem 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.press-news-title {
    display: inline-block;
    margin-top: 0.375rem;
    font-size: 1.125rem;
    font-weight: 600;
    line-height: 1.35;
    color: #FFFFFF;
    text-decoration: none;
}
.press-news-title:hover,
.press-news-title:focus-visible { color: #33CFA7; }
.press-feed {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;
}

@media print {
    .press-copy-btn { display: none !important; }
    .press-copy, .press-product, .press-mark-tile, .press-news, .press-news-item { border-color: #CCCCCC !important; }
    .press-swatch-chip {
        background: var(--swatch, #33CFA7) !important;
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }
}

/* ---------- Product page: the product's own site ---------------------------
   A dated screenshot of the product's home page (pages/product.php), in a
   browser frame with its address. The frame links to the site, so it lifts on
   hover like the cards do. The glow under it is the group green, not the
   product's accent: every product site is green, so an accent glow put red
   under Table Buddy's green screenshot and violet under Voice Buddy's. */

.product-shot { margin: 0; }
.product-shot-frame {
    display: block;
    border: 1px solid rgba(255, 255, 255, 0.10);
    border-radius: 10px;
    overflow: hidden;
    /* Black, not the blue-tinted near-black the cards use: around a product's own
       dark screenshot the tint read as a blue box. */
    background: #000000;
    text-decoration: none;
    box-shadow:
        0 30px 80px -40px rgba(0, 0, 0, 0.9),
        0 0 0 1px rgba(0, 0, 0, 0.4);
    box-shadow:
        0 30px 80px -40px rgba(0, 0, 0, 0.9),
        0 40px 120px -60px rgba(51, 207, 167, 0.35);
    transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1), border-color 0.3s ease;
}
.product-shot-frame:hover,
.product-shot-frame:focus-visible {
    transform: translateY(-3px);
    border-color: rgba(255, 255, 255, 0.18);
}
.product-shot-bar {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    height: 2.25rem;
    padding: 0 0.875rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.07);
    background: #0A0A0A;
}
.product-shot-dots { display: inline-flex; gap: 6px; flex: none; }
.product-shot-dots span {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.14);
}
.product-shot-url {
    flex: 1;
    min-width: 0;
    max-width: 22rem;
    margin: 0 auto;
    padding: 0.2rem 0.75rem;
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.05);
    font-size: 0.75rem;
    color: var(--ink-500, #9AA1AC);
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.product-shot-frame img {
    display: block;
    width: 100%;
    height: auto;
}
.product-shot-caption {
    margin-top: 0.875rem;
    font-size: 0.8125rem;
    color: var(--ink-400, #868D98);
}

/* The date stays on one line: "27" and "September 2026" split across a phone
   line read as two facts. */
.product-shot-date { white-space: nowrap; }

@media (prefers-reduced-motion: reduce) {
    .product-shot-frame:hover,
    .product-shot-frame:focus-visible { transform: none; }
}

/* A dark screenshot of another site is ink and no information on paper. */
@media print {
    .product-shot { display: none; }
}

/* ---------- Home: "A look inside" (index.php) ------------------------------
   The section is the product spotlight now (.spot-*, further down). The
   thumbnail grid's .home-shot* rules went with it on 2026-10-10. */

/* The whole section, heading and rule included: hiding only the tiles left a
   heading with nothing under it on paper. */
@media print {
    .home-inside,
    .home-inside-rule { display: none; }
}

/* ---------- Who we build for (index.php) ----------------------------------
   One tile per kind of customer, each a list of product rows (mark, name and
   that product's role). The tile is a plain container, not a link, because it
   holds one link per product; the rows carry the hover state. */

.audience-grid {
    display: grid;
    gap: 1rem;
}
@media (min-width: 640px) {
    .audience-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .audience-tile-wide { grid-column: 1 / -1; }
    .audience-tile-wide .audience-rows {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        column-gap: 1.5rem;
    }
}
.audience-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    padding: 1.5rem 1.25rem 1.25rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.018));
}
.audience-tile::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: 3.25rem;
    height: 2px;
    background: #33CFA7;
}
.audience-title {
    padding: 0 0.25rem;
    font-size: 1.125rem;
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: -0.01em;
    color: #FFFFFF;
}
.audience-rows {
    display: grid;
    gap: 0.125rem;
    margin-top: 0.75rem;
}
.audience-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem 0.25rem;
    border-radius: 6px;
    color: inherit;
    text-decoration: none;
    transition: background-color 0.2s ease;
}
.audience-row:hover,
.audience-row:focus-visible { background: rgba(255, 255, 255, 0.05); }
.audience-row-mark {
    width: 2rem;
    height: 2rem;
    flex: none;
}
.audience-row-dot {
    width: 2rem;
    height: 2rem;
    flex: none;
    border-radius: 999px;
    background: rgba(51, 207, 167, 0.18);
}
.audience-row-text {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}
.audience-row-name {
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.3;
    color: #FFFFFF;
}
.audience-row:hover .audience-row-name,
.audience-row:focus-visible .audience-row-name { color: #33CFA7; }
.audience-row-soon {
    margin-left: 0.375rem;
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--ink-400, #868D98);
}
.audience-row-role {
    font-size: 0.8125rem;
    line-height: 1.4;
    color: var(--ink-500, #9AA1AC);
}
.audience-more {
    margin-top: auto;
    padding: 0.75rem 0.25rem 0;
    font-size: 0.875rem;
}
@media print {
    .audience-tile { border-color: #CCCCCC !important; background: none !important; }
    .audience-tile::before { display: none; }
}

/* ---------- Built around Radio Workflow (pages/products.php) --------------
   Radio Workflow as a bar, the products that work alongside it in a half
   above and a half below. The centre is first in the source (phone order and
   tab order); from 640px flex order moves it between the halves. From 1024px
   each half is one line and every node is joined to the bar by a short green
   rule (its ::after) across the gap. Below 1024px a half can wrap onto two
   lines, where a rule would end beside a card instead of at the bar, so there
   are no rules there. */

.hub {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    margin-top: 2.5rem;
}
.hub-row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1rem;
}
.hub-row > li { flex: 1 1 100%; }
@media (min-width: 640px) {
    .hub-row-top { order: 1; }
    .hub-center { order: 2; }
    .hub-row-bottom { order: 3; }
    .hub-row > li { flex: 0 1 calc((100% - 1rem) / 2); }
}
@media (min-width: 1024px) {
    .hub { gap: 1.5rem; }
    .hub-row { flex-wrap: nowrap; }
    .hub-row > li { flex: 0 1 calc((100% - 2rem) / 3); }
}
.hub-node {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    height: 100%;
    padding: 1.125rem 1.25rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.03);
    color: inherit;
    text-decoration: none;
    transition: border-color 0.25s ease, background-color 0.25s ease;
}
.hub-node:hover,
.hub-node:focus-visible {
    border-color: rgba(51, 207, 167, 0.5);
    background: rgba(255, 255, 255, 0.05);
}
@media (min-width: 1024px) {
    .hub-node::after {
        content: "";
        position: absolute;
        left: 50%;
        width: 1px;
        height: 1.5rem;
        background: rgba(51, 207, 167, 0.55);
    }
    .hub-row-top .hub-node::after { top: 100%; margin-top: 1px; }
    .hub-row-bottom .hub-node::after { bottom: 100%; margin-bottom: 1px; }
}
/* Centred, because each node's rule meets the bar at the node's centre:
   left-aligned content read as off-axis (owner, 2026-10-10). */
.hub-node {
    align-items: center;
    text-align: center;
}
.hub-node-head {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.625rem;
}
.hub-node-mark {
    width: 2rem;
    height: 2rem;
    flex: none;
}
.hub-node-name {
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.3;
    color: #FFFFFF;
}
.hub-node-role {
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--ink-500, #9AA1AC);
}
/* Built like a node: mark and name on one centred row, the role centred
   beneath, so the bar and the cards it joins read as one family. */
.hub-center {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.375rem;
    text-align: center;
    padding: 1.25rem 1.5rem;
    border: 1px solid rgba(51, 207, 167, 0.45);
    border-radius: 8px;
    background: linear-gradient(90deg, rgba(16, 152, 117, 0.16), rgba(51, 207, 167, 0.06) 50%, rgba(16, 152, 117, 0.16));
    color: inherit;
    text-decoration: none;
    transition: border-color 0.25s ease;
}
.hub-center-head {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
}
.hub-center:hover,
.hub-center:focus-visible { border-color: #33CFA7; }

.hub-center-name {
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: -0.01em;
    color: #FFFFFF;
}
.hub-center-role {
    font-size: 0.875rem;
    color: var(--ink-500, #9AA1AC);
}
@media print {
    .hub-node,
    .hub-center { border-color: #CCCCCC !important; background: none !important; }
    .hub-node::after { display: none; }
}

/* ---------- Products menu (partials/nav.php) ------------------------------
   From 1024px "Products" on the desktop bar is a button that opens a panel of
   every published product, grouped as on the home page. Below that it stays a
   plain link. The panel hangs from the sticky header (its containing block)
   at full width, so it lines up with the page's max-w-6xl column. */

.nav-products-btn {
    display: none;
    align-items: center;
    gap: 0.25rem;
    padding-inline: 0;
    border: 0;
    background: none;
    font-family: inherit;
    line-height: inherit;
    cursor: pointer;
}
.nav-products-btn[aria-expanded="true"] {
    color: #FFFFFF;
    text-decoration: underline;
    text-decoration-color: #33CFA7;
    text-decoration-thickness: 2px;
    text-underline-offset: 6px;
}
.nav-products-chevron {
    width: 0.875rem;
    height: 0.875rem;
    transition: transform 0.2s ease;
}
.nav-products-btn[aria-expanded="true"] .nav-products-chevron { transform: rotate(180deg); }
@media (min-width: 1024px) {
    .nav-products-link { display: none; }
    .nav-products-btn { display: inline-flex; }
}
.products-panel {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    border-top: 1px solid rgba(255, 255, 255, 0.07);
    border-bottom: 1px solid rgba(255, 255, 255, 0.07);
    background: #08090B;
    box-shadow: 0 30px 60px -30px rgba(0, 0, 0, 0.9);
    /* It hangs from a sticky header, so anything past the viewport could never
       be scrolled into view (short landscape screens, 200% zoom). */
    max-height: calc(100vh - var(--header-bottom, 72px));
    max-height: calc(100dvh - var(--header-bottom, 72px));
    overflow-y: auto;
}
.products-panel[hidden] { display: none; }
.products-panel-item[aria-current="page"] .products-panel-name { color: #33CFA7; }
.products-panel-inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 2fr) 13rem;
    gap: 2.5rem;
    padding-top: 1.75rem;
    padding-bottom: 2rem;
}
.products-panel-list {
    display: grid;
    gap: 0.125rem;
    margin-top: 0.75rem;
}
.products-panel-group-industry .products-panel-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 1rem;
}
.products-panel-item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem;
    margin-inline: -0.5rem;
    border-radius: 6px;
    color: inherit;
    text-decoration: none;
    transition: background-color 0.2s ease;
}
.products-panel-item:hover,
.products-panel-item:focus-visible { background: rgba(255, 255, 255, 0.05); }
.products-panel-mark {
    width: 2rem;
    height: 2rem;
    flex: none;
}
.products-panel-dot {
    border-radius: 999px;
    background: rgba(51, 207, 167, 0.18);
}
.products-panel-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}
.products-panel-name {
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.3;
    color: #FFFFFF;
}
.products-panel-item:hover .products-panel-name,
.products-panel-item:focus-visible .products-panel-name { color: #33CFA7; }
.products-panel-soon {
    margin-left: 0.375rem;
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--ink-400, #868D98);
}
.products-panel-cat {
    font-size: 0.8125rem;
    line-height: 1.35;
    color: var(--ink-500, #9AA1AC);
}
.products-panel-side {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
    padding-left: 2rem;
    border-left: 1px solid rgba(255, 255, 255, 0.07);
}
.products-panel-note {
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--ink-500, #9AA1AC);
}
.products-panel-sidelink {
    display: inline-block;
    padding-block: 4px;
    font-size: 0.875rem;
    color: var(--ink-700, #C7CBD2);
    text-decoration: none;
}
.products-panel-audiences-label { margin-top: 1rem; }
.products-panel-audiences {
    display: grid;
    margin-top: 0.25rem;
}
.products-panel-more {
    align-self: stretch;
    display: flex;
    gap: 1rem;
    margin-top: 0.75rem;
    padding-top: 0.75rem;
    border-top: 1px solid rgba(255, 255, 255, 0.07);
}
.products-panel-sidelink[aria-current="page"] { color: #33CFA7; }
.products-panel-sidelink:hover,
.products-panel-sidelink:focus-visible { color: #FFFFFF; }
@media (prefers-reduced-motion: reduce) {
    .nav-products-chevron { transition: none; }
}
@media print {
    .products-panel { display: none !important; }
}

/* ---------- Home product cards (index.php) ---------------------------------
   One card shape in both home grids: the grid stretches the cards in a row to
   the same height and the "Explore" link sits on the card's floor, so the links
   in a row line up whatever the summary's length. */
.co-card-home {
    display: flex;
    flex-direction: column;
}
.co-card-home .co-card-cta {
    align-self: flex-start;
    margin-top: auto;
    padding-top: 1.25rem;
}
.co-card-home > .corp-teaser-content {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
}

/* ---------- Home newsroom cards (index.php) --------------------------------
   The three latest announcements in one row (two on a tablet, one on a
   phone), each a whole-card link to the item on /pages/news.php. Bodies are
   clamped to four lines so the cards in a row match; the full text is in the
   markup and on the newsroom. */
.news-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem 2rem;
}
.news-cards {
    display: grid;
    gap: 1rem;
    margin-top: 2.5rem;
}
@media (min-width: 640px) {
    .news-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Two columns and three cards would leave the third alone beside an empty
   cell, so a tablet shows the two latest; "All news" has the rest. */
@media (min-width: 640px) and (max-width: 1023.98px) {
    .news-cards > li:nth-child(3) { display: none; }
}
@media (min-width: 1024px) {
    .news-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.news-cards > li { display: flex; }
.news-card {
    display: flex;
    flex-direction: column;
    width: 100%;
    padding: 1.5rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.018));
    color: inherit;
    text-decoration: none;
    transition: border-color 0.25s ease, transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}
.news-card:hover,
.news-card:focus-visible {
    border-color: rgba(51, 207, 167, 0.45);
    transform: translateY(-3px);
}
.news-card-meta {
    display: flex;
    align-items: center;
    gap: 0.625rem;
}
.news-card-mark {
    width: 2rem;
    height: 2rem;
    flex: none;
}
.news-card-dot {
    border-radius: 999px;
    background: rgba(51, 207, 167, 0.18);
}
.news-card-date {
    margin-top: 1rem;
    font-size: 0.8125rem;
    color: var(--ink-400, #868D98);
}
.news-card-title {
    margin-top: 0.375rem;
    font-size: 1.1875rem;
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: -0.015em;
    color: #FFFFFF;
}
.news-card-body {
    margin-top: 0.625rem;
    font-size: 0.9375rem;
    line-height: 1.55;
    color: var(--ink-500, #9AA1AC);
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 4;
    line-clamp: 4;
    overflow: hidden;
}
.news-card-more {
    align-self: flex-start;
    margin-top: auto;
    padding-top: 1.25rem;
    font-size: 0.9375rem;
}
@media (prefers-reduced-motion: reduce) {
    .news-card:hover,
    .news-card:focus-visible { transform: none; }
}
@media print {
    .news-card { border-color: #CCCCCC !important; background: none !important; }
    .news-card-body { display: block; -webkit-line-clamp: none; overflow: visible; }
}

/* ---------- A look inside: product spotlight (index.php) -------------------
   Tabs in the left column (a wrapping row of chips on a phone), one framed
   capture and the active product's text on the right. The capture box is a
   fixed 2:1, and the text panels share one grid cell (the inactive ones are
   visibility:hidden), so switching products never changes the section's
   height. Without corp.js the tabs are plain links and only the first panel
   shows. */
.spot-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 2rem;
}
@media (min-width: 768px) {
    .spot-tabs {
        flex-direction: column;
        flex-wrap: nowrap;
        gap: 0.125rem;
    }
}
.spot-tab {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.375rem 0.75rem 0.375rem 0.375rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 999px;
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--ink-500, #9AA1AC);
    text-decoration: none;
    transition: color 0.2s ease, background-color 0.2s ease, border-color 0.2s ease;
}
@media (min-width: 768px) {
    .spot-tab {
        padding: 0.375rem 0.625rem;
        border-color: transparent;
        border-radius: 6px;
        font-size: 0.9375rem;
    }
}
.spot-tab:hover,
.spot-tab:focus-visible { color: #FFFFFF; background: rgba(255, 255, 255, 0.04); }
.spot-tab[aria-selected="true"],
.spot-tab[aria-current="true"] {
    color: #FFFFFF;
    border-color: rgba(51, 207, 167, 0.45);
    background: rgba(51, 207, 167, 0.08);
}
.spot-tab-mark {
    width: 1.75rem;
    height: 1.75rem;
    flex: none;
}
.spot-frame { cursor: default; }
.spot-frame:hover,
.spot-frame:focus-visible { transform: none; }
/* contain, never cover: cover cut the sides off the widest crops (Radio
   Workflow's headline) and was already removed once from the old gallery for
   that. A crop shorter than 2:1 leaves a band under it that starts in the
   capture's own bottom colour (--shot-edge, from screens.json) at the point
   the image ends (--shot-cut) and fades to the frame's black. */
.spot-frame img {
    aspect-ratio: 2 / 1;
    height: auto;
    object-fit: contain;
    object-position: top;
    background: linear-gradient(to bottom, var(--shot-edge, #000000) var(--shot-cut, 100%), #000000);
    transition: opacity 0.25s ease;
}
.spot-frame img.is-loading { opacity: 0.35; }
.spot-panels {
    display: grid;
    margin-top: 1.75rem;
}
.spot-panel { grid-area: 1 / 1; }
.spot-panel:not(.is-active) { display: none; }
.spot.is-ready .spot-panel:not(.is-active) {
    display: block;
    visibility: hidden;
}
.spot-name {
    margin-top: 0.5rem;
    font-size: 1.5rem;
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -0.02em;
    color: #FFFFFF;
}
.spot-tagline {
    margin-left: 0.5rem;
    font-size: 1rem;
    font-weight: 400;
    letter-spacing: 0;
    color: var(--ink-400, #868D98);
}
.spot-summary {
    margin-top: 0.75rem;
    max-width: 42rem;
    font-size: 0.9375rem;
    line-height: 1.6;
    color: var(--ink-500, #9AA1AC);
}
.spot-points {
    display: grid;
    gap: 0.5rem 1.5rem;
    margin-top: 1.25rem;
}
@media (min-width: 640px) {
    .spot-points { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.spot-points li {
    display: flex;
    gap: 0.625rem;
    font-size: 0.875rem;
    line-height: 1.4;
    color: var(--ink-700, #C7CBD2);
}
.spot-points .co-dot { margin-top: 0.375rem; flex: none; }
.spot-cta { margin-top: 1.5rem; font-size: 0.9375rem; }
@media (prefers-reduced-motion: reduce) {
    .spot-frame img { transition: none; }
}

/* ---------- Contact cards (pages/contact.php) -----------------------------
   The same rule as the home cards: a flex column whose link row sits on the
   card's floor, so the links in a row line up whatever the summary's length.
   Radio Workflow's extra routes are a list above its "Visit" link. */
.co-card-stack {
    display: flex;
    flex-direction: column;
}
.co-card-stack > .corp-teaser-content {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
}
.co-card-stack .co-card-actions {
    margin-top: auto;
    padding-top: 1.25rem;
}
/* A bare eyebrow (Support, Press) is a flex item here and would take its own
   11px line box, lifting the heading 8px out of line with the Partnerships
   card below; keep the line box it had as inline text. */
.co-card-stack > .eyebrow {
    align-self: flex-start;
    line-height: 1.6rem;
}
.co-card-extras {
    display: grid;
    gap: 0.375rem;
    margin-top: 1rem;
}

/* ---------- Audience pages (pages/for.php) and their tile links ------------ */
.audience-title-link {
    display: inline-flex;
    align-items: center;
    min-height: 1.5rem;
    gap: 0.375rem;
    color: inherit;
    text-decoration: none;
}
.audience-title-arrow {
    width: 1rem;
    height: 1rem;
    color: var(--ink-400, #868D98);
    transition: transform 0.25s ease, color 0.25s ease;
}
.audience-title-link:hover,
.audience-title-link:focus-visible { color: #33CFA7; }
.audience-title-link:hover .audience-title-arrow,
.audience-title-link:focus-visible .audience-title-arrow { color: #33CFA7; transform: translateX(3px); }
.for-others {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.for-other {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    min-height: 2.5rem;
    padding: 0.375rem 1rem;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 999px;
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--ink-700, #C7CBD2);
    text-decoration: none;
    transition: border-color 0.2s ease, color 0.2s ease;
}
.for-other:hover,
.for-other:focus-visible { color: #FFFFFF; border-color: rgba(51, 207, 167, 0.5); }
@media (prefers-reduced-motion: reduce) {
    .audience-title-link:hover .audience-title-arrow,
    .audience-title-link:focus-visible .audience-title-arrow { transform: none; }
}

/* ---------- Footer columns (partials/footer.php) -------------------------
   Five columns from 1024px (brand 4, then 2/2/2/2 of 12; when Radio Workflow
   is unpublished its column goes and the row ends short). From 768 to 1023px
   that left 75px link columns, so there the brand block spans the row and the
   link columns share the row beneath it. Two classes deep, because the
   md: utilities load after this file and would win a one-class tie. */
/* Up to the container's cap (max-w-6xl, 1152px): below it the 12-column split
   leaves link columns under 136px and the headings wrap. The link columns
   share one row however many there are (Radio Workflow's is optional), so
   the grid becomes a wrapping flex row here. */
@media (min-width: 768px) and (max-width: 1151.98px) {
    .corp-footer .footer-grid { display: flex; flex-wrap: wrap; column-gap: 2rem; }
    .corp-footer .footer-grid > .footer-brand { flex: 0 0 100%; }
    .corp-footer .footer-grid > div:not(.footer-brand) { flex: 1 1 0; min-width: 0; }
}

/* ---------- Announcement bar (partials/nav.php) ----------------------------
   One slim line above the sticky header for the newest news item while it is
   under 30 days old; it scrolls away with the page. */
/* Above the fixed ambient layers (wash, grid, cursor light), like the header,
   main and footer; static, it was painted underneath them. */
.corp-announce {
    position: relative;
    z-index: 1;
    border-bottom: 1px solid rgba(51, 207, 167, 0.18);
    background: linear-gradient(90deg, rgba(16, 152, 117, 0.16), rgba(51, 207, 167, 0.06) 50%, rgba(16, 152, 117, 0.16));
}
.corp-announce[hidden] { display: none; }
.corp-announce-inner {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 2.5rem;
}
.corp-announce-link {
    display: inline-flex;
    align-items: center;
    gap: 0.625rem;
    min-width: 0;
    padding-block: 0.375rem;
    font-size: 0.875rem;
    color: var(--ink-700, #C7CBD2);
    text-decoration: none;
}
.corp-announce-link:hover .corp-announce-text,
.corp-announce-link:focus-visible .corp-announce-text { color: #FFFFFF; text-decoration: underline; text-underline-offset: 3px; }
.corp-announce-tag {
    flex: none;
    padding: 0.0625rem 0.5rem;
    border-radius: 999px;
    background: rgba(51, 207, 167, 0.18);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #33CFA7;
}
.corp-announce-text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.corp-announce-arrow {
    width: 0.875rem;
    height: 0.875rem;
    flex: none;
    color: #33CFA7;
}
.corp-announce-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 1.75rem;
    height: 1.75rem;
    margin-left: auto;
    border: 0;
    border-radius: 6px;
    background: none;
    color: var(--ink-400, #868D98);
    cursor: pointer;
}
.corp-announce-close svg { width: 1rem; height: 1rem; }
.corp-announce-close[hidden] { display: none; }
@media (max-width: 359.98px) {
    .corp-announce-arrow { display: none; }
}
.corp-announce-close:hover,
.corp-announce-close:focus-visible { color: #FFFFFF; background: rgba(255, 255, 255, 0.06); }
/* The close button sits at the right edge; the link stays centred on wide
   screens by giving it the same space on the left. */
@media (min-width: 640px) {
    .corp-announce-inner::before { content: ""; width: 1.75rem; flex: none; margin-right: auto; }
}
@media print {
    .corp-announce { display: none !important; }
}

/* ---------- Phone menu: products disclosure (partials/nav.php) ------------ */
/* The menu hangs from the sticky header, so a menu taller than the screen
   (the products disclosure open, or any phone in landscape) could not scroll:
   its lower links were out of reach until the page ended. It scrolls itself. */
#corp-menu {
    max-height: calc(100vh - var(--header-bottom, 72px));
    max-height: calc(100dvh - var(--header-bottom, 72px));
    overflow-y: auto;
    overscroll-behavior: contain;
}
.mnav-products { margin: 0.25rem 0 0.5rem; }
.mnav-products-summary {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 2.75rem;
    font-size: 0.9375rem;
    color: #33CFA7;
    cursor: pointer;
    list-style: none;
}
.mnav-products-summary::-webkit-details-marker { display: none; }
.mnav-products-summary::after {
    content: "";
    width: 0.5rem;
    height: 0.5rem;
    border-right: 1.75px solid currentColor;
    border-bottom: 1.75px solid currentColor;
    transform: translateY(-2px) rotate(45deg);
    transition: transform 0.2s ease;
}
.mnav-products[open] > .mnav-products-summary::after { transform: translateY(2px) rotate(-135deg); }
.mnav-products-group {
    margin-top: 0.75rem;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-400, #868D98);
}
.mnav-products-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.25rem 0.75rem;
    margin-top: 0.5rem;
}
.mnav-product {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 2.75rem;
    font-size: 0.9375rem;
    color: var(--ink-700, #C7CBD2);
    text-decoration: none;
}
.mnav-product img { width: 1.75rem; height: 1.75rem; flex: none; }
.mnav-product[aria-current="page"] { color: #FFFFFF; font-weight: 500; }
@media (prefers-reduced-motion: reduce) {
    .mnav-products-summary::after { transition: none; }
}

/* ---------- Newsroom filter (pages/news.php) ------------------------------ */
.news-filter {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    padding-bottom: 1.5rem;
}
.news-filter[hidden] { display: none; }
.news-filter-btn {
    min-height: 2.25rem;
    padding: 0.375rem 0.875rem;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 999px;
    background: none;
    font-family: inherit;
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--ink-500, #9AA1AC);
    cursor: pointer;
    transition: color 0.2s ease, border-color 0.2s ease, background-color 0.2s ease;
}
.news-filter-btn:hover,
.news-filter-btn:focus-visible { color: #FFFFFF; border-color: rgba(255, 255, 255, 0.22); }
.news-filter-btn[aria-pressed="true"] {
    color: #FFFFFF;
    border-color: rgba(51, 207, 167, 0.5);
    background: rgba(51, 207, 167, 0.1);
}
.news-item.news-item-first { border-top-width: 0; }
@media print {
    .news-filter { display: none !important; }
    .news-item[hidden] { display: block !important; }
    .news-item.news-item-first:not(:first-of-type) { border-top-width: 1px; }
}

/* ---------- Hub: on their own (pages/products.php) -------------------------
   The products that are not Radio Workflow's companions, as the same node
   cards with no rules (nothing joins them to the bar), ruled off below it. */
.hub-standalone {
    margin-top: 3rem;
    padding-top: 2rem;
    border-top: 1px dashed rgba(255, 255, 255, 0.12);
}
.hub-standalone-label { text-align: center; }
/* Flex like the hub rows, so a short last row is centred, not left-hung. */
.hub-standalone-list {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1rem;
    margin-top: 1.25rem;
}
.hub-standalone-list > li { flex: 1 1 100%; }
@media (min-width: 640px) {
    .hub-standalone-list > li { flex: 0 1 calc((100% - 1rem) / 2); }
}
@media (min-width: 1024px) {
    .hub-standalone-list > li { flex: 0 1 calc((100% - 2rem) / 3); }
}
.hub-standalone .hub-node::after { display: none; }

/* Footer Products list (partials/footer.php): a single column like the other
   footer lists (space-y-3 is not used here, so the gap is set directly). */
.footer-products {
    display: grid;
    gap: 0.75rem;
}

/* Semantic spacing where the purged tailwind-utilities.css has no class
   (pt-10, pb-12, pb-20 and sm:pb-28 are not compiled; grep it before using a
   utility). */
.for-more { padding-top: 2.5rem; }
.for-links { gap: 0.625rem; }
.product-audiences-section { padding-bottom: 3rem; }
/* Its top gap normally comes from "Where it fits" above it. A product with no
   'fit' and no news drops that section, which puts a band directly above, and
   a band keeps its padding inside its own background, so this brings its own
   (the py-16 sm:py-20 of "More from the group"). */
.band + .product-audiences-section { padding-top: 4rem; }
@media (min-width: 640px) {
    .band + .product-audiences-section { padding-top: 5rem; }
}

/* ---------- About: timeline (pages/about.php) ------------------------------
   A vertical line with a dot per entry: the date to the left of the line on
   wide screens, above the card on a phone. */
.timeline {
    position: relative;
    display: grid;
    gap: 0.75rem;
}
.timeline::before {
    content: "";
    position: absolute;
    top: 0.5rem;
    bottom: 0.5rem;
    left: calc(0.5rem - 0.5px);
    width: 1px;
    background: linear-gradient(180deg, rgba(51, 207, 167, 0.6), rgba(51, 207, 167, 0.12));
}
.timeline-item {
    position: relative;
    display: grid;
    grid-template-columns: 1rem minmax(0, 1fr);
    column-gap: 1rem;
    align-items: center;
}
.timeline-date {
    grid-column: 2;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-400, #868D98);
}
.timeline-dot {
    grid-column: 1;
    grid-row: 1 / span 2;
    width: 0.875rem;
    height: 0.875rem;
    border: 2px solid #33CFA7;
    border-radius: 999px;
    background: #08090B;
    justify-self: center;
    z-index: 1;
}
.timeline-card {
    grid-column: 2;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-top: 0.25rem;
    padding: 0.75rem 1rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.03);
    color: inherit;
    text-decoration: none;
    transition: border-color 0.2s ease, background-color 0.2s ease;
}
.timeline-card:hover,
.timeline-card:focus-visible { border-color: rgba(51, 207, 167, 0.5); background: rgba(255, 255, 255, 0.05); }
@media (min-width: 640px) {
    .timeline-item { grid-template-columns: 10.5rem 1rem minmax(0, 1fr); }
    .timeline::before { left: calc(12rem - 0.5px); }
    .timeline-date { white-space: nowrap; }
    .timeline-date { grid-column: 1; grid-row: 1; text-align: right; }
    .timeline-dot { grid-column: 2; grid-row: 1; }
    .timeline-card { grid-column: 3; grid-row: 1; margin-top: 0; }
}
.timeline-mark { width: 2rem; height: 2rem; flex: none; }
/* Company milestones carry initials where a product mark goes. */
.timeline-mono {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    flex: none;
    border: 1px solid rgba(51, 207, 167, 0.45);
    border-radius: 999px;
    font-size: 0.6875rem;
    font-weight: 700;
    color: #33CFA7;
}
/* The turn from the founders' own years to the launches they share. */
/* .timeline-item.timeline-together so the flex layout does not rest on
   source order against .timeline-item's grid. Top-aligned: the label wraps
   on narrow screens and the initials start it rather than float beside it. */
.timeline-item.timeline-together {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    margin: 0.5rem 0 0.25rem 2rem;
}
.timeline-together-pair { display: inline-flex; flex: none; }
.timeline-together-pair .timeline-mono { background: #08090B; }
.timeline-together-pair .timeline-mono + .timeline-mono { margin-left: -0.5rem; }
/* The column sets the width; text-wrap keeps a lone word off the last line. */
.timeline-together-label {
    padding-top: 0.375rem;
    font-size: 0.8125rem;
    line-height: 1.4;
    font-weight: 500;
    text-wrap: pretty;
    color: #33CFA7;
}
@media (min-width: 640px) {
    .timeline-item.timeline-together { margin-left: 13.5rem; }
}
.timeline-text { display: flex; flex-direction: column; min-width: 0; }
.timeline-title { font-size: 0.9375rem; font-weight: 600; line-height: 1.35; color: #FFFFFF; }
.timeline-cat { font-size: 0.8125rem; color: var(--ink-500, #9AA1AC); }

/* About, under the hero: the owner's team photos. Two across on phones, four from md.
   The frame is fixed at 3:4 so the four shots line up whatever their source. */
.team-photos {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.25rem 1rem;
}
@media (min-width: 768px) {
    .team-photos { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1.5rem; }
}
.team-photos-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem 1.5rem;
    margin-bottom: 2rem;
}
.team-photos-link {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.9375rem;
    font-weight: 500;
    color: #33CFA7;
    text-decoration: none;
}
.team-photos-link:hover,
.team-photos-link:focus-visible { color: #66DBBD; text-decoration: underline; text-underline-offset: 3px; }
/* Careers: the owner's group photos under "What it is like". */
.group-photos {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem 0.75rem;
    margin-top: 3.5rem;
}
@media (min-width: 640px) {
    .group-photos { gap: 1.5rem; }
}
@media (min-width: 1024px) {
    .group-photos { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1.25rem; }
}
.group-photo { margin: 0; }
.group-photo img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 1rem;
    background: #0B0C0E;
}
.group-photo figcaption { margin-top: 0.75rem; font-size: 0.875rem; color: var(--ink-500, #9AA1AC); }
.team-photo { display: flex; flex-direction: column; min-width: 0; }
.team-photo picture {
    display: block;
    overflow: hidden;
    aspect-ratio: 3 / 4;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 1rem;
    background: #0B0C0E;
}
.team-photo img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.6s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.team-photo:hover img { transform: scale(1.03); }
@media (prefers-reduced-motion: reduce) {
    .team-photo img { transition: none; }
    .team-photo:hover img { transform: none; }
}
.team-photo-name { margin-top: 0.875rem; font-weight: 600; color: #FFFFFF; }
.team-photo-role { font-size: 0.875rem; color: var(--ink-500, #9AA1AC); }


/* Leadership: a headshot fills the avatar circle, founders and key team alike. */
.founder-avatar-photo,
.key-team-avatar-photo { overflow: hidden; }
.founder-avatar-photo picture,
.founder-avatar-photo img,
.key-team-avatar-photo picture,
.key-team-avatar-photo img { display: block; width: 100%; height: 100%; }
.founder-avatar-photo img,
.key-team-avatar-photo img { object-fit: cover; }

/* Leadership: focus areas, and the family the one team builds. */
.founder-focus {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 0.5rem 0.75rem;
    margin-top: 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid rgba(255, 255, 255, 0.07);
}
.founder-focus-label {
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-400, #868D98);
}
.founder-focus-list { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.375rem; }
.founder-focus-list > li {
    padding: 0.1875rem 0.625rem;
    border: 1px solid rgba(51, 207, 167, 0.35);
    border-radius: 999px;
    font-size: 0.8125rem;
    color: var(--ink-700, #C7CBD2);
}
.leadership-family-section { padding-top: 2.5rem; padding-bottom: 4rem; }
@media (min-width: 640px) {
    .leadership-family-section { padding-bottom: 6rem; }
}
.leadership-family {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.leadership-family-item,
.careers-family-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: inherit;
    text-decoration: none;
}
.leadership-family-item {
    min-height: 2.5rem;
    padding: 0.25rem 0.875rem 0.25rem 0.375rem;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 999px;
    font-size: 0.875rem;
    color: var(--ink-700, #C7CBD2);
    transition: border-color 0.2s ease, color 0.2s ease;
}
.leadership-family-item img { width: 1.75rem; height: 1.75rem; flex: none; }
.leadership-family-item:hover,
.leadership-family-item:focus-visible { color: #FFFFFF; border-color: rgba(51, 207, 167, 0.5); }

/* Careers: the family two or three across, and the office card. */
.careers-family {
    display: grid;
    gap: 0.5rem;
}
@media (min-width: 640px) {
    .careers-family { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
    .careers-family { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.careers-family-item {
    gap: 0.75rem;
    padding: 0.75rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.03);
    transition: border-color 0.2s ease;
}
.careers-family-item:hover,
.careers-family-item:focus-visible { border-color: rgba(51, 207, 167, 0.5); }
.careers-family-item img { width: 2rem; height: 2rem; flex: none; }
.careers-family-text { display: flex; flex-direction: column; min-width: 0; }
.careers-family-name { font-size: 0.9375rem; font-weight: 600; color: #FFFFFF; }
.careers-family-cat { font-size: 0.8125rem; color: var(--ink-500, #9AA1AC); }

/* ---------- Leadership: key team (pages/leadership.php) --------------------
   Sized to sit beside the founder cards rather than under them as a footnote
   (owner, 2026-10-10: "make the team a bit bigger"). */
.key-team-section { padding-bottom: 4rem; }
.key-team-heading { text-align: center; }
.key-team-lede {
    max-width: 36rem;
    margin: 0.75rem auto 0;
    text-align: center;
    color: var(--ink-500, #9AA1AC);
}
.key-team {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
    max-width: 72rem;
    margin: 1.5rem auto 0;
}
/* The founders carry a heading of the same size, so the wider team row does
   not read as more important than the founder pair above it. */
.founders-heading { margin-bottom: 1.5rem; text-align: center; }
@media (min-width: 1024px) {
    .key-team { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.key-team-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    padding: 2.25rem 1.25rem 2rem;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.018));
    text-align: center;
}
.key-team-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 5.5rem;
    height: 5.5rem;
    margin-bottom: 0.75rem;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 999px;
    background: #0B0C0E;
    font-size: 1.375rem;
    font-weight: 600;
    color: #33CFA7;
}
.key-team-name {
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -0.015em;
    color: #FFFFFF;
}
.key-team-role {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-400, #868D98);
}
@media print {
    .key-team-card { border-color: #CCCCCC !important; background: none !important; }
}
