/* Xi Software theme for the xi layout.
 *
 * Colours, fonts and spacing come from theme.json's config section, emitted by
 * the processor as --theme-GROUP-KEY. Recolour by editing theme.json.
 *
 * The one rule that decides whether this palette reads as confident or dated:
 * MAGENTA IS AN ACCENT ON A NEUTRAL BASE, NEVER A BACKGROUND. Links, buttons,
 * active states, focus rings, the top rule, table row highlights. Where a band
 * is wanted, use background-alt or background-accent; where a dark band is
 * wanted, use structure (navy). One or two full-strength magenta moments per
 * page. See ../../../../../../DESIGN-SYSTEM.md.
 */

*, *::before, *::after { box-sizing: border-box; }

:where(a, button, input, textarea, select, summary):focus-visible {
    outline: 2px solid var(--theme-colours-primary);
    outline-offset: 2px;
}

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    /* The top rule: a single decisive stripe of brand colour above an
       otherwise neutral page. The brand's work, done without a coloured panel. */
    border-top: var(--theme-spacing-rule) solid var(--theme-colours-primary);
    background: var(--theme-colours-background);
    color: var(--theme-colours-text);
    font-family: var(--theme-fonts-body);
    font-size: 16px;
    line-height: 1.5;
    overflow-x: hidden;
    /* The site carries version numbers, release dates, port numbers and
       comparison tables. Line the digits up. */
    font-variant-numeric: tabular-nums;
}

.xi-in { width: 100%; max-width: var(--theme-spacing-wide); margin: 0 auto; padding: 0 1.25rem; }

.xi-skip { position: absolute; left: -9999px; }
.xi-skip:focus {
    position: static; display: inline-block; margin: .5rem;
    padding: .6rem 1rem; background: var(--theme-colours-primary);
    color: var(--theme-colours-primary-text); text-decoration: none;
}

/* ---- Header and navigation ------------------------------------------------
   Mobile first: the nav collapses behind a toggle below 60rem. No layout
   depends on the script running. */

/* Header layout.
 *
 * One row on a wide screen: mark on the left, navigation pushed right, a
 * compact search at the far end. Below 60rem the navigation AND the search
 * both collapse into the panel behind the menu button - putting the search in
 * the bar next to the button made both of them fight for the same few
 * centimetres, and neither had enough.
 */
.xi-head { background: var(--theme-colours-background); border-bottom: 1px solid var(--theme-colours-border); }
.xi-head .xi-in {
    display: flex; flex-wrap: wrap; align-items: center;
    gap: .6rem 1rem; padding-top: .8rem; padding-bottom: .8rem;
}
.xi-mark { display: inline-flex; align-items: center; margin-right: auto; text-decoration: none; color: var(--theme-colours-heading); font-weight: 700; font-size: 1.15rem; }
.xi-mark img { display: block; height: 32px; width: auto; }

.xi-nav-toggle {
    display: inline-flex; align-items: center; gap: .45rem;
    background: none; cursor: pointer; flex: 0 0 auto;
    border: 1px solid var(--theme-colours-border); border-radius: var(--theme-spacing-radius);
    color: var(--theme-colours-heading); font: inherit; font-size: .9rem; line-height: 1;
    padding: .5rem .7rem;
}
.xi-nav-toggle::before { content: "\2630"; font-size: 1.05rem; }
.xi-nav-toggle:hover { border-color: var(--theme-colours-primary); color: var(--theme-colours-primary); }

/* Collapsed state: the panel holds the search and then the navigation. */
.xi-nav, .xi-search { display: none; width: 100%; order: 5; }
body.xi-nav-open .xi-nav, body.xi-nav-open .xi-search { display: block; }
body.xi-nav-open .xi-search { display: flex; }

.xi-nav ul { list-style: none; margin: 0; padding: 0; }
.xi-nav > ul > li { border-top: 1px solid var(--theme-colours-border); }
.xi-nav a, .xi-nav-group {
    display: block; padding: .6rem 0; text-decoration: none;
    color: var(--theme-colours-text); font-size: .97rem;
}
.xi-nav a:hover, .xi-nav a:focus { color: var(--theme-colours-primary); }
.xi-nav a.active { color: var(--theme-colours-primary); font-weight: 600; }
.xi-nav-group { color: var(--theme-colours-text-muted); font-weight: 600; }
.xi-nav ul ul { padding-left: 1rem; padding-bottom: .4rem; }
.xi-nav ul ul a { padding: .35rem 0; color: var(--theme-colours-text-muted); }

@media (min-width: 62rem) {
    .xi-nav-toggle { display: none; }
    /* Order rather than DOM position. In the collapsed panel the search sits
       at the TOP, above a list that runs to sixteen items - a control below
       that list is one nobody scrolls to. On a wide screen there is no list to
       bury it under, so it belongs at the far end instead. */
    .xi-nav { display: block; width: auto; order: 1; }
    .xi-search { display: flex; width: auto; order: 2; flex: 0 0 12.5rem; margin-left: 1.4rem; }

    .xi-nav > ul { display: flex; gap: 1.35rem; align-items: center; }
    .xi-nav > ul > li { border-top: 0; position: relative; }
    .xi-nav a, .xi-nav-group { padding: .3rem 0; font-size: .95rem; white-space: nowrap; }

    /* The panel is FLUSH with the parent item. A margin here leaves a dead
       strip between the two, and the pointer crosses it on the way to a child,
       which closes the menu. Visual separation comes from the brand rule on the
       panel's own top edge instead. */
    .xi-nav > ul > li.has-kids > a,
    .xi-nav > ul > li.has-kids > .xi-nav-group { padding-bottom: .95rem; margin-bottom: -.65rem; }
    .xi-nav li.has-kids > ul {
        display: none; position: absolute; top: 100%; left: -.9rem; z-index: 30;
        min-width: 14rem; padding: .6rem .9rem .7rem; margin-top: 0;
        background: var(--theme-colours-background);
        border: 1px solid var(--theme-colours-border);
        border-top: 3px solid var(--theme-colours-primary);
        box-shadow: 0 6px 18px var(--theme-colours-shadow);
    }
    .xi-nav li.has-kids > ul a { white-space: normal; }
    .xi-nav li.has-kids:hover > ul, .xi-nav li.has-kids:focus-within > ul { display: block; }
}

