/* ==========================================================================
   كُتبجي — kutubji.com

   Two rules govern this file.

   1. The colour tokens are LIFTED FROM THE APP, not chosen here. They come
      from Rewaya/Core/DesignSystem/Tokens/DSColor.swift, so the site and the
      app are the same product rather than two things that resemble each
      other. If a token changes there, change it here.

   2. Every directional property is LOGICAL (inline-start/end), never left or
      right. The page is Arabic and RTL; the app's own home rails shipped
      broken twice because of hard-coded left/right, and a stylesheet that
      only works in one direction is a stylesheet with a latent bug.
   ========================================================================== */

@font-face {
    font-family: 'Almarai';
    src: url('/fonts/Almarai-Regular.woff2') format('woff2');
    font-weight: 400;
    font-display: swap;
}
@font-face {
    font-family: 'Almarai';
    src: url('/fonts/Almarai-Bold.woff2') format('woff2');
    font-weight: 700;
    font-display: swap;
}
@font-face {
    font-family: 'Almarai';
    src: url('/fonts/Almarai-ExtraBold.woff2') format('woff2');
    font-weight: 800;
    font-display: swap;
}
:root {
    --bg: #FCF9F5;
    --surface: #F4EFE8;
    --raised: #FCF9F4;
    --text: #1F1F1F;
    --muted: #6B6B6B;
    --brand: #02323E;         /* app icon plate + splash canvas */
    --brand-lift: #0C5C6E;    /* legible against cream where the true
                                 brand colour would read as black */
    --gold: #C9A645;
    --line: #E9E2DA;

    --measure: 34rem;          /* prose column — ~65 Arabic characters */
    --wrap: 68rem;
    --pad: clamp(1.25rem, 5vw, 2.5rem);

    /* One family, as in the app itself — DSTypography.swift builds the whole
       type system on Almarai. Display weight rather than a display face is
       what separates headings from body here. */
    --display: 'Almarai', system-ui, sans-serif;
    --body: 'Almarai', system-ui, sans-serif;
}

/* Light only, deliberately. Book covers are printed artwork designed for
   paper, and they read as intended on a warm cream page and muddy on
   near-black. The app ships a dark mode; this page does not need one. */

* { box-sizing: border-box; }

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

body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font-family: var(--body);
    font-size: 17px;
    line-height: 1.85;          /* Arabic needs more leading than Latin */
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
}

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

a { color: inherit; }

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

/* Prose is deliberately narrow and left un-justified. Justified Arabic on the
   web stretches the kashida badly in every engine. */
.prose {
    max-width: var(--measure);
    text-align: start;
}

/* --------------------------------------------------------------- topbar -- */

.topbar {
    position: sticky;
    top: 0;
    z-index: 40;
    background: color-mix(in srgb, var(--bg) 88%, transparent);
    backdrop-filter: saturate(140%) blur(12px);
    border-block-end: 1px solid var(--line);
}

.topbar-inner {
    max-width: var(--wrap);
    margin-inline: auto;
    padding: 0.7rem var(--pad);
    display: flex;
    align-items: center;
    gap: 0.7rem;
}

.mark { width: 30px; height: 30px; border-radius: 8px; }

.wordmark {
    font-family: var(--display);
    font-weight: 800;
    font-size: 1.2rem;
    line-height: 1;
}

.topbar nav {
    margin-inline-start: auto;
    display: flex;
    align-items: center;
    gap: 1.25rem;
    font-size: 0.9rem;
}

.topbar nav a { color: var(--muted); text-decoration: none; }
.topbar nav a:hover { color: var(--text); }

/* Hidden until the narrow breakpoint at the bottom of this file. */
.menu-btn {
    display: none;
    margin-inline-start: auto;
    width: 40px;
    height: 40px;
    align-items: center;
    justify-content: center;
    background: none;
    border: 1px solid var(--line);
    border-radius: 10px;
    color: var(--text);
    cursor: pointer;
    padding: 0;
}
.menu-btn svg { width: 20px; height: 20px; }
.menu-btn .ic-x { display: none; }
.menu-btn[aria-expanded="true"] .ic-x { display: block; }
.menu-btn[aria-expanded="true"] .ic-m { display: none; }

