/* ==========================================================================
   Warlord Softwares — site stylesheet
   Everything shared across pages lives here. Page-specific CSS goes in the
   template's {% block head %}.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. TOKENS
   -------------------------------------------------------------------------- */
:root {
    --ink:         #0E1219;   /* deep blue-black, primary dark surface */
    --ink-raised:  #171C26;   /* raised surface on dark */
    --ink-line:    rgba(255, 255, 255, 0.09);

    --porcelain:   #EDF0F3;   /* cool light page background */
    --porcelain-2: #FFFFFF;   /* cards on light */
    --slate-line:  #DCE1E7;

    --brass:       #E0A94B;   /* the one accent */
    --brass-deep:  #8C6A20;   /* brass that passes contrast on light */
    --brass-soft:  rgba(224, 169, 75, 0.14);
    --steel:       #8A94A6;   /* meta text on dark */
    --graphite:    #55606F;   /* meta text on light */
    --verified:    #3FB98C;   /* functional only, small scale */

    --display: "Bricolage Grotesque", "Archivo", system-ui, sans-serif;
    --body:    "Instrument Sans", system-ui, -apple-system, sans-serif;
    --mono:    "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;

    --r-sm: 8px;
    --r:    14px;
    --r-lg: 20px;

    --gutter:  clamp(20px, 5vw, 48px);
    --sec-pad: clamp(64px, 9vw, 120px);
    --max:     1180px;
    --nav-h:   68px;
}

/* --------------------------------------------------------------------------
   2. BASE
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    scroll-padding-top: calc(var(--nav-h) + 12px);
}

body {
    margin: 0;
    font-family: var(--body);
    font-size: clamp(16px, 1.05vw, 17px);
    line-height: 1.65;
    color: #1B222C;
    background: var(--porcelain);
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;

    /* Sticky footer: on a short page the footer would otherwise stop partway
       down and leave a pale strip beneath it on tall screens. */
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}
body > main { flex: 1 0 auto; }
body > .site-footer { flex-shrink: 0; }

img { max-width: 100%; display: block; }
a   { color: inherit; }

h1, h2, h3, h4 {
    font-family: var(--display);
    font-weight: 700;
    line-height: 1.08;
    letter-spacing: -0.025em;
    margin: 0;
    text-wrap: balance;
}
h1 { font-size: clamp(2.2rem, 5.6vw, 4.15rem); font-weight: 800; }
h2 { font-size: clamp(1.85rem, 4.2vw, 2.9rem); }
h3 { font-size: clamp(1.12rem, 2vw, 1.32rem); letter-spacing: -0.015em; }

p { margin: 0 0 1em; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

/* No border-radius here: the outline already follows whatever radius the
   element has, and forcing one flattened pill controls while focused. */
:focus-visible { outline: 2px solid var(--brass); outline-offset: 3px; }

/* Mobile browsers paint a tap flash over the pressed element that ignores its
   border-radius, so every pill button flashed as a grey rectangle. The press
   is expressed with :active below instead, which does follow the shape. */
a, button, summary, label, select, input, textarea, [role="button"] {
    -webkit-tap-highlight-color: transparent;
}

/* One press response for every control on the site. Anything that already
   carries a transform of its own — .btn's hover lift, .lightbox-step's
   centring translate — restates the whole value in its own :active rule,
   because transform is one property and the shorthand here would replace it. */
.act:active,
.act-sm:active:not(:disabled),
.share a:active, .share button:active,
.account-btn:active,
.burger:active,
.get > summary:active,
.install button:active,
.install-tabs button:active,
.id-chip:active,
.lightbox-shut:active,
.next-card:active,
.side-links a:active,
.error-links a:active {
    transform: scale(0.97);
}

.wrap {
    max-width: var(--max);
    margin-inline: auto;
    padding-inline: var(--gutter);
}

.skip {
    position: absolute; left: -9999px;
    background: var(--brass); color: var(--ink);
    padding: 12px 18px; z-index: 999;
    border-radius: 0 0 var(--r-sm) 0; font-weight: 600;
}
.skip:focus { left: 0; top: 0; }

.visually-hidden {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* --------------------------------------------------------------------------
   3. SHARED BITS
   -------------------------------------------------------------------------- */
.eyebrow {
    font-family: var(--mono);
    font-size: 0.72rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--brass);
    margin: 0 0 20px;
    display: flex; align-items: center; gap: 10px;
}
.eyebrow::before { content: ""; width: 22px; height: 1px; background: var(--brass); flex: none; }

.lede {
    font-size: clamp(1.02rem, 1.6vw, 1.16rem);
    color: var(--graphite);
    max-width: 56ch;
}

.sec { padding-block: var(--sec-pad); }
.sec--ink   { background: var(--ink); color: var(--porcelain); }
.sec--ink .lede { color: var(--steel); }
.sec--paper { background: var(--porcelain-2); }
.sec-head   { max-width: 62ch; margin-bottom: clamp(40px, 5vw, 64px); }

.link-brass { color: var(--brass-deep); }
.sec--ink .link-brass { color: var(--brass); }

/* Buttons ------------------------------------------------------------------ */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 10px;
    min-height: 50px; padding: 0 26px;
    border-radius: 100px;
    font-family: var(--body); font-weight: 600; font-size: 0.97rem;
    text-decoration: none; border: 1px solid transparent; cursor: pointer;
    transition: transform 0.18s ease, background 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}
.btn:hover  { transform: translateY(-2px); }
.btn:active { transform: scale(0.97); }