/* ---- Page ---------------------------------------------------------------- */

.xi-main { padding: 2.5rem 0 3.5rem; }

.xi-title {
    font-size: clamp(1.8rem, 4.5vw, 2.6rem); line-height: 1.15; letter-spacing: -.01em;
    color: var(--theme-colours-heading); margin: 0 0 .6rem; max-width: 22em;
}
/* The signature rule: the top rule at object scale. Once in a reader's view,
   or it stops meaning anything - so it sits on the page title and nowhere else. */
.xi-title::before {
    content: ""; display: block; width: 56px; height: 4px;
    background: var(--theme-colours-primary); margin-bottom: 1rem;
}
.xi-standfirst {
    font-size: clamp(1.05rem, 2.2vw, 1.25rem); color: var(--theme-colours-text-muted);
    margin: 0 0 2rem; max-width: var(--theme-spacing-measure);
}

/* The body is a 6-column grid so that CARD BLOCKS can sit side by side with no
   wrapper element. A PLAIN decorative ::: fence does not nest, and Markdown inside
   a raw <div> is left verbatim, so a wrapper div is not available here.
   (Correction: COMPONENT fences - a ::: name matching components/name.tt - are
   nesting-aware and take child fences as slots, per D035 Phase 2. This layout
   has no components directory, so that route was not open to it.) Everything that is
   not a card spans the full width and behaves exactly as it would in normal flow. */
.xi-body { display: grid; grid-template-columns: repeat(6, 1fr); gap: 0 1.2rem; align-content: start; max-width: var(--theme-spacing-wide); }
.xi-body > * { grid-column: 1 / -1; min-width: 0; }
.xi-body > p, .xi-body > ul, .xi-body > ol, .xi-body > dl, .xi-body > blockquote {
    max-width: var(--theme-spacing-measure);
}

h2, h3, h4, h5, h6 { color: var(--theme-colours-heading); line-height: 1.25; }
h2 { font-size: clamp(1.35rem, 2.8vw, 1.7rem); font-weight: 700; margin: 2.4rem 0 .7rem; }
h3 { font-size: 1.18rem; font-weight: 700; margin: 1.8rem 0 .5rem; }
h4 { font-size: 1.03rem; font-weight: 600; margin: 1.4rem 0 .4rem; }
h5, h6 { font-size: .97rem; font-weight: 600; margin: 1.2rem 0 .35rem; color: var(--theme-colours-text-muted); }
p { margin: 0 0 1.05rem; }