.topbar .get {
    color: var(--bg);
    background: var(--brand);
    padding: 0.4rem 0.95rem;
    border-radius: 999px;
    font-weight: 700;
}
.topbar .get:hover { color: var(--bg); opacity: 0.85; }

/* ----------------------------------------------------------------- hero -- */

.hero { position: relative; overflow: hidden; }

/* The wall of real covers. This is the whole visual idea: 1,814 Arabic books
   is something no stock image and no generator can imitate, so the library
   itself is the artwork rather than a phone mock-up. */
.wall {
    position: absolute;
    inset: 0;
    display: flex;
    gap: 0.75rem;
    justify-content: center;
    padding-block-start: 2rem;
    /* Quiet, but still recognisably books. Below about 0.35 they stop looking
       like covers and start looking like a printing fault. */
    opacity: 0.46;
    /* ONE mask, not two composited together. `mask-composite` over a layer
       that animates every frame re-rasterises the whole wall continuously and
       stalls the renderer; the rest of the fading is done by .hero::after,
       which composites as an ordinary layer. */
    -webkit-mask-image: linear-gradient(to bottom, transparent, #000 20%, #000 60%, transparent 94%);
    mask-image: linear-gradient(to bottom, transparent, #000 20%, #000 60%, transparent 94%);
    pointer-events: none;
}

/* A cream veil, heaviest where the copy sits (inline-start, i.e. the right in
   RTL) and thinning across to the left. This replaces the floating card: the
   headline sits on the page itself, and the covers simply dissolve beneath it. */
.hero::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
        linear-gradient(to left,
            var(--bg) 20%,
            color-mix(in srgb, var(--bg) 74%, transparent) 55%,
            transparent 88%),
        linear-gradient(to bottom, var(--bg), transparent 15%, transparent 78%, var(--bg));
}

.wall-col {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    /* Grow to fill, so the wall spans the full width at any viewport instead
       of leaving bare margins on a wide screen. Capped so the covers stay
       small enough to read as a backdrop. */
    flex: 1 1 0;
    min-width: 0;
    max-width: 190px;
    animation: drift linear infinite;
    /* No `will-change`. It forces six compositor layers to be rasterised
       before first paint, and on a throttled mobile CPU that lands squarely in
       LCP's render-delay phase. The animation still composites fine — the
       browser promotes the layer when the animation actually starts. */
}

/* Alternating direction and duration; without this the columns move as one
   slab and the whole thing reads as a single sliding image. */
.wall-col:nth-child(odd)  { animation-duration: 96s; }
.wall-col:nth-child(even) { animation-duration: 128s; animation-direction: reverse; }
.wall-col:nth-child(3n)   { animation-duration: 150s; }

.wall-col img {
    width: 100%;
    aspect-ratio: 2 / 3;
    object-fit: cover;
    border-radius: 4px;
    box-shadow: 0 1px 3px rgb(0 0 0 / 0.16);
}

@keyframes drift {
    from { transform: translateY(0); }
    to   { transform: translateY(-50%); }   /* each column's list is doubled */
}

@media (prefers-reduced-motion: reduce) {
    .wall-col { animation: none; }
}

.hero-inner {
    position: relative;
    z-index: 1;
    max-width: var(--wrap);
    margin-inline: auto;
    padding: clamp(3.5rem, 9vw, 6rem) var(--pad) clamp(3rem, 7vw, 4.5rem);
}

/* No card, no border, no shadow — the copy sits on the page, and .hero::after
   above does the work of clearing the covers out from behind it. */
.hero-plate { max-width: 38rem; }

h1 {
    font-family: var(--display);
    font-weight: 800;
    /* Smaller than a calligraphic face would need: Almarai ExtraBold carries
       far more weight per point, and 3.4rem of it shouts. */
    font-size: clamp(1.85rem, 5.2vw, 2.9rem);
    line-height: 1.45;
    margin: 0 0 1rem;
}

.lede {
    margin: 0 0 1.6rem;
    font-size: 1.06rem;
    color: var(--muted);
    max-width: 33rem;
}

/* ------------------------------------------------------- app store badge -- */

.badge-row { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }

.appstore {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    background: var(--brand);
    color: var(--bg);
    text-decoration: none;
    padding: 0.6rem 1.15rem;
    border-radius: 12px;
    transition: opacity 0.15s ease;
}
.appstore:hover { opacity: 0.86; }
.appstore svg { width: 22px; height: 26px; flex: none; }
.appstore .t { display: flex; flex-direction: column; line-height: 1.25; }
.appstore .t small { font-size: 0.66rem; opacity: 0.8; }
.appstore .t strong { font-size: 1rem; font-weight: 700; }

.free { color: var(--muted); font-size: 0.9rem; }

/* -------------------------------------------------------------- sections -- */

section { padding-block: clamp(3.25rem, 8vw, 5.5rem); }

.bordered { border-block-start: 1px solid var(--line); }

h2 {
    font-family: var(--display);
    font-weight: 800;
    font-size: clamp(1.35rem, 3.2vw, 1.85rem);
    line-height: 1.5;
    margin: 0 0 1rem;
}

h3 {
    font-size: 1.06rem;
    font-weight: 800;
    margin: 0 0 0.4rem;
}

p { margin: 0 0 1.1rem; }

.muted { color: var(--muted); }

/* --------------------------------------------------------------- library -- */

/* Deliberately asymmetric: a display numeral on one side, prose on the other.
   A centred three-card row is the layout this page is avoiding. */
.library {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(1.5rem, 4vw, 3rem);
    align-items: start;
}

@media (min-width: 800px) {
    .library { grid-template-columns: 15rem minmax(0, 1fr); }
}

/* The twelve shelves, named. This replaced a column of exact counts — names
   say more than numbers, and they don't go stale every time books are added. */
.cats {
    list-style: none;
    margin: 0;
    padding: 0 1.15rem 0 0;
    border-inline-start: 3px solid var(--gold);
    padding-inline-start: 1.15rem;
    padding-inline-end: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.cats li {
    font-size: 0.95rem;
    font-weight: 700;
}

.cats a {
    color: var(--text);
    text-decoration: none;
}
.cats a:hover { color: var(--brand-lift); text-decoration: underline; text-underline-offset: 4px; }

/* Wrap into rows on narrow screens rather than a 12-line tower. */
@media (max-width: 799px) {
    .cats {
        flex-direction: row;
        flex-wrap: wrap;
        gap: 0.45rem 0.9rem;
    }
    .cats li { font-size: 0.88rem; font-weight: 400; color: var(--muted); }
}

/* ---------------------------------------------------------------- quotes -- */

.quotes {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
}

figure.q {
    margin: 0;
    padding: 1.5rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 14px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 1.1rem;
}

/* Regular weight, not the heading's ExtraBold — a quote set bold reads as
   shouting rather than as someone else's voice. */
figure.q blockquote {
    margin: 0;
    font-weight: 400;
    font-size: 1.1rem;
    line-height: 2;
}

figure.q figcaption {
    font-size: 0.84rem;
    color: var(--muted);
    border-block-start: 1px solid var(--line);
    padding-block-start: 0.85rem;
}

figure.q figcaption b { color: var(--text); font-weight: 700; }

/* ------------------------------------------------------------- features -- */

/* Prose beside a real screenshot, alternating sides — the Standard Ebooks
   approach. Every claim gets a sentence that justifies it instead of a
   one-line label under an interchangeable outline icon. */
.feature {
    display: grid;
    gap: clamp(1.25rem, 4vw, 3rem);
    align-items: center;
    padding-block: clamp(1.5rem, 4vw, 2.5rem);
}

@media (min-width: 800px) {
    .feature { grid-template-columns: minmax(0, 1fr) 15rem; }

    /* Alternating sides. `order` alone is NOT enough: it moves the item into
       the first track while the tracks keep their widths, so the screenshot
       lands in the 1fr column and renders three times too tall. The template
       has to be mirrored along with the order. */
    .feature.flip { grid-template-columns: 15rem minmax(0, 1fr); }
    .feature.flip > .shot { order: -1; }
}

/* The screenshots ship inside a drawn device frame with rounded, transparent
   corners. So no border and no box-shadow — both would trace a rectangle
   around a shape that isn't one. `drop-shadow` follows the alpha instead. */
.feature .shot img {
    width: 100%;
    /* Required: the markup carries width/height attributes so the browser can
       reserve space before the image loads, and without `auto` the height
       attribute wins over the percentage width and stretches the frame. */
    height: auto;
    filter: drop-shadow(0 18px 30px rgb(0 0 0 / 0.18));
}

/* --------------------------------------------------------------- sources -- */

.sources {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 16px;
    padding: clamp(1.5rem, 4vw, 2.25rem);
}

.sources a { color: var(--text); text-underline-offset: 3px; }

/* --------------------------------------------------------------- reviews -- */

/* Masonry-ish columns rather than a grid: the reviews are wildly different
   lengths ("Wow" next to four lines), and a grid would leave one row of tall
   cards beside a row of stubs. */
.reviews {
    columns: 3 17rem;
    column-gap: 1rem;
    margin-block-start: 1.75rem;
}

figure.rev {
    break-inside: avoid;
    margin: 0 0 1rem;
    padding: 1.35rem 1.5rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 14px;
}

.rev .stars {
    color: var(--gold);
    letter-spacing: 0.12em;
    font-size: 0.9rem;
    line-height: 1;
    margin-block-end: 0.7rem;
}

.rev h3 {
    font-size: 0.98rem;
    font-weight: 800;
    margin: 0 0 0.45rem;
}

.rev blockquote {
    margin: 0 0 0.9rem;
    font-size: 0.94rem;
    line-height: 1.85;
    color: var(--muted);
}

.rev figcaption {
    font-size: 0.82rem;
    color: var(--text);
    opacity: 0.75;
}

.revnote { margin-block-start: 0.75rem; font-size: 0.88rem; }
.revnote a { color: var(--text); text-underline-offset: 3px; }

/* ------------------------------------------------------------------- faq -- */

.faq { max-width: 44rem; }

.faq details {
    border-block-end: 1px solid var(--line);
    padding-block: 1.1rem;
}

.faq summary {
    cursor: pointer;
    font-weight: 700;
    list-style: none;
    display: flex;
    align-items: center;
    gap: 0.75rem;
}
.faq summary::-webkit-details-marker { display: none; }

.faq summary::after {
    content: '+';
    margin-inline-start: auto;
    color: var(--gold);
    font-size: 1.3rem;
    line-height: 1;
    flex: none;
}
.faq details[open] summary::after { content: '−'; }

.faq .a {
    color: var(--muted);
    padding-block-start: 0.7rem;
    max-width: var(--measure);
}

/* ================================================================
   CATALOGUE PAGES — /categories, /authors, /books
   Generated by build-kutubji-catalog.py. Same tokens as the landing
   page; these are the extra components those templates need.
   ================================================================ */

.brand {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    text-decoration: none;
    color: inherit;
}

.crumbs {
    font-size: 0.84rem;
    color: var(--muted);
    margin-block-end: 1.1rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}
.crumbs a { color: var(--muted); text-decoration: none; }
.crumbs a:hover { color: var(--text); text-decoration: underline; }

h1 + .muted, .count { margin-block-start: -0.4rem; }
.count { font-size: 0.9rem; }

/* Catalogue h1s are content headings, not the hero — smaller than the
   landing page's, which is sized to carry a whole viewport on its own. */
main section h1 {
    font-family: var(--display);
    font-weight: 800;
    font-size: clamp(1.5rem, 3.4vw, 2.1rem);
    line-height: 1.45;
    margin: 0 0 0.9rem;
}

/* -------------------------------------------------------- category grid -- */

.cat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 13rem), 1fr));
    gap: 0.85rem;
    margin-block-start: 1.75rem;
}

