html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

a, .btn-link {
    color: #006bb7;
}

.btn-primary {
    color: #fff;
    background-color: #1b6ec2;
    border-color: #1861ac;
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

.content {
    padding-top: 1.1rem;
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}
/* ===================== QSync brand ===================== */
:root {
    --qs-bg: #0b0d17;
    --qs-bg-soft: #12152339;
    --qs-ink: #1a1d2b;
    --qs-muted: #6b7280;
    --qs-brand: #5b6cff;
    --qs-brand-2: #14b8a6;
    --qs-line: #e6e8ef;

    /* ⛔TEXT GREYS ARE TOKENS BECAUSE A THEME CANNOT REACH A HEX LITERAL.
       These five values were pinned directly into twenty-one rules, every one of them a grey chosen to
       sit on WHITE. On a dark background they run from dim to unreadable, and there is no way to
       restyle them without listing all twenty-one - at which point the twenty-second rule someone adds
       next month inherits nothing and fails silently.
       ⭐The values here are the ORIGINAL hex, unchanged, so the light site renders exactly as before. */
    --qs-ink-strong: #111827;   /* headings and emphasis */
    --qs-ink-2:      #374151;   /* strong body copy */
    --qs-ink-3:      #4b5563;   /* secondary body copy */
    --qs-muted-2:    #9ca3af;   /* the quietest label */
}
html { font-size: 14px; }
html, body { font-family: 'Inter', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; color: var(--qs-ink); background: #fff; }
a { text-decoration: none; }
*, *::before, *::after { box-sizing: border-box; }
/* ⭐⭐THE SIDE GUTTER SCALES WITH THE SCREEN, AND THE READING WIDTH DOES NOT.
   ⛔Owner, 2026-09-01, on an iPad: "no side margins destroys the page appeal. the text is 0 pixel
   touching or outside the screen itself. Horrible." He was right and the measurement agrees - the
   gutter was a FLAT 20px from 360px all the way to 1180px. A 360px phone and a 1024px iPad got the
   same twenty pixels, so the wider the tablet, the more the text looked pasted onto the glass.

   ⭐--qs-gutter grows with the viewport; CONTENT-MAX is the reading measure and is fixed. Keeping
   those two separate is the whole point: max-width has to include the padding (box-sizing is
   border-box everywhere here), so a bigger gutter inside a FIXED max-width would have quietly
   narrowed every desktop page by 72px while fixing the tablet. The calc() adds the gutter back, so
   the text inset at 1440/1920/2560/3840 is byte-identical to what it was before this change -
   measured, 170/410/730/1370px - and only 360-1180px moves.
   ⛔So do not hard-code a number in either declaration. Changing --qs-gutter alone must keep the
   desktop measure fixed; that invariant is what ContainerGutterTests holds. */
:root {
    --qs-content-max: 1100px;                     /* the reading measure, gutters excluded */
    --qs-gutter: clamp(20px, 5vw, 56px);          /* 20px at 360, 38 at 768, 51 at 1024, 56 from 1120 */
}
.container { max-width: calc(var(--qs-content-max) + 2 * var(--qs-gutter));
             margin: 0 auto; padding: 0 var(--qs-gutter); }
.muted { color: var(--qs-muted); }

/* ⭐FIELD DESCRIPTIONS, 20% smaller (owner, 2026-09-01). MEASURED at 14px, so 14 x 0.8 = 11.2 -> 11px.
   ⛔A SEPARATE CLASS RATHER THAN CHANGING .muted, and the reason is arithmetic: .muted appears 76 times
   across 20 pages - footer copy, page captions, pricing notes, the AMCF register. Shrinking all of it to
   11px to fix the three hint lines under the sign-up fields would have been a site-wide type change
   nobody asked for, arriving invisibly in a commit about a form.
   ⚠11px is small ON PURPOSE and only appropriate BELOW the field it explains. Do not reach for this
   class for body copy - it is a hint, not a paragraph. */
.field-hint { font-size: 11px; line-height: 1.5; }
.site-main { min-height: 60vh; }

/* nav */
.site-nav { position: sticky; top: 0; z-index: 50; background: rgba(255,255,255,.9); backdrop-filter: blur(8px); border-bottom: 1px solid var(--qs-line); }
/* ⚠min-height, NOT height. A fixed height silently CLIPS a wrapped second row, which is exactly how
   eleven links became an invisible navigation bar instead of an ugly one. If the links ever wrap again
   the bar now grows and the fault is visible immediately. */
.nav-inner { display: flex; align-items: center; justify-content: space-between; min-height: 48px; }
.nav-brand { display: inline-flex; align-items: center; gap: 9px; font-weight: 800; font-size: 1.35rem; color: var(--qs-ink); letter-spacing: -.02em; }
.brand-mark { display: block; border-radius: 5px; }
.nav-brand span { color: var(--qs-brand); }
.nav-links { display: flex; gap: 26px; align-items: center; flex-wrap: wrap; }
/* ⭐VERTICAL PADDING IS THE TOUCH TARGET, and it is not cosmetic. From 901px up the nav shows the full
   link row, and 901-1366 is where TABLETS live - iPad Pro 12.9 portrait is 1024, Surface Pro portrait is
   912, iPad Air landscape is 1180. Those are FINGERS on a desktop-shaped bar. Without this the anchor is
   only as tall as its text, about 20px, against the ~44px a touch target needs, so every one of those
   users gets a row of links that are hard to hit accurately.
   ⚠It costs nothing on a mouse and .nav-inner's min-height absorbs it, so the bar stays 48px.
   ⛔:not(.btn-buy) because Get-a-licence carries its own padding and this selector would outrank it. */
.nav-links a { color: var(--qs-ink-2); font-weight: 500; }
.nav-links a:not(.btn-buy) { padding: 12px 0; }
.nav-links a:hover { color: var(--qs-brand); }
.nav-toggle, .nav-burger { display: none; }
.nav-burger { width: 44px; height: 44px; cursor: pointer; flex-direction: column; justify-content: center; gap: 5px; padding: 10px; margin: -10px; }
.nav-burger span { display: block; height: 2px; border-radius: 2px; background: var(--qs-ink); }
.btn-buy { background: var(--qs-brand); color: #fff !important; padding: 9px 16px; border-radius: 9px; font-weight: 600; }
.btn-buy:hover { filter: brightness(1.08); }

/* hero */
.hero { background: radial-gradient(1200px 500px at 70% -10%, #5b6cff22, transparent), linear-gradient(180deg, #0b0d17, #161a2e); color: #fff; padding: 18px 0 18px; }
.hero h1 { font-size: clamp(1.8rem, 4vw, 2.8rem); font-weight: 800; letter-spacing: -.03em; max-width: 18ch; line-height: 1.05; }
.hero .lead { color: #c3c8da; font-size: 1.05rem; max-width: 62ch; margin-top: 8px; }
/* ⛔⛔"THE BANNER STILL HAS LINEFEEDS" (owner, 2026-08-30), AND HE WAS RIGHT WHILE I WAS LOOKING AT
   THE WRONG THING. The rendered HTML is one unbroken line - I checked that and reported it - but what
   a reader sees is the 62ch measure above folding a 210-character sentence into four short lines
   inside a 1140px banner. The line feeds were real; they were just made by CSS, not by the content.
   ⚠65ch is the right measure for a COLUMN of prose. This is a single wide intro sentence under a
   heading, so it gets the container's width and wraps twice instead of four times. */
.hero-wide .lead { max-width: none; }
.hero-cta { margin-top: 12px; display: flex; gap: 10px; flex-wrap: wrap; }
.btn-primary, .btn-ghost { padding: 13px 22px; border-radius: 11px; font-weight: 600; display: inline-block; }
.btn-primary { background: var(--qs-brand); color: #fff; }
.btn-primary:hover { filter: brightness(1.08); }
.btn-ghost { border: 1px solid #ffffff44; color: #fff; }
.btn-ghost:hover { background: #ffffff14; }

/* sections */
section { padding: 5px 0; }
section h2 { font-size: 1.5rem; font-weight: 800; letter-spacing: -.02em; margin-bottom: 4px; }
.why-grid { display: grid; gap: 12px; margin-top: 10px; }
.why-grid { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.why-grid h3 { font-size: 1.15rem; }
/* ⭐FLEX, NOT GRID, and deliberately so. There are FIVE app tiles. A 3-column grid leaves the last two
   stranded against the left edge with a dead third column - it reads as a mistake rather than a layout.
   Flex-wrap with justify-content:center CENTRES the trailing row, so 3+2 looks intentional. It also
   survives the count changing: 4 tiles give 3+1 centred, 6 give 3+3, without touching this rule.
   ⚠max-width stops a lone trailing card stretching to the full container width. */
.product-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; margin-top: 10px; }
.product-grid > .product-card { flex: 1 1 300px; max-width: 366px; }

/* product cards */
.product-card { display: block; border: 1px solid var(--qs-line); border-radius: 14px; padding: 16px; background: #fff; transition: transform .15s, box-shadow .15s, border-color .15s; }
.product-card:hover { transform: translateY(-3px); box-shadow: 0 12px 30px #0b0d1714; border-color: var(--accent, var(--qs-brand)); }
.product-card .card-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.product-card .dot { width: 12px; height: 12px; border-radius: 50%; background: var(--accent, var(--qs-brand)); }
.product-card .platforms { color: var(--qs-muted); font-size: .82rem; }
.product-card h3 { font-size: 1.3rem; color: var(--qs-ink); }
.product-card .tagline { color: var(--qs-ink-3); margin: 4px 0 10px; }
/* Headline capabilities on the home tile. Tick markers in the accent colour so the list reads as
   "what you get" at a glance rather than as body copy. Sized down from the tagline so the card still
   has a clear hierarchy: name, promise, proof, call to action. */
.product-card .card-highlights { list-style: none; margin: 0 0 12px; padding: 0; }
.product-card .card-highlights li { position: relative; padding-left: 18px; margin: 5px 0; color: var(--qs-ink-3); font-size: .88rem; line-height: 1.4; }
.product-card .card-highlights li::before { content: "\2713"; position: absolute; left: 0; top: 0; color: var(--accent, var(--qs-brand)); font-weight: 700; }
/* An add-on is not a standalone app. The tile has to say so, or a buyer reads it as one. */
.badge-addon { background: color-mix(in srgb, var(--accent, var(--qs-brand)) 14%, #fff); color: var(--accent, var(--qs-brand)); }
.product-card .learn { color: var(--accent, var(--qs-brand)); font-weight: 600; }
.badge { display: inline-block; background: #f3f4f6; color: var(--qs-muted); font-size: .72rem; font-weight: 700; padding: 3px 9px; border-radius: 99px; margin-right: 10px; text-transform: uppercase; letter-spacing: .04em; }

/* product detail */
.detail-hero { color: #fff; padding: 16px 0; }
.detail-hero h1 { font-size: clamp(1.8rem, 4vw, 2.6rem); font-weight: 800; letter-spacing: -.02em; }
.detail-hero .tagline { font-size: 1.15rem; opacity: .9; margin-top: 6px; }
.pain { background: var(--qs-bg-soft); border-left: 4px solid var(--qs-brand); padding: 12px 18px; border-radius: 10px; font-size: 1.02rem; color: var(--qs-ink-2); }
.feature-list { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(280px,1fr)); gap: 8px; }
.feature-list li { padding: 12px 14px 12px 38px; position: relative; border: 1px solid var(--qs-line); border-radius: 10px; }
.feature-list li::before { content: "\2713"; position: absolute; left: 14px; color: var(--qs-brand-2); font-weight: 800; }

/* partners */
.partner-list { display: grid; gap: 16px; margin-top: 10px; }
.partner-card { border: 1px solid var(--qs-line); border-radius: 16px; padding: 24px; background: #fff; }
.partner-head { margin-bottom: 16px; }
.partner-logo { height: 52px; width: auto; display: block; }
.partner-body { display: grid; grid-template-columns: 1.1fr .9fr; gap: 28px; align-items: center; }
.partner-figure { margin: 0; }
/* Owner ruling 2026-08-11: NO ROUNDED CORNERS ON ARTWORK, anywhere in QSync. Real sleeves and posters have square corners; rounding them is a gimmick that makes our own artwork look like someone else's chrome. Applies to covers, posters, artist images and stills - NOT to buttons, chips or cards. */
.partner-figure img { max-width: 100%; height: auto; border-radius: 0; }
.partner-quote { margin: 16px 0 0; padding: 14px 20px; border-left: 4px solid var(--qs-brand); background: var(--qs-bg-soft); border-radius: 10px; font-size: 1.05rem; font-style: italic; color: var(--qs-ink-2); }
.partner-links { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; margin-top: 18px; }
.partner-link { color: var(--qs-brand); font-weight: 600; }
.partner-link:hover { text-decoration: underline; }

/* pricing */
/* Currency switcher - small native <details> dropdown at the top of the pricing page. */
.ccy-switch { position: relative; float: right; margin: 2px 0 0; }
.ccy-switch > summary { list-style: none; cursor: pointer; user-select: none;
    border: 1px solid var(--qs-line); border-radius: 9px; padding: 6px 12px; font-weight: 600;
    display: inline-flex; align-items: center; gap: 6px; background: transparent; }
.ccy-switch > summary::-webkit-details-marker { display: none; }
.ccy-switch > summary .chev { color: var(--qs-muted); font-size: .8em; }
.ccy-switch[open] > summary { border-color: var(--qs-brand); }
.ccy-menu { position: absolute; right: 0; top: calc(100% + 4px); z-index: 20; min-width: 128px;
    background: var(--qs-card, #fff); border: 1px solid var(--qs-line); border-radius: 10px;
    box-shadow: 0 12px 30px #0003; padding: 4px; }
.ccy-menu a { display: flex; align-items: center; gap: 8px; padding: 7px 10px; border-radius: 7px;
    text-decoration: none; color: inherit; font-weight: 500; }
.ccy-menu a:hover { background: #5b6cff14; }
.ccy-menu a.sel { color: var(--qs-brand); font-weight: 700; }
.ccy-menu a .sym { display: inline-block; min-width: 1.6em; color: var(--qs-muted); }

/* ⛔A FIXED TRACK COUNT, NOT auto-fit. auto-fit with 1fr STRETCHES whatever is present, so a product
   with only two tiers got two cards half again as wide as every other product's, and nothing lined up
   down the page. QSYNC Media Reports has exactly two, and it is the last row on the page - the one a
   reader compares everything against.
   ⚠The old comment beside this rule reasoned about three tiers and four. It never considered TWO,
   which is the case that actually shipped.
   ⭐Still no arithmetic in the markup: three columns by default, four if a fourth card exists (so
   Developer returning needs no change here), and a single card - an add-on on its own - keeps the full
   width it had. :has() reads the child count so the razor does not have to count. */
.tier-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin-top: 4px; }
.tier-grid:has(> :nth-child(4)) { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.tier-grid:has(> :only-child)   { grid-template-columns: 1fr; }
.tier { border: 1px solid var(--qs-line); border-radius: 14px; padding: 14px; }
.tier.highlight { border-color: var(--qs-brand); box-shadow: 0 10px 30px #5b6cff1f; }
/* ===================== Tier identity colours (owner, 2026-08-30) =====================
   ⭐One colour per RUNG, used everywhere that rung appears: Basic green, Pro orange, Pro+ QSYNC blue,
   and QSM purple. The point is recognition - a reader scanning five products should be able to find
   "the Pro one" by colour before reading a word.

   ⛔KEYED ON THE EDITION CODE, never on the display name. `basic`/`pro`/`proPlus`/`proPlusSM` are the
   same codes the licensing DB and the checkout URLs use, so a tier renamed in marketing copy keeps its
   colour and a NEW tier gets no colour rather than silently borrowing one.

   ⚠These are text colours on white, so they are the DARKER end of each hue - #22c55e green and #f97316
   orange look right as a fill and fail contrast as 1.2rem type. Blue is the existing brand token
   rather than a second blue that would drift from it. */
:root {
    --qs-tier-basic: #15803d;
    --qs-tier-pro:   #ea580c;
    --qs-tier-plus:  var(--qs-brand);
    --qs-tier-qsm:   #7c3aed;
}
.tier h3.t-basic { color: var(--qs-tier-basic); }
.tier h3.t-pro   { color: var(--qs-tier-pro); }
.tier h3.t-plus  { color: var(--qs-tier-plus); }
.tier h3.t-qsm   { color: var(--qs-tier-qsm); }

/* The bundle cards carry the same identity as an OUTLINE. ⚠The tint in the shadow is the same hex at
   1f alpha, matching how .tier.highlight already does it, so the cards read as a set. */
.tier.b-pro  { border-color: var(--qs-tier-pro);  box-shadow: 0 10px 30px #ea580c1f; }
.tier.b-plus { border-color: var(--qs-tier-plus); box-shadow: 0 10px 30px #5b6cff1f; }
.tier.b-qsm  { border-color: var(--qs-tier-qsm);  box-shadow: 0 10px 30px #7c3aed1f; }

.tier h3 { font-size: 1.2rem; }
/* Add-on cards carry a full product name ("QSync Surround Master (QSM)"), not a one-word tier label,
   and the add-on is a product in its own right rather than a rung on the ladder. Give it room -
   name and headline price both, so the card reads as a product rather than a footnote to one. */
.tier.addon h3 { font-size: 1.55rem; line-height: 1.25; }
.tier.addon .price { font-size: 2.1rem; }
/* The "or $5/mo" secondary line stays small - the annual figure is the one being led with. */
.tier.addon .price small { font-size: .8rem; }
.tier .price { font-size: 1.8rem; font-weight: 800; margin: 4px 0 10px; }
/* ⚠margin-left, because Razor eats the whitespace between `@bundlePrice` and `<small>`: the bundle
   cards rendered "$100/yrper year" with the price and the period touching. Seen in a screenshot, not
   in the markup, where the two sit on separate lines and look fine. */
.tier .price small { font-size: .9rem; color: var(--qs-muted); font-weight: 500; margin-left: 4px; }
/* ⚠The per-product cards put the period on its OWN line (display:block inline-styled), so the margin
   above would indent it. Reset for that case. */
.tier .price small[style*="block"] { margin-left: 0; }
/* ⭐Tightened 2026-08-30 (owner). The rows were 4px top and bottom PLUS the ul's default 1em margin,
   so a five-feature tier spent more height on gaps than on words and the cards ran long enough to
   push the availability line out of sight on a laptop. */
/* ⛔⛔PADDING WAS NOT THE GAP. Reducing it 4px -> 2px on 2026-08-30 changed almost nothing visible,
   and the owner said so: the row height is dominated by LINE-HEIGHT, which was inheriting the body's
   1.5 on a 14px base - about 21px of the ~25px row. A feature is one short line, so it does not need
   paragraph leading. Tightening line-height is what actually closes the gap. */
.tier ul { list-style: none; padding: 0; margin: 4px 0 0; }
.tier li { padding: 1px 0; line-height: 1.35; border-top: 1px solid var(--qs-line); color: var(--qs-ink-3); }

/* ⚠.tier-availability lived here for about an hour on 2026-08-30 and is DELETED, not kept "in case":
   the owner removed the "Available at launch" wording entirely the same afternoon. A CSS rule with no
   markup behind it is dead weight that the next reader has to prove is dead. */

/* Player pricing: fixed 3-column row - Basic | Pro/Pro+ stack | Developer.
   Add-ons moved OUT of this row into their own section below, so the ladder reads as a ladder.
   Cards size to their own content (align-items:start) so an uneven stack doesn't stretch the rest. */
/* Two columns when the Developer tier is not published. Declared AFTER the 3-column rule so it wins on
   source order - both are single-class selectors, so specificity alone would not decide it. */
/* footer */
.site-footer { border-top: 1px solid var(--qs-line); padding: 14px 0 10px; margin-top: 12px; background: #fafbff; }
.footer-grid { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 20px; }
.footer-brand { display: inline-flex; align-items: center; gap: 8px; font-weight: 800; font-size: 1.15rem; }
.footer-brand span { color: var(--qs-brand); }
.site-footer h6 { font-weight: 700; text-transform: uppercase; font-size: .75rem; letter-spacing: .06em; color: var(--qs-muted-2); margin-bottom: 6px; }
.site-footer a { display: block; color: var(--qs-ink-3); padding: 1px 0; }
.site-footer a:hover { color: var(--qs-brand); }
.copyright { margin-top: 14px; font-size: .85rem; }

/* ⚠BREAKPOINT RAISED 720 -> 900 on 2026-08-07, when App UI and FAQ were added to the nav.
   Nine links plus the Get-a-licence button no longer fit on one row below about 900px: the row wrapped
   and "Support" landed on top of the brand and the button. Measured at 760px before the change.
   ⭐If another nav item is ever added, re-measure this - the number is a consequence of the link count,
   not a round number someone liked. */
@media (max-width: 900px) {
    html, body { overflow-x: hidden; max-width: 100%; }
    .nav-inner > * { min-width: 0; }
    .hero-home .hero-copy h1 { white-space: normal; }
    .why-grid, .feature-list, .tier-grid, .partner-body { grid-template-columns: 1fr; }
    /* ⚠.product-grid is FLEX now, so grid-template-columns does nothing to it. One card per row on
       mobile has to come from the flex-basis instead, or the tiles stay side by side and squash. */
    .product-grid > .product-card { flex: 1 1 100%; max-width: none; }
    .hero { padding: 22px 0 20px; }
    .hero h1 { font-size: clamp(1.7rem, 7vw, 2.3rem); }
    .hero .lead { font-size: 1.08rem; }
    .footer-grid { grid-template-columns: 1fr; }
}
/* ⛔⛔THE NAV KEEPS ITS LINKS VISIBLE. A BURGER ON A DESKTOP READS AS A BROKEN TOOLBAR.
   ⚠OWNER, 2026-08-31: "the website toolbar no longer is visible and looks corrupted". He was looking
   at a window under 1180px, where an earlier version of this rule swapped the whole link row for a
   burger. That FIXED the clipping but it was the wrong trade - it hid the navigation on exactly the
   widths a laptop uses, and a lone hamburger on a wide screen looks like a page that failed to load.
   ⭐SO THE ROW TIGHTENS INSTEAD OF COLLAPSING. Twelve items - eleven links plus Get-a-licence - need
   about 1150px at the full 26px gap. Between 901px and 1180px the gap, the type and the brand shrink
   by measured amounts so all twelve still FIT ON ONE ROW and stay readable. The burger is for phones
   and small tablets, which is what it was always for.
   ⛔THESE NUMBERS ARE A CONSEQUENCE OF THE ITEM COUNT. Add or remove a nav item and RE-MEASURE them.
   NavCollapseBreakpointTests fails the build if the count moves, because the comment that used to say
   this was ignored twice - once when Atmos Mix Funding was added on 2026-08-28 and again when News was
   added on 2026-08-30, which is what produced a nav that did not fit at all. A comment is not a check. */
@media (max-width: 1180px) and (min-width: 901px) {
    .nav-links { gap: 14px; font-size: .92rem; }
    .nav-brand { font-size: 1.2rem; }
    .btn-buy { padding: 8px 12px; }
}

@media (max-width: 1040px) and (min-width: 901px) {
    .nav-links { gap: 11px; font-size: .88rem; }
    .nav-brand { font-size: 1.1rem; }
    .btn-buy { padding: 7px 11px; }
}

/* ⭐The burger is the PHONE and small-tablet form, and it keeps its own block rather than joining the
   shared 900px one below: that block also switches the hero, the footer and the product cards to their
   single-column layouts, so anyone re-measuring the nav would have restyled half the site by accident. */
@media (max-width: 900px) {
    .nav-burger { display: flex; }
    .nav-links {
        display: none;
        position: absolute; top: 64px; left: 0; right: 0;
        /* ⛔nowrap IS LOAD-BEARING HERE. .nav-links carries flex-wrap: wrap from the base rule, and a
           COLUMN flex box with a capped height does not overflow when it is allowed to wrap - it starts a
           SECOND COLUMN. Adding the max-height below without this produced a two-column menu with a
           horizontal scrollbar and half the links off the right edge. Seen 2026-08-31 the moment the cap
           was added, which is the only reason it was caught. */
        flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: 2px;
        background: #fff; border-bottom: 1px solid var(--qs-line);
        /* ⭐the same gutter as the page, so the menu links line up under the wordmark instead of
           sitting 25px to its left on a tablet-width phone. */
        padding: 10px var(--qs-gutter) 18px; box-shadow: 0 16px 30px #0000001a;
        /* ⛔THE OPEN MENU MUST SCROLL, OR ITS BOTTOM ITEMS DO NOT EXIST.
           Twelve items stack to about 570px. This panel is absolutely positioned inside a STICKY bar,
           so it does not lengthen the page and scrolling cannot bring the lower items into view - they
           are simply unreachable on any viewport shorter than the menu.
           ⚠MEASURED 2026-08-31 on the live site: at 667x375 (an ordinary phone in LANDSCAPE) only SIX
           of the twelve were reachable, and at 320x568 (iPhone SE) "Get a licence" - the buy button -
           could not be reached at all. A visitor could see the menu open and still not get to Support,
           Downloads or checkout.
           ⭐dvh first for the units, with vh as the fallback for anything that does not know dvh: on a
           phone 100vh is the chrome-less height, so a vh-only rule still hides the last item behind the
           browser bar. Both are declared, later wins where supported. */
        max-height: calc(100vh - 64px);
        max-height: calc(100dvh - 64px);
        overflow-y: auto;
        overscroll-behavior: contain;
    }
    .nav-toggle:checked ~ .nav-links { display: flex; }
    .nav-links a { padding: 12px 2px; width: 100%; }
    .nav-links .btn-buy { margin-top: 8px; text-align: center; }
}

/* ===================== live product demo ===================== */
.demo-wrap { display: flex; flex-direction: column; align-items: center; }
.demo-phone { width: 320px; max-width: 92vw; background: #0e1120; border: 1px solid #ffffff1a; border-radius: 28px; padding: 18px; box-shadow: 0 30px 70px #00000066; }
.demo-np { background: linear-gradient(165deg, #161a2e, #0b0d17); border-radius: 18px; padding: 18px; text-align: center; }
.demo-art { width: 190px; height: 190px; margin: 4px auto 16px; border-radius: 0; box-shadow: 0 14px 34px #00000055; }
.demo-track { color: #fff; font-weight: 700; font-size: 1.1rem; }
.demo-artist { color: #aab0c6; font-size: .92rem; margin-top: 2px; }
.demo-progress { height: 5px; background: #ffffff1f; border-radius: 99px; margin: 16px 4px 14px; overflow: hidden; }
.demo-progress span { display: block; height: 100%; background: var(--qs-brand); transition: width .35s ease; }
.demo-controls { display: flex; align-items: center; justify-content: center; gap: 22px; }
.demo-controls button { background: none; border: none; color: #fff; font-size: 1.5rem; cursor: pointer; line-height: 1; padding: 4px; }
.demo-controls .play { width: 56px; height: 56px; border-radius: 50%; background: var(--qs-brand); font-size: 1.4rem; display: inline-flex; align-items: center; justify-content: center; }
.demo-controls .play:hover { filter: brightness(1.1); }
.demo-list { margin-top: 14px; display: flex; flex-direction: column; gap: 6px; }
.demo-item { display: flex; align-items: center; gap: 12px; text-align: left; background: none; border: none; cursor: pointer; padding: 8px; border-radius: 12px; color: #e7e9f3; }
.demo-item:hover { background: #ffffff0d; }
.demo-item.on { background: #5b6cff22; outline: 1px solid #5b6cff55; }
.demo-thumb { width: 42px; height: 42px; border-radius: 0; flex: none; }
.demo-meta { display: flex; flex-direction: column; line-height: 1.25; }
.demo-meta small { color: #aab0c6; }
.demo-cap { margin-top: 16px; color: #aab0c6 !important; font-size: .85rem; }
/* ===================== live demo: tablet ===================== */
.demo-tablet { width: 760px; max-width: 95vw; aspect-ratio: 16 / 11; background: #0e1120; border: 1px solid #ffffff1a; border-radius: 26px; padding: 16px; box-shadow: 0 30px 70px #00000066; display: grid; grid-template-columns: 44% 56%; gap: 14px; }
.demo-np2 { background: linear-gradient(165deg, #161a2e, #0b0d17); border-radius: 18px; padding: 22px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; }
.demo-art2 { width: 200px; height: 200px; max-width: 78%; aspect-ratio: 1; border-radius: 0; box-shadow: 0 14px 34px #00000055; margin-bottom: 14px; }
.demo-list2 { background: #0b0d17; border: 1px solid #ffffff0d; border-radius: 18px; padding: 10px; overflow: auto; }
@media (max-width: 680px) {
    .demo-tablet { grid-template-columns: 1fr; aspect-ratio: auto; }
    .demo-art2 { width: 160px; height: 160px; }
}
/* ===================== Home hero: copy + animated waveform ===================== */
.hero-home .container { display: grid; grid-template-columns: .9fr 1.1fr; gap: 48px; align-items: center; }
/* home headline: small + LIGHT weight, held on one line on DESKTOP ONLY.
   ⛔⛔THIS ONE-LINE RULE TOOK THE MOBILE NAV OFF THE SCREEN. `white-space: nowrap` used to live
   here, in the base block - which sits AFTER the max-width:900px block that tries to set it back to
   `normal`. Same specificity, later source order, so NOWRAP WON ON PHONES TOO. The headline could not
   wrap, the page became about 496px wide, and everything past the viewport was clipped: on a 390px
   phone that is the whole right-hand side of the header, INCLUDING THE BURGER MENU. The site had no
   navigation at all on a phone, and nothing looked broken - the brand still rendered.
   ⭐Measured 2026-08-31: gone at 390 and 430, present at 500, which is exactly where a ~57-character
   headline at this font size stops fitting.
   ⭐Now scoped to a MIN-WIDTH query, so it cannot reach a narrow screen no matter where it sits in the
   file. An override that depends on source order is one reorder away from silently coming back. */
.hero-home .hero-copy h1 { max-width: none; font-weight: 300; letter-spacing: -.01em; font-size: clamp(1.05rem, 1.9vw, 1.2rem); line-height: 1.25; }
@media (min-width: 901px) {
    .hero-home .hero-copy h1 { white-space: nowrap; }
}
.hero-visual { display: flex; justify-content: center; align-items: center; min-height: 340px; }
.channel-wave { width: 100%; max-width: 600px; aspect-ratio: 16 / 9; height: auto; display: block; }
@media (max-width: 900px) {
    .hero-home .container { grid-template-columns: 1fr; }
    .hero-visual { display: none; }
}

/* ===================== Devices page ===================== */
/* .devices-partners removed 2026-08-06 - the partner band moved to /partners. */
.devices-supported, .devices-recos { padding: 4px 0; }
.dev-group { margin-top: 12px; }
.dev-label { font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--qs-muted-2); margin-bottom: 6px; }
.dev-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.dev-chip { font-weight: 600; font-size: .9rem; color: var(--qs-ink-2); background: #f3f4f6; border: 1px solid var(--qs-line); padding: 7px 14px; border-radius: 10px; }
.dev-card { border: 1px solid var(--qs-line); border-radius: 14px; padding: 14px 16px 11px; background: #fff; }
.dev-card h3 { font-size: 1.12rem; margin-bottom: 8px; }
.dev-specs { grid-template-columns: 1fr; gap: 0; margin: 4px 0 0; }
.dev-specs li { border: none; padding: 3px 0 3px 26px; }
.dev-specs li::before { left: 2px; }
.ast { color: var(--qs-brand); font-weight: 700; }
.foot { color: var(--qs-muted); font-size: .85rem; margin: 5px 0 0; }
.partner-band { border: 1px solid var(--qs-line); border-radius: 16px; padding: 18px 20px; background: linear-gradient(180deg,#f7f8ff,#fff); box-shadow: 0 10px 30px #5b6cff12; }
.partner-band h2 { margin-bottom: 6px; }
.partner-band p { max-width: 70ch; }
.partner-cta { margin-top: 10px; font-weight: 600; }
.partner-cta a { color: var(--qs-brand); }

/* Product page hero screenshot */
.shot-band { background: linear-gradient(180deg,#0b0d17,#0e1120); padding: 24px 0; }
.product-shot { width: min(1000px, 100%); border-radius: 0; border: 1px solid #ffffff14; box-shadow: 0 24px 70px #0009; }

/* ===================== Home hero: beta pill, spec chips, note ===================== */
.hero-beta { display: inline-flex; align-items: center; gap: 8px; font-size: .74rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: #d7dbea; background: #ffffff12; border: 1px solid #ffffff26; padding: 5px 12px; border-radius: 99px; margin-bottom: 10px; }
.hero-beta .dot { width: 7px; height: 7px; border-radius: 50%; background: #14b8a6; box-shadow: 0 0 10px #14b8a6; }
.hero-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.hero-chips .chip { font-size: .82rem; font-weight: 600; color: #e7e9f3; background: #ffffff10; border: 1px solid #ffffff20; padding: 6px 12px; border-radius: 10px; }
.hero-note { margin-top: 12px; color: #aab0c6; font-size: .9rem; }
.hero-note a { color: #8b97ff; font-weight: 600; }
.hero-note a:hover { color: #a7b0ff; }

/* ===================== Home: Social Music band ===================== */
/* full-bleed coloured band, but inner content stays in the shared container so it lines up with every other section */
.social { background: radial-gradient(1400px 460px at 18% -30%, #14b8a626, transparent), linear-gradient(180deg, #0b0d17, #101a1e); color: #fff; padding: 22px 0; margin-top: 4px; }
.social h2 { color: #fff; font-size: clamp(1.4rem, 3.4vw, 1.75rem); font-weight: 800; letter-spacing: -.02em; }
.social p { color: #c8cdde; max-width: none; margin-top: 8px; font-size: 1.05rem; line-height: 1.5; }
.social .social-note { color: #99a1b8; font-size: .85rem; margin-top: 12px; max-width: 66ch; }
.social .via { margin-top: 10px; color: #2dd4bf; font-weight: 700; font-size: .78rem; text-transform: uppercase; letter-spacing: .06em; }

/* ===================== App UI + FAQ =====================
   Shared section wrapper for the two pages added 2026-08-07. Uses the same tokens as .partner-card
   (var(--qs-line), var(--qs-bg-soft)) so these read as the same site rather than a bolt-on.
   ⚠.shot is NEW here - .shot-band and .product-shot already existed and are UNRELATED; do not merge them. */
.app-section { padding: 26px 0; border-top: 1px solid var(--qs-line); }
.app-section:first-of-type { border-top: 0; padding-top: 8px; }
.app-section h2 { font-size: clamp(1.3rem, 3vw, 1.6rem); font-weight: 800; letter-spacing: -.02em; margin-bottom: 6px; }
.app-section > p { color: var(--qs-ink-3); max-width: 74ch; line-height: 1.55; }

/* ⚠TWO columns, fixed - NOT auto-fit. auto-fit fitted THREE shots across at 1440px, which left the
   Media Player section as a row of three plus one orphan on its own line. A fixed pair makes four
   shots a tidy 2x2, and the single-figure section opts out via .shot-grid-one. */
.shot-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px; margin-top: 20px; }
.shot-grid-one { grid-template-columns: minmax(0, 820px); }
.shot { margin: 0; }
/* The trigger is a BUTTON, so every default has to be stripped before it can look like a picture. */
.shot-btn { display: block; position: relative; width: 100%; padding: 0; border: 0; background: none;
            cursor: zoom-in; border-radius: 12px; line-height: 0; }
.shot-btn img { width: 100%; height: auto; display: block; border: 1px solid var(--qs-line);
                border-radius: 12px; background: #fff; transition: border-color .15s, box-shadow .15s; }
.shot-btn:hover img { border-color: var(--qs-brand); box-shadow: 0 10px 26px #0b0d1721; }
.shot-btn:focus-visible { outline: 2px solid var(--qs-brand); outline-offset: 3px; }
/* A magnifier badge, because a bare screenshot gives no hint that it is clickable. Revealed on hover
   and focus, and left visible on touch, where there is no hover to reveal it. */
.shot-cue { position: absolute; right: 10px; bottom: 10px; display: grid; place-items: center;
            width: 34px; height: 34px; border-radius: 9px; color: #fff; background: #0b0d17b8;
            opacity: 0; transition: opacity .15s; pointer-events: none; }
.shot-btn:hover .shot-cue, .shot-btn:focus-visible .shot-cue { opacity: 1; }
@media (hover: none) { .shot-cue { opacity: .9; } }
.shot figcaption { margin-top: 8px; font-size: .88rem; color: var(--qs-muted); line-height: 1.45; }
.shot-hint { color: var(--qs-muted); font-size: .9rem; margin-bottom: 2px; }

/* ---------- lightbox ---------- */
body.lightbox-open { overflow: hidden; }
.lightbox { position: fixed; inset: 0; z-index: 200; background: #0b0d17f2; display: flex;
            flex-direction: column; align-items: center; justify-content: center; gap: 14px; padding: 28px; }
.lightbox[hidden] { display: none; }
/* Capped on BOTH axes. The report shots are tall portrait pages and would otherwise run off the top
   and bottom of the viewport - the one thing this overlay exists to prevent. */
.lightbox-img { max-width: 100%; max-height: calc(100vh - 130px); width: auto; height: auto;
                object-fit: contain; border-radius: 10px; background: #fff; cursor: default; }
.lightbox-cap { color: #c8cdde; font-size: .92rem; text-align: center; max-width: 80ch; margin: 0; }
.lightbox-close { position: absolute; top: 16px; right: 20px; width: 44px; height: 44px; border: 0;
                  border-radius: 10px; background: #ffffff1a; color: #fff; font-size: 1.9rem;
                  line-height: 1; cursor: pointer; }
.lightbox-close:hover { background: #ffffff2e; }
.lightbox-close:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* Native <details> accordion: no JavaScript, works with the keyboard, and survives with styles off. */
.faq { border: 1px solid var(--qs-line); border-radius: 12px; padding: 0; margin-top: 10px; background: #fff; }
.faq > summary { cursor: pointer; list-style: none; padding: 14px 18px; font-weight: 650; color: var(--qs-ink-strong); display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.faq > summary::-webkit-details-marker { display: none; }
.faq > summary::after { content: "+"; font-weight: 700; color: var(--qs-brand); font-size: 1.2rem; line-height: 1; flex: none; }
.faq[open] > summary::after { content: "\2212"; }
.faq[open] > summary { border-bottom: 1px solid var(--qs-line); }
.faq > p { margin: 0; padding: 14px 18px; color: var(--qs-ink-2); line-height: 1.6; }
.faq > summary:focus-visible { outline: 2px solid var(--qs-brand); outline-offset: -2px; border-radius: 12px; }

@media (max-width: 640px) {
  .shot-grid { grid-template-columns: 1fr; gap: 18px; }
}

/* ===================== Home: the four-app block diagram =====================
   ⭐Text INSIDE the SVG is styled here, not with presentation attributes, so it inherits the site font
   and can be tuned in one place. SVG text does not inherit body font automatically in every engine,
   hence the explicit family. */
.arch { margin-top: 34px; padding-top: 26px; border-top: 1px solid var(--qs-line); }
.arch h3 { font-size: 1.15rem; font-weight: 750; color: var(--qs-ink); text-align: center; margin-bottom: 6px; }
.arch-svg { display: block; width: 100%; max-width: 900px; height: auto; margin: 0 auto; }

/* ===== the product blocks are links (owner, 2026-09-01) =====
   ⛔A HOTSPOT NOBODY CAN SEE IS NOT NAVIGATION. Five boxes that silently became clickable look exactly
   like five boxes that did not, so the affordance is the feature - without it the work is invisible and
   the only people who find it are the ones who click at random.
   ⭐Three signals, because one is not enough for all three ways in: the POINTER changes for a mouse, the
   outline thickens and the name underlines for anyone hovering or tabbing, and focus-visible draws a
   real ring for the keyboard. Colour is deliberately not one of them - every box on this diagram already
   uses colour to say which product it is, and a fourth meaning for colour would collide with that.
   ⚠These rules must beat the rects' presentation attributes (stroke-width="2" and friends are written
   inline), which they do: a CSS declaration always wins over a presentation attribute. That is the same
   ordering the text styling above already relies on. */
.arch-link { cursor: pointer; }
.arch-link rect { transition: stroke-width .12s ease; }
.arch-link:hover rect,
.arch-link:focus-visible rect { stroke-width: 3.4; }
.arch-link:hover .arch-hot,
.arch-link:focus-visible .arch-hot { text-decoration: underline; text-underline-offset: 2px; }
/* ⚠SVG needs an explicit focus ring: the UA default outline is unreliable inside an <svg> and in some
   engines is drawn at zero size, which is a focus state that exists and cannot be seen. */
.arch-link:focus { outline: none; }
.arch-link:focus-visible rect { outline: 2px solid var(--qs-brand); outline-offset: 3px; }
.arch-hint { text-align: center; margin: 10px auto 0; color: var(--qs-muted); font-size: .88rem; }
.arch-svg text { font-family: 'Inter', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; }
.arch-name { font-size: 17px; font-weight: 700; }
/* ⛔A LABEL WITH NO FILL INHERITS SVG-DEFAULT BLACK, which is invisible on a black page. Every
   product name on this diagram carries an explicit fill= for its brand hue; "Your AVR / TV" is not a
   product and had none, so it rendered as near-black on near-black.
   ⚠It cannot be fixed by putting fill on .arch-name: a CSS property BEATS a presentation attribute,
   so that one line would strip the brand colour off every product name in the light theme. It needs a
   class of its own, and the token then carries it in both themes. */
.arch-t-neutral { fill: var(--qs-ink-2); }
/* Content sources and the sub-blocks inside the Player. Smaller than .arch-name on purpose: they are
   not apps you install, and equal weight would read as five products rather than four. */
/* ⛔THE TOP ROW HAS ITS OWN SIZE, AND IT IS A CONSEQUENCE OF THE BOX WIDTH.
   Five content sources share the width three used to have - the diagram is already the widest thing on
   the page and below 640px it scrolls sideways at a 560px minimum, so widening it was not an option.
   164 units per box will not hold "Future Partner Content" at the .arch-small size, so the labels get
   smaller for the boxes to get narrower. Change one and re-measure the other. */
.arch-src { font-size: 12.2px; font-weight: 700; fill: var(--qs-ink-2); }
.arch-src-sub { font-size: 10.3px; font-weight: 600; fill: var(--qs-muted); letter-spacing: .05em;
                text-transform: uppercase; }
.arch-small { font-size: 14.5px; font-weight: 700; fill: var(--qs-ink-2); }
.arch-sub { font-size: 12.5px; font-weight: 600; fill: var(--qs-muted); letter-spacing: .06em; text-transform: uppercase; }
.arch-edge { font-size: 13px; font-weight: 600; fill: var(--qs-muted); }

/* The owner's line. Deliberately the last thing under the diagram and given room to breathe - it is
   the emotional close to a technical picture, so it must not read as another caption. */
.arch-note { text-align: center; margin: 14px auto 0; max-width: 72ch; color: var(--qs-muted); font-size: .92rem; line-height: 1.5; }
.arch-note a { color: var(--qs-brand); font-weight: 600; }
.arch-quote { text-align: center; margin-top: 14px; font-size: 1.15rem; font-style: italic; font-weight: 600; color: var(--qs-brand); }

@media (max-width: 640px) {
  /* The diagram is one wide row of boxes; below ~640px the labels would be unreadable if it kept
     scaling down, so let it scroll sideways at a legible size instead of shrinking to nothing. */
  .arch { overflow-x: auto; }
  .arch-svg { min-width: 560px; }
}

/* ===================== App UI: the moving clip =====================
   Sized exactly like a .shot so the video and the stills read as one set rather than a video bolted on. */
.shot-video { margin: 20px 0 0; max-width: 100%; }
.app-video { width: 100%; height: auto; display: block; border: 1px solid var(--qs-line);
             border-radius: 12px; background: #000; }
.shot-video figcaption { margin-top: 8px; font-size: .88rem; color: var(--qs-muted); line-height: 1.45; }

/* ===================== The .qnfo specification page =====================
   ⭐The examples are real XML fixtures and they are the point of the page, so they get a proper code
   block rather than being squeezed into body type. ⚠overflow-x on the <pre>: some lines are long and a
   page that scrolls SIDEWAYS as a whole is the classic mobile defect - the block scrolls, the page
   does not. */
.spec-code { background: #0b0d17; color: #d7dbea; border: 1px solid #1c2138; border-radius: 12px;
             padding: 16px 18px; margin: 14px 0 0; overflow-x: auto; max-width: 100%; }
.spec-code code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
                  font-size: .82rem; line-height: 1.5; white-space: pre; display: block; }
.spec-list { margin: 10px 0 0; padding-left: 20px; color: var(--qs-ink-3); line-height: 1.6; max-width: 78ch; }
.spec-list li { margin-bottom: 8px; }
.spec-list code, .app-section p code, .spec-table code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .88em;
    background: #f3f4f6; border-radius: 5px; padding: 1px 5px; }
.spec-table { width: 100%; border-collapse: collapse; margin-top: 12px; font-size: .93rem; }
.spec-table th, .spec-table td { text-align: left; vertical-align: top; padding: 9px 12px;
                                 border-bottom: 1px solid var(--qs-line); color: var(--qs-ink-3); }
.spec-table thead th { color: var(--qs-ink-strong); font-weight: 700; }

/* ===================== App UI: the clip as a grid thumbnail =====================
   ⭐It reuses .shot-btn wholesale so the clip and the stills are the same size and behave the same way.
   Only the CUE differs - a play triangle rather than a magnifier - because the two do different things
   and a visitor should be able to tell which before clicking. */
.shot-cue-play { background: var(--qs-brand); color: #fff; opacity: .92; }
.shot-btn-video:hover .shot-cue-play, .shot-btn-video:focus-visible .shot-cue-play { opacity: 1; }

/* The clip inside the lightbox. ⭐Sized like .lightbox-img so a video and a screenshot open to the same
   near-fullscreen frame - the owner asked for "near full size", and matching the stills is what makes
   the overlay feel like one viewer rather than two. */
.lightbox-vid { max-width: 100%; max-height: calc(100vh - 130px); width: auto; height: auto;
                border-radius: 10px; background: #000; }
.lightbox-vid[hidden] { display: none; }
.lightbox-img[hidden] { display: none; }

/* ===================== News =====================
   ⭐The owner asked for "small page width sections, click to open to a full view". So a card is a
   NARROW strip - 760px, the same reading measure as About - and opening it expands the same strip
   rather than navigating to a different-looking page. The list stays visible underneath, which is what
   makes it feel like opening a section rather than leaving for an article. */
.news-wrap { max-width: 760px; }

.news-item { border: 1px solid var(--qs-line); border-radius: 12px; margin-bottom: 14px;
             background: #fff; overflow: hidden; transition: border-color .15s, box-shadow .15s; }
.news-item:hover { border-color: #cbd0e0; box-shadow: 0 2px 14px #0b0d1710; }
.news-item.open { border-color: var(--qs-brand); box-shadow: 0 4px 22px #5b6cff1f; }

/* The whole card is the control. ⚠display:block on the anchor so the hit area is the card, not just
   the run of text - a 12px "Read more" is a poor target on a phone. */
.news-card { display: block; padding: 18px 22px; color: inherit; }
.news-card:focus-visible { outline: 2px solid var(--qs-brand); outline-offset: -2px; border-radius: 12px; }

.news-meta { display: flex; align-items: center; gap: 10px; font-size: .82rem; color: var(--qs-muted); }
.news-tag { background: #eef0ff; color: var(--qs-brand); border-radius: 999px;
            padding: 2px 9px; font-weight: 600; font-size: .75rem; }

.news-item h2 { font-size: 1.3rem; font-weight: 800; letter-spacing: -.02em; margin: 6px 0 0; line-height: 1.25; }
.news-card:hover h2 { color: var(--qs-brand); }
.news-summary { color: var(--qs-ink-3); margin: 6px 0 0; }
.news-more { display: inline-block; margin-top: 10px; color: var(--qs-brand); font-weight: 600; font-size: .9rem; }

/* The full view. ⭐Indented under the card's own padding so it reads as the card having grown, and
   ruled off at the top so the summary above it does not look like a duplicated first paragraph. */
.news-full { padding: 0 22px 20px; border-top: 1px solid var(--qs-line); margin: 0 22px; }
.news-full p { color: var(--qs-ink-2); margin: 14px 0 0; line-height: 1.65; }
.news-link { margin-top: 18px !important; }
.news-link a { color: var(--qs-brand); font-weight: 600; }
.news-link a:hover { text-decoration: underline; }

@media (max-width: 640px) {
    .news-card { padding: 15px 16px; }
    .news-full { padding: 0 16px 16px; margin: 0 16px; }
}

/* ⬜The temporary .nav-dev-* dropdown styles were removed here on 2026-09-01 with the markup they
   styled. ⚠A first pass at deleting them by pattern left `.nav-dev-menu:hover .nav-dev-items,` behind -
   a selector ending in a COMMA, which would have swallowed the @media rule that followed it and taken
   the phone navigation with it. CSS fails silently at exactly this kind of edit, which is why the block
   was removed whole rather than by regex. */

/* ── Launch countdown (Pricing) ────────────────────────────────────────────────────────────────
   Colours come from the existing tokens, never from literals: theme-dark.css redefines the tokens
   and is loaded AFTER this file, so anything hard-coded here would stay light-themed in dark mode
   with nothing to explain why. */
.countdown {
    margin: 22px 0 4px;
    padding: 16px 20px;
    border: 1px solid var(--qs-line, #d9dce6);
    border-radius: 14px;
    background: var(--qs-panel, #f6f7fb);
    display: inline-block;
    min-width: min(100%, 420px);
}
.cd-label {
    font-size: .82rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--qs-muted, #6b7280);
    margin-bottom: 8px;
}
.cd-clock {
    display: flex;
    align-items: baseline;
    gap: 6px;
    /* Tabular figures, or every tick changes the WIDTH of the row and the whole block jitters once a
       second. It is the difference between a clock and a distraction. */
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}
.cd-unit { display: inline-flex; flex-direction: column; align-items: center; min-width: 46px; }
.cd-unit b {
    font-size: 2rem;
    line-height: 1.05;
    font-weight: 700;
    color: var(--qs-brand, #5b6cff);
}
.cd-unit i {
    font-style: normal;
    font-size: .68rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--qs-muted, #6b7280);
}
.cd-sep {
    font-size: 1.6rem;
    font-weight: 700;
    color: var(--qs-muted, #6b7280);
    transform: translateY(-6px);
}
.cd-when { margin-top: 10px; font-size: .84rem; color: var(--qs-muted, #6b7280); }
.cd-local { display: block; opacity: .8; }
/* Past the moment: the digits stay at zero and stop. It does NOT announce a sale - whether anything
   is purchasable then is a commercial fact this stylesheet cannot know. */
.countdown[data-elapsed="true"] .cd-label::after { content: " - launch day"; }

@media (max-width: 520px) {
    .cd-unit b { font-size: 1.5rem; }
    .cd-unit { min-width: 38px; }
}