a { color: var(--theme-colours-primary); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover, a:focus { color: var(--theme-colours-primary-hover); }

ul, ol { padding-left: 1.3rem; margin: 0 0 1.05rem; }
li { margin-bottom: .35rem; }

dl { margin: 1.2rem 0; max-width: var(--theme-spacing-measure); }
dt { font-weight: 600; color: var(--theme-colours-heading); margin-top: 1rem; }
dd { margin: .2rem 0 0; color: var(--theme-colours-text-muted); }

code, kbd, samp { font-family: var(--theme-fonts-code); font-size: .92em; }
:not(pre) > code {
    background: var(--theme-colours-background-alt); padding: .12em .35em;
    border: 1px solid var(--theme-colours-border); border-radius: 3px;
}
pre {
    background: var(--theme-colours-background-alt); border: 1px solid var(--theme-colours-border);
    border-left: 3px solid var(--theme-colours-structure);
    padding: .9rem 1rem; overflow-x: auto; font-size: .9rem; line-height: 1.45;
}
pre code { background: none; border: 0; padding: 0; }

blockquote {
    margin: 1.4rem 0; padding: .2rem 0 .2rem 1.1rem;
    border-left: 3px solid var(--theme-colours-primary);
    color: var(--theme-colours-text-muted);
}

img { max-width: 100%; height: auto; }
hr { border: 0; border-top: 1px solid var(--theme-colours-border); margin: 2.2rem 0; }

/* ---- Tables ---------------------------------------------------------------
   Four pages carry comparison or matrix tables that must stay legible on a
   phone, so the table scrolls inside its own box rather than the page. */

.xi-body table { display: block; max-width: 100%; overflow-x: auto; margin: 1.4rem 0; font-size: .95rem; }
table { border-collapse: separate; border-spacing: 0 .25em; }
th, td { text-align: left; padding: .55rem .8rem; vertical-align: top; }
thead th {
    color: var(--theme-colours-heading); font-weight: 700; white-space: nowrap;
    border-bottom: 2px solid var(--theme-colours-structure);
}
tbody tr { background: var(--theme-colours-background-alt); }
tbody tr:hover { background: var(--theme-colours-background-accent); }
tbody td:first-child { white-space: nowrap; font-weight: 600; color: var(--theme-colours-heading); }
@media (max-width: 40rem) { tbody td:first-child { white-space: normal; } }

/* Availability emphasis. Rows carry data-av from the platform data itself, so
   the weight follows the data and no class is applied by hand. What is built
   for every release is what most readers came for, so it carries the most
   weight; a retired row stays fully readable but recedes, so a scan lands on
   what is current. This dims weight and saturation only - the muted token is
   the same one the subtitles use, so legibility is unchanged. */
tbody tr[data-av="routine"] td { font-weight: 600; }
tbody tr[data-av="routine"] td:first-child { font-weight: 700; }
tbody tr[data-av="retired"] { background: transparent; }
tbody tr[data-av="retired"]:hover { background: var(--theme-colours-background-alt); }
tbody tr[data-av="retired"] td { color: var(--theme-colours-text-muted); font-weight: 400; }
tbody tr[data-av="retired"] td:first-child { color: var(--theme-colours-text-muted); font-weight: 500; }

/* A per-row note. <details> so it needs no script, opens on click or keyboard,
   and is readable with the disclosure closed - the row still says what it is
   without it. Kept quiet: the summary is a small muted affordance rather than a
   control competing with the platform name beside it. */
td .xi-note { margin: .35rem 0 0; }
td .xi-note > summary {
    display: inline-block; cursor: pointer; font-size: .78rem; letter-spacing: .04em;
    text-transform: uppercase; color: var(--theme-colours-text-muted);
    border: 1px solid var(--theme-colours-border); border-radius: 999px;
    padding: .05rem .5rem; font-weight: 500; white-space: nowrap;
}
td .xi-note > summary:hover { color: var(--theme-colours-heading); border-color: var(--theme-colours-structure); }
td .xi-note[open] > summary { margin-bottom: .3rem; }
td .xi-note > span { display: block; max-width: 22rem; font-weight: 400; font-size: .9rem; white-space: normal; }

/* ---- Blocks ---------------------------------------------------------------
   The ::: blocks the drafts use. Where a layout has no component by that name
   lazysite falls back to a plain div, so these are styled by class. */

.widebox, .textbox, .examplebox, .marginbox, .recommendation {
    border-radius: var(--theme-spacing-radius);
}

/* Full-width statement. Neutral ground with a brand rule, never a magenta panel. */
.widebox {
    background: var(--theme-colours-background-alt);
    border: 1px solid var(--theme-colours-border);
    border-top: 4px solid var(--theme-colours-primary);
    padding: 1.4rem 1.5rem; margin: 1.8rem 0;
}
.widebox > :first-child { margin-top: 0; }
.widebox > :last-child { margin-bottom: 0; }

/* Callout, and the comparison-box pattern the competitor review found most
   persuasive in this market: a tinted box, a heading, a ticked list. */
.textbox, .recommendation {
    background: var(--theme-colours-background-accent);
    border: 1px solid var(--theme-colours-border);
    padding: 1.2rem 1.3rem; margin: 1.6rem 0;
    max-width: var(--theme-spacing-measure);
}
.textbox > :first-child, .recommendation > :first-child { margin-top: 0; }
.textbox > :last-child, .recommendation > :last-child { margin-bottom: 0; }

/* Evidence. */
.examplebox {
    background: var(--theme-colours-background); border: 1px solid var(--theme-colours-border);
    border-left: 4px solid var(--theme-colours-structure);
    padding: 1.1rem 1.3rem; margin: 1.6rem 0;
    max-width: var(--theme-spacing-measure);
}
.examplebox > :first-child { margin-top: 0; }
.examplebox > :last-child { margin-bottom: 0; }

/* Pull quote, never a carousel.
   NOTE: this used to float right on a wide screen. `.xi-body` is a grid, and
   float is ignored on a grid item, so the rule did nothing except leave the
   quote narrow with dead space beside it. In the flow at the reading measure
   is both honest and better to read. */
.marginbox {
    border-left: 4px solid var(--theme-colours-primary);
    background: var(--theme-colours-background-alt);
    padding: 1rem 1.2rem; margin: 1.6rem 0;
    max-width: var(--theme-spacing-measure);
    color: var(--theme-colours-text); font-size: .98rem;
}
.marginbox > :first-child { margin-top: 0; }
.marginbox > :last-child { margin-bottom: 0; }

/* ---- Buttons --------------------------------------------------------------
   Solid brand with white text at 6.11 contrast, which passes AA. Hover by
   brightness rather than by hue change. */

.xi-btn, a.xi-btn {
    display: inline-block; padding: .65rem 1.35rem; margin: .2rem .4rem .2rem 0;
    background: var(--theme-colours-primary); color: var(--theme-colours-primary-text);
    border: 0; border-radius: var(--theme-spacing-radius);
    font-weight: 600; font-size: .97rem; text-decoration: none; cursor: pointer;
}
.xi-btn:hover, a.xi-btn:hover, .xi-btn:focus, a.xi-btn:focus {
    background: var(--theme-colours-primary-hover); color: var(--theme-colours-primary-text);
}
.xi-btn-quiet, a.xi-btn-quiet {
    background: transparent; color: var(--theme-colours-primary);
    border: 2px solid var(--theme-colours-primary);
}
.xi-btn-quiet:hover, a.xi-btn-quiet:hover {
    background: var(--theme-colours-background-accent); color: var(--theme-colours-primary-hover);
}

/* ---- Forms ----------------------------------------------------------------
   The enquiry form is the site's primary conversion point. Full width on a
   phone, never wider than the reading measure. */

form { max-width: 36rem; margin: 1.4rem 0 0; }
.form-field { margin-bottom: 1rem; }
form label { display: block; font-size: .93rem; font-weight: 600; color: var(--theme-colours-heading); margin-bottom: .3rem; }
form input, form select, form textarea {
    width: 100%; font: inherit; font-size: 1rem; padding: .6rem .7rem;
    background: var(--theme-colours-background); color: var(--theme-colours-text);
    border: 1px solid var(--theme-colours-border); border-radius: var(--theme-spacing-radius);
}
form textarea { min-height: 9rem; resize: vertical; }
form button, form input[type="submit"] {
    width: auto; margin-top: .6rem; cursor: pointer; font-weight: 600;
    background: var(--theme-colours-primary); color: var(--theme-colours-primary-text); border: 0;
    padding: .7rem 1.5rem;
}
form button:hover, form input[type="submit"]:hover { background: var(--theme-colours-primary-hover); }
.form-status, .form-success { margin-top: 1rem; }

.xi-modified { margin-top: 2.5rem; font-size: .88rem; color: var(--theme-colours-text-dim); }

/* ---- Footer ---------------------------------------------------------------
   The top rule again, above the footer. */

.xi-foot {
    border-top: var(--theme-spacing-rule) solid var(--theme-colours-primary);
    background: var(--theme-colours-background-alt);
    margin-top: 3rem; padding: 2.2rem 0 1.6rem;
}
.xi-foot-cols { display: grid; grid-template-columns: 1fr; gap: 1.6rem; }
@media (min-width: 40rem) { .xi-foot-cols { grid-template-columns: repeat(3, 1fr); } }
.xi-foot h2 {
    font-size: .8rem; text-transform: uppercase; letter-spacing: .07em;
    color: var(--theme-colours-text-muted); margin: 0 0 .6rem;
}
.xi-foot ul { list-style: none; margin: 0; padding: 0; }
.xi-foot li { margin-bottom: .35rem; }
.xi-foot a { color: var(--theme-colours-text); text-decoration: none; font-size: .95rem; }
.xi-foot a:hover, .xi-foot a:focus { color: var(--theme-colours-primary); text-decoration: underline; }
.xi-legal {
    display: flex; flex-wrap: wrap; gap: .4rem 1.5rem;
    margin: 1.8rem 0 0; padding-top: 1.1rem;
    border-top: 1px solid var(--theme-colours-border);
    font-size: .85rem; color: var(--theme-colours-text-muted);
}
.xi-legal a { color: var(--theme-colours-text-muted); }

/* ---- Reduced motion -------------------------------------------------------
   The portal already honours this and anything added here must too. */

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important; animation-iteration-count: 1 !important;
        transition-duration: .01ms !important; scroll-behavior: auto !important;
    }
}

