/* ==========================================================================
   TOUCH — WCAG 2.2 target size (2.5.8) and coarse-pointer ergonomics
   --------------------------------------------------------------------------
   The desktop layouts use small, dense controls: 0.62rem labels with 3-5px
   padding. That is fine for a mouse and hostile for a thumb. Everything
   interactive below is raised to a 44x44px minimum on coarse pointers, which
   is the WCAG 2.2 AA target size and roughly a fingertip.

   Applied through (pointer: coarse) rather than a width query so a narrow
   desktop window keeps the dense layout while a phone gets the large targets.
   Purely additive: no existing rule is overridden, so the desktop design is
   untouched. Hover-only affordances get a matching :active state below,
   because a touch device never fires :hover.
   ========================================================================== */

/* ==========================================================================
   KEYBOARD FOCUS — the single focus ring for the whole site
   --------------------------------------------------------------------------
   WCAG 2.4.7 (Focus Visible, AA) and 1.4.11 (Non-text Contrast, AA).

   One declaration, here, because this sheet is loaded by every interactive
   page — the core pages and the member portals.
   Page and component sheets must never remove or re-declare this ring; if a
   component needs a different indicator it must ship that indicator in the
   same rule. A bare `outline: none` anywhere else is a regression.

   The shape: a 1px red ring held 2px off the element edge, with a 2px black
   ring filling the gap. The black ring is what keeps it legible on red and
   light surfaces; the red ring is what reads as "XtrCom" rather than as a
   UI alert. Measured contrast (ring vs adjacent colour):

     red   #FF0000 vs #000000 ... 5.25:1   vs #0A0A0A ... 4.95:1
     red   #FF0000 vs #FFFFFF ... 4.00:1   (worst case, light surfaces)
     black #000000 vs #FFFFFF ... 21.0:1
     black #000000 vs #FF0000 ... 5.25:1   (.direct__next focused state)

   [tabindex="-1"] targets are programmatic focus anchors (skip-to-content
   patterns, dialogs); they are not keyboard-reachable and get no ring.
   ========================================================================== */