.cat-card {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    padding: 1.15rem 1.25rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 14px;
    text-decoration: none;
    transition: border-color 0.15s ease, transform 0.15s ease;
}
.cat-card:hover { border-color: var(--brand-lift); transform: translateY(-2px); }
.cat-n { font-weight: 800; }
.cat-c { font-size: 0.84rem; color: var(--muted); }

/* ------------------------------------------------------------ book grid -- */

.grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(45%, 8.5rem), 1fr));
    gap: 1.4rem 1rem;
    margin-block-start: 1.75rem;
}
.grid.sm { margin-block-start: 1rem; }

.bk { text-decoration: none; display: block; }

.bk img {
    width: 100%;
    height: auto;
    aspect-ratio: 2 / 3;
    object-fit: cover;
    border-radius: 6px;
    background: var(--surface);
    box-shadow: 0 2px 8px rgb(0 0 0 / 0.12);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.bk:hover img { transform: translateY(-3px); box-shadow: 0 8px 20px rgb(0 0 0 / 0.18); }

.bk-t {
    display: block;
    margin-block-start: 0.55rem;
    font-size: 0.88rem;
    font-weight: 700;
    line-height: 1.5;
}
.bk-a { display: block; font-size: 0.8rem; color: var(--muted); }

/* ---------------------------------------------------------------- chips -- */

.chips { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-block-start: 0.9rem; }

.chips a {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.8rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--surface);
    font-size: 0.86rem;
    text-decoration: none;
}
.chips a:hover { border-color: var(--brand-lift); }
.chips a span { color: var(--muted); font-size: 0.78rem; }