@media print {
    body { border-top: 0; }
    .xi-head, .xi-foot, .xi-skip, .xi-nav-toggle { display: none; }
    .xi-body { max-width: none; }
}

/* ---- Product-site components ----------------------------------------------
 * Added after review: the first build read as a document rather than a product
 * site. The remedy the design notes call for is structure and DRAWINGS, not
 * photography - "product interface, architecture diagrams, or nothing".
 */

/* Hero. One headline, one supporting sentence, one primary action. No carousel.
   The band is neutral with a brand rule, because magenta is an accent. */
.xi-hero {
    background: var(--theme-colours-background-alt);
    border: 1px solid var(--theme-colours-border);
    border-top: 4px solid var(--theme-colours-primary);
    padding: 2rem 1.8rem 1.8rem; margin: 0 0 1.2rem;
}
@media (min-width: 62rem) { .xi-hero { padding: 2.6rem 2.4rem 2.4rem; } }
.xi-hero > :first-child { margin-top: 0; }
.xi-hero > :last-child { margin-bottom: 0; }
.xi-hero p { max-width: 40em; }
.xi-hero h1, .xi-hero h2, .xi-hero .xi-hero-title {
    font-size: clamp(1.9rem, 4.2vw, 2.75rem); line-height: 1.12; letter-spacing: -.015em;
    color: var(--theme-colours-heading); margin: 0 0 .9rem; max-width: 16em;
}
.xi-hero h1::before, .xi-hero h2::before, .xi-hero .xi-hero-title::before {
    content: ""; display: block; width: 56px; height: 4px;
    background: var(--theme-colours-primary); margin-bottom: 1rem;
}
.xi-hero p { font-size: 1.12rem; color: var(--theme-colours-text-muted); max-width: 34em; }
.xi-hero-actions { margin-top: 1.4rem; }
.xi-hero-figure img { display: block; width: 100%; height: auto;
    border: 1px solid var(--theme-colours-border); background: var(--theme-colours-background); }

/* Proof strip. Longevity and platforms are the honest proof here, and no
   competitor can match the dates. */