.btn--brass { background: var(--brass); color: #1A1204; }
.btn--brass:hover { background: #EDBA61; }

.btn--ghost { background: transparent; color: var(--porcelain); border-color: var(--ink-line); }
.btn--ghost:hover { border-color: var(--brass); color: var(--brass); }

.btn--outline { background: transparent; color: #1B222C; border-color: var(--slate-line); }
.btn--outline:hover { border-color: #1B222C; }

/* --------------------------------------------------------------------------
   4. NAVIGATION
   -------------------------------------------------------------------------- */
.nav {
    position: sticky; top: 0; z-index: 100;
    background: rgba(14, 18, 25, 0.85);
    backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--ink-line);
}
.nav-inner {
    display: flex; align-items: center; gap: 16px;
    min-height: var(--nav-h);
    max-width: var(--max); margin-inline: auto; padding-inline: var(--gutter);
}

.brand {
    display: flex; align-items: center; gap: 11px;
    text-decoration: none; color: var(--porcelain);
    font-family: var(--display); font-weight: 700; font-size: 1.02rem;
    letter-spacing: -0.02em; margin-right: auto;
}
.brand img { height: 30px; width: auto; }

.nav-links {
    display: flex; align-items: center; gap: 2px;
    list-style: none; margin: 0; padding: 0;
}
.nav-links a {
    display: block; padding: 9px 13px; border-radius: var(--r-sm);
    text-decoration: none; color: var(--steel);
    font-size: 0.91rem; font-weight: 500;
    transition: color 0.16s ease, background 0.16s ease;
}
.nav-links a:hover { color: var(--porcelain); background: rgba(255,255,255,0.05); }
.nav-links a[aria-current="page"] { color: var(--brass); }

/* Account menu ------------------------------------------------------------- */
.account { position: relative; margin-left: 8px; }

.account-btn {
    display: inline-flex; align-items: center; gap: 9px;
    min-height: 42px; padding: 0 16px;
    border-radius: 100px;
    border: 1px solid var(--ink-line);
    background: transparent; color: var(--porcelain);
    font-family: var(--body); font-size: 0.89rem; font-weight: 600;
    cursor: pointer;
    transition: border-color 0.16s ease, color 0.16s ease;
}
.account-btn:hover { border-color: var(--brass); color: var(--brass); }
.account-btn .chev {
    width: 7px; height: 7px;
    border-right: 1.6px solid currentColor; border-bottom: 1.6px solid currentColor;
    transform: translateY(-2px) rotate(45deg);
    transition: transform 0.2s ease;
}
.account-btn[aria-expanded="true"] .chev { transform: translateY(1px) rotate(-135deg); }

.account-menu {
    display: none;
    position: absolute; right: 0; top: calc(100% + 10px);
    width: 274px; padding: 8px;
    background: var(--ink-raised);
    border: 1px solid var(--ink-line);
    border-radius: var(--r);
    box-shadow: 0 24px 50px -18px rgba(0,0,0,0.75);
    list-style: none; margin: 0;
}
.account.open .account-menu { display: block; }

.account-menu a {
    display: block; padding: 10px 12px;
    border-radius: var(--r-sm);
    text-decoration: none; color: var(--steel);
    font-size: 0.88rem; line-height: 1.4;
    transition: color 0.16s ease, background 0.16s ease;
}
.account-menu a:hover { color: var(--porcelain); background: rgba(255,255,255,0.05); }

.account-id {
    padding: 10px 12px 12px;
    border-bottom: 1px solid var(--ink-line);
    margin-bottom: 6px;
}
.account-id small {
    display: block;
    font-family: var(--mono); font-size: 0.62rem;
    letter-spacing: 0.14em; text-transform: uppercase; color: var(--steel);
    margin-bottom: 3px;
}
.account-id b {
    color: var(--porcelain); font-size: 0.92rem; font-weight: 600;
    word-break: break-all;
}

.account-sep {
    margin: 6px 0; padding: 10px 12px 4px;
    border-top: 1px solid var(--ink-line);
    font-family: var(--mono); font-size: 0.62rem;
    letter-spacing: 0.14em; text-transform: uppercase; color: var(--steel);
}
.account-menu .is-alert { color: var(--brass); }
.account-menu .is-exit  { color: #C98B8B; }

/* Burger ------------------------------------------------------------------- */
/* Grid rather than margins on the bars: the gap is what the close transform
   has to travel, and reading it off one value keeps the two in step. Bars are
   7px apart centre to centre (2px tall + 5px gap), so that is the translate. */
.burger {
    display: none; width: 44px; height: 44px; flex: none;
    border: 1px solid var(--ink-line); border-radius: 12px;
    background: rgba(255, 255, 255, 0.05); cursor: pointer; padding: 0;
    gap: 5px; place-content: center; justify-items: center;
    transition: background 0.18s ease, border-color 0.18s ease, transform 0.18s ease;
}
.burger:hover { background: rgba(255, 255, 255, 0.09); border-color: rgba(255, 255, 255, 0.2); }
.burger span {
    display: block; width: 20px; height: 2px; border-radius: 2px;
    background: var(--porcelain);
    transition: transform 0.24s cubic-bezier(0.2, 0.7, 0.3, 1), opacity 0.18s ease;
}
.nav.open .burger { background: rgba(255, 255, 255, 0.09); border-color: rgba(255, 255, 255, 0.2); }
.nav.open .burger span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav.open .burger span:nth-child(2) { opacity: 0; transform: scaleX(0.25); }
/* -45deg, not -135deg: a 2px bar is symmetrical, so -135deg lands on the same
   diagonal as the top bar and the two read as parallel slashes, not a cross. */
.nav.open .burger span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

@media (max-width: 1020px) {
    .burger { display: grid; }

    /* The drawer is a flex item of .nav-inner. Without wrapping it is squeezed
       onto the bar's own row next to the burger instead of dropping below it.
       row-gap 0: the drawer draws its own top rule, and a row gap would float
       that rule away from the bar. */
    .nav-inner { flex-wrap: wrap; gap: 0 16px; }

    /* Once the bar wraps, its first line is sized by its own content, so the
       whole bar shrank from 68px to 44px the moment the drawer opened and the
       logo jumped up with it. The brand holds the line at full height. */
    .brand { min-height: var(--nav-h); }

    .nav-drawer {
        display: none; width: 100%;
        padding: 8px 0 26px;
        border-top: 1px solid var(--ink-line);
        max-height: calc(100dvh - var(--nav-h)); overflow-y: auto;
    }
    .nav.open .nav-drawer { display: block; }

    .nav-links { flex-direction: column; align-items: stretch; gap: 0; }
    .nav-links a {
        padding: 14px 4px; font-size: 1rem; border-radius: 0;
        border-bottom: 1px solid var(--ink-line);
    }

    .account { margin: 18px 0 0; }
    .account-btn { display: none; }
    .account-menu {
        display: block; position: static; width: 100%;
        padding: 0; background: transparent; border: 0; box-shadow: none;
    }
    .account-menu a { padding: 13px 4px; font-size: 0.96rem; border-bottom: 1px solid var(--ink-line); border-radius: 0; }
    .account-id { padding-inline: 4px; }
    .account-sep { padding-inline: 4px; }
}
@media (min-width: 1021px) {
    .nav-drawer { display: contents; }
}

/* --------------------------------------------------------------------------
   5. FOOTER
   -------------------------------------------------------------------------- */
.site-footer {
    background: var(--ink); color: var(--steel);
    padding-block: clamp(52px, 6vw, 76px) 34px;
    border-top: 1px solid var(--ink-line);
}
.foot-grid {
    display: grid; grid-template-columns: 1.5fr repeat(3, 1fr);
    gap: 40px 28px; padding-bottom: 40px;
    border-bottom: 1px solid var(--ink-line);
}
.foot-brand p { font-size: 0.9rem; max-width: 34ch; margin-top: 16px; }
.foot-col h4 {
    font-family: var(--mono); font-size: 0.7rem; font-weight: 500;
    letter-spacing: 0.16em; text-transform: uppercase; color: var(--porcelain);
    margin: 0 0 16px;
}
.foot-col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.foot-col a { text-decoration: none; font-size: 0.9rem; transition: color 0.16s ease; }
.foot-col a:hover { color: var(--brass); }
.foot-col address { font-style: normal; font-size: 0.9rem; }

.foot-base {
    padding-top: 26px;
    display: flex; flex-wrap: wrap; gap: 12px 26px; justify-content: space-between;
    font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.05em;
}
.foot-legal { display: flex; flex-wrap: wrap; gap: 12px 20px; }
.foot-legal a { text-decoration: none; }
.foot-legal a:hover { color: var(--brass); }

/* --------------------------------------------------------------------------
   6. APP CARDS  (used on the landing page and the catalogue)
   -------------------------------------------------------------------------- */
.app-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(288px, 1fr));
    gap: 22px;
}

/* Layered shadow at rest — a tight contact edge, a mid layer and a wide
   ambient one — so a card sits above the page instead of being outlined on it.
   Hover deepens the same three layers rather than introducing a shadow from
   nothing, which is what made the lift read as a jump before. */
.card {
    position: relative;
    display: flex; flex-direction: column;
    background: var(--porcelain-2);
    border: 1px solid var(--slate-line);
    border-radius: var(--r-lg);
    overflow: hidden;
    box-shadow:
        0 1px 2px rgba(16, 24, 40, 0.05),
        0 10px 20px -12px rgba(16, 24, 40, 0.16),
        0 26px 48px -30px rgba(16, 24, 40, 0.26);
    transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
}
.card:hover {
    transform: translateY(-4px);
    border-color: #C3CCD6;
    box-shadow:
        0 1px 2px rgba(16, 24, 40, 0.06),
        0 18px 32px -14px rgba(16, 24, 40, 0.22),
        0 40px 72px -34px rgba(16, 24, 40, 0.4);
}
.card.is-hidden { display: none; }

.card-shot { aspect-ratio: 16 / 10; background: var(--ink); overflow: hidden; }
.card-shot img {
    width: 100%; height: 100%; object-fit: cover;
    transition: transform 0.5s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.card:hover .card-shot img { transform: scale(1.045); }

.card-body { padding: 20px 20px 18px; display: flex; flex-direction: column; flex: 1; }
.card-top  { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 9px; }
.card-top h3 { flex: 1; min-width: 0; }
.card-top h3 a { text-decoration: none; }
/* Stretched link — the whole card navigates to the features page */
.card-top h3 a::after { content: ""; position: absolute; inset: 0; z-index: 1; }

.tag {
    flex: none;
    font-family: var(--mono); font-size: 0.63rem;
    letter-spacing: 0.1em; text-transform: uppercase;
    padding: 5px 10px; border-radius: 100px; margin-top: 2px;
}
.tag--free { background: rgba(63,185,140,0.12); color: #1F7D5C; }
.tag--pro  { background: var(--brass-soft); color: var(--brass-deep); }

.card-body p { font-size: 0.9rem; color: var(--graphite); margin-bottom: 18px; }
.card-pkg {
    font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.04em;
    color: var(--graphite); margin-bottom: 14px;
}

.card-actions {
    position: relative; z-index: 2;      /* sits above the stretched link */
    margin-top: auto; padding-top: 15px;
    border-top: 1px solid var(--slate-line);
    display: flex; flex-wrap: wrap; gap: 8px;
}
.act {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 40px; padding: 0 15px;
    border-radius: 100px; border: 1px solid var(--slate-line);
    text-decoration: none; font-size: 0.84rem; font-weight: 600;
    transition: background 0.16s ease, border-color 0.16s ease, color 0.16s ease;
}
.act:hover { border-color: #1B222C; }
.act--get { background: var(--brass); border-color: var(--brass); color: #1A1204; }
.act--get:hover { background: #EDBA61; border-color: #EDBA61; }

/* Store picker — one "Get it" button that opens the stores the app is on.
   Built on <details> so it still opens and closes with no JS at all. The menu
   opens upward, which keeps it inside the card and clear of .card's overflow. */
.get { position: relative; }
/* .act supplies the pill; gap is set here because .act has no gap of its own
   and the chevron would otherwise sit flush against the label. */
.get > summary { list-style: none; cursor: pointer; gap: 9px; }
.get > summary::-webkit-details-marker { display: none; }
.get > summary::marker { content: ""; }

.get-chev {
    width: 6px; height: 6px; flex: none;
    border-right: 1.7px solid currentColor;
    border-bottom: 1.7px solid currentColor;
    transform: translateY(-2px) rotate(45deg);
    transition: transform 0.2s ease;
}
.get[open] .get-chev { transform: translateY(1px) rotate(-135deg); }

.get-menu {
    position: absolute;
    left: 0; bottom: calc(100% + 8px);
    z-index: 20;
    min-width: 206px;
    padding: 6px;
    /* Light surface: the menu sits on a white card, so an ink popover reads as
       a foreign object dropped on top of it. */
    background: var(--porcelain-2);
    border: 1px solid var(--slate-line);
    border-radius: var(--r);
    box-shadow: 0 18px 40px -14px rgba(16, 24, 40, 0.38);
}
.get-menu a {
    display: flex; align-items: center; gap: 10px;
    padding: 11px 12px;
    border-radius: var(--r-sm);
    text-decoration: none;
    color: #1B222C;
    font-size: 0.88rem; font-weight: 600;
    transition: background 0.16s ease;
}
.get-menu a:hover { background: var(--porcelain); }
.get-menu svg { flex: none; color: var(--brass-deep); }

/* Picker whose trigger is a full-size .btn instead of a card action pill —
   used in the article header, sidebar and download band. It opens downward:
   in a page header there is nothing above it to open into. */
.get--down > .get-menu { top: calc(100% + 8px); bottom: auto; }
.side-card .get, .side-card .get > summary { width: 100%; }

/* --------------------------------------------------------------------------
   6b. PROOF STRIP  (the checks a visitor can make before installing)
   -------------------------------------------------------------------------- */
.proof {
    background: var(--ink-raised);
    border-bottom: 1px solid var(--ink-line);
    padding-block: 26px;
    color: var(--steel);
}
/* Same strip sitting at the foot of the page: it closes the content rather
   than separating the header from it, so the rule moves to the top edge and
   it gets room to breathe. */
.proof--foot {
    border-bottom: 0;
    border-top: 1px solid var(--ink-line);
    padding-block: clamp(30px, 4vw, 44px);
}
.proof-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px 28px; }
.proof-item {
    display: flex; align-items: center; gap: 11px;
    font-size: 0.85rem; line-height: 1.4;
}
.proof-item svg { flex: none; color: var(--brass); }
.proof-item b { color: var(--porcelain); font-weight: 600; display: block; }

/* See-more strip ----------------------------------------------------------- */
.more-apps {
    margin-top: 22px;
    display: flex; align-items: center; justify-content: space-between; gap: 20px;
    padding: 24px clamp(22px, 3vw, 32px);
    border: 1px dashed #C3CCD6; border-radius: var(--r-lg);
    text-decoration: none; color: inherit; background: var(--porcelain);
    transition: border-color 0.2s ease, background 0.2s ease;
}
.more-apps:hover { border-color: var(--brass); background: #FBF6EC; }
.more-text b {
    display: block; font-family: var(--display); font-weight: 700;
    font-size: clamp(1.05rem, 1.9vw, 1.25rem); letter-spacing: -0.015em; margin-bottom: 4px;
}
.more-text small { font-size: 0.9rem; color: var(--graphite); }
.more-arrow {
    flex: none; width: 44px; height: 44px;
    display: grid; place-items: center; border-radius: 50%;
    background: var(--brass); color: #1A1204; font-size: 1.05rem;
    transition: transform 0.2s ease;
}
.more-apps:hover .more-arrow { transform: translateX(4px); }

/* Empty state -------------------------------------------------------------- */
.empty {
    display: none;
    padding: 60px 24px; text-align: center;
    border: 1px dashed #C3CCD6; border-radius: var(--r-lg);
    color: var(--graphite);
}
.empty.show { display: block; }
.empty b {
    display: block; font-family: var(--display);
    font-size: 1.2rem; color: #1B222C; margin-bottom: 6px;
}

/* --------------------------------------------------------------------------
   7. MODAL + TOAST
   -------------------------------------------------------------------------- */
.modal-veil {
    position: fixed; inset: 0; z-index: 200;
    display: none; place-items: center; padding: 20px;
    background: rgba(8, 11, 16, 0.72);
    backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
}
.modal-veil.show { display: grid; }

.modal {
    width: min(440px, 100%);
    background: var(--porcelain-2);
    border-radius: var(--r-lg);
    padding: clamp(26px, 4vw, 34px);
    box-shadow: 0 30px 70px -20px rgba(0,0,0,0.5);
}
.modal h2 { font-size: 1.5rem; margin: 0 0 12px; }
.modal p  { font-size: 0.94rem; color: var(--graphite); margin-bottom: 24px; }
.modal-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.modal-actions .btn { flex: 1 1 140px; min-height: 46px; }

.toast {
    position: fixed; left: 50%; bottom: 26px; z-index: 210;
    transform: translate(-50%, 20px);
    max-width: min(460px, calc(100vw - 32px));
    background: var(--ink); color: var(--porcelain);
    border: 1px solid var(--ink-line); border-radius: var(--r);
    padding: 14px 20px; font-size: 0.9rem;
    opacity: 0; pointer-events: none;
    transition: opacity 0.25s ease, transform 0.25s ease;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }

/* --------------------------------------------------------------------------
   8. MOTION
   -------------------------------------------------------------------------- */
.rise {
    opacity: 0; transform: translateY(18px);
    transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.rise.in { opacity: 1; transform: none; }

/* --------------------------------------------------------------------------
   9. RESPONSIVE
   -------------------------------------------------------------------------- */
@media (max-width: 980px) {
    .foot-grid  { grid-template-columns: 1fr 1fr; }
    .proof-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
    .foot-grid { grid-template-columns: 1fr; gap: 32px; }
    .app-grid  { grid-template-columns: 1fr; }
    .proof-grid { grid-template-columns: 1fr; }
    .more-apps { flex-direction: column; align-items: flex-start; gap: 18px; }
    .btn--block-sm { width: 100%; }

    /* Download / call-to-action pairs sized by their own label end up at wildly
       different widths once they wrap onto separate lines, which reads as a
       mistake. On a phone every action in the row gets the full width. */
    .head-actions { width: 100%; }
    .head-actions > .btn,
    .head-actions > .get,
    .head-actions > .get > summary { flex: 1 1 100%; width: 100%; }

    /* The card pills stay as they are: their labels are single words, so
       forcing three of them to one width only clips text on a narrow phone. */
}

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

/* --------------------------------------------------------------------------
   10. PAGE HEADER  (compact dark header used on every interior page)
   -------------------------------------------------------------------------- */
.page-head {
    position: relative;
    overflow: hidden;
    background: var(--ink);
    color: var(--porcelain);
    padding-block: clamp(44px, 6vw, 78px) clamp(38px, 5vw, 62px);
}
.page-head::after {
    content: "";
    position: absolute;
    top: -45%; right: -8%;
    width: 52vw; height: 52vw;
    max-width: 620px; max-height: 620px;
    background: radial-gradient(circle, rgba(224, 169, 75, 0.13), transparent 62%);
    pointer-events: none;
}
.page-head > .wrap { position: relative; z-index: 1; }
.page-head h1 { font-size: clamp(2.1rem, 4.8vw, 3.2rem); }
.page-head h1 em { font-style: normal; color: var(--brass); }
.head-lede {
    margin-top: 16px;
    font-size: clamp(1rem, 1.5vw, 1.1rem);
    color: var(--steel);
    max-width: 58ch;
}
.head-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 30px; }

.dot-ok {
    width: 7px; height: 7px; border-radius: 50%;
    background: var(--verified);
    flex: none;
    box-shadow: 0 0 0 3px rgba(63, 185, 140, 0.18);
}

/* --------------------------------------------------------------------------
   11. PROSE  (legal pages and other long-form copy)
   -------------------------------------------------------------------------- */
.prose { max-width: 74ch; }
.prose > :first-child { margin-top: 0; }
.prose h2 {
    font-size: clamp(1.25rem, 2.3vw, 1.55rem);
    margin: 42px 0 12px;
}
.prose h3 { margin: 28px 0 8px; }
.prose p, .prose li { color: var(--graphite); }
.prose ul, .prose ol { margin: 0 0 1em; padding-left: 1.15em; display: grid; gap: 8px; }
.prose strong { color: #1B222C; font-weight: 600; }
.prose a { color: var(--brass-deep); text-underline-offset: 3px; }
.prose hr { border: 0; border-top: 1px solid var(--slate-line); margin: 40px 0; }

.updated {
    font-family: var(--mono);
    font-size: 0.71rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--steel);
}

/* Callout ------------------------------------------------------------------ */
.notice {
    display: flex; gap: 12px; align-items: flex-start;
    padding: 16px 18px;
    border-radius: var(--r);
    background: var(--brass-soft);
    border: 1px solid rgba(224, 169, 75, 0.35);
    font-size: 0.9rem;
    color: #1B222C;
}
.notice svg { flex: none; color: var(--brass-deep); margin-top: 2px; }
.notice--ok { background: rgba(63, 185, 140, 0.1); border-color: rgba(63, 185, 140, 0.35); }
.notice--ok svg { color: #1F7D5C; }

/* --------------------------------------------------------------------------
   12. FORMS  (styles the markup django-crispy-forms bootstrap5 emits, since
       Bootstrap itself is not loaded on these pages)
   -------------------------------------------------------------------------- */
/* The form is the point of these pages, so it is lifted off the page rather
   than outlined on it: a tight contact edge, a mid shadow and a wide ambient
   one. A brass hairline across the top ties it to the rest of the site, drawn
   as a background layer so the card's own radius clips it into the corners. */
.form-card {
    background:
        linear-gradient(90deg, var(--brass), #F3C978 55%, var(--brass)) top left / 100% 3px no-repeat,
        var(--porcelain-2);
    border: 1px solid var(--slate-line);
    border-radius: var(--r-lg);
    padding: clamp(24px, 3.5vw, 36px);
    box-shadow:
        0 1px 2px rgba(16, 24, 40, 0.05),
        0 14px 28px -14px rgba(16, 24, 40, 0.18),
        0 36px 68px -34px rgba(16, 24, 40, 0.3);
}

.mb-3 { margin-bottom: 20px; }
.mb-3:last-of-type { margin-bottom: 0; }

.form-label {
    display: block;
    font-size: 0.82rem; font-weight: 600;
    color: #1B222C;
    margin-bottom: 7px;
}
.asteriskField { color: var(--brass-deep); margin-left: 3px; }

.form-control, .form-select {
    width: 100%;
    min-height: 48px;
    padding: 12px 15px;
    border: 1px solid var(--slate-line);
    border-radius: var(--r-sm);
    background: var(--porcelain-2);
    color: #1B222C;
    font-family: var(--body);
    font-size: 0.95rem;
    line-height: 1.5;
    transition: border-color 0.16s ease, box-shadow 0.16s ease;
}
textarea.form-control { min-height: 150px; resize: vertical; }
.form-control::placeholder { color: #9AA3B0; }

.form-select {
    appearance: none;
    padding-right: 42px;
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%2355606F' stroke-width='1.8' d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 15px center;
}

.form-control:focus, .form-select:focus {
    outline: none;
    border-color: var(--brass);
    box-shadow: 0 0 0 3px var(--brass-soft);
}

.is-invalid { border-color: #C0564F; }
.invalid-feedback, .errorlist, .alert-danger {
    color: #A5352E;
    font-size: 0.85rem;
    margin: 6px 0 0;
    padding: 0;
    list-style: none;
}
.cf-turnstile { display: flex; justify-content: center; margin: 4px 0; }

.form-actions { margin-top: 26px; }
.form-actions .btn { width: 100%; }

/* --------------------------------------------------------------------------
   13. ILLUSTRATED STEPS  (the how-to guides)
   -------------------------------------------------------------------------- */
.guide { display: grid; gap: clamp(22px, 3vw, 32px); }

.gstep {
    background: var(--porcelain-2);
    border: 1px solid var(--slate-line);
    border-radius: var(--r-lg);
    overflow: hidden;
}
.gstep-head { display: flex; gap: 16px; align-items: flex-start; padding: clamp(20px, 3vw, 26px); }
.gstep-num {
    flex: none;
    width: 36px; height: 36px;
    display: grid; place-items: center;
    border-radius: 50%;
    background: var(--brass-soft);
    color: var(--brass-deep);
    font-family: var(--mono); font-weight: 700; font-size: 0.85rem;
}
.gstep-head h3 { margin: 5px 0 0; }
.gstep-head p { color: var(--graphite); font-size: 0.92rem; margin: 8px 0 0; }
.gstep figure { margin: 0; border-top: 1px solid var(--slate-line); background: var(--porcelain); }
.gstep figure img { width: 100%; }

/* --------------------------------------------------------------------------
   14. DATA TABLE  (supporters)
   -------------------------------------------------------------------------- */
.table-wrap {
    overflow-x: auto;
    background: var(--porcelain-2);
    border: 1px solid var(--slate-line);
    border-radius: var(--r-lg);
}
.data-table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
.data-table th {
    text-align: left;
    font-family: var(--mono); font-size: 0.66rem; font-weight: 500;
    letter-spacing: 0.12em; text-transform: uppercase;
    color: var(--graphite);
    padding: 14px 16px;
    border-bottom: 1px solid var(--slate-line);
    white-space: nowrap;
}
.data-table td { padding: 14px 16px; border-bottom: 1px solid var(--slate-line); }
.data-table tbody tr:last-child td { border-bottom: 0; }
.data-table tbody tr:hover { background: var(--porcelain); }
.data-table .rank { font-family: var(--mono); color: var(--graphite); white-space: nowrap; }
.data-table .amount { font-family: var(--mono); font-weight: 700; color: var(--brass-deep); white-space: nowrap; }
.data-table .who { font-weight: 600; }

.table-empty { padding: 56px 24px; text-align: center; color: var(--graphite); }

@media (max-width: 700px) {
    .data-table thead { position: absolute; left: -9999px; }
    .data-table tr { display: block; padding: 12px 16px; border-bottom: 1px solid var(--slate-line); }
    .data-table tbody tr:last-child { border-bottom: 0; }
    .data-table td { display: flex; justify-content: space-between; gap: 18px; padding: 5px 0; border: 0; }
    .data-table td::before {
        content: attr(data-th);
        flex: none;
        font-family: var(--mono); font-size: 0.64rem;
        letter-spacing: 0.1em; text-transform: uppercase; color: var(--graphite);
    }
}

/* --------------------------------------------------------------------------
   15. FAQ  (disclosure list)
   -------------------------------------------------------------------------- */
.qa-list { border-top: 1px solid var(--slate-line); }
details.qa { border-bottom: 1px solid var(--slate-line); }
details.qa summary {
    list-style: none;
    cursor: pointer;
    padding: 18px 40px 18px 0;
    position: relative;
    font-family: var(--display); font-weight: 700;
    font-size: clamp(0.98rem, 1.5vw, 1.05rem);
    letter-spacing: -0.015em; line-height: 1.35;
}
details.qa summary::-webkit-details-marker { display: none; }
details.qa summary::after {
    content: "";
    position: absolute;
    right: 4px; top: 50%;
    width: 10px; height: 10px;
    border-right: 2px solid var(--brass);
    border-bottom: 2px solid var(--brass);
    transform: translateY(-70%) rotate(45deg);
    transition: transform 0.22s ease;
}
details.qa[open] summary::after { transform: translateY(-20%) rotate(-135deg); }
details.qa .qa-body { padding: 0 12px 22px 0; font-size: 0.93rem; color: var(--graphite); }
details.qa .qa-body a { color: var(--brass-deep); }

/* --------------------------------------------------------------------------
   16. TWO-COLUMN INTERIOR LAYOUT
   -------------------------------------------------------------------------- */
.split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 0.82fr);
    gap: clamp(32px, 5vw, 64px);
    align-items: start;
}
.split--narrow { grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); }
@media (max-width: 900px) {
    .split, .split--narrow { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   17. PAYMENT OUTCOME  (success / cancelled)
   -------------------------------------------------------------------------- */
.outcome-stage {
    background: var(--ink);
    padding-block: clamp(48px, 8vw, 96px);
}

.outcome {
    position: relative;
    max-width: 540px;
    margin-inline: auto;
    background: var(--porcelain-2);
    border-radius: var(--r-lg);
    padding: clamp(34px, 5vw, 52px) clamp(26px, 4vw, 44px) clamp(30px, 4vw, 40px);
    text-align: center;
    overflow: hidden;
    box-shadow: 0 40px 80px -40px rgba(0, 0, 0, 0.85);
}
/* A colour band across the top says which outcome this is before any reading */
.outcome::before {
    content: "";
    position: absolute; inset: 0 0 auto 0; height: 6px;
}
.outcome--ok::before  { background: linear-gradient(90deg, #1F7D5C, #3FB98C); }
.outcome--bad::before { background: linear-gradient(90deg, #A5352E, #D2726A); }

.outcome-mark {
    width: 84px; height: 84px;
    margin: 0 auto 24px;
    display: grid; place-items: center;
    border-radius: 50%;
}
.outcome-mark--ok  { background: rgba(63, 185, 140, 0.13); color: #1F7D5C; box-shadow: 0 0 0 10px rgba(63,185,140,0.07); }
.outcome-mark--bad { background: rgba(192, 86, 79, 0.11);  color: #A5352E; box-shadow: 0 0 0 10px rgba(192,86,79,0.06); }

.outcome h1 { font-size: clamp(1.7rem, 3.4vw, 2.25rem); margin-bottom: 14px; }
.outcome-lede { color: var(--graphite); max-width: 40ch; margin-inline: auto; font-size: 1rem; }

/* Everything that is a list of facts sits in its own panel, left-aligned on
   purpose, so the mixed alignment reads as deliberate rather than broken. */
.outcome-panel {
    margin-top: 30px;
    padding: 22px;
    border-radius: var(--r);
    background: var(--porcelain);
    text-align: left;
}
.outcome-panel + .outcome-panel { margin-top: 12px; }
.outcome-panel--warn { background: var(--brass-soft); }

.outcome-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 16px; }
.outcome-steps li { display: flex; align-items: flex-start; gap: 13px; }
.outcome-steps i {
    flex: none; font-style: normal;
    width: 27px; height: 27px;
    display: grid; place-items: center; border-radius: 50%;
    background: var(--brass); color: #1A1204;
    font-family: var(--mono); font-size: 0.73rem; font-weight: 700;
}
.outcome-steps b { display: block; color: #1B222C; font-size: 0.92rem; line-height: 1.35; }
.outcome-steps small { display: block; margin-top: 2px; font-size: 0.85rem; color: var(--graphite); line-height: 1.45; }

.outcome-note { display: flex; align-items: flex-start; gap: 11px; font-size: 0.87rem; color: var(--graphite); line-height: 1.5; }
.outcome-note svg { flex: none; margin-top: 2px; }
.outcome-note strong { color: #1B222C; }
.outcome-panel--warn .outcome-note svg { color: var(--brass-deep); }

.outcome-actions {
    display: flex; flex-wrap: wrap; gap: 10px;
    margin-top: 28px;
}
.outcome-actions .btn { flex: 1 1 190px; }

.outcome-help {
    margin-top: 20px; padding-top: 18px;
    border-top: 1px solid var(--slate-line);
    font-size: 0.85rem; color: var(--graphite);
}
.outcome-help a { color: var(--brass-deep); font-weight: 600; }

@media (max-width: 480px) {
    .outcome-actions .btn { flex: 1 1 100%; }
}

/* --------------------------------------------------------------------------
   18. STATUS PILLS + IN-TABLE ACTIONS
   -------------------------------------------------------------------------- */
.pill {
    display: inline-block;
    padding: 4px 11px;
    border-radius: 100px;
    font-family: var(--mono); font-size: 0.68rem; font-weight: 700;
    letter-spacing: 0.04em; white-space: nowrap;
}
.pill--ok      { background: rgba(63, 185, 140, 0.13); color: #1F7D5C; }
.pill--bad     { background: rgba(192, 86, 79, 0.11);  color: #A5352E; }
.pill--muted   { background: var(--porcelain);         color: var(--graphite); }
.pill--brass   { background: var(--brass-soft);        color: var(--brass-deep); }

/* Buttons that live inside a data table row */
.act-sm {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 34px; padding: 0 14px;
    border-radius: 100px;
    border: 1px solid var(--slate-line);
    background: var(--porcelain-2); color: #1B222C;
    font-family: var(--body); font-size: 0.8rem; font-weight: 700;
    cursor: pointer; white-space: nowrap;
    transition: border-color 0.16s ease, background 0.16s ease, transform 0.16s ease;
}
.act-sm:hover:not(:disabled) { border-color: var(--brass); background: var(--brass-soft); transform: translateY(-1px); }
.act-sm:disabled { opacity: 0.4; cursor: not-allowed; }
.act-sm--primary { background: var(--brass); border-color: var(--brass); color: #1A1204; }
.act-sm--primary:hover:not(:disabled) { background: #EDBA61; border-color: #EDBA61; }

.table-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* Account-page section heading */
.section-head {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 16px; flex-wrap: wrap; margin-bottom: 18px;
}
.section-head h2 { font-size: clamp(1.15rem, 2.2vw, 1.4rem); }
.section-head .count {
    font-family: var(--mono); font-size: 0.68rem;
    letter-spacing: 0.12em; text-transform: uppercase; color: var(--graphite);
}

/* --------------------------------------------------------------------------
   19. ACCOUNT TABLES  (wider container, composed cells, no side-scrolling)
   -------------------------------------------------------------------------- */
.wrap--wide { max-width: 1360px; }

/* A cell that carries a headline plus its supporting detail, so the table
   needs far fewer columns and never has to scroll sideways. */
.cell { display: grid; gap: 3px; }
.cell b { color: #1B222C; font-weight: 700; font-size: 0.94rem; line-height: 1.25; }
.cell small { color: var(--graphite); font-size: 0.79rem; line-height: 1.35; }
.cell .money { font-family: var(--mono); }

/* Rows vary in height (two-line cells beside one-line ones), so cells are
   centred rather than pinned to the top — otherwise short cells like Status
   float above the row's centre line. */
.data-table td { vertical-align: middle; }
/* The actions column sizes to its buttons and keeps them on one line; the
   width:1% trick was collapsing it so the pair wrapped. */
.data-table .col-actions { width: 1%; white-space: nowrap; }
.data-table .col-actions .table-actions { flex-wrap: nowrap; }

/* Status and action columns read better centred under their heading than
   pinned to the left of a wide column. */
.data-table .col-centre,
.data-table td.col-centre { text-align: center; }
.data-table td.col-centre .cell { justify-items: center; }
.data-table td.col-centre .table-actions { justify-content: center; }

/* Short, fixed-width identifier — a full UUID would wrap to three lines */
.id-chip {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 5px 10px;
    border-radius: 7px;
    background: var(--porcelain);
    border: 1px solid var(--slate-line);
    font-family: var(--mono); font-size: 0.74rem; color: #1B222C;
    white-space: nowrap; cursor: pointer;
    transition: border-color 0.16s ease, background 0.16s ease, color 0.16s ease;
}
.id-chip:hover { border-color: var(--brass); background: var(--brass-soft); }
.id-chip .id-icon { flex: none; color: var(--graphite); }
.id-chip:hover .id-icon { color: var(--brass-deep); }
.id-chip.is-copied {
    background: rgba(63, 185, 140, 0.13);
    border-color: rgba(63, 185, 140, 0.45);
    color: #1F7D5C;
}
.id-chip.is-copied .id-icon { color: #1F7D5C; }

.amount-strong { font-family: var(--mono); font-weight: 700; color: #1B222C; font-size: 0.94rem; }
.tip-line { font-family: var(--mono); font-size: 0.78rem; color: var(--brass-deep); }

@media (max-width: 700px) {
    /* Each row becomes a self-contained card: label on the left, value on the
       right, with the leading cell promoted to a heading across the top. */
    .data-table tr {
        padding: 16px;
        border: 1px solid var(--slate-line);
        border-radius: var(--r);
        background: var(--porcelain-2);
        margin-bottom: 12px;
    }
    .data-table tbody tr:last-child { margin-bottom: 0; border-bottom: 1px solid var(--slate-line); }
    .table-wrap { border: 0; background: transparent; }

    .data-table td {
        align-items: flex-start;
        padding: 7px 0;
        border-bottom: 1px solid var(--porcelain);
    }
    .data-table td:last-child { border-bottom: 0; padding-bottom: 0; }

    /* first cell = the card's title, full width, no label */
    .data-table td:first-child {
        display: block; padding: 0 0 12px;
        border-bottom: 1px solid var(--slate-line);
        margin-bottom: 6px;
    }
    .data-table td:first-child::before { content: none; }
    .data-table td:first-child .cell b { font-size: 1.02rem; }

    .data-table td::before { padding-top: 2px; }
    .data-table .cell { text-align: right; }
    .data-table td:first-child .cell { text-align: left; }

    .data-table .col-actions { width: auto; white-space: normal; }
    .data-table .col-actions .table-actions { flex-wrap: wrap; justify-content: flex-end; }
    /* on a stacked card the value belongs on the right, not centred */
    .data-table td.col-centre { text-align: right; }
    .data-table td.col-centre .cell { justify-items: end; }
    .data-table td.col-centre .table-actions { justify-content: flex-end; }
    .cell { gap: 2px; }

    /* comfortable tap targets on touch screens */
    .id-chip { min-height: 40px; padding: 8px 14px; font-size: 0.8rem; }
    .act-sm  { min-height: 42px; padding: 0 18px; }
}

/* --------------------------------------------------------------------------
   20. ERROR PAGES
   -------------------------------------------------------------------------- */
.error-code {
    font-family: var(--display);
    font-weight: 800;
    font-size: clamp(4.5rem, 14vw, 8rem);
    line-height: 0.9;
    letter-spacing: -0.05em;
    margin-bottom: 6px;
    background: linear-gradient(160deg, var(--brass), #F3C978);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}
.error-code--bad { background: linear-gradient(160deg, #C0564F, #E08A83); -webkit-background-clip: text; background-clip: text; }

.error-kicker {
    font-family: var(--mono); font-size: 0.68rem;
    letter-spacing: 0.16em; text-transform: uppercase;
    color: var(--graphite); margin-bottom: 18px;
}

.error-links {
    list-style: none; margin: 26px 0 0; padding: 22px 0 0;
    border-top: 1px solid var(--slate-line);
    display: grid; gap: 10px; text-align: left;
}
.error-links a {
    display: flex; align-items: center; gap: 10px;
    color: #1B222C; text-decoration: none; font-size: 0.9rem; font-weight: 600;
    padding: 9px 12px; border-radius: var(--r-sm);
    transition: background 0.16s ease;
}
.error-links a:hover { background: var(--porcelain); }
.error-links svg { flex: none; color: var(--brass-deep); }

/* --------------------------------------------------------------------------
   21. BLOG — shared between the index and the article
   -------------------------------------------------------------------------- */

/* Breadcrumbs — visible trail, and the JSON-LD alongside gives Google the
   same trail in the search result. */
.crumbs {
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
    list-style: none; margin: 0 0 22px; padding: 0;
    font-family: var(--mono); font-size: 0.68rem;
    letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--steel);
}
.crumbs li { display: flex; align-items: center; gap: 8px; }
.crumbs li + li::before { content: "/"; color: var(--ink-line); }
.crumbs a { color: var(--steel); text-decoration: none; transition: color 0.16s ease; }
.crumbs a:hover { color: var(--brass); }
.crumbs [aria-current="page"] { color: var(--brass); }

/* Facts under a page-head heading */
.head-facts {
    display: flex; flex-wrap: wrap;
    gap: 18px clamp(24px, 4vw, 46px);
    margin-top: clamp(26px, 3.5vw, 34px);
}
.head-fact { display: grid; gap: 3px; }
.head-fact b {
    font-family: var(--display); font-weight: 800;
    font-size: clamp(1.25rem, 2.4vw, 1.65rem);
    letter-spacing: -0.02em; color: var(--porcelain);
}
.head-fact small {
    font-family: var(--mono); font-size: 0.64rem;
    letter-spacing: 0.14em; text-transform: uppercase; color: var(--steel);
}

/* Meta line — author, date, reading time */
.post-meta {
    display: flex; flex-wrap: wrap; align-items: center; gap: 7px 12px;
    font-family: var(--mono); font-size: 0.68rem;
    letter-spacing: 0.06em; text-transform: uppercase;
    color: var(--graphite);
}
.post-meta .sep { color: var(--slate-line); }
.sec--ink .post-meta, .page-head .post-meta { color: var(--steel); }
.page-head .post-meta .sep { color: var(--ink-line); }

/* --------------------------------------------------------------------------
   21a. BLOG INDEX
   -------------------------------------------------------------------------- */

/* Featured write-up — the newest post, given the room it deserves */
.post-feature {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
    gap: 0;
    margin-bottom: clamp(26px, 3.5vw, 38px);
    background: var(--porcelain-2);
    border: 1px solid var(--slate-line);
    border-radius: var(--r-lg);
    overflow: hidden;
    text-decoration: none; color: inherit;
    transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
}
.post-feature:hover {
    transform: translateY(-4px);
    border-color: #C3CCD6;
    box-shadow: 0 30px 60px -32px rgba(16, 24, 40, 0.45);
}
.post-feature-shot { background: var(--ink); overflow: hidden; min-height: 260px; }
.post-feature-shot img {
    width: 100%; height: 100%; object-fit: cover;
    transition: transform 0.55s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.post-feature:hover .post-feature-shot img { transform: scale(1.04); }

.post-feature-body {
    padding: clamp(24px, 3.4vw, 40px);
    display: flex; flex-direction: column; justify-content: center;
}
.post-feature-body h2 {
    font-size: clamp(1.45rem, 2.8vw, 2.05rem);
    margin: 14px 0 12px;
}
.post-feature-body p { color: var(--graphite); font-size: 0.95rem; margin-bottom: 22px; }
.post-feature .read-on {
    display: inline-flex; align-items: center; gap: 10px;
    font-weight: 600; font-size: 0.92rem; color: var(--brass-deep);
}
.post-feature .read-on span { transition: transform 0.2s ease; }
.post-feature:hover .read-on span { transform: translateX(4px); }

/* "Latest" flag */
.flag {
    display: inline-flex; align-items: center; gap: 8px;
    font-family: var(--mono); font-size: 0.64rem;
    letter-spacing: 0.14em; text-transform: uppercase;
    color: var(--brass-deep);
}
.flag::before {
    content: ""; width: 7px; height: 7px; border-radius: 50%;
    background: var(--brass); box-shadow: 0 0 0 3px var(--brass-soft);
}

/* The rest of the write-ups, as a numbered editorial index.
   Deliberately NOT the boxed image-on-top card used for the app catalogue:
   these two pages sit one click apart, and identical cards left readers unsure
   whether they were looking at an article or a product. Hairline-separated
   numbered rows with a small thumbnail read as a journal instead. */
.post-index {
    list-style: none; margin: 0; padding: 0;
    counter-reset: post-idx;
    border-top: 1px solid var(--slate-line);
}
/* Search hides rows with an inline display:none, which also stops the counter
   incrementing — so a filtered list stays numbered 01, 02, 03 with no gaps. */
.post-row { counter-increment: post-idx; border-bottom: 1px solid var(--slate-line); }

.post-row-link {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: start;
    gap: clamp(16px, 2.6vw, 30px);
    padding: clamp(20px, 2.6vw, 28px) clamp(10px, 1.4vw, 16px);
    text-decoration: none; color: inherit;
    transition: background 0.18s ease;
}
.post-row-link:hover { background: var(--porcelain); }

/* Running number — the strongest single signal that this is an index */
.post-row-link::before {
    content: counter(post-idx, decimal-leading-zero);
    font-family: var(--mono); font-size: 0.8rem; font-weight: 700;
    color: var(--brass-deep);
    padding-top: 3px;
    font-variant-numeric: tabular-nums;
}

.post-row h3 {
    margin: 9px 0 8px;
    font-size: clamp(1.1rem, 2vw, 1.35rem);
    transition: color 0.18s ease;
}
.post-row-link:hover h3 { color: var(--brass-deep); }
.post-row-excerpt {
    font-size: 0.9rem; color: var(--graphite);
    max-width: 68ch; margin: 0;
}
/* Wraps: a write-up with Linux, Flathub, Windows and Source pills runs past
   the right edge of a phone otherwise, and the last pill is cut in half. */
.post-row-tail { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 12px; }

/* Large enough to actually read the screenshot — at 168px these were only
   telling you an image existed. */
.post-row-thumb {
    flex: none;
    width: clamp(170px, 23vw, 280px);
    aspect-ratio: 16 / 10;
    border-radius: var(--r);
    overflow: hidden;
    background: var(--ink);
    border: 1px solid var(--slate-line);
}
.post-row-thumb img {
    width: 100%; height: 100%; object-fit: cover;
    transition: transform 0.4s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.post-row-link:hover .post-row-thumb img { transform: scale(1.06); }

/* Platform pills — which builds the write-up actually links to */
.plat {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 5px 11px; border-radius: 100px;
    background: var(--porcelain);
    border: 1px solid var(--slate-line);
    font-family: var(--mono); font-size: 0.62rem;
    letter-spacing: 0.08em; text-transform: uppercase;
    color: var(--graphite);
}
.plat svg { flex: none; color: var(--brass-deep); }

/* --------------------------------------------------------------------------
   21b. ARTICLE
   -------------------------------------------------------------------------- */

/* Hairline that fills as you read. Sits on the nav's top edge. */
.read-progress {
    position: fixed; top: 0; left: 0; z-index: 101;
    height: 3px; width: 0;
    background: var(--brass);
    transition: width 0.1s linear;
}

/* The screenshot in the dark header, framed like an app window */
.shot-frame {
    border: 1px solid var(--ink-line);
    border-radius: var(--r);
    overflow: hidden;
    background: var(--ink-raised);
    box-shadow: 0 34px 80px -34px rgba(0, 0, 0, 0.95);
}
.shot-bar {
    display: flex; align-items: center; gap: 7px;
    padding: 11px 14px;
    border-bottom: 1px solid var(--ink-line);
    background: rgba(255, 255, 255, 0.03);
}
.shot-bar i {
    width: 9px; height: 9px; border-radius: 50%;
    background: var(--ink-line);
}
.shot-bar i:first-child { background: rgba(224, 169, 75, 0.55); }
.shot-bar span {
    margin-left: 6px;
    font-family: var(--mono); font-size: 0.64rem;
    letter-spacing: 0.1em; text-transform: uppercase; color: var(--steel);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* height:auto and no width/height attributes on the tag: the screenshots are
   all landscape but at differing ratios (1.53 to 1.88), so anything that pins
   a ratio here stretches some of them. The intrinsic ratio is the right one. */
.shot-frame img { width: 100%; height: auto; display: block; }

/* The hero screenshot is a button that opens the lightbox. */
.shot-open {
    display: block; width: 100%;
    padding: 0; border: 0; background: none;
    cursor: zoom-in;
    position: relative;
}
.shot-open::after {
    /* Darkens the shot on hover so the zoom cue reads against a light UI */
    content: "";
    position: absolute; inset: 0;
    background: rgba(10, 13, 19, 0);
    transition: background 0.2s ease;
}
.shot-open:hover::after { background: rgba(10, 13, 19, 0.22); }

.shot-cue {
    position: absolute; right: 12px; bottom: 12px; z-index: 1;
    display: inline-flex; align-items: center; gap: 7px;
    padding: 7px 12px;
    border-radius: 100px;
    background: rgba(10, 13, 19, 0.78);
    border: 1px solid var(--ink-line);
    color: var(--porcelain);
    font-family: var(--mono); font-size: 0.62rem;
    letter-spacing: 0.1em; text-transform: uppercase;
    opacity: 0; transform: translateY(4px);
    transition: opacity 0.2s ease, transform 0.2s ease;
}
.shot-open:hover .shot-cue,
.shot-open:focus-visible .shot-cue { opacity: 1; transform: none; }

/* Thumbnail strip under the hero */
.shot-thumbs {
    display: flex; flex-wrap: wrap; gap: 8px;
    margin-top: 10px;
}
.shot-thumb {
    width: 76px;
    aspect-ratio: 16 / 10;
    flex: none;
    padding: 0; overflow: hidden;
    border: 1px solid var(--ink-line);
    border-radius: 8px;
    background: var(--ink-raised);
    cursor: pointer;
    opacity: 0.62;
    transition: opacity 0.16s ease, border-color 0.16s ease;
}
.shot-thumb img { width: 100%; height: 100%; object-fit: cover; }
.shot-thumb:hover { opacity: 1; }
.shot-thumb[aria-current="true"] { opacity: 1; border-color: var(--brass); }

/* --------------------------------------------------------------------------
   23. LIGHTBOX
   -------------------------------------------------------------------------- */
.lightbox {
    position: fixed; inset: 0; z-index: 300;
    display: none;
    grid-template-rows: auto 1fr auto;
    /* minmax(0, …) rather than 1fr: a grid track sized to auto lets the image's
       intrinsic width push the stage wider than the screen, which clips the
       screenshot on a phone instead of scaling it down. */
    grid-template-columns: minmax(0, 1fr);
    background: rgba(6, 8, 12, 0.94);
    backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}
.lightbox.is-open { display: grid; }
/* Stops the page scrolling behind the overlay */
body.is-locked { overflow: hidden; }

/* Every child is placed by hand. The arrows share the stage's row, and with
   auto-placement that occupied cell pushed the stage down into the rail's row
   instead — the picture ended up short and pinned to the bottom. */
.lightbox-bar   { grid-row: 1; grid-column: 1; }
.lightbox-stage { grid-row: 2; grid-column: 1; }
.lightbox-rail  { grid-row: 3; grid-column: 1; }

.lightbox-bar {
    display: flex; align-items: center; justify-content: space-between;
    gap: 16px;
    padding: 14px clamp(14px, 3vw, 26px);
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.lightbox-caption {
    min-width: 0;
    font-family: var(--mono); font-size: 0.68rem;
    letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--steel);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lightbox-caption b { color: var(--porcelain); font-weight: 600; }

.lightbox-shut {
    flex: none;
    width: 42px; height: 42px;
    display: grid; place-items: center;
    border: 1px solid var(--ink-line); border-radius: 50%;
    background: transparent; color: var(--porcelain);
    cursor: pointer;
    transition: border-color 0.16s ease, color 0.16s ease;
}
.lightbox-shut:hover { border-color: var(--brass); color: var(--brass); }

/* Flex, not grid: a grid row sizes itself to the image, so max-height:100% had
   no definite height to resolve against and a landscape screenshot grew past
   the stage and ran under the thumbnail rail. A flex line has the definite
   height the percentage needs, so the image is scaled to fit instead. */
.lightbox-stage {
    position: relative;
    display: flex; align-items: center; justify-content: center;
    min-height: 0; min-width: 0;
    overflow: hidden;
    padding: clamp(12px, 2.5vw, 26px);
}
.lightbox-stage img {
    max-width: 100%; max-height: 100%;
    width: auto; height: auto;
    object-fit: contain;
    border-radius: var(--r-sm);
    box-shadow: 0 30px 80px -30px rgba(0, 0, 0, 0.9);
}

/* Laid into the stage's own grid row rather than positioned inside the stage
   or against the viewport. Inside the stage they tracked each screenshot's
   letterboxing; against the viewport they sat above the picture on a phone,
   where the rail is hidden but the title bar is not, so the two centres do not
   coincide. Sharing the stage's row centres them on the picture at every size.
   No transform is involved, so the press scale has nothing to fight. */
.lightbox-step {
    grid-row: 2; grid-column: 1;
    align-self: center; justify-self: start;
    margin-inline: clamp(8px, 2vw, 22px);
    z-index: 2;
    width: 46px; height: 46px;
    display: grid; place-items: center;
    border: 1px solid var(--ink-line); border-radius: 50%;
    background: rgba(10, 13, 19, 0.72);
    color: var(--porcelain);
    cursor: pointer;
    transition: border-color 0.16s ease, color 0.16s ease, background 0.16s ease;
}
.lightbox-step:hover { border-color: var(--brass); color: var(--brass); background: rgba(10, 13, 19, 0.9); }
.lightbox-step:active { transform: scale(0.94); }
.lightbox-step--next { justify-self: end; }

/* One line that scrolls sideways rather than wrapping: a gallery with enough
   screenshots to wrap would take two or three rows off the height of the
   image above it. */
.lightbox-rail {
    display: flex; justify-content: center; flex-wrap: nowrap; gap: 8px;
    padding: 14px clamp(14px, 3vw, 26px);
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    overflow-x: auto;
    scrollbar-width: thin;
}
.lightbox-rail .shot-thumb { width: 84px; }

/* A single-image gallery has nothing to step through or pick from */
.lightbox--solo .lightbox-step,
.lightbox--solo .lightbox-rail { display: none; }

@media (max-width: 620px) {
    .lightbox-rail { display: none; }
    .lightbox-step { width: 40px; height: 40px; }
}

/* Article + sidebar */
.article-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 320px);
    gap: clamp(32px, 5vw, 60px);
    align-items: start;
}
.article-aside {
    position: sticky;
    top: calc(var(--nav-h) + 20px);
    display: grid; gap: 16px;
}

/* Author's note — an opinion before the spec sheet. Set off by a brass rule
   rather than boxed, so it reads as the writer's voice and not a callout. */
.authors-note {
    margin: 0 0 clamp(30px, 3.6vw, 44px);
    padding-left: clamp(18px, 2.4vw, 26px);
    border-left: 3px solid var(--brass);
}
.authors-note p {
    font-size: clamp(1.02rem, 1.6vw, 1.14rem);
    line-height: 1.65;
    color: #1B222C;
    margin: 0 0 0.9em;
    max-width: 62ch;
}
.authors-note p:last-of-type { margin-bottom: 0; }
/* The opening line carries the argument, so it gets the extra weight. */
.authors-note p:first-of-type { font-size: clamp(1.1rem, 1.9vw, 1.28rem); }
.authors-note .byline {
    display: flex; align-items: center; gap: 10px;
    margin-top: 20px;
    font-family: var(--mono); font-size: 0.65rem;
    letter-spacing: 0.13em; text-transform: uppercase;
    color: var(--graphite);
}
.authors-note .byline b { color: #1B222C; font-weight: 700; }
.authors-note .byline .author-mark { width: 36px; height: 36px; }

/* Source repository, sitting with the install commands */
.source-link {
    display: inline-flex; align-items: center; gap: 9px;
    margin-top: 14px;
    font-family: var(--mono); font-size: 0.7rem;
    letter-spacing: 0.06em;
    color: var(--steel);
    text-decoration: none;
    transition: color 0.16s ease;
}
.source-link:hover { color: var(--brass); }
.source-link svg { flex: none; }

/* Long-form copy pasted in from the admin. The rules below have to cope with
   whatever tags the author used, which in practice means h4/h5 headings, a
   snapcraft iframe, and <br> used for spacing between blocks. */
.prose--post { max-width: 72ch; }
.prose--post h4, .prose--post h5 {
    font-family: var(--display); font-weight: 700;
    letter-spacing: -0.015em; line-height: 1.2;
    color: #1B222C;
    margin: 40px 0 14px;
}
.prose--post h4 { font-size: clamp(1.2rem, 2.2vw, 1.45rem); }
.prose--post h5 { font-size: clamp(1.02rem, 1.7vw, 1.15rem); }
.prose--post > :first-child { margin-top: 0; }

/* The copy uses <br> for spacing. Where one follows a block element its own
   margin has already opened the gap, so the <br> only doubles it — and a run
   of them triples it.
   Deliberately narrow: the older write-ups have loose text at the top level
   with nothing but <br><br> between paragraphs, and hiding those would run
   their sentences together. A <br> that follows inline text keeps working. */
.prose--post > :is(p, ul, ol, h1, h2, h3, h4, h5, h6,
                   blockquote, table, pre, figure, iframe, div) + br { display: none; }
.prose--post > br + br { display: none; }

.prose--post ul, .prose--post ol { padding-left: 0; list-style: none; gap: 10px; }
.prose--post ul > li {
    position: relative;
    padding-left: 26px;
}
.prose--post ul > li::before {
    content: "";
    position: absolute; left: 4px; top: 0.62em;
    width: 7px; height: 7px; border-radius: 2px;
    background: var(--brass);
    transform: rotate(45deg);
}
.prose--post ol { counter-reset: prose-ol; }
.prose--post ol > li { position: relative; padding-left: 30px; counter-increment: prose-ol; }
.prose--post ol > li::before {
    content: counter(prose-ol);
    position: absolute; left: 0; top: 0;
    font-family: var(--mono); font-size: 0.78rem; font-weight: 700;
    color: var(--brass-deep);
}

.prose--post iframe {
    display: block;
    width: 100%;
    max-width: 100%;
    margin: 30px 0;
    border: 1px solid var(--slate-line) !important;
    border-radius: var(--r) !important;
    background: var(--porcelain-2);
}
.prose--post img {
    border-radius: var(--r);
    border: 1px solid var(--slate-line);
    margin: 26px 0;
}
.prose--post table { width: 100%; border-collapse: collapse; margin: 26px 0; font-size: 0.92rem; }
.prose--post th, .prose--post td { padding: 11px 14px; border: 1px solid var(--slate-line); text-align: left; }
.prose--post th { background: var(--porcelain); font-weight: 600; }
.prose--post blockquote {
    margin: 26px 0; padding: 4px 0 4px 20px;
    border-left: 3px solid var(--brass);
    color: var(--graphite); font-style: italic;
}
.prose--post code {
    font-family: var(--mono); font-size: 0.86em;
    background: var(--porcelain); border: 1px solid var(--slate-line);
    border-radius: 5px; padding: 2px 6px;
}
.prose--post pre {
    background: var(--ink); color: #E6EAF0;
    border-radius: var(--r); padding: 18px 20px;
    overflow-x: auto; margin: 26px 0;
    font-family: var(--mono); font-size: 0.85rem; line-height: 1.6;
}
.prose--post pre code { background: none; border: 0; padding: 0; color: inherit; }

/* Table of contents ------------------------------------------------------- */
.toc-title, .side-title {
    font-family: var(--mono); font-size: 0.64rem; font-weight: 500;
    letter-spacing: 0.16em; text-transform: uppercase;
    color: var(--graphite);
    margin: 0 0 14px;
}
.toc { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.toc a {
    display: block;
    padding: 7px 12px;
    border-left: 2px solid var(--slate-line);
    text-decoration: none;
    font-size: 0.87rem; line-height: 1.4; color: var(--graphite);
    transition: color 0.16s ease, border-color 0.16s ease, background 0.16s ease;
}
.toc a:hover { color: #1B222C; background: var(--porcelain); }
.toc a.is-current {
    color: var(--brass-deep); font-weight: 600;
    border-color: var(--brass); background: var(--brass-soft);
}
.toc .lvl-3 { padding-left: 24px; font-size: 0.83rem; }

/* Sidebar panels ---------------------------------------------------------- */
.side-card {
    background: var(--porcelain-2);
    border: 1px solid var(--slate-line);
    border-radius: var(--r-lg);
    padding: clamp(18px, 2.4vw, 24px);
}
.side-card--dark {
    background: var(--ink);
    border-color: var(--ink-line);
    color: var(--porcelain);
}
.side-card--dark .side-title { color: var(--steel); }
.side-card--dark p { color: var(--steel); font-size: 0.88rem; }
.side-card > .btn { width: 100%; }
.side-card .stack { display: grid; gap: 9px; margin-top: 4px; }

.side-links { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.side-links a {
    display: block; padding: 10px 12px;
    border-radius: var(--r-sm);
    text-decoration: none;
    font-size: 0.88rem; font-weight: 600; line-height: 1.35; color: #1B222C;
    transition: background 0.16s ease, color 0.16s ease;
}
.side-links a:hover { background: var(--brass-soft); color: var(--brass-deep); }

/* Author ------------------------------------------------------------------ */
.author {
    display: flex; align-items: center; gap: 14px;
    margin-bottom: 14px;
}
.author-mark {
    flex: none;
    width: 46px; height: 46px;
    display: grid; place-items: center;
    border-radius: 50%;
    overflow: hidden;
    background: var(--brass-soft);
    color: var(--brass-deep);
    font-family: var(--display); font-weight: 800; font-size: 1.05rem;
}
/* A photograph when there is one, initials when there is not. The source is
   pre-cropped square and centred on the face, so cover needs no nudging. */
.author-mark img { width: 100%; height: 100%; object-fit: cover; }
.author-mark--photo { background: var(--ink); box-shadow: 0 0 0 2px var(--brass-soft); }
.author b { display: block; font-size: 0.98rem; line-height: 1.25; }
.author small {
    display: block;
    font-family: var(--mono); font-size: 0.63rem;
    letter-spacing: 0.1em; text-transform: uppercase; color: var(--graphite);
}
.side-card--dark .author small { color: var(--steel); }
.side-card--dark .author-mark { background: rgba(224, 169, 75, 0.16); color: var(--brass); }

/* Author band across the foot of the index */
.author-band {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 0.72fr);
    gap: clamp(26px, 4vw, 52px);
    align-items: center;
}
.author-band .author-mark { width: 56px; height: 56px; font-size: 1.25rem; }

/* Share + tags ------------------------------------------------------------ */
.share { display: flex; flex-wrap: wrap; gap: 8px; }
.share a, .share button {
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    min-height: 40px; padding: 0 15px;
    border-radius: 100px;
    border: 1px solid var(--slate-line);
    background: var(--porcelain-2); color: #1B222C;
    font-family: var(--body); font-size: 0.83rem; font-weight: 600;
    text-decoration: none; cursor: pointer;
    transition: border-color 0.16s ease, background 0.16s ease, color 0.16s ease;
}
.share a:hover, .share button:hover {
    border-color: var(--brass); background: var(--brass-soft); color: var(--brass-deep);
}
.share svg { flex: none; }

/* Keyword lists in the copy are pulled out of the flow and shown as chips —
   a wall of comma-separated keywords mid-article reads as spam. */
.tagcloud { display: flex; flex-wrap: wrap; gap: 7px; }
.tagcloud span {
    padding: 5px 11px;
    border-radius: 100px;
    background: var(--porcelain);
    border: 1px solid var(--slate-line);
    font-family: var(--mono); font-size: 0.7rem;
    color: var(--graphite);
}

.article-foot {
    margin-top: clamp(34px, 4vw, 46px);
    padding-top: clamp(26px, 3vw, 34px);
    border-top: 1px solid var(--slate-line);
    display: grid; gap: 26px;
}

/* Download call to action at the foot of the article */
.get-band {
    display: flex; flex-wrap: wrap; align-items: center; gap: 20px 28px;
    justify-content: space-between;
    padding: clamp(24px, 3.4vw, 34px);
    border-radius: var(--r-lg);
    background: var(--ink-raised);
    border: 1px solid var(--ink-line);
    color: var(--porcelain);
}
.get-band h2 { font-size: clamp(1.3rem, 2.4vw, 1.7rem); }
.get-band p { color: var(--steel); font-size: 0.92rem; margin: 10px 0 0; max-width: 46ch; }
.get-band .head-actions { margin-top: 0; }

/* "Read next" ------------------------------------------------------------- */
.next-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 14px;
}
.next-card {
    display: flex; gap: 14px; align-items: center;
    padding: 14px;
    border: 1px solid var(--slate-line);
    border-radius: var(--r);
    background: var(--porcelain-2);
    text-decoration: none; color: inherit;
    transition: border-color 0.18s ease, transform 0.18s ease;
}
.next-card:hover { border-color: var(--brass); transform: translateY(-2px); }
.next-card img {
    flex: none; width: 62px; height: 48px;
    object-fit: cover; border-radius: 8px; background: var(--ink);
}
.next-card b {
    display: block;
    font-family: var(--display); font-weight: 700; font-size: 0.94rem;
    letter-spacing: -0.015em; line-height: 1.25;
}
.next-card small {
    display: block; margin-top: 3px;
    font-family: var(--mono); font-size: 0.63rem;
    letter-spacing: 0.08em; text-transform: uppercase; color: var(--graphite);
}

/* --------------------------------------------------------------------------
   21c. BLOG RESPONSIVE
   -------------------------------------------------------------------------- */
@media (max-width: 1000px) {
    .article-grid { grid-template-columns: 1fr; }
    /* Stuck to the top of a single column the sidebar would follow the reader
       down the whole article, so it goes back in the flow. */
    .article-aside { position: static; }
    .toc-card { display: none; }
    .author-band { grid-template-columns: 1fr; }
}
/* Side by side the featured card leaves the headline barely 260px on a tablet,
   so it stacks well before the other cards do. */
@media (max-width: 860px) {
    .post-feature { grid-template-columns: 1fr; }
    .post-feature-shot { min-height: 0; aspect-ratio: 16 / 9; }
}
@media (max-width: 620px) {
    /* Beside a thumbnail the headline gets ~150px on a phone and runs to five
       lines. The featured post above already carries a large image, so the
       index goes text-first and the row thumbnails come off. */
    .post-row-thumb { display: none; }
    .post-row-link { grid-template-columns: auto minmax(0, 1fr); }
}
@media (max-width: 560px) {
    .get-band .head-actions { width: 100%; }
    .get-band .btn, .get-band .get, .get-band .get > summary { flex: 1 1 100%; width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
    .read-progress { transition: none; }
}

/* --------------------------------------------------------------------------
   22. INSTALL STRIP  (the one-line snap command, on a dark surface)
   -------------------------------------------------------------------------- */
.install {
    display: flex; align-items: center; gap: 12px;
    padding: 15px 15px 15px 18px;
    background: #0A0D13;
    border: 1px solid var(--ink-line);
    border-radius: var(--r);
    box-shadow: 0 24px 60px -30px rgba(0, 0, 0, 0.9);
    font-family: var(--mono); font-size: 0.86rem;
}
.install .prompt { color: var(--brass); flex: none; }
.install code {
    flex: 1; min-width: 0;
    color: #E6EAF0;
    font-family: inherit;
    white-space: nowrap; overflow: hidden;
}
.install button {
    flex: none;
    background: transparent;
    border: 1px solid var(--ink-line);
    border-radius: 6px;
    color: var(--steel);
    font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.08em;
    padding: 6px 12px; cursor: pointer;
    transition: color 0.16s ease, border-color 0.16s ease;
}
.install button:hover { color: var(--brass); border-color: var(--brass); }

.install-note {
    display: flex; align-items: center; gap: 9px;
    margin-top: 14px;
    font-family: var(--mono); font-size: 0.7rem; line-height: 1.5;
    color: var(--steel);
}

/* Snap / Flatpak switch above the strip, for apps published to both. Tabs sit
   on the strip's top edge so the two read as one object. */
.install-tabs { display: flex; gap: 4px; margin-bottom: -1px; position: relative; z-index: 1; }
.install-tabs button {
    padding: 7px 15px;
    border: 1px solid var(--ink-line);
    border-bottom-color: transparent;
    border-radius: 8px 8px 0 0;
    background: transparent;
    color: var(--steel);
    font-family: var(--mono); font-size: 0.66rem;
    letter-spacing: 0.1em; text-transform: uppercase;
    cursor: pointer;
    transition: color 0.16s ease, background 0.16s ease;
}
.install-tabs button:hover { color: var(--porcelain); }
.install-tabs button[aria-selected="true"] {
    background: #0A0D13;
    color: var(--brass);
}
/* With tabs attached, the strip's own top-left corner would cut across them. */
.install-tabs + .install { border-top-left-radius: 0; border-top-right-radius: 0; }

/* Blinking cursor at the end of a typed command */
.caret {
    display: inline-block; width: 8px;
    background: var(--brass);
    animation: blink 1.05s steps(2, start) infinite;
    margin-left: 1px;
}
@keyframes blink { to { visibility: hidden; } }

@media (prefers-reduced-motion: reduce) {
    .caret { display: none; }
}