/* --------------------------------------------------------- author index -- */

.au-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr));
    gap: 0.15rem 1.5rem;
    margin-block-start: 1.5rem;
}

.au-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding: 0.6rem 0;
    border-block-end: 1px solid var(--line);
    text-decoration: none;
    font-size: 0.94rem;
}
.au-row:hover { color: var(--brand-lift); }
.au-c { color: var(--muted); font-size: 0.82rem; flex: none; }

/* ----------------------------------------------------------- pagination -- */

.pager { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-block-start: 2rem; }

.pager .pg {
    min-width: 2.3rem;
    padding: 0.35rem 0.6rem;
    text-align: center;
    border: 1px solid var(--line);
    border-radius: 8px;
    text-decoration: none;
    font-size: 0.88rem;
}
.pager .pg:hover { border-color: var(--brand-lift); }
.pager .pg.on { background: var(--brand); color: var(--bg); border-color: var(--brand); }

/* ------------------------------------------------------------ book page -- */

.book {
    display: grid;
    gap: clamp(1.25rem, 4vw, 2.5rem);
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
    margin-block-start: 0.5rem;
}

@media (min-width: 720px) {
    .book { grid-template-columns: 13rem minmax(0, 1fr); }
}

.book-cover img {
    width: 100%;
    height: auto;
    aspect-ratio: 2 / 3;
    object-fit: cover;
    border-radius: 8px;
    box-shadow: 0 14px 34px rgb(0 0 0 / 0.18);
}