.xi-proof {
    background: var(--theme-colours-structure); color: #FFFFFF;
    padding: .95rem 1.8rem; margin: 0 0 2.4rem; font-size: .92rem;
    display: flex; flex-wrap: wrap; gap: .5rem 2.2rem; align-items: baseline;
}
.xi-proof p { margin: 0; color: #C9CEDA; max-width: none; }
.xi-proof strong { color: #FFFFFF; font-weight: 700; }
.xi-proof span { color: #C9CEDA; }

/* Card grid for products and capabilities. */
/* Cards are individual ::: blocks placed on the body grid. Full width on a
   phone, two up from 44rem, three up from 56rem. */
.xi-body > .xi-card { margin: .6rem 0 1.2rem; }
/* align-self stops a row of cards stretching to match its tallest member,
   which leaves the shorter ones with a block of empty space underneath. */
.xi-body > .xi-card { align-self: start; }
@media (min-width: 44rem) { .xi-body > .xi-card { grid-column: span 3; } }
@media (min-width: 56rem) { .xi-body > .xi-card { grid-column: span 2; } }
/* A page whose groups are fours and fives reads better two across: three
   leaves an orphan on the second row. Set `cards: 2` in the page front matter
   under tt_page_var. */
@media (min-width: 44rem) { .xi-body.cards-2 > .xi-card { grid-column: span 3; } }
.xi-card {
    background: var(--theme-colours-background); border: 1px solid var(--theme-colours-border);
    border-top: 3px solid var(--theme-colours-primary);
    padding: 1.2rem 1.3rem 1.3rem; display: flex; flex-direction: column;
}
.xi-card h3 { margin-top: 0; }
.xi-card p { color: var(--theme-colours-text-muted); font-size: .96rem; }
.xi-card > :last-child { margin-top: auto; margin-bottom: 0; padding-top: .6rem; }
/* The eyebrow is the card's first paragraph, so it needs no class of its own -
   which matters because a ::: block's body is Markdown and cannot carry one. */
.xi-card > p:first-child, .xi-card .xi-card-tag {
    font-size: .74rem; text-transform: uppercase; letter-spacing: .08em; font-weight: 700;
    color: var(--theme-colours-primary); margin-bottom: .35rem;
}
.xi-card > h3 { margin-top: 0; }
.xi-card > p:last-of-type { margin-bottom: 0; }

/* Figures: diagrams and product screenshots, the two image types this site
   uses. Full content width, captioned, and scrollable rather than shrunk. */
.xi-figure { margin: 2rem 0; max-width: 100%; }
.xi-figure img, .xi-figure object {
    display: block; width: 100%; height: auto;
    border: 1px solid var(--theme-colours-border);
    background: var(--theme-colours-background);
}
.xi-figure figcaption {
    margin-top: .6rem; font-size: .9rem; color: var(--theme-colours-text-muted);
    max-width: var(--theme-spacing-measure);
}
.xi-figure.is-placeholder img { border-style: dashed; border-color: var(--theme-colours-primary); }
.xi-figure.is-placeholder figcaption::before {
    content: "Placeholder. "; color: var(--theme-colours-primary); font-weight: 700;
}

/* ---- Site search ----------------------------------------------------------
 * A plain GET form to /search-results, so it works with scripting disabled.
 */
.xi-vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.xi-search { gap: .35rem; }
.xi-search input {
    flex: 1 1 auto; min-width: 0; font: inherit; font-size: .92rem; padding: .42rem .65rem;
    border: 1px solid var(--theme-colours-border); border-radius: var(--theme-spacing-radius);
    background: var(--theme-colours-background); color: var(--theme-colours-text);
}
.xi-search button {
    font: inherit; font-size: .9rem; font-weight: 600; padding: .42rem .9rem; cursor: pointer;
    border: 1px solid var(--theme-colours-primary); border-radius: var(--theme-spacing-radius);
    background: var(--theme-colours-primary); color: var(--theme-colours-primary-text);
}
.xi-search button:hover { background: var(--theme-colours-primary-hover); border-color: var(--theme-colours-primary-hover); }
@media (min-width: 62rem) {
    .xi-search button { padding: .42rem .7rem; font-size: .85rem; }
}

/* ---- Browse and filter ----------------------------------------------------
 * The knowledge base is 55 articles. A filter box in front of a grouped list
 * is the difference between a browse interface and a wall of links.
 */
.xi-filter { margin: 1.4rem 0 .6rem; }
.xi-filter input {
    width: 100%; max-width: 28rem; font: inherit; font-size: 1rem; padding: .6rem .75rem;
    border: 1px solid var(--theme-colours-border); border-radius: var(--theme-spacing-radius);
}
.xi-filter-count { margin: .5rem 0 0; font-size: .9rem; color: var(--theme-colours-text-muted); }
.xi-kb-group[hidden], .xi-kb-item[hidden] { display: none; }
.xi-kb-item { margin: 0 0 1rem; }
.xi-kb-item a { font-weight: 600; }
/* Target the subtitle by class. A bare `.xi-kb-item span` also matches the tag
   chips and, being more specific than `.xi-kb-tag`, turns every chip into a
   full-width block. */
.xi-kb-item .xi-kb-sub { display: block; color: var(--theme-colours-text-muted); font-size: .93rem; }
.xi-kb-tags { margin: .25rem 0 0; display: flex; flex-wrap: wrap; gap: .25rem; }
.xi-kb-item .xi-kb-tag {
    display: inline-block; width: auto; font-size: .72rem; letter-spacing: .04em; text-transform: uppercase;
    background: var(--theme-colours-background-alt); color: var(--theme-colours-text-muted);
    border: 1px solid var(--theme-colours-border); border-radius: 999px;
    padding: .08rem .5rem; margin: 0;
}

/* ---- Documentation layout -------------------------------------------------
 * Release notes and any long reference page: a sticky contents column beside
 * the body, collapsing to a plain list on a phone.
 */
.xi-doc-toc { margin: 1.6rem 0; }
.xi-doc-toc h2 { margin-top: 0; font-size: .82rem; text-transform: uppercase; letter-spacing: .07em; color: var(--theme-colours-text-muted); }
.xi-doc-toc ol { list-style: none; margin: 0; padding: 0; font-size: .92rem; }
.xi-doc-toc li { margin-bottom: .55rem; display: flex; flex-direction: column; gap: .1rem; }
/* The item leads; the severity is the qualifier, so it follows in a smaller,
   quieter line rather than shouting above every title. */
.xi-doc-toc .xi-sev { font-size: .72rem; text-transform: uppercase; letter-spacing: .05em; }
.xi-doc-toc a { text-decoration: none; }
.xi-doc-toc a:hover { text-decoration: underline; }
@media (min-width: 62rem) {
    .xi-body.has-toc { grid-template-columns: 16rem 1fr; gap: 0 2.6rem; }
    .xi-body.has-toc > * { grid-column: 2; }
    .xi-body.has-toc > .xi-doc-toc {
        grid-column: 1; grid-row: 1 / span 999; align-self: start;
        position: sticky; top: 1.5rem; max-height: calc(100vh - 3rem); overflow-y: auto;
        border-right: 1px solid var(--theme-colours-border); padding-right: 1.2rem;
    }
}

/* Severity marks in the release notes. */
.xi-sev { font-weight: 700; }
.xi-sev-critical { color: #B3261E; }
.xi-sev-high     { color: #A72E90; }
.xi-sev-medium   { color: #8A6100; }
.xi-sev-low, .xi-sev-info { color: var(--theme-colours-text-muted); }

/* ---- Distributor map ------------------------------------------------------
 * Reproduces the live site's two-tone map: countries where a distributor is
 * based read differently from countries they merely cover. Colours are the
 * brand magenta and its light tint rather than the live page's #ff73e5, which
 * is not in the palette.
 */
.xi-map { margin: 1.4rem 0 .5rem; }
.xi-map-legend { display: flex; flex-wrap: wrap; gap: .4rem 1.6rem; margin: 0 0 .8rem; font-size: .9rem; color: var(--theme-colours-text-muted); }
.xi-map-legend span { display: inline-flex; align-items: center; gap: .45rem; }
.xi-key { width: .8rem; height: .8rem; border-radius: 2px; display: inline-block; }
.xi-key-base  { background: var(--theme-colours-primary-light); }
.xi-key-cover { background: var(--theme-colours-primary); }

.xi-map-holder { width: 100%; }
.xi-map-holder svg { display: block; width: 100%; height: auto; }
/* Every country starts neutral; only the ones in the data are lit.
   A country made of several parts - the United States with Alaska, Canada and
   the United Kingdom with their islands - is a <g> of paths, not a single
   path, so the class lands on the GROUP. Colour the element and its
   descendants, or the multi-part countries stay grey while single-path ones
   light correctly. */
.xi-map-holder svg path { fill: #D9DCE1; stroke: #FFFFFF; stroke-width: .4; transition: fill .12s ease; }
.xi-map-holder svg .is-cover, .xi-map-holder svg .is-cover path { fill: var(--theme-colours-primary); cursor: pointer; }
.xi-map-holder svg .is-base,  .xi-map-holder svg .is-base path  { fill: var(--theme-colours-primary-light); cursor: pointer; }
.xi-map-holder svg .is-cover:hover, .xi-map-holder svg .is-cover:hover path,
.xi-map-holder svg .is-base:hover,  .xi-map-holder svg .is-base:hover path { fill: var(--theme-colours-primary-hover); }
.xi-map-holder svg .is-active, .xi-map-holder svg .is-active path { fill: var(--theme-colours-structure); }
/* Unserved countries are clickable too - selecting one says we supply it
   directly and offers the distributorship. They stay neutral until hovered so
   the legend still means what it says. */
.xi-map-holder svg .is-clickable { cursor: pointer; }
.xi-map-holder svg .is-clickable:hover path,
.xi-map-holder svg path.is-clickable:hover { fill: #BFC4CC; }
.xi-map-holder svg .is-cover:hover, .xi-map-holder svg .is-cover:hover path,
.xi-map-holder svg .is-base:hover,  .xi-map-holder svg .is-base:hover path { fill: var(--theme-colours-primary-hover); }
.xi-map-alt { margin: .7rem 0 0; font-size: .9rem; color: var(--theme-colours-text-muted); }
.xi-map-panel .xi-btn { margin-top: .5rem; }
.xi-map-holder svg .is-cover:focus-visible, .xi-map-holder svg .is-base:focus-visible { outline: 2px solid var(--theme-colours-structure); }

/* The card floats over the map at the pointer and is clamped inside it, so it
   never hangs off the edge of the screen. */
.xi-map-holder { position: relative; }
.xi-map-pop {
    position: absolute; z-index: 30; width: min(21rem, calc(100% - 1rem));
    max-height: 26rem; overflow-y: auto;
    background: var(--theme-colours-background);
    border: 1px solid var(--theme-colours-border); border-radius: 10px;
    box-shadow: 0 8px 28px rgba(31, 42, 68, .22);
    padding: .9rem 1rem 1rem;
}
.xi-map-pop[hidden] { display: none; }
.xi-map-pop h3 { margin: 0 0 .7rem; font-size: 1.02rem; text-align: center; }
.xi-map-close {
    position: absolute; top: .3rem; right: .45rem; border: 0; background: none;
    font-size: 1.3rem; line-height: 1; cursor: pointer; padding: .1rem .3rem;
    color: var(--theme-colours-text-muted);
}
.xi-map-close:hover { color: var(--theme-colours-primary); }

.xi-pop-item { padding-bottom: .6rem; margin-bottom: .6rem; border-bottom: 1px solid rgba(167, 46, 144, .28); }
.xi-pop-item:last-of-type { border-bottom: 0; margin-bottom: .2rem; }
.xi-pop-name { display: flex; align-items: center; gap: .45rem; margin: 0 0 .35rem; font-size: .95rem; }
.xi-pop-name img { width: 34px; height: 18px; object-fit: contain; flex: 0 0 auto; }
.xi-pop-flag {
    font-size: .66rem; text-transform: uppercase; letter-spacing: .06em; font-weight: 700;
    color: var(--theme-colours-primary); border: 1px solid var(--theme-colours-primary);
    border-radius: 999px; padding: 0 .4rem;
}
.xi-pop-line { display: flex; align-items: center; gap: .4rem; margin: 0 0 .15rem .2rem; font-size: .87rem; }
.xi-pop-line svg { width: 13px; height: 13px; flex: 0 0 auto; fill: none; stroke: var(--theme-colours-primary); stroke-width: 1.2; }
.xi-pop-line a { word-break: break-word; }
.xi-pop-alt, .xi-pop-direct { margin: .6rem 0 0; font-size: .87rem; color: var(--theme-colours-text-muted); }
.xi-pop-actions { display: flex; flex-wrap: wrap; gap: .4rem; margin: .7rem 0 0; }
.xi-pop-actions .xi-btn { margin: 0; padding: .45rem .85rem; font-size: .85rem; }

.xi-map-hint { margin: .7rem 0 0; color: var(--theme-colours-text-muted); font-size: .95rem; }
.xi-map-credit { font-size: .8rem; color: var(--theme-colours-text-dim); margin: .2rem 0 1.6rem; }

/* Distributor list with logos. */
.xi-dist-list { display: grid; grid-template-columns: 1fr; gap: 1rem; margin: 1.4rem 0 2rem; }
@media (min-width: 48rem) { .xi-dist-list { grid-template-columns: repeat(2, 1fr); } }
.xi-dist {
    display: flex; align-items: center; gap: 1rem;
    border: 1px solid var(--theme-colours-border); padding: .9rem 1rem;
    background: var(--theme-colours-background);
}
.xi-dist-logo { width: 84px; height: 40px; object-fit: contain; flex: 0 0 auto; }
.xi-dist-name { font-weight: 700; display: block; }
.xi-dist span { display: block; font-size: .9rem; color: var(--theme-colours-text-muted); }

/* ---- Case-study cards -----------------------------------------------------
 * Two across on a wide screen, one on a phone. They sit directly on the body
 * grid because lazysite's ::: fences cannot nest, so there is no wrapper to
 * put a grid on - the six-column body is the grid.
 */
/* Case studies vary a lot in length, and fighting that produces either
   stretched cards with dead space or a ragged grid. The design answers it
   instead: the longest case in each section LEADS at full width, where a long
   read belongs anyway, and the shorter ones pair up beneath it. */
.xi-case, .xi-case-lead {
    background: var(--theme-colours-background);
    border: 1px solid var(--theme-colours-border);
    border-top: 3px solid var(--theme-colours-primary);
    padding: 1.2rem 1.3rem 1.3rem;
    margin: 0 0 1.2rem;
}
/* The eyebrow is the card's first paragraph: a ::: body is Markdown and cannot
   carry a class of its own. */
.xi-case > p:first-child, .xi-case-lead > p:first-child {
    font-size: .72rem; text-transform: uppercase; letter-spacing: .08em; font-weight: 700;
    color: var(--theme-colours-primary); margin: 0 0 .3rem;
}
.xi-case > h3, .xi-case-lead > h3 { margin-top: 0; font-size: 1.1rem; }
.xi-case p, .xi-case li, .xi-case-lead p, .xi-case-lead li { font-size: .95rem; }
.xi-case > :last-child, .xi-case-lead > :last-child { margin-bottom: 0; }
.xi-case-lead > h3 { font-size: 1.25rem; }
/* The lead card is full width, so the prose is held to a readable measure and
   the quotation sits BESIDE it in a second column - the pull-quote pattern the
   design system asks for. Capping the prose without using the freed space just
   moves the dead area from the grid to the inside of the card. */
@media (min-width: 62rem) {
    .xi-case-lead { display: grid; grid-template-columns: minmax(0, 1fr) 20rem; column-gap: 2.4rem; }
    .xi-case-lead > * { grid-column: 1; }
    .xi-case-lead > blockquote {
        grid-column: 2; grid-row: 2 / span 99; align-self: start;
        margin: .3rem 0 0; background: none; border-left-width: 4px;
        font-size: .95rem;
    }
}
.xi-case blockquote, .xi-case-lead blockquote {
    margin: 1rem 0 0; padding: .7rem .9rem; font-size: .92rem;
    background: var(--theme-colours-background-accent);
    border-left: 3px solid var(--theme-colours-primary);
    color: var(--theme-colours-text);
}
.xi-case blockquote p:last-child, .xi-case-lead blockquote p:last-child { margin-bottom: 0; }
/* align-self keeps each card the height of its own content. Without it the
   grid stretches both cards in a row to match the taller one, and a short case
   study sits under half a card of empty space. */
@media (min-width: 52rem) { .xi-body > .xi-case { grid-column: span 3; align-self: start; } }
.xi-body > .xi-case-lead { grid-column: 1 / -1; align-self: start; }

/* The lead quotation. It used to be a widebox, which stretched to the full
   container while every paragraph around it stopped at the reading measure -
   so it read as a mistake rather than as emphasis. Centred and held to a
   generous measure, it reads as deliberate. */
.xi-quote-lead {
    margin: 2rem auto 2.4rem; max-width: 46rem; padding: 1.6rem 2rem;
    text-align: center; background: var(--theme-colours-background-alt);
    border-top: 3px solid var(--theme-colours-primary);
    border-bottom: 1px solid var(--theme-colours-border);
}
.xi-quote-lead p { margin: 0 auto; max-width: 34em; }
.xi-quote-lead p:first-child {
    font-family: var(--theme-fonts-heading); font-size: clamp(1.15rem, 2.6vw, 1.5rem);
    line-height: 1.35; color: var(--theme-colours-heading); font-weight: 600;
}
.xi-quote-lead p:first-child::before { content: "\201C"; }
.xi-quote-lead p:first-child::after  { content: "\201D"; }
.xi-quote-lead p + p { margin-top: .8rem; font-size: .9rem; color: var(--theme-colours-text-muted); }

/* Two short testimonials side by side. */
.xi-quote-pair { display: grid; grid-template-columns: 1fr; gap: 1rem; margin: 1.4rem 0 2rem; }
@media (min-width: 52rem) { .xi-quote-pair { grid-template-columns: repeat(2, 1fr); } }
.xi-quote-pair blockquote {
    margin: 0; padding: 1rem 1.1rem; font-size: .95rem;
    background: var(--theme-colours-background-alt);
    border-left: 3px solid var(--theme-colours-primary);
}
.xi-quote-pair blockquote p:last-child { margin-bottom: 0; }

/* ---- Screen recordings ----------------------------------------------------
 * The screenshot spec is being extended with recordings. A <video> in a
 * xi-figure gets the same frame as a still, so a shot can be replaced by a
 * clip without the page changing shape. Autoplay is deliberately absent: a
 * queue filling up is worth watching on purpose, not by ambush.
 */
.xi-figure video { display: block; width: 100%; height: auto; border: 1px solid var(--theme-colours-border); background: #000; }
.xi-figure .xi-figure-poster { position: relative; }

/* ---- Knowledge base articles ----------------------------------------------
 * These are ordered procedures, so the body stays as continuous prose - a
 * troubleshooting sequence read as a grid of boxes loses the one property that
 * matters, which is its order. What they gain instead is a visible header, a
 * contents column on the longer ones, and related articles at the foot.
 */
.xi-kb-meta { display: flex; flex-wrap: wrap; gap: .3rem; align-items: center; margin: 0 0 1.6rem; }
.xi-kb-meta-product {
    font-size: .72rem; text-transform: uppercase; letter-spacing: .07em; font-weight: 700;
    color: var(--theme-colours-primary-text); background: var(--theme-colours-primary);
    border-radius: 999px; padding: .12rem .6rem;
}
.xi-kb-meta .xi-kb-tag { margin: 0; }


/* == Interface gallery ==================================================== */
/* A compact set of shots showing the same product through each of its
   interfaces. Small on the page, full size on click - the detail in a queue
   view only reads at full resolution, and shrinking it to fit a column
   throws away the thing worth showing. */
.xi-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 1.25rem;
  margin: 2rem 0 2.5rem;
}
.xi-gallery figure { margin: 0; }
.xi-gallery a {
  display: block;
  border: 1px solid var(--theme-colours-border, #d8d8d8);
  background: #fff;
  overflow: hidden;
  transition: border-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
}
.xi-gallery a:hover, .xi-gallery a:focus-visible {
  border-color: var(--theme-colours-primary, #a72e90);
  box-shadow: 0 6px 20px rgba(35,31,32,0.12);
  transform: translateY(-2px);
}
.xi-gallery img {
  display: block; width: 100%; height: 168px;
  object-fit: cover; object-position: top left;
}
.xi-gallery figcaption {
  font-size: 0.82rem; line-height: 1.45;
  padding-top: 0.5rem; color: var(--theme-colours-muted, #5a6473);
}
.xi-gallery figcaption strong {
  display: block; color: var(--theme-colours-ink, #231f20); font-weight: 700;
}
.xi-gallery-note {
  font-size: 0.85rem; color: var(--theme-colours-muted, #5a6473);
  border-left: 3px solid var(--theme-colours-border, #d8d8d8);
  padding-left: 0.9rem; margin: -1rem 0 2.2rem;
}
@media (max-width: 560px) {
  .xi-gallery { grid-template-columns: 1fr 1fr; gap: 0.9rem; }
  .xi-gallery img { height: 120px; }
  .xi-gallery figcaption { font-size: 0.76rem; }
}


/* == Lightbox ============================================================= */
/* Pure CSS, driven by :target. No JavaScript, so nothing for a content
   security policy to allow and nothing to fail if a script is blocked.
   Closing is explicit: a labelled Close control, and the backdrop itself is a
   link back to the gallery. Both return to the gallery anchor rather than to
   "#", so the page does not jump to the top on close. */
.xi-lightbox {
  display: none;
  position: fixed; inset: 0; z-index: 900;
  padding: 3.2rem 1.5rem 1.5rem;
  background: rgba(20, 18, 22, 0.86);
  overflow: auto;
}
.xi-lightbox:target { display: block; }
/* The backdrop is a link covering the whole overlay, so a click anywhere off
   the image closes. It sits BELOW the figure in z-order. */
.xi-lightbox-back {
  position: absolute; inset: 0; z-index: 0;
  cursor: zoom-out;
}
.xi-lightbox figure {
  position: relative; z-index: 1;
  margin: 0 auto; max-width: 1400px;
  background: #fff; padding: 0.6rem;
}
/* Bounded at 62vh so the caption and the arrows are always on screen.
   Unbounded, a 1147px-tall capture pushed both below the fold, which is the
   same dead end as opening the raw file.

   The bound is applied to the FRAME, computed from the picture's own aspect
   ratio (--w/--h are emitted with the markup). The frame is then exactly the
   image box, which is what puts the arrows on the picture rather than out on
   the card margin. Shrink-to-fit cannot do this: it takes the intrinsic width,
   which is the width the image would have had WITHOUT the height cap. */
.xi-lb-frame {
  position: relative;
  width: min(100%, calc(62vh * var(--w, 4) / var(--h, 3)));
  margin: 0 auto;
}
.xi-lightbox img { display: block; width: 100%; height: auto; }
.xi-lightbox figcaption {
  font-size: 0.86rem; line-height: 1.5; padding: 0.7rem 0.3rem 0.2rem;
  color: #231f20;
}
.xi-lightbox-close {
  position: fixed; top: 0.9rem; right: 1.1rem; z-index: 2;
  display: inline-flex; align-items: center; gap: 0.45rem;
  background: #fff; color: #231f20;
  border: 1px solid rgba(255,255,255,0.4);
  padding: 0.4rem 0.85rem;
  font-size: 0.85rem; font-weight: 700;
  text-decoration: none; border-radius: 3px;
}
.xi-lightbox-close::after { content: '\00d7'; font-size: 1.15rem; line-height: 1; }
.xi-lightbox-close:hover, .xi-lightbox-close:focus-visible {
  background: var(--theme-colours-primary, #a72e90); color: #fff;
}
@media (max-width: 560px) {
  .xi-lightbox { padding: 3rem 0.6rem 0.6rem; }
  .xi-lightbox-close { top: 0.5rem; right: 0.6rem; }
}


/* Lightbox: caption block and prev/next. The label and description sit under
   the image, with the standing note beneath them, so the reader is told what
   they are looking at and that it is fictitious without leaving the overlay. */
.xi-lightbox figcaption { padding: 0.8rem 0.3rem 0.3rem; }
.xi-lb-count {
  display: block; font-size: 0.72rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: #6b6e70; margin-bottom: 0.25rem;
}
.xi-lightbox figcaption strong {
  display: block; font-size: 1.02rem; color: #231f20; margin-bottom: 0.2rem;
}
.xi-lb-desc { display: block; color: #3a3a3a; }
.xi-lb-note {
  display: block; margin-top: 0.6rem; padding-top: 0.6rem;
  border-top: 1px solid #e4e4e4;
  font-size: 0.8rem; color: #6b6e70;
}
/* Back/Next sit ON the image, vertically centred. The frame wraps the image
   alone, so 50% of it is halfway up the picture - 50% of the figure would be
   halfway down the caption as well. */
.xi-lb-frame { position: relative; }
.xi-lb-prev, .xi-lb-next {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
  display: flex; align-items: center; justify-content: center;
  width: 3rem; height: 3rem; border-radius: 50%;
  background: rgba(20, 18, 22, 0.62); color: #fff;
  text-decoration: none; font-size: 1.5rem; line-height: 1;
  transition: background-color 0.15s ease;
}
.xi-lb-prev { left: 0.6rem; }
.xi-lb-next { right: 0.6rem; }
.xi-lb-prev::before { content: '\2190'; }
.xi-lb-next::before { content: '\2192'; }
.xi-lb-prev:hover, .xi-lb-next:hover,
.xi-lb-prev:focus-visible, .xi-lb-next:focus-visible {
  background: var(--theme-colours-primary, #a72e90);
}
/* The glyph carries the meaning visually; the text is for screen readers. */
.xi-lb-prev span, .xi-lb-next span {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
@media (max-width: 40rem) {
  .xi-lb-prev, .xi-lb-next {
    width: 2.4rem; height: 2.4rem; font-size: 1.2rem;
  }
  .xi-lb-prev { left: 0.35rem; }
  .xi-lb-next { right: 0.35rem; }
}