:focus-visible:not([tabindex="-1"]) {
    outline: 1px solid var(--red, #ff0000);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--void, #000000);
}

@media (pointer: coarse) {
    /* Header menu button and the footer motion toggle. */
    .xfoot__motion,
    .xtop__hamb {
        min-height: 44px;
        min-width: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        padding-top: 10px;
        padding-bottom: 10px;
    }

    /* Generic small buttons across the site chrome and content pages. */
    .afterglow button,
    .xbtn,
    .btn-ghost,
    .tabs button,
    form.book button[type="submit"] {
        min-height: 44px;
    }

    /* Filter/registry controls: the pipeline stages and lifecycle filters. */
    .pipe,
    .docs-toc a,
    .dtoc a,
    .xfoot__links a,
    .crumbs a {
        min-height: 44px;
    }

    .pipe { display: inline-flex; align-items: center; }
    .dtoc a, .docs-toc a { display: flex; align-items: center; }

    /* The skip link is invisible until focused; keep it a real target. */
    .skip { min-height: 44px; display: inline-flex; align-items: center; }
}

/* --------------------------------------------------------------------------
   iOS FOCUS-ZOOM GUARD.
   Safari scales the whole viewport when a focused text control renders below
   16px, and does not scale back on blur — the page is left zoomed mid-field.
   These two controls still sit under 16px (.term__input at 0.875rem,
   .xsearch at 0.84rem). Held at 16px on touch pointers only, so the desktop
   density is untouched.
   -------------------------------------------------------------------------- */
@media (pointer: coarse) {
    .term__input,
    .xsearch {
        font-size: 16px;
    }
}

/* --------------------------------------------------------------------------
   Touch equivalents for hover-only interactions.
   A tap fires :active, not :hover, so any state that only exists under
   :hover is invisible on a phone. These mirror the hover treatments for
   press-and-hold.
   -------------------------------------------------------------------------- */
@media (pointer: coarse) {
    .eco-node-link:active,
    .xfoot__links a:active,
    .dtoc a:active,
    .docs-toc a:active { color: var(--red); }

    .xbtn:active,
    .btn-ghost:active { transform: translateY(1px); opacity: 0.82; }

    /* The ledger rows are the primary navigation on /projects. */
    .ledger__row:active { background: var(--surface-2); }
    .idx-row:active { background: var(--surface-2); }
}

/* --------------------------------------------------------------------------
   Reduced motion: honour the OS setting for CSS-driven animation too.
   The JS motion layer reads the same query in js/motion.js; this covers the
   transitions, sweeps and marquees that CSS owns.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* --------------------------------------------------------------------------
   Site-level nav for self-contained pages.
   The five ecosystem portals own
   their chrome and carry no shared header, so they had no site navigation at
   all. These are the two nav shapes added to give them a crawlable, tappable
   path back into the site.
   Deliberately unstyled-looking: muted, small, and out of the way of whatever
   visual system the page already has.
   -------------------------------------------------------------------------- */
.sitenav {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 20px;
    justify-content: center;
    padding: 22px 20px;
    border-top: 1px solid rgba(0, 0, 0, 0.12);
    font-size: 0.78rem;
}
.sitenav a { color: #555; text-decoration: none; }
.sitenav a:hover, .sitenav a:focus-visible { color: #000; text-decoration: underline; }

.xt-hub {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 18px;
    padding: 14px 22px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
    font-size: 0.72rem;
    letter-spacing: 0.06em;
}
.xt-hub__label { opacity: 0.5; letter-spacing: 0.16em; }
.xt-hub a { color: inherit; opacity: 0.72; text-decoration: none; }
.xt-hub a:hover, .xt-hub a:focus-visible { opacity: 1; text-decoration: underline; }

@media (pointer: coarse) {
    .sitenav a, .xt-hub a { min-height: 44px; display: inline-flex; align-items: center; }
}

/* The compatibility dossier list on /project?id= — the one page that lists
   every dossier by name, since the id is in the query and no single dossier
   can be prerendered there. */
.dossierlist { list-style: none; margin: 22px 0; padding: 0; }
.dossierlist li {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 12px;
    align-items: baseline;
    padding: 11px 0;
    border-bottom: 1px solid var(--border-1);
}
.dossierlist li a { font-weight: 700; }
.dossierlist li span { color: var(--text-3); font-size: 0.78rem; letter-spacing: 0.06em; }
@media (pointer: coarse) {
    .dossierlist li a { min-height: 44px; display: inline-flex; align-items: center; }
}

/* --------------------------------------------------------------------------
   R&D disclosure on /projects.
   Private systems are labelled, not hidden — the disclosure says so, so the
   marker has to read as a statement of maturity rather than as an apology.
   -------------------------------------------------------------------------- */
.rnd {
    margin: 44px 0 8px;
    padding: 26px 22px;
    border: 1px solid var(--border-2);
    background: linear-gradient(180deg, var(--surface-1), transparent 70%);
}
.rnd h2 { margin: 0 0 14px; font-size: clamp(1.1rem, 3.4vw, 1.5rem); }
.rnd p { margin: 0 0 12px; max-width: 68ch; color: var(--text-2); line-height: 1.75; font-size: 0.9rem; }
.rnd strong { color: var(--text-1); }
.rnd__lead {
    color: var(--text-1) !important;
    font-size: 1rem !important;
    border-left: 2px solid var(--red);
    padding-left: 14px;
}
.rnd__lineage { margin: 0 0 14px 18px; padding: 0; list-style: none; max-width: 68ch; }
.rnd__lineage li {
    padding: 7px 0;
    border-bottom: 1px solid var(--border-1);
    color: var(--text-2);
    font-size: 0.86rem;
}
.rnd__lineage a { color: var(--red); font-weight: 700; }
.rnd__lineage code {
    font-family: 'Share Tech Mono', monospace;
    color: var(--text-3);
    font-size: 0.9em;
}
.rnd__note { color: var(--text-3) !important; font-size: 0.82rem !important; font-style: italic; }

/* Private rows read as "not a public edition", not as "hidden". */
.ledger__row--private { opacity: 0.72; border-left: 2px dashed var(--border-2); }
.ledger__row--private:hover { opacity: 1; }
.ledger__priv {
    display: inline-block;
    margin-right: 8px;
    padding: 1px 6px;
    border: 1px solid var(--red-dim);
    color: var(--red);
    font-size: 0.6rem;
    letter-spacing: 0.14em;
    vertical-align: 1px;
}
.stag--private { border-color: var(--red-dim); color: var(--red); }

.dsec--notice {
    border: 1px solid var(--red-dim);
    border-left-width: 3px;
    padding-left: 16px;
    margin: 0 0 28px;
}
.dsec--notice p { color: var(--text-2); }
.dsec--notice a { color: var(--red); }

/* --------------------------------------------------------------------------
   MOBILE EFFECT BUDGET

   Tap targets and a "no hover" pass do not cost frames. Ambient loops do: every
   one of these is a keyframe animation that never stops, so it holds a composited
   layer and asks for a frame forever, for the whole time the page is open. A
   desktop has the headroom to not care. A phone does not, and the cost shows up
   as the page feeling heavy while you scroll — which reads as the animation
   system being slow rather than the decoration being expensive.

   What is reduced here is decoration that is *ambient*: the site reads the same
   without it. What is NOT reduced is the entrance and the scroll reveals, which
   carry meaning and which a visitor actually waits for.

   Deliberately not touched: prefers-reduced-motion stays the only thing that
   switches motion off outright. This profile softens cost, it does not override
   an accessibility preference.
   -------------------------------------------------------------------------- */
@media (pointer: coarse) {

    /* The kicker rule draws a 5s shimmer sweep forever. It is 40x2px of red
       gradient doing nothing but repainting. Slowed to a stop-state sweep so it
       still reads as "live" without a permanent repaint loop. */
    .xkicker__line { animation: none; opacity: 0.7; }

    /* A hero caret is a nice touch at rest and pure cost in motion: a 1.1s
       steps(2) blink is ~1.8 repaints a second for the life of the page. */
    .entry-hero h1 .cursor { animation: none; opacity: 0.85; }

    /* Status dots and live indicators pulse on opacity only, which is cheap, but
       there are several of them per page and none of them is load-bearing. */
    .sdot--active,
    .xtop__dot,
    .live { animation: none; }

    /* Pseudo-element sweeps that only exist as motion. Stopping the animation
       leaves whatever the element settles at, which keeps it visible — these
       are decorative, not content, but nothing here should hide a heading. */
    .sec.in-view .sec-title::after { animation: none; }

    /* Hover-lift and magnetic handlers are already inert without a pointer;
       this makes sure a stray synthetic hover cannot promote a layer either. */
    .pcard, .card, .cmdline, .gw { transition: none; }

    /* The transit overlay is deliberately NOT disabled here. It is a designed
       part of the route change, and after XM.afterTransit() serialises the
       scene against the page's entrance it is no longer the contention it used
       to be — the scene now animates alone. It stays on mobile. */
}

/* --------------------------------------------------------------------------
   CROSS-DOCUMENT VIEW TRANSITIONS.
   A short browser-driven crossfade between pages. The browser owns the timing,
   so navigation is never gated behind the animation (the site's departure
   model is "navigate first"), and browsers without support ignore the block
   entirely. Reduced motion turns it off.
   -------------------------------------------------------------------------- */
@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root) {
    animation-duration: 220ms;
    animation-timing-function: cubic-bezier(0.2, 0.7, 0.2, 1);
}

@media (prefers-reduced-motion: reduce) {
    ::view-transition-group(*),
    ::view-transition-old(*),
    ::view-transition-new(*) { animation: none !important; }
}