.book-meta h1 { margin-block-start: 0; }

.bm {
    font-size: 0.9rem;
    color: var(--muted);
    margin-block-end: 1.1rem;
}
.bm a { color: var(--text); text-underline-offset: 3px; }

.summary { max-width: var(--measure); }

/* ------------------------------------------------------------------ blog -- */

.posts {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 21rem), 1fr));
    gap: 1rem;
    margin-block-start: 1.75rem;
}

.post-card {
    display: block;
    padding: 1.4rem 1.55rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 14px;
    text-decoration: none;
    transition: border-color 0.15s ease, transform 0.15s ease;
}
.post-card:hover { border-color: var(--brand-lift); transform: translateY(-2px); }

.post-card h2 {
    font-size: 1.06rem;
    font-weight: 800;
    line-height: 1.6;
    margin: 0 0 0.5rem;
    font-family: var(--body);
}
.post-card p { font-size: 0.9rem; color: var(--muted); margin: 0 0 0.75rem; }
.post-card time { font-size: 0.78rem; color: var(--muted); opacity: 0.8; }

/* The article column is narrower than the catalogue's — this is the one part
   of the site meant to be read straight through rather than scanned. */
.post { max-width: 40rem; }
.post h2 { font-size: clamp(1.2rem, 2.6vw, 1.45rem); margin-block-start: 2.4rem; }
.post p { max-width: var(--measure); }
.post a { color: var(--text); text-underline-offset: 3px; }
.post a:hover { color: var(--brand-lift); }

.post-lede {
    font-size: 1.1rem;
    line-height: 1.95;
    color: var(--text);
}

.post-date {
    display: block;
    font-size: 0.82rem;
    color: var(--muted);
    padding-block-end: 1.25rem;
    border-block-end: 1px solid var(--line);
    margin-block-end: 0.5rem;
}

.post-list {
    max-width: var(--measure);
    margin: 0 0 1.25rem;
    padding-inline-start: 1.15rem;
}
.post-list li { margin-block-end: 0.55rem; }

/* ---------------------------------------------------------------- footer -- */

footer {
    border-block-start: 1px solid var(--line);
    padding-block: 2.5rem 3rem;
    font-size: 0.88rem;
    color: var(--muted);
}

.flinks {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem 1.4rem;
    margin-block-end: 1.4rem;
}

.flinks a { text-decoration: none; }
.flinks a:hover { color: var(--text); text-decoration: underline; }

/* Icons are inline SVG, not an icon font or a sprite: three paths cost less
   than one extra request, and nothing here should block on a network hop. */
.social {
    display: flex;
    gap: 0.55rem;
    margin-block-end: 1.25rem;
}

.social a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border: 1px solid var(--line);
    border-radius: 10px;
    color: var(--muted);
    transition: color 0.15s ease, border-color 0.15s ease;
}
.social a:hover { color: var(--brand-lift); border-color: var(--brand-lift); }
.social svg { width: 18px; height: 18px; }

.credit {
    font-size: 0.8rem;
    opacity: 0.75;
    margin-block-end: 1rem;
}

.sign { margin-block-end: 0.35rem; }

/* --------------------------------------------------------------- narrow -- */

@media (max-width: 620px) {
    /* ---- hamburger ----------------------------------------------------
       The links were simply hidden here, which left the whole catalogue
       unreachable from a phone — the only way to a category page was the
       chips further down the landing page. */
    .menu-btn { display: inline-flex; }

    .topbar nav {
        position: absolute;
        inset-inline: 0;
        top: 100%;
        margin: 0;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        background: var(--bg);
        border-block-end: 1px solid var(--line);
        box-shadow: 0 18px 30px -18px rgb(0 0 0 / 0.25);
        /* Closed by default. Not `visibility` — a hidden-but-present menu is
           still reachable by keyboard, which is worse than no menu. */
        display: none;
    }
    .topbar nav.open { display: flex; }

    .topbar nav a {
        padding: 0.95rem var(--pad);
        border-block-start: 1px solid var(--line);
        color: var(--text);
        font-size: 1rem;
    }
    .topbar nav .hide-sm { display: block; }

    .topbar .get {
        margin: 0.9rem var(--pad) 1.1rem;
        border-radius: 12px;
        text-align: center;
        padding-block: 0.75rem;
        border-block-start: none;
        color: var(--bg);
    }

    /* ---- feature screenshots -------------------------------------------
       A full-width shot was 335x711 and made each feature 1041px tall, so
       the five of them ran 5,067px — about seven phone screens of scrolling
       to read five short paragraphs. */
    .feature .shot {
        max-width: 150px;
        margin-inline: auto;
    }
    .feature { gap: 1rem; padding-block: 0.75rem; }

    /* The trailing aside in each feature is elaboration, not substance.
       It stays in the DOM for search engines and reads fine on desktop. */
    .feature .prose p.muted { display: none; }

    /* Three columns, not six. At 360px a six-column wall gives each column
       ~52px, which is visual mush AND downloads six 220px covers to render
       them at a quarter size — Lighthouse's "properly size images" in the
       flesh. Half the columns is half the bytes and reads better. */
    .wall-col:nth-child(n+4) { display: none; }

    /* The plate covers most of a phone screen, so the wall is only ever seen
       at the edges — turn it down rather than have it fight the copy. */
    .wall { opacity: 0.3; }

    /* Slightly tighter: the lede is four lines on desktop and eleven here. */
    .hero-inner { padding-block-start: clamp(2.5rem, 12vw, 4.5rem); }
    .lede { font-size: 1rem; }
}
