/* ==========================================================================
   Client site — "ledger" design.

   One idea carried through the whole page: a paper ground, near-black ink and
   hairline rules. Structure is drawn with 1px lines instead of shadows, and
   corners are square. Every colour an administrator can set on the Header,
   Banner, Language Switcher and Bottom Footer screens still arrives through
   the same --client-* custom properties with the same fallbacks, so the admin
   contract is untouched — the design only decides what the *defaults* look
   like and how everything is shaped.
   ========================================================================== */

.client-body {
    /* Design tokens. Everything below draws from these five. */
    --paper: #fff;
    --ink: #161512;
    --ink-2: #4c4a44;
    --ink-3: #8b877d;
    --line: #e5e2da;
    --line-strong: #c9c5bb;

    /*
     * Header, main, footer in a column, with the main growing into whatever is
     * left. Before this the main was told to stand at least a screen tall on
     * its own, so on a short page the footer was pushed past the bottom of the
     * window and the browser drew a scrollbar for it — a page with nothing to
     * scroll to but its own footer. Now the three of them add up to exactly one
     * screen, and the page scrolls only when it really is longer than one.
     */
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
    background: var(--paper);
    color: var(--ink);
    font-family: var(--client-font, var(--font-sans));
}

/* Neither end gives up its height when the middle is full. */
.client-site-header,
.client-footer { flex-shrink: 0; }

.client-body ::selection { background: var(--ink); color: var(--paper); }

/* Takes what the header and footer leave, and no more. */
.client-main { flex: 1 0 auto; }

.client-narrow { max-width: 48rem; }

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

/* Honeypot: moved off-screen rather than display:none, which some bots skip. */
.client-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ==========================================================================
   Header
   ========================================================================== */
/* Sticky by default; Settings > Header > Behaviour can switch it off, which
   adds .is-static and lets the header scroll away with the page. */
.client-site-header {
    position: sticky;
    top: 0;
    z-index: 50;
    border-bottom: 1px solid var(--line);
    background: var(--client-header-bg, var(--paper));
    color: var(--client-header-item, var(--ink));
}

/* Not pinned, but still positioned: below 500px the language panel is laid
   out against the header, and `position: static` would leave it with no
   containing block but the viewport — `top: 100%` would then throw it a
   whole screen down, out of sight. `relative` with the inherited `top: 0`
   sits exactly where `static` did and keeps the header as the reference. */
.client-site-header.is-static { position: relative; }

.client-site-header-inner {
    min-height: 76px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1.5rem;
}

.client-site-brand {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: .75rem;
    color: var(--client-header-item, var(--ink));
}
.client-site-brand.is-empty { display: none; }

.client-site-logo {
    display: block;
    max-width: 250px;
    max-height: 60px;
    width: auto;
    height: auto;
    object-fit: contain;
}

/* --------------------------------------------------------------------------
   Desktop navigation
   -------------------------------------------------------------------------- */
.client-desktop-nav {
    flex: 1 1 auto;
    display: flex;
    justify-content: flex-end;
    min-width: 0;
}

.client-menu-list,
.client-mobile-menu-list,
.client-submenu {
    list-style: none;
    margin: 0;
    padding: 0;
}

.client-menu-list {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: .25rem;
}

.client-menu-item { position: relative; }

.client-menu-link {
    display: inline-flex;
    align-items: center;
    justify-content: space-between;
    gap: .35rem;
    padding: .65rem .85rem;
    color: var(--client-header-item, var(--ink));
    font-size: 18px;
    line-height: 1.35;
    transition: color .15s ease, background-color .15s ease;
    border-radius: 12px;
}

/* Header hover colour — DESKTOP nav only.
   The :hover state applies to every ancestor of the pointer, so an unscoped
   ".client-menu-item:hover > .client-menu-link" fires on the PARENT link while
   a submenu child is hovered. On desktop that is wanted (the top item stays lit
   while browsing its dropdown); inside the mobile panel it painted the parent
   with the Header group's colour — the mobile panel must only ever use the
   Mobile Menu Dropdown colours. */
/* Hover colouring is additionally gated on a real hover pointer: touchscreens
   make :hover STICK after a tap, so on tablets (or phones in desktop-site
   mode, where the desktop nav is visible) tapping an item painted it with the
   hover colour and left it that way. Devices with a mouse are unaffected. */
@media (hover: hover) {
    .client-desktop-nav .client-menu-link:hover,
    .client-desktop-nav .client-menu-item:hover > .client-menu-link {
        color: var(--client-header-item-hover, var(--ink));
    }
}

/* "Active Item Background Color" (Settings > Header > Header) — declared before
   the hover rule so hovering still wins on equal specificity. */
.client-desktop-nav > .client-menu-list > .client-menu-item.is-active > .client-menu-link {
    background: var(--client-header-item-active-bg, transparent);
}

/* "Item Hover Background Color" (Settings > Header > Header). Scoped to
   top-level items so it never bleeds into the submenu or mobile groups. */
@media (hover: hover) {
    .client-desktop-nav > .client-menu-list > .client-menu-item > .client-menu-link:hover,
    .client-desktop-nav > .client-menu-list > .client-menu-item:hover > .client-menu-link {
        background: var(--client-header-item-hover-bg, rgba(22, 21, 18, .05));
    }
}

/* Header active colour — desktop only, same reasoning as the hover rule. The
   mobile panel's own is-active rules carry the Mobile Menu Dropdown colours. */
.client-desktop-nav .client-menu-item.is-active > .client-menu-link {
    color: var(--client-header-item-active, var(--ink));
}

.client-menu-caret {
    width: 15px;
    height: 15px;
    flex: 0 0 auto;
    transition: transform .15s ease;
}
/* Hover-rotate is a desktop affordance; mobile carets rotate via .is-open. */
@media (hover: hover) {
    .client-desktop-nav .client-menu-item:hover > .client-menu-link .client-menu-caret { transform: rotate(180deg); }
}

/* --------------------------------------------------------------------------
   Desktop submenu — a ruled sheet rather than a floating rounded card
   -------------------------------------------------------------------------- */
.client-submenu {
    position: absolute;
    top: calc(100% + .35rem);
    right: 0;
    border-radius: 12px;
    min-width: 230px;
    background: var(--client-submenu-bg, var(--paper));
    box-shadow: 0 10px 24px rgba(22, 21, 18, .08);
    padding: .375rem;
    opacity: 0;
    visibility: hidden;
    transform: translateY(6px);
    transition: opacity .15s ease, visibility .15s ease, transform .15s ease;
}

[dir="rtl"] .client-submenu { left: auto; right: 0; }

.client-menu-item:hover > .client-submenu,
.client-menu-item:focus-within > .client-submenu {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

/* Sub Menu Dropdown colours apply to the DESKTOP dropdown only; the mobile
   panel re-renders the same markup and owns its own colours below. */
.client-desktop-nav .client-submenu .client-menu-link {
    width: 100%;
    color: var(--client-submenu-item, var(--ink));
    padding: .65rem .75rem;
    white-space: nowrap;
}

@media (hover: hover) {
    .client-desktop-nav .client-submenu .client-menu-link:hover,
    .client-desktop-nav .client-submenu .client-menu-item:hover > .client-menu-link {
        color: var(--client-submenu-item-hover, var(--ink));
        background: var(--client-submenu-item-hover-bg, rgba(22, 21, 18, .05));
    }
}

.client-desktop-nav .client-submenu .client-menu-item.is-active > .client-menu-link {
    color: var(--client-submenu-item-active, var(--ink));
    background: var(--client-submenu-item-active-bg, transparent);
}
/* The active rule above outranks the general hover; restore hover feedback. */
@media (hover: hover) {
    .client-desktop-nav .client-submenu .client-menu-item.is-active > .client-menu-link:hover {
        background: var(--client-submenu-item-hover-bg, rgba(22, 21, 18, .05));
    }
}

.client-submenu .client-submenu { top: 0; left: calc(100% + .35rem); }
[dir="rtl"] .client-submenu .client-submenu { left: auto; right: calc(100% + .35rem); }

.client-header-actions {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: .75rem;
}

/* Touch-only control; the desktop nav opens submenus on hover instead. */
.client-submenu-toggle { display: none; }

/* --------------------------------------------------------------------------
   Language switcher
   -------------------------------------------------------------------------- */
.client-language-switcher { position: relative; }

.client-language-switcher summary {
    list-style: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .35rem;
    min-height: 40px;
    border: 1px solid var(--client-header-item, var(--ink));
    background: var(--client-header-bg, transparent);
    padding: .45rem .78rem;
    color: var(--client-header-item, var(--ink));
    font-size: 18px;
    font-weight: 500;
    cursor: pointer;
    transition: color .15s ease, border-color .15s ease;
    border-radius: 6px;
}
.client-language-switcher summary::-webkit-details-marker { display: none; }

.client-language-switcher[open] summary,
.client-language-switcher summary:hover {
    color: var(--client-header-item-hover, var(--ink));
    border-color: var(--client-header-item-hover, var(--ink));
}

.client-language-caret { width: 14px; height: 14px; flex: 0 0 auto; transition: transform .15s ease; }
.client-language-switcher[open] .client-language-caret { transform: rotate(180deg); }

.client-language-list {
    position: absolute;
    top: calc(100% + .5rem);
    right: 0;
    min-width: 300px;
    background: var(--client-language-bg, var(--paper));
    box-shadow: 0 10px 24px rgba(22, 21, 18, .08);
    padding: .5rem;
    z-index: 80;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: .35rem;
    border-radius: 8px;
}
[dir="rtl"] .client-language-list { right: auto; left: 0; }

.client-language-list a {
    display: flex;
    align-items: center;
    min-height: 38px;
    padding: .55rem .65rem;
    color: var(--client-language-item, var(--ink));
    font-size: 18px;
    line-height: 1.25;
    border-radius: 8px;
}

/* "Item Hover Background Color" (Settings > Language Switcher). */
.client-language-list a:hover {
    color: var(--client-language-hover, var(--ink));
    background: var(--client-language-hover-bg, rgba(22, 21, 18, .05));
}

/* "Active Item Background Color" (Settings > Language Switcher). */
.client-language-list a.is-active {
    color: var(--client-language-active, var(--ink));
    background: var(--client-language-active-bg, transparent);
}
.client-language-list a.is-active:hover {
    background: var(--client-language-hover-bg, rgba(22, 21, 18, .05));
}

/* --------------------------------------------------------------------------
   Mobile toggle and panel
   -------------------------------------------------------------------------- */
.client-mobile-toggle {
    display: none;
    width: 42px;
    height: 42px;
    border: 0;
    background: transparent;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 5px;
    cursor: pointer;
}
.client-mobile-toggle span {
    display: block;
    width: 18px;
    height: 2px;
    background: var(--client-header-item, var(--ink));
}

.client-mobile-panel {
    background: var(--client-mobile-bg, var(--paper));
}
.client-mobile-panel-inner { padding-top: 1rem; padding-bottom: 1rem; }

/* --------------------------------------------------------------------------
   Mobile panel animation

   The panel is revealed by removing the [hidden] attribute, and keyframe
   animations run every time an element goes from unrendered to rendered — so
   the open animation needs no JS at all: the panel sweeps down, and the rows
   inside cascade up one after another (fill-mode: backwards keeps each row
   invisible until its delayed animation starts). Closing stays instant, which
   is the expected feel for dismissing a menu.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
    .client-mobile-panel:not([hidden]) {
        animation: client-panel-open .28s ease-out;
    }

    .client-mobile-panel:not([hidden]) .client-mobile-menu-list > .client-menu-item {
        animation: client-panel-item .38s cubic-bezier(.2, .7, .2, 1) backwards;
    }
    .client-mobile-menu-list > .client-menu-item:nth-child(1) { animation-delay: .05s; }
    .client-mobile-menu-list > .client-menu-item:nth-child(2) { animation-delay: .09s; }
    .client-mobile-menu-list > .client-menu-item:nth-child(3) { animation-delay: .13s; }
    .client-mobile-menu-list > .client-menu-item:nth-child(4) { animation-delay: .17s; }
    .client-mobile-menu-list > .client-menu-item:nth-child(5) { animation-delay: .21s; }
    .client-mobile-menu-list > .client-menu-item:nth-child(6) { animation-delay: .25s; }
    .client-mobile-menu-list > .client-menu-item:nth-child(7) { animation-delay: .29s; }
    .client-mobile-menu-list > .client-menu-item:nth-child(n+8) { animation-delay: .33s; }

    /* Tapping a caret expands its submenu with the same rise. */
    .client-mobile-menu-list .client-menu-item.is-open > .client-submenu {
        animation: client-panel-item .3s ease-out;
    }

    /* Hamburger-to-X morph eases; without motion it still snaps to the X. */
    .client-mobile-toggle span {
        transition: transform .3s cubic-bezier(.2, .7, .2, 1), opacity .2s ease;
    }
}

@keyframes client-panel-open {
    from { opacity: 0; transform: translateY(-10px); }
}
@keyframes client-panel-item {
    from { opacity: 0; transform: translateY(10px); }
}

/* The three bars fold into a close icon while the menu is open — driven by
   the aria-expanded state the script already maintains. */
.client-mobile-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.client-mobile-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; transform: scaleX(.4); }
.client-mobile-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

.client-mobile-menu-list { display: grid; gap: .35rem; }
.client-mobile-menu-list .client-menu-item { position: static; }

.client-mobile-menu-list .client-menu-link {
    display: flex;
    width: 100%;
    color: var(--client-mobile-item, var(--ink));
    padding: .8rem 1rem;
    background: rgba(22, 21, 18, .03);
    font-size: 18px;
}

/* "Item Hover Background Color" (Settings > Header > Mobile Menu Dropdown).
   Gated on a real hover pointer: on touchscreens :hover sticks after a tap,
   so a tapped row would keep the hover paint. Mouse users who open the
   hamburger in a narrow window still get the hover colours. */
@media (hover: hover) {
    .client-mobile-menu-list .client-menu-link:hover {
        color: var(--client-mobile-item-hover, var(--ink));
        background: var(--client-mobile-item-hover-bg, rgba(22, 21, 18, .07));
    }
}

/* "Active Item Background Color" — covers nested submenu items too, since the
   mobile group owns every colour inside the panel. */
.client-mobile-menu-list .client-menu-item.is-active > .client-menu-link {
    color: var(--client-mobile-item-active, var(--ink));
    background: var(--client-mobile-item-active-bg, rgba(22, 21, 18, .03));
}
@media (hover: hover) {
    .client-mobile-menu-list .client-menu-item.is-active > .client-menu-link:hover {
        background: var(--client-mobile-item-hover-bg, rgba(22, 21, 18, .07));
    }
}

/* Mobile submenus are collapsed until their toggle is tapped. */
.client-mobile-menu-list .client-submenu {
    display: none;
    position: static;
    min-width: 0;
    border: 0;
    box-shadow: none;
    background: transparent;
    padding: .25rem 0 .25rem 1rem;
    opacity: 1;
    visibility: visible;
    transform: none;
}
.client-mobile-menu-list .client-menu-item.is-open > .client-submenu { display: block; }

/* Row becomes a two-column grid so the toggle sits beside the link and the
   submenu spans underneath — no hardcoded row heights. */
.client-mobile-menu-list .client-menu-item.has-children {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
        "link toggle"
        "submenu submenu";
    gap: .35rem;
}
.client-mobile-menu-list .client-menu-item.has-children > .client-menu-link { grid-area: link; }
.client-mobile-menu-list .client-menu-item.has-children > .client-submenu-toggle { grid-area: toggle; }
.client-mobile-menu-list .client-menu-item.has-children > .client-submenu { grid-area: submenu; }

/* The button carries the caret on mobile, so the link's copy is redundant. */
.client-mobile-menu-list .client-menu-item.has-children > .client-menu-link .client-menu-caret { display: none; }

.client-mobile-menu-list .client-submenu-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 3rem;
    border: 0;
    background: rgba(22, 21, 18, .03);
    color: var(--client-mobile-item, var(--ink));
    cursor: pointer;
    border-radius: 12px;
    transition: background-color .15s ease, color .15s ease;
}
@media (hover: hover) {
    .client-mobile-menu-list .client-submenu-toggle:hover {
        background: var(--client-mobile-item-hover-bg, rgba(22, 21, 18, .07));
        color: var(--client-mobile-item-hover, var(--ink));
    }
}
.client-mobile-menu-list .client-submenu-toggle .client-menu-caret { width: 18px; height: 18px; }
.client-mobile-menu-list .client-menu-item.is-open > .client-submenu-toggle .client-menu-caret { transform: rotate(180deg); }

[dir="rtl"] .client-mobile-menu-list .client-submenu { padding-left: 0; padding-right: 1rem; }

/* Nested items in the panel: colours from Mobile Menu Dropdown; slight inset
   tint so children read as nested. */
.client-mobile-menu-list .client-submenu .client-menu-link {
    font-size: 18px;
    padding: .7rem .9rem;
    color: var(--client-mobile-item, var(--ink));
    background: rgba(22, 21, 18, .025);
}
/* Self-hover only — no ":hover >" parent variant, so touching a nested item
   never repaints the item above it. */
@media (hover: hover) {
    .client-mobile-menu-list .client-submenu .client-menu-link:hover {
        color: var(--client-mobile-item-hover, var(--ink));
        background: var(--client-mobile-item-hover-bg, rgba(22, 21, 18, .07));
    }
}
.client-mobile-menu-list .client-submenu .client-menu-item.is-active > .client-menu-link {
    color: var(--client-mobile-item-active, var(--ink));
    background: var(--client-mobile-item-active-bg, rgba(22, 21, 18, .03));
}

/* --------------------------------------------------------------------------
   Header breakpoints — max-width queries run widest to narrowest so the
   narrower block wins where they overlap.
   -------------------------------------------------------------------------- */
@media (max-width: 1023px) {
    .client-desktop-nav { display: none; }

    /* The switcher stays in the bar next to the hamburger, so changing
       language never requires opening the menu first. */
    .client-mobile-toggle { display: inline-flex; }
    .client-header-actions { gap: .5rem; }
    .client-site-header-inner { min-height: 68px; gap: .75rem; }
    .client-site-logo { max-height: 42px; max-width: 170px; }
    .client-language-list { min-width: 300px; max-width: calc(100vw - 2rem); }
}

/* Below 500px the language dropdown becomes a full-width sheet under the
   header: position comes off the switcher, so the header itself becomes the
   containing block — pinned or not — and the panel stretches edge to edge. */
@media (max-width: 499px) {
    .client-language-switcher { position: static; }

    .client-language-list {
        top: 100%;
        left: 0;
        right: 0;
        width: 100%;
        min-width: 0;
        max-width: none;
        margin: 0;
        border-left: 0;
        border-right: 0;
        padding: .5rem;
        gap: .25rem;
    }
    /* Roomier rows — this is now the primary way to switch language. */
    .client-language-list a { min-height: 48px; padding: .8rem .9rem; }
}

/* Narrow phones: trim the switcher so the row still fits beside the logo. */
@media (max-width: 420px) {
    .client-site-logo { max-height: 36px; max-width: 130px; }
    .client-header-actions { gap: .375rem; }
    .client-mobile-toggle { width: 38px; height: 38px; }

    .client-language-switcher summary {
        min-height: 38px;
        padding: .4rem .55rem;
        font-size: .8125rem;
        max-width: 8rem;
    }
    .client-language-switcher summary span {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
}

@media (min-width: 1024px) {
    .client-mobile-panel { display: none !important; }
}

/* ==========================================================================
   Banner — copy from the page, colours from Settings > Banner
   ========================================================================== */
.client-banner {
    border-bottom: 1px solid var(--line);
    background: var(--client-banner-bg, var(--ink));
    padding: 3.5rem 0;
}

.client-banner-inner { text-align: center; }

.client-banner-title {
    margin: 0 0 1rem;
    color: var(--client-banner-heading, var(--paper));
    font-size: 1.75rem;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: -.02em;
}

.client-banner-subtitle {
    max-width: 60rem;
    margin: 0 auto 2rem;
    color: var(--client-banner-subheading, var(--paper));
    font-size: 1rem;
    line-height: 1.6;
    opacity: .92;
}

.client-banner-form {
    display: flex;
    align-items: stretch;
    justify-content: center;
    gap: .625rem;
    max-width: 52rem;
    margin: 0 auto;
    flex-wrap: wrap;
}

.client-banner-field {
    position: relative;
    display: flex;
    align-items: center;
    flex: 1 1 20rem;
    min-width: 0;
    background: #fff;
    border-radius: 12px;
}

.client-banner-input {
    width: 100%;
    min-width: 0;
    border: 0;
    background: transparent;
    padding: 1.125rem 3.25rem 1.125rem 1.25rem;
    color: var(--ink);
    font-size: 16px;
    line-height: 1.4;
    border-radius: 12px;
}
.client-banner-input::placeholder { color: var(--ink-3); }
.client-banner-input:focus { outline: 0; }
.client-banner-field:focus-within { box-shadow: 0 0 0 2px var(--paper), 0 0 0 4px var(--ink); }

/* One slot, two controls: paste while empty, clear once there is a value.
   JS swaps them via [hidden]; the override below must beat the display rule,
   since an author display always wins over the UA's own [hidden] rule. */
.client-banner-action {
    position: absolute;
    right: .625rem;
    background: transparent;
    cursor: pointer;
    transition: background-color .15s ease;
}
.client-banner-action[hidden] { display: none; }
.client-banner-action svg { width: 30px; height: 3%; }
.client-banner-clear svg { width: 30px; height: 30px; }

[dir="rtl"] .client-banner-action { right: auto; left: .625rem; }
[dir="rtl"] .client-banner-input { padding: 1.125rem 1.25rem 1.125rem 3.25rem; }

.client-banner-button {
    border: 1px solid var(--client-banner-btn-border, var(--paper));
    background: var(--client-banner-btn-bg, var(--paper));
    padding: 0 20px;
    color: var(--client-banner-btn-text, var(--ink));
    cursor: pointer;
    font-size: 18px;
    border-radius: 8px;
}
.client-banner-button svg { width: 18px; height: 18px; }
.client-banner-button:hover { filter: brightness(.94); }

@media (max-width: 640px) {
    .client-banner { padding: 2.5rem 0; }
    .client-banner-title { font-size: 1.375rem; }
    .client-banner-subtitle { margin-bottom: 1.5rem; font-size: .9375rem; }
    .client-banner-field { flex: 1 1 100%; }
    .client-banner-button {flex: 1 1 100%; height: 50px}
}

@media (min-width: 900px) {
    .client-banner { padding: 4.5rem 0; }
    .client-banner-title { font-size: 2.5rem; }
    .client-banner-subtitle { font-size: 1.0625rem; }
}

/* ==========================================================================
   Notes — admin-authored notices shown directly below the banner.
   Callout cards: a brand-tinted wash and left accent tie them to the banner
   above without shouting over the page content that follows.
   ========================================================================== */
/* Doubled class beats the later .client-section { margin: 50px 0 } rule, so
   notes sit close under the banner instead of a full section gap away. */
.client-section.client-notes { margin: 2rem 0; }
.client-notes .container-main { display: grid; gap: .875rem; }

.client-note {
    padding: 1.125rem 1.375rem;
    border: 1px solid var(--line);
    border-left: 4px solid var(--client-banner-bg, #e60023);
    border-radius: 12px;
    background: #fbfbfa;
    background: color-mix(in oklab, var(--client-banner-bg, #e60023) 4%, #fdfdfc);
}

[dir="rtl"] .client-note {
    border-left: 1px solid var(--line);
    border-right: 4px solid var(--client-banner-bg, #e60023);
}

.client-note-title {
    margin: 0 0 .375rem;
    color: var(--ink);
    font-size: var(--client-h4);
    font-weight: var(--client-heading-weight);
    line-height: var(--client-heading-lh);
    letter-spacing: var(--client-heading-tracking);
}

.client-note .client-rich { font-size: 1rem; line-height: 1.65; }

/* ==========================================================================
   Keyword search — suggestions under the box, and the videos they return
   ========================================================================== */

/* The field is the positioning context, so the list hangs from its edge. */
.client-banner-field { position: relative; }

.client-suggest {
    position: absolute;
    top: calc(100% + .375rem);
    left: 0;
    right: 0;
    z-index: 40;
    max-height: 18rem;
    overflow-y: auto;
    margin: 0;
    padding: .3125rem;
    list-style: none;
    border-radius: 12px;
    background: var(--paper);
    box-shadow: 0 12px 30px rgba(22, 21, 18, .16);
    text-align: start;
}

.client-suggest-item {
    padding: .625rem .75rem;
    border-radius: 8px;
    color: var(--ink);
    font-size: 1rem;
    cursor: pointer;
}

@media (hover: hover) {
    .client-suggest-item:hover { background: var(--line); }
}

/* ==========================================================================
   Banner search — status line and the download results below the banner
   ========================================================================== */
.client-banner-status {
    max-width: 40rem;
    margin: 1rem auto 0;
    text-align: center;
    color: var(--client-banner-subheading, rgba(255, 255, 255, .85));
    font-size: .9375rem;
}

.client-banner-status.is-error {
    display: inline-block;
    max-width: none;
    padding: .5rem 1rem;
    border-radius: 10px;
    background: rgba(0, 0, 0, .22);
    font-weight: 600;
}

/* The searching state dims the button; the status line narrates progress. */
.client-banner-form.is-searching .client-banner-button { opacity: .7; cursor: progress; }

/* Banner ad slot (Settings > Ads > Banner Ads), under the search field.
   Centred and width-capped so a wide creative cannot stretch the banner. */
.client-banner-ad {
    max-width: 40rem;
    margin: 1.25rem auto 0;
    text-align: center;
}

.client-banner-ad :is(img, iframe) { max-width: 100%; height: auto; }

/* ==========================================================================
   Results page (/viewer) — the results, and nothing around them
   ========================================================================== */

/* No banner here: the page opens on what was found. The search box is still on
   the page, hidden, because it is what the script searches in. */
.client-viewer-form { display: none; }

/* Viewer Page Ads (Settings > Ads), above the state card and inside its
   section, so it keeps the card's own measure and disappears with it once the
   results arrive. Centred, and images held to the width they are given. */
.client-viewer-ad {
    max-width: 46rem;
    margin: 0 auto 1.75rem;
    text-align: center;
}

.client-viewer-ad :is(img, iframe) { max-width: 100%; height: auto; }

@media (max-width: 640px) {
    .client-viewer-ad { margin-bottom: 1.25rem; }
}

/* Progress and failure, as a card in the middle of the page: there is no field
   on show here for a line of text to sit under. One card carries all three
   states — searching, nothing found, and nothing searched for yet — so the page
   never jumps between differently shaped blocks.

   The section itself is nothing but spacing — the card is what is seen. */
.client-dl-state { padding: 4rem 0; background: #f5f5f7; box-shadow: 0 15px 35px rgba(0, 0, 0, .05); border: 1px solid rgba(0, 0, 0, .03); }

.client-dl-state[hidden] { display: none; }
.client-dl-state-card[hidden] { display: none; }

/* Once the results are drawn the card goes, and the ad above it stays — it
   belongs to the page rather than to the wait. What is left is the ad alone, so
   the section drops its own panel and keeps only the space the ad needs. */
.client-dl-state.is-ad-only {
    padding: 1.75rem 0 0;
    background: none;
    border: 0;
    box-shadow: none;
}

.client-dl-state.is-ad-only .client-viewer-ad { margin-bottom: 0; }

/* Nothing behind the card any more, so the lift has to come from the shadow
   alone: three of them, each wider and fainter than the last — a hairline that
   draws the edge, a close shadow that seats it on the page, and a wide soft one
   that lets it float. The border is lighter than the site's usual line, since
   the shadow is already describing the shape. */
.client-dl-state-card {
    max-width: 46rem;
    margin: 0 auto;
    padding: 3.5rem 1.75rem;
    border: 1px solid color-mix(in oklab, var(--line) 55%, var(--paper));
    border-radius: 28px;
    background: var(--paper);
    box-shadow:
        0 1px 2px rgba(22, 21, 18, .04),
        0 10px 24px -14px rgba(22, 21, 18, .18),
        0 40px 70px -40px rgba(22, 21, 18, .3);
    text-align: center;
}

/* The icon sits in a soft wash of the site's own colour, fading out to the
   card — the glow in the middle rather than a hard disc. */
.client-dl-state-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 7rem;
    height: 7rem;
    margin-bottom: 1.5rem;
    border-radius: 50%;
    background: radial-gradient(
        circle,
        color-mix(in oklab, var(--client-banner-bg, #e60023) 20%, var(--paper)) 0%,
        color-mix(in oklab, var(--client-banner-bg, #e60023) 6%, var(--paper)) 55%,
        var(--paper) 78%
    );
}

.client-dl-state-ghost {
    width: 3rem;
    height: 3rem;
    color: var(--client-banner-bg, #e60023);
}

.client-dl-state-ghost[hidden] { display: none; }

/* The searching state: a ring turning in the same colour. */
.client-dl-state-spinner {
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 50%;
    border: 3px solid color-mix(in oklab, var(--client-banner-bg, #e60023) 20%, transparent);
    border-top-color: var(--client-banner-bg, #e60023);
    animation: client-dl-spin .85s linear infinite;
}

.client-dl-state-spinner[hidden] { display: none; }

@keyframes client-dl-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
    .client-dl-state-spinner { animation-duration: 2.4s; }
}

.client-dl-state-title {
    margin: 0 0 .625rem;
    color: var(--ink);
    font-size: 1.625rem;
    font-weight: 800;
    line-height: 1.25;
    letter-spacing: -.015em;
}

.client-dl-state-text {
    max-width: 34rem;
    /* The gap below belongs to the button, not to this line, so a card with no
       button ends cleanly on the message. */
    margin: 0 auto;
    color: var(--ink-2);
    font-size: 1.0625rem;
    line-height: 1.6;
    /* A service's message can carry a long link; it wraps rather than widening
       the card. */
    overflow-wrap: anywhere;
}

/* The way back to the downloader. A pill, so it reads as the one thing left to
   do on a page that has nothing else on it. */
.client-dl-state-action {
    margin-top: 1.75rem;
    border-radius: 999px;
    padding: .875rem 1.75rem;
    font-size: .875rem;
}

.client-dl-state-action[hidden] { display: none; }

.client-dl-state-action svg {
    width: 1.0625rem;
    height: 1.0625rem;
}

/* The results are the first thing on the page, so they keep a little air above
   them rather than butting against the header. */
.client-viewer .client-section.client-dl { margin: 3rem 0; }

@media (max-width: 640px) {
    .client-dl-state { padding: 2.5rem 0; }
    .client-dl-state-card {
        padding: 2.5rem 1.25rem;
        border-radius: 22px;
    }
    .client-dl-state-icon {
        width: 5.5rem;
        height: 5.5rem;
        margin-bottom: 1.125rem;
    }
    .client-dl-state-ghost { width: 2.5rem; height: 2.5rem; }
    .client-dl-state-spinner { width: 2.25rem; height: 2.25rem; }
    .client-dl-state-title { font-size: 1.3125rem; }
    .client-dl-state-text { font-size: .9375rem; }
    .client-dl-state-action { margin-top: 1.5rem; }
    .client-viewer .client-section.client-dl { margin: 2rem 0; }
}

.client-section.client-dl { margin: 2rem 0; }

.client-dl-summary {
    margin: 0 0 1.25rem;
    color: var(--ink-3);
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    text-align: center;
}

/* Posts / Stories tabs for profile searches. */
.client-dl-tabs {
    display: flex;
    justify-content: center;
    gap: .5rem;
    margin: 0 0 1.5rem;
}

.client-dl-tab {
    padding: .55rem 1.5rem;
    border: 1px solid var(--line-strong);
    border-radius: 999px;
    background: var(--paper);
    color: var(--ink-2);
    font: inherit;
    font-size: .9375rem;
    font-weight: 600;
    cursor: pointer;
    transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}

@media (hover: hover) {
    .client-dl-tab:hover { border-color: var(--ink); color: var(--ink); }
}

.client-dl-tab.is-active {
    background: var(--ink);
    border-color: var(--ink);
    color: var(--paper);
}

/* An empty tab explains itself instead of showing a blank grid. */
.client-dl-empty {
    grid-column: 1 / -1;
    margin: 0;
    padding: 2.5rem 1rem;
    text-align: center;
    color: var(--ink-3);
    font-size: 1rem;
}

.client-dl-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: 1.25rem;
}

/* A single result reads better as one portrait card in the middle. */
.client-dl-grid:has(> :only-child) {
    grid-template-columns: minmax(0, 380px);
    justify-content: center;
}

.client-dl-card {
    border: 1px solid var(--line);
    border-radius: 14px;
    overflow: hidden;
    background: var(--paper);
    box-shadow: 0 1px 2px rgba(22, 21, 18, .05);
    transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
    animation: client-dl-in .45s cubic-bezier(.2, .7, .2, 1) backwards;
    animation-delay: calc(var(--dl-i, 0) * 60ms);
}

@keyframes client-dl-in {
    from { opacity: 0; transform: translateY(18px); }
    to { opacity: 1; transform: none; }
}

@media (hover: hover) {
    .client-dl-card:hover {
        transform: translateY(-4px);
        border-color: color-mix(in oklab, var(--client-banner-bg, #e60023) 45%, var(--line));
        box-shadow: 0 14px 30px -16px color-mix(in oklab, var(--client-banner-bg, #e60023) 45%, rgba(22, 21, 18, .3));
    }
}

/* A button, so the preview opens from keyboard too. */
.client-dl-thumb {
    position: relative;
    display: block;
    width: 100%;
    aspect-ratio: 4 / 5;
    padding: 0;
    border: 0;
    background: var(--line);
    cursor: pointer;
}

/* Play affordance on video cards: circle + triangle, no image assets. */
.client-dl-play {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 3.25rem;
    height: 3.25rem;
    transform: translate(-50%, -50%);
    border-radius: 999px;
    background: rgba(16, 15, 13, .55);
    backdrop-filter: blur(4px);
    pointer-events: none;
    transition: transform .2s ease, background-color .2s ease;
}

.client-dl-play::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 54%;
    transform: translate(-50%, -50%);
    border-style: solid;
    border-width: .55rem 0 .55rem .9rem;
    border-color: transparent transparent transparent #fff;
}

@media (hover: hover) {
    .client-dl-thumb:hover .client-dl-play {
        transform: translate(-50%, -50%) scale(1.12);
        background: var(--client-banner-bg, #e60023);
    }
}

.client-dl-thumb img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.client-dl-type {
    position: absolute;
    top: 10px;
    inset-inline-start: 10px;
    padding: .25rem .7rem;
    border-radius: 999px;
    background: rgba(16, 15, 13, .6);
    color: #fff;
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .04em;
    backdrop-filter: blur(6px);
}

.client-dl-actions { padding: .875rem; }

/* Public counts on a profile: followers and the rest, above its downloads. */
.client-stats {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .625rem;
    margin: 0 0 1.25rem;
}

.client-stat {
    display: grid;
    gap: .125rem;
    min-width: 5.5rem;
    padding: .625rem .875rem;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: var(--paper);
    text-align: center;
}

.client-stat-value {
    color: var(--ink);
    font-size: 1.0625rem;
    font-weight: 700;
    line-height: 1.2;
}

.client-stat-label {
    color: var(--ink-3);
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
}

@media (max-width: 480px) {
    .client-stat { min-width: 4.5rem; padding: .5rem .625rem; }
    .client-stat-value { font-size: .9375rem; }
}
/* Title and channel on a search result, so twelve cards can be told apart. */
.client-dl-title {
    margin: 0 0 .125rem;
    color: var(--ink);
    font-size: .9375rem;
    font-weight: 600;
    line-height: 1.35;
    /* Two lines at most: titles run long and would push cards out of line. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.client-dl-channel {
    margin: 0 0 .625rem;
    color: var(--ink-3);
    font-size: .8125rem;
}
/* A single result is the same card as any other — same width cap from the
   grid's one-child rule, same portrait frame, same shadow and hover. Only its
   actions differ: the downloads are offered directly, one button per line. */
.client-dl-stack { display: grid; gap: .625rem; }

.client-dl-button {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    padding: .7rem 1rem;
    border: 0;
    border-radius: 10px;
    font: inherit;
    font-size: .9375rem;
    font-weight: 600;
    cursor: pointer;
    text-align: center;
    transition: filter .15s ease, transform .1s ease;
}

.client-dl-button:hover { filter: brightness(1.08); }
.client-dl-button:active { transform: translateY(1px); }


.client-dl-save {
    background: var(--ink);
    color: var(--paper);
}

/* While the file transfers the button is disabled and narrates progress;
   it then reports the outcome for a moment before returning to its label. */
.client-dl-button:disabled { cursor: progress; opacity: .8; }
.client-dl-button:disabled:hover { filter: none; }
.client-dl-save.is-done { background: #1d7a46; }
.client-dl-save.is-failed { background: #b3261e; }

/* Why a download failed, under the button that failed. */
.client-dl-error {
    margin: .625rem 0 0;
    color: #b3261e;
    font-size: .8125rem;
    font-weight: 600;
    line-height: 1.45;
    text-align: center;
}

.client-dl-again {
    display: flex;
    justify-content: center;
    margin-top: 1.75rem;
}

/* Preview lightbox — the media itself is the whole surface. */
.client-dl-modal {
    padding: 0;
    border: 0;
    border-radius: 14px;
    background: #0c0b0a;
    max-width: min(92vw, 56rem);
    overflow: visible;
}

.client-dl-modal::backdrop {
    background: rgba(10, 9, 8, .78);
    backdrop-filter: blur(3px);
}

/* A floor under the dialog so a still-loading preview reads as "loading",
   not as an empty sliver. */
.client-dl-modal-body {
    display: grid;
    place-items: center;
    min-width: min(18rem, 80vw);
    min-height: 12rem;
}

/* Audio preview: the video's still with a player beneath it. */
.client-dl-audio-preview { display: grid; gap: .75rem; padding: 1rem; }
.client-dl-audio-preview img { max-width: 100%; max-height: 60vh; border-radius: 10px; }
.client-dl-audio-preview audio { width: 100%; }

.client-dl-modal-body :is(video, img) {
    display: block;
    max-width: 100%;
    max-height: 84vh;
    margin: 0 auto;
    border-radius: 14px;
    background: #000;
}

.client-dl-modal-close {
    position: absolute;
    top: -2.75rem;
    inset-inline-end: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: rgba(255, 255, 255, .14);
    color: #fff;
    cursor: pointer;
    transition: background-color .15s ease;
}

.client-dl-modal-close:hover { background: rgba(255, 255, 255, .3); }
.client-dl-modal-close svg { width: 18px; height: 18px; }

@media (prefers-reduced-motion: reduce) {
    .client-dl-card { animation: none; transition: none; }
}

/* ==========================================================================
   Typography — one variable scale for the whole site
   ========================================================================== */
.client-body {
    --client-h1: 1.875rem;
    --client-h2: 1.75rem;
    --client-h3: 1.25rem;
    --client-h4: 1.0625rem;
    --client-heading-weight: 700;
    --client-heading-lh: 1.25;
    --client-heading-tracking: -.02em;
    --client-heading-space: 2rem;

    --client-text: 18px;
    --client-text-lh: 1.75;
    --client-text-space: 1rem;
}

.client-section { margin: 50px 0; }
/* Whatever follows the band — or the intro under it — sits directly beneath:
   those already carry the space, and the 404 brings 5rem of padding of its own. */
.client-page-head + .client-section,
.client-page-intro-wrap + .client-section { padding-top: 0; }

.client-rich { color: var(--ink-2); font-size: var(--client-text); line-height: var(--client-text-lh); }
.client-rich > :first-child { margin-top: 0; }
.client-rich > :last-child { margin-bottom: 0; }

/* The single heading definition. .client-page-title is the page-level h1 on
   footer pages and the 404, and uses the same scale as any other heading. */
.client-rich :is(h1, h2, h3, h4, h5, h6),
.client-page-title {
    margin: var(--client-heading-space) 0 .875rem;
    color: var(--ink);
    font-weight: var(--client-heading-weight);
    line-height: var(--client-heading-lh);
    letter-spacing: var(--client-heading-tracking);
}

.client-page-title,
.client-rich h1 { font-size: var(--client-h1); }
.client-rich h2 { font-size: var(--client-h2); }
.client-rich h3 { font-size: var(--client-h3); }
.client-rich h4 { font-size: var(--client-h4); }
/* The page-level h1 rides in a soft wash band. The band is its own element
   rather than the heading itself, so the colour runs the full width of the
   window while the words stay inside the same measure as the content below —
   no vw arithmetic, and nothing that can push a horizontal scrollbar. */
.client-page-head {
    /* Flush against the site header: this is the first thing under it. */
    margin: 0 0 var(--client-heading-space);
    padding: 3.75rem 0;
    background: #f5f5f3;
    background: color-mix(in oklab, var(--ink) 4%, var(--paper));
}

.client-page-title {
    margin: 0;
    text-align: center;
}

/* Optional intro below the band, from Settings > Blog Page. Held to a readable
   measure so a long line does not run the full width of the page. */
.client-page-intro-wrap { margin-bottom: var(--client-heading-space); }

.client-page-intro {
    max-width: 44rem;
    margin: 0 auto;
    color: var(--ink-2);
    font-size: 1.0625rem;
    line-height: 1.65;
    text-align: center;
}

/* The intro is authored in the rich-text editor, so it arrives as paragraphs,
   lists and links rather than one run of text. */
.client-page-intro > :first-child { margin-top: 0; }
.client-page-intro > :last-child { margin-bottom: 0; }
.client-page-intro p { margin: 0 0 .75rem; }
.client-page-intro :is(h1, h2, h3, h4, h5, h6) { margin: 0 0 .5rem; color: var(--ink); }
.client-page-intro :is(ul, ol) { display: inline-block; margin: 0 0 .75rem; padding-inline-start: 1.25rem; text-align: start; }
.client-page-intro li { margin-bottom: .25rem; }
.client-page-intro strong { color: var(--ink); }
.client-page-intro a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }

.client-rich p { margin: 0 0 var(--client-text-space); }

/* Standalone section headings (Feature Heading, FAQ Heading): spacing only. */
.client-section-heading { margin-bottom: 1.75rem; }
.client-section-heading :is(h1, h2, h3, h4, h5, h6) { margin: 0; }


.client-rich :is(ul, ol) { margin: 0 0 1.25rem; padding-left: 1.5rem; }
.client-rich li { margin-bottom: .625rem; padding-left: .25rem; }
.client-rich a {
    color: var(--ink);
    text-decoration: underline;
    text-decoration-color: var(--line-strong);
    text-underline-offset: 3px;
}
.client-rich a:hover { text-decoration-color: var(--ink); }
.client-rich img { max-width: 100%; height: auto; }
.client-rich strong, .client-rich b { color: var(--ink); font-weight: 700; }
.client-rich blockquote {
    margin: 1.25rem 0;
    padding: .5rem 0 .5rem 1.125rem;
    border-left: 3px solid var(--ink);
    color: var(--ink-2);
    font-style: italic;
}
.client-rich pre { overflow-x: auto; padding: 1rem; background: var(--ink); color: var(--paper); font-size: .875rem; }
.client-rich code { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: .9em; }
.client-rich table { width: 100%; border-collapse: collapse; margin: 0 0 1rem; }
.client-rich :is(th, td) { border: 1px solid var(--line); padding: .625rem .75rem; text-align: left; }
.client-rich th { background: rgba(22, 21, 18, .03); }

/* Quill output: alignment/indent classes, list types, and the .ql-ui span. */
.client-rich .ql-align-center { text-align: center; }
.client-rich .ql-align-right { text-align: right; }
.client-rich .ql-align-justify { text-align: justify; }
.client-rich .ql-ui { display: none; }
.client-rich li[data-list="bullet"] { list-style-type: disc; }
.client-rich li[data-list="ordered"] { list-style-type: decimal; }
.client-rich li[data-list="unchecked"],
.client-rich li[data-list="checked"] { list-style-type: none; }
.client-rich .ql-indent-1 { padding-left: 3em; }
.client-rich .ql-indent-2 { padding-left: 6em; }
.client-rich .ql-indent-3 { padding-left: 9em; }

[dir="rtl"] .client-rich .ql-indent-1 { padding-left: 0; padding-right: 3em; }
[dir="rtl"] .client-rich .ql-indent-2 { padding-left: 0; padding-right: 6em; }
[dir="rtl"] .client-rich .ql-indent-3 { padding-left: 0; padding-right: 9em; }

/* ==========================================================================
   Feature cards

   Clean white cards with soft depth, keyed to the site's brand colour: the
   numbered badge, the hover glow and the coloured shadow all derive from
   --client-banner-bg (Settings > Banner), so the section matches the banner
   with no extra configuration. Where colour math is needed the value is
   mixed toward white with color-mix — a solid-colour fallback is declared
   first for browsers without it.

   Motion: staggered fade-up on first scroll into view (same [data-animate]/
   --reveal-i/.is-revealed contract the layout script drives), and on hover
   the card lifts on a brand-tinted shadow while the badge tilts.
   ========================================================================== */
/* On the white page ground the section gets its own faintly brand-tinted
   band, so the white cards have a surface to sit on at rest instead of
   dissolving into the page. Full-width because the section element spans the
   viewport; the container inside keeps the content measure. */
.client-features {
    background: #fafafa;
    background: color-mix(in oklab, var(--client-banner-bg, #e60023) 3%, #fbfbfa);
    padding: 2.25rem 0;
}

.client-feature-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.5rem;
}

.client-feature-card {
    position: relative;
    display: flex;
    flex-direction: column;
    border: 1px solid var(--line);
    border-radius: 20px;
    background: #fff;
    padding: 1.875rem 1.625rem;
    /* Resting depth: a contact shadow plus a soft ambient one, so the card
       already floats on the band before the hover lift takes over. */
    box-shadow:
        0 1px 2px rgba(22, 21, 18, .05),
        0 12px 28px -18px rgba(22, 21, 18, .14);
    transition:
        transform .35s cubic-bezier(.2, .7, .2, 1),
        box-shadow .35s ease,
        border-color .35s ease;
}

.client-feature-card:hover {
    transform: translateY(-6px);
    border-color: color-mix(in oklab, var(--client-banner-bg, #e60023) 30%, var(--line));
    box-shadow: 0 22px 44px -18px color-mix(in oklab, var(--client-banner-bg, #e60023) 35%, rgba(22, 21, 18, .25));
}

/* A soft brand-coloured wash that breathes in from the top on hover. */
.client-feature-card::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: radial-gradient(
        120% 65% at 50% 0%,
        color-mix(in oklab, var(--client-banner-bg, #e60023) 8%, transparent),
        transparent 70%
    );
    opacity: 0;
    transition: opacity .35s ease;
    pointer-events: none;
}
.client-feature-card:hover::after { opacity: 1; }

/* The number sits in a gradient badge — brand colour into a lighter tint. */
.client-feature-number {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 3rem;
    height: 3rem;
    flex: 0 0 auto;
    align-self: flex-start;
    margin-bottom: 1.125rem;
    border-radius: 14px;
    background: var(--client-banner-bg, #e60023);
    background: linear-gradient(
        135deg,
        var(--client-banner-bg, #e60023),
        color-mix(in oklab, var(--client-banner-bg, #e60023) 65%, white)
    );
    color: #fff;
    font-size: 1.125rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    box-shadow: 0 10px 20px -10px color-mix(in oklab, var(--client-banner-bg, #e60023) 70%, transparent);
    transition: transform .35s cubic-bezier(.2, .7, .2, 1);
}
.client-feature-card:hover .client-feature-number { transform: scale(1.08) rotate(-5deg); }

/* Cards sit one step down the shared scale rather than inventing sizes. */
.client-feature-card .client-rich {
    position: relative;
    --client-text: 1rem;
    --client-text-lh: 1.65;
    --client-heading-space: 0;
}
.client-feature-card .client-rich :is(h1, h2, h3, h4, h5, h6) {
    margin-bottom: .625rem;
    font-size: var(--client-h4);
    line-height: 1.35;
}
.client-feature-card .client-rich p:last-child { margin-bottom: 0; }

/* Entrance: gentle fade-up, only while [data-animate] is present — the
   script removes it afterwards so hover keeps its own timing. */
@media (prefers-reduced-motion: no-preference) {
    .client-feature-grid[data-animate] .client-feature-card {
        opacity: 0;
        transform: translateY(24px);
    }
    .client-feature-grid[data-animate].is-revealed .client-feature-card {
        opacity: 1;
        transform: none;
        transition:
            opacity .55s ease calc(var(--reveal-i, 0) * 90ms),
            transform .55s cubic-bezier(.2, .7, .2, 1) calc(var(--reveal-i, 0) * 90ms);
    }
}

/* ==========================================================================
   FAQ — a ruled list, no boxes
   ========================================================================== */
/* FAQ — cards matching the features section: white, rounded, resting shadow,
   brand-tinted when open. The answer expands smoothly with pure CSS: the
   panel is a grid whose single row animates 0fr -> 1fr, and its one child
   clips with overflow:hidden — no JS measuring, any content height works.
   visibility keeps the collapsed answer out of the tab order and screen
   readers. */
.client-faq-list { display: grid; gap: .75rem; }

.client-faq-item {
    overflow: hidden;
    border: 1px solid var(--line);
    border-radius: 16px;
    background: #fff;
    box-shadow: 0 1px 2px rgba(22, 21, 18, .04);
    transition: border-color .3s ease, box-shadow .3s ease;
}
.client-faq-item.is-open {
    border-color: color-mix(in oklab, var(--client-banner-bg, #e60023) 35%, var(--line));
    box-shadow: 0 14px 30px -20px color-mix(in oklab, var(--client-banner-bg, #e60023) 30%, rgba(22, 21, 18, .2));
}

.client-faq-trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    width: 100%;
    border: 0;
    background: transparent;
    padding: 1.125rem 1.25rem;
    color: var(--ink);
    font: inherit;
    font-size: .9375rem;
    font-weight: 700;
    line-height: 1.45;
    text-align: left;
    cursor: pointer;
    transition: color .3s ease;
}
[dir="rtl"] .client-faq-trigger { text-align: right; }
.client-faq-item.is-open .client-faq-trigger { color: var(--client-banner-bg, #e60023); }

/* The plus sits in a chip; opening fills it with the brand colour and
   rotates the plus into a close cross. */
.client-faq-icon {
    flex: 0 0 auto;
    width: 1.75rem;
    height: 1.75rem;
    padding: .375rem;
    border: 1px solid var(--line-strong);
    border-radius: 999px;
    background: #fff;
    color: var(--ink-2);
    transition:
        transform .3s cubic-bezier(.2, .7, .2, 1),
        background-color .3s ease,
        border-color .3s ease,
        color .3s ease;
}
.client-faq-item.is-open .client-faq-icon {
    background: var(--client-banner-bg, #e60023);
    border-color: var(--client-banner-bg, #e60023);
    color: #fff;
    transform: rotate(45deg);
}

/* Animated expand: the row goes 0fr -> 1fr and the child clips. Padding
   lives on the child, inside the clip, so nothing shows while collapsed. */
.client-faq-panel {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows .35s cubic-bezier(.2, .7, .2, 1);
}
/* Bottom padding is part of the animated state: with border-box sizing a
   child in a 0-height row can never shrink below its own padding, so a
   constant padding-bottom showed as a blank band under every closed
   question. Horizontal padding adds no height and can stay constant. */
.client-faq-panel > .client-rich {
    overflow: hidden;
    min-height: 0;
    visibility: hidden;
    padding: 0 1.25rem;
    --client-text: 1rem;
    transition: visibility .35s, padding-bottom .35s cubic-bezier(.2, .7, .2, 1);
}
.client-faq-item.is-open .client-faq-panel { grid-template-rows: 1fr; }
.client-faq-item.is-open .client-faq-panel > .client-rich {
    visibility: visible;
    padding-bottom: 1.25rem;
}

@media (prefers-reduced-motion: reduce) {
    .client-faq-item,
    .client-faq-trigger,
    .client-faq-icon,
    .client-faq-panel,
    .client-faq-panel > .client-rich { transition: none; }
}

/* ==========================================================================
   Panels, contact form, flashes, buttons
   ========================================================================== */
/* On phones the panel dissolves into the page — no border, no padding — so the
   form uses the full container width; the framed card returns from 640px up. */
.client-panel { background: var(--paper); }

@media (min-width: 640px) {
    .client-panel {
        border: 1px solid var(--line-strong);
        padding: 1.75rem;
    }
}

.client-flash { margin: 1.5rem 0 0; padding: .875rem 1rem; font-size: .9375rem; font-weight: 600; border: 1px solid; border-left-width: 3px; }
.client-flash-success { border-color: #b7dcc4; border-left-color: #1d7a46; background: #f0f7f2; color: #1d5c39; }
.client-flash-error { border-color: #e5b8b4; border-left-color: #b3261e; background: #faf1f0; color: #8c2822; }

.client-contact-title {
    margin: 0;
    color: var(--ink);
    font-size: var(--client-h3);
    font-weight: var(--client-heading-weight);
    line-height: var(--client-heading-lh);
    letter-spacing: var(--client-heading-tracking);
}
.client-contact-copy { margin: .375rem 0 1.5rem; color: var(--ink-3); font-size: .9375rem; }

.client-form { display: grid; gap: 1.125rem; }
.client-form-row { display: grid; gap: 1.125rem; }
.client-field { display: grid; gap: .375rem; }
.client-field label {
    color: var(--ink-2);
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
}
.client-field :is(input, textarea) {
    width: 100%;
    border: 1px solid var(--line-strong);
    background: #fff;
    padding: .75rem .875rem;
    color: var(--ink);
    font: inherit;
    font-size: .9375rem;
    outline: none;
    transition: border-color .15s ease, box-shadow .15s ease;
}
.client-field :is(input, textarea)::placeholder { color: var(--ink-3); }
.client-field :is(input, textarea):focus { border-color: var(--ink); box-shadow: inset 0 0 0 1px var(--ink); }
.client-field .is-invalid { border-color: #b3261e; }
.client-field textarea { resize: vertical; min-height: 8rem; }
.client-field-error { margin: 0; color: #b3261e; font-size: .8125rem; font-weight: 600; }

.client-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    justify-self: start;
    border: 1px solid var(--ink);
    background: var(--ink);
    padding: .8125rem 1.625rem;
    color: var(--paper);
    font: inherit;
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background-color .15s ease, color .15s ease;
}
.client-btn:hover { background: transparent; color: var(--ink); }

/* ==========================================================================
   Empty state and 404
   ========================================================================== */
.client-empty, .client-notfound { padding: 5rem 0; text-align: center; }
.client-empty h1 {
    margin: 0;
    color: var(--ink);
    font-size: var(--client-h1);
    font-weight: var(--client-heading-weight);
    line-height: var(--client-heading-lh);
    letter-spacing: var(--client-heading-tracking);
}
.client-notfound .client-btn { justify-self: center; }
.client-notfound-code {
    margin: 0 0 .5rem;
    color: var(--ink);
    font-size: 4.5rem;
    line-height: 1;
    font-weight: 300;
    letter-spacing: .02em;
    font-variant-numeric: tabular-nums;
}
.client-notfound-copy { margin: 0 0 1.75rem; color: var(--ink-3); font-size: 1rem; line-height: 1.7; }

/* ==========================================================================
   Footer — colours from Settings > Bottom Footer; no logo or site name
   ========================================================================== */
.client-footer {
    margin-top: 4rem;
    border-top: 1px solid var(--line);
    background: var(--client-footer-bg, var(--ink));
    color: var(--client-footer-item, var(--paper));
}
.client-footer-inner {
    display: grid;
    gap: 1.25rem;
    justify-items: center;
    padding-top: 2.5rem;
    padding-bottom: 2.5rem;
    text-align: center;
}
.client-footer-nav { display: flex; flex-wrap: wrap; justify-content: center; gap: .625rem 2rem; }
.client-footer-nav a {
    color: var(--client-footer-item, var(--paper));
    font-size: 18px;
    font-weight: 500;
    transition: color .15s ease;
}
.client-footer-nav a:hover { color: var(--client-footer-item-hover, var(--paper)); }
.client-footer-nav a.is-active { color: var(--client-footer-item-active, var(--paper)); }

.client-footer-text { width: 100%; color: inherit; font-size: 18px; line-height: 1.65; }
.client-footer-text p { margin: 0 0 18px; }
.client-footer-text > :last-child { margin-bottom: 0; }
.client-footer-text a { color: var(--client-footer-item-hover, var(--paper)); text-decoration: underline; }
.client-footer-text img { max-width: 100%; height: auto; margin: .25rem auto; }

/* ==========================================================================
   Layout breakpoints
   ========================================================================== */
@media (min-width: 640px) {
    .client-form-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .client-feature-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 900px) {
    .client-feature-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }

    .client-body {
        --client-h1: 2.375rem;
        --client-h2: 2rem;
        --client-h3: 1.375rem;
    }
    .client-faq-trigger { font-size: 1rem; padding: 1.25rem 1.5rem; }
    /* Same rule as the base styles: horizontal padding constant, bottom
       padding only in the open state so closed cards reserve no height. */
    .client-faq-panel > .client-rich { padding: 0 1.5rem; }
    .client-faq-item.is-open .client-faq-panel > .client-rich { padding-bottom: 1.375rem; }
}

/* RTL: lists and quote rules flip to the other edge. */
[dir="rtl"] .client-rich blockquote { border-left: 0; border-right: 3px solid var(--ink); padding: .5rem 1.125rem .5rem 0; }
[dir="rtl"] .client-rich :is(ul, ol) { padding-left: 0; padding-right: 1.5rem; }
[dir="rtl"] .client-rich :is(th, td) { text-align: right; }

/* ==========================================================================
   Blog — the /blog grid and a single article.

   Cards follow the download results: hairline border, square-ish 14px corners,
   a lift on hover tinted with the administrator's banner colour, so the blog
   reads as part of the same site rather than a bolted-on section.
   ========================================================================== */
.client-blog-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 1.5rem;
}

.client-blog-card {
    /* Anchor for the stretched link, the cover scrim and the top rule. */
    position: relative;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border: 1px solid var(--line);
    border-radius: 18px;
    background: var(--paper);
    box-shadow: 0 1px 2px rgba(22, 21, 18, .04);
    transition: transform .25s ease, box-shadow .25s ease, border-color .25s ease;
    animation: client-dl-in .45s cubic-bezier(.2, .7, .2, 1) backwards;
    animation-delay: calc(var(--blog-i, 0) * 60ms);
}

/* A rule in the site's own accent colour draws itself across the top on
   hover — the one flourish on an otherwise quiet card. */
.client-blog-card::before {
    content: "";
    position: absolute;
    top: 0;
    inset-inline: 0;
    z-index: 2;
    height: 3px;
    background: var(--client-banner-bg, #e60023);
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform .35s cubic-bezier(.2, .7, .2, 1);
}

[dir="rtl"] .client-blog-card::before { transform-origin: right center; }

@media (hover: hover) {
    .client-blog-card:hover {
        transform: translateY(-6px);
        border-color: color-mix(in oklab, var(--client-banner-bg, #e60023) 40%, var(--line));
        box-shadow: 0 22px 40px -22px color-mix(in oklab, var(--client-banner-bg, #e60023) 50%, rgba(22, 21, 18, .45));
    }

    .client-blog-card:hover::before { transform: scaleX(1); }
}

.client-blog-thumb {
    position: relative;
    display: block;
    width: 100%;
    aspect-ratio: 16 / 10;
    background: var(--line);
    overflow: hidden;
}

.client-blog-thumb img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform .5s cubic-bezier(.2, .7, .2, 1);
}

/* Keeps the date legible over a bright photograph without dimming the whole
   picture. Only where there is a photograph: over the stand-in initial it
   would just look like a smudge. */
.client-blog-thumb:has(img)::after {
    content: "";
    position: absolute;
    inset: 40% 0 0;
    background: linear-gradient(to bottom, transparent, rgba(16, 15, 13, .5));
    pointer-events: none;
}

@media (hover: hover) {
    .client-blog-card:hover .client-blog-thumb img { transform: scale(1.06); }
}

/* Stand-in cover: the article's initial washed in the banner colour. */
.client-blog-thumb-fallback {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    background: linear-gradient(
        135deg,
        color-mix(in oklab, var(--client-banner-bg, #e60023) 20%, var(--paper)),
        color-mix(in oklab, var(--client-banner-bg, #e60023) 5%, var(--paper))
    );
    color: color-mix(in oklab, var(--client-banner-bg, #e60023) 70%, var(--ink));
    font-size: 3.25rem;
    font-weight: 700;
    line-height: 1;
}

.client-blog-date {
    position: absolute;
    z-index: 1;
    bottom: .875rem;
    inset-inline-start: .875rem;
    padding: .3rem .7rem;
    border-radius: 999px;
    background: rgba(16, 15, 13, .55);
    backdrop-filter: blur(6px);
    color: #fff;
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
}

.client-blog-body {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: .625rem;
    padding: 1.375rem 1.5rem 1.25rem;
}

.client-blog-title {
    margin: 0;
    color: var(--ink);
    font-size: var(--client-h4);
    font-weight: var(--client-heading-weight);
    line-height: 1.35;
    letter-spacing: var(--client-heading-tracking);
}

.client-blog-title a { color: inherit; text-decoration: none; }

/*
 * The title link covers the card, so a click anywhere on it opens the article.
 * Done this way rather than by wrapping everything in an anchor: the card keeps
 * one link, one tab stop and one accessible name — the title — instead of
 * announcing the date and the whole blurb as the link text. The trade-off is
 * that the card's text can no longer be selected with the mouse, which is a
 * fair price on a card whose entire job is to be clicked.
 */
.client-blog-title a::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 3;
}

/* Keyboard focus lands on that link, so the ring belongs on the whole card. */
.client-blog-card:has(a:focus-visible) {
    outline: 2px solid var(--ink);
    outline-offset: 3px;
}

.client-blog-title a:focus-visible { outline: none; }

/* Hovering anywhere on the card marks the title, since the whole card is the
   link — underlining only on a direct hover of the words would read as if the
   rest of the card were dead. */
@media (hover: hover) {
    .client-blog-card:hover .client-blog-title a {
        color: #444;
    }
}

/*
 * Exactly three lines, whatever the card's width, with an ellipsis where the
 * text is cut. Trimming by character count in PHP cannot do this — the number
 * of characters that fit a line is only known once the browser has laid the
 * card out.
 */
.client-blog-excerpt {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    overflow: hidden;
    margin: 0;
    color: var(--ink-2);
    font-size: .9688rem;
    line-height: 1.6;
}

/* Pushed to the bottom on a hairline, so cards of differing text length still
   line their footers up across a row. */
.client-blog-foot {
    display: flex;
    align-items: center;
    margin-top: auto;
    padding-top: .875rem;
    border-top: 1px solid var(--line);
}

.client-blog-more {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    color: var(--client-banner-bg, #e60023);
    font-size: .9375rem;
    font-weight: 600;
}

.client-blog-more::after {
    content: "\2192";
    transition: transform .25s ease;
}

[dir="rtl"] .client-blog-more::after { content: "\2190"; }

@media (hover: hover) {
    .client-blog-card:hover .client-blog-more::after { transform: translateX(4px); }
    [dir="rtl"] .client-blog-card:hover .client-blog-more::after { transform: translateX(-4px); }
}

/* --- Featured article ---------------------------------------------------
   The hero at the top of the index: a dark slab, cover on one side, the words
   on the other. Deliberately the one inverted surface on the page, so the eye
   lands on it before the grid below. --------------------------------------- */
.client-blog-hero {
    /* Anchor for the stretched link. */
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    overflow: hidden;
    border-radius: 20px;
    background: var(--ink);
    box-shadow: 0 18px 40px -28px rgba(22, 21, 18, .6);
    transition: transform .25s ease, box-shadow .25s ease;
}

.client-blog-hero-media {
    position: relative;
    aspect-ratio: 16 / 10;
    background: color-mix(in oklab, var(--ink) 82%, var(--paper));
}

.client-blog-hero-media img {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform .6s cubic-bezier(.2, .7, .2, 1);
}

.client-blog-hero-body {
    display: flex;
    flex-direction: column;
    gap: .875rem;
    padding: 2rem 1.75rem;
}

.client-blog-hero-eyebrow {
    margin: 0;
    color: var(--client-banner-bg, #e60023);
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
}

.client-blog-hero-title {
    margin: 0;
    color: var(--paper);
    font-size: var(--client-h3);
    font-weight: var(--client-heading-weight);
    line-height: 1.25;
    letter-spacing: var(--client-heading-tracking);
}

.client-blog-hero-title a { color: inherit; text-decoration: none; }

/* Same stretched-link pattern as the cards: the whole slab is the target,
   while the accessible name stays just the title. */
.client-blog-hero-title a::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 2;
}

.client-blog-hero-title a:focus-visible { outline: none; }

.client-blog-hero:has(a:focus-visible) {
    outline: 2px solid var(--client-banner-bg, #e60023);
    outline-offset: 3px;
}

.client-blog-hero-excerpt {
    margin: 0;
    color: rgba(255, 255, 255, .72);
    font-size: 1rem;
    line-height: 1.65;
}

/* Rests on the bottom edge on a hairline, the way the cards' footers do. */
.client-blog-hero-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-top: auto;
    padding-top: 1.125rem;
    border-top: 1px solid rgba(255, 255, 255, .16);
    color: rgba(255, 255, 255, .55);
    font-size: .875rem;
}

@media (hover: hover) {
    .client-blog-hero:hover {
        transform: translateY(-4px);
        box-shadow: 0 26px 50px -26px rgba(22, 21, 18, .7);
    }

    .client-blog-hero:hover .client-blog-hero-media img { transform: scale(1.04); }

    .client-blog-hero:hover .client-blog-hero-title a {
        text-decoration: underline;
        text-decoration-thickness: 2px;
        text-underline-offset: 4px;
    }
}

@media (min-width: 860px) {
    /* Cover a shade wider than the words, as in the reference. */
    .client-blog-hero { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }

    .client-blog-hero-media {
        aspect-ratio: auto;
        min-height: 21rem;
    }

    .client-blog-hero-body { padding: 2.75rem 2.5rem; }

    .client-blog-hero-title { font-size: var(--client-h2); }

    /* Nothing to sit beside without a cover, so the words take the full slab. */
    .client-blog-hero.is-imageless { grid-template-columns: minmax(0, 1fr); }
}

.client-blog-empty {
    margin: 0;
    padding: 3rem 1rem;
    border: 1px dashed var(--line-strong);
    border-radius: 14px;
    text-align: center;
    color: var(--ink-3);
    font-size: 1rem;
}

/* --- Pager --------------------------------------------------------------- */
.client-blog-pager {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .5rem;
    margin-top: 2.5rem;
}

.client-blog-pager-link {
    min-width: 2.5rem;
    padding: .5rem .75rem;
    border: 1px solid var(--line);
    border-radius: 8px;
    color: var(--ink-2);
    font-size: .9375rem;
    text-align: center;
    text-decoration: none;
}

@media (hover: hover) {
    a.client-blog-pager-link:hover { border-color: var(--ink); color: var(--ink); }
}

.client-blog-pager-link.is-current {
    border-color: var(--client-banner-bg, #e60023);
    background: var(--client-banner-bg, #e60023);
    color: var(--client-banner-heading, #fff);
}

/* --- One article --------------------------------------------------------- */
.client-blog-meta {
    margin: .75rem 0 0;
    color: var(--ink-3);
    font-size: .9375rem;
    text-align: center;
}

/*
 * The cover is framed rather than printed at whatever size it was uploaded:
 * the same 16/9 window the cards use, filled by the image. Without it a tall
 * portrait upload fills the screen and pushes the first paragraph below the
 * fold, and no two articles read as the same site.
 */
.client-blog-cover {
    aspect-ratio: 16 / 9;
    margin: 0 0 2rem;
    overflow: hidden;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--line);
}

.client-blog-cover img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

@media (max-width: 520px) {
    .client-blog-grid { gap: 1.25rem; }
    .client-blog-body { padding: 1.125rem 1.25rem 1.125rem; }
    .client-blog-thumb { aspect-ratio: 16 / 9; }
}

@media (max-width: 640px) {
    .client-page-head {
        margin-bottom: 1.75rem;
        padding: 2rem 0;
    }
}

/* ------------------------------------------------------------------ *
 * Download notice
 *
 * A download is pulled into the page before the browser is asked to save
 * it, so closing the tab part way through throws the transfer away. This
 * sits out of the way and says so for as long as one is running.
 *
 * Two shapes: a pill floating in the middle on a wide screen, and a bar
 * across the foot of a narrow one. A pill is the wrong shape once the
 * sentence wraps — a 999px radius eats into two-line text — and on a
 * phone this sentence always wraps.
 * ------------------------------------------------------------------ */
.client-toast {
    position: fixed;
    left: 50%;
    bottom: 1.25rem;
    z-index: 90;
    display: flex;
    align-items: center;
    gap: .625rem;

    /*
     * Sized against the viewport, not 100vw: vw includes the space a
     * vertical scrollbar occupies, so a full-width value there is wider
     * than what can actually be seen and pushes the page sideways.
     */
    max-width: min(30rem, calc(100% - 2rem));

    padding: .75rem 1.125rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--paper);
    color: var(--ink);
    font-size: .9375rem;
    line-height: 1.4;
    box-shadow: 0 6px 24px rgba(22, 21, 18, .14), 0 1px 2px rgba(22, 21, 18, .06);

    /*
     * Centred by shifting half its own width, so the notice does not have to
     * be a fixed size. The vertical nudge is what it animates in from.
     */
    transform: translate(-50%, .75rem);
    opacity: 0;
    transition: opacity .2s ease, transform .2s ease;
}

.client-toast.is-open {
    opacity: 1;
    transform: translate(-50%, 0);
}

.client-toast[hidden] { display: none; }

.client-toast-spinner {
    flex: none;
    width: 1rem;
    height: 1rem;
    border: 2px solid var(--line-strong);
    border-top-color: var(--ink);
    border-radius: 50%;
    animation: client-toast-spin .7s linear infinite;
}

/*
 * A flex child will not shrink below the width of its longest word unless it
 * is told it may, which is what pushes the notice wider than the screen.
 */
.client-toast-text {
    min-width: 0;
    overflow-wrap: break-word;
}

@keyframes client-toast-spin {
    to { transform: rotate(360deg); }
}

/*
 * The notice is centred, so it needs no side flip for Arabic; only the text
 * inside it runs the other way, which the document direction already handles.
 */
[dir="rtl"] .client-toast { flex-direction: row-reverse; }

/*
 * On a phone it spans the foot of the screen instead. Pinning both edges
 * means the sentence decides the height and nothing has to be centred, so
 * there is no half-its-own-width shift to go wrong at any text length.
 */
@media (max-width: 640px) {
    .client-toast {
        left: .75rem;
        right: .75rem;
        bottom: .75rem;
        max-width: none;
        padding: .75rem .875rem;
        border-radius: 14px;
        font-size: .875rem;
        transform: translate(0, .75rem);
    }

    .client-toast.is-open { transform: translate(0, 0); }
}

@media (prefers-reduced-motion: reduce) {
    .client-toast { transition: none; }
    .client-toast-spinner { animation: none; }
}

/* ---------------------------------------------------------------------------
   The head of a profile search: cover, picture, name and bio.

   Only a profile answers with one, so the block stays hidden until the script
   fills it. The cover is optional — Facebook does not give one to a signed-out
   visitor — and without it the picture sits on a plain band rather than
   floating over nothing.
--------------------------------------------------------------------------- */
.client-profile {
    margin: 0 0 1.25rem;
    border: 1px solid var(--line);
    border-radius: 16px;
    background: var(--paper);
    overflow: hidden;
}

.client-profile-cover {
    position: relative;
    display: block;
    width: 100%;
    aspect-ratio: 40 / 13;
    background: linear-gradient(120deg, var(--line), var(--paper));
}

.client-profile-cover img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Without a cover the band is short: enough to sit the picture on, no more. */
.client-profile-cover.is-empty { aspect-ratio: auto; height: 4.5rem; }

.client-profile-body {
    display: grid;
    justify-items: center;
    gap: .5rem;
    padding: 0 1.25rem 1.25rem;
    text-align: center;
}

/* Pulled up so it straddles the cover, as a profile page does. */
.client-profile-avatar {
    position: relative;
    width: 6.5rem;
    height: 6.5rem;
    margin-top: -3.25rem;
    border-radius: 50%;
    border: 4px solid var(--paper);
    background: var(--paper);
    overflow: hidden;
}

.client-profile-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.client-profile-name {
    margin: .25rem 0 0;
    color: var(--ink);
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1.3;
}

.client-profile-bio {
    margin: 0;
    max-width: 44rem;
    color: var(--ink-2, var(--ink-3));
    font-size: .875rem;
    line-height: 1.6;
    white-space: pre-line;
}

.client-profile-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .5rem;
    margin-top: .25rem;
}

@media (max-width: 480px) {
    .client-profile-avatar { width: 5rem; height: 5rem; margin-top: -2.5rem; }
    .client-profile-name { font-size: 1.0625rem; }
    .client-profile-bio { font-size: .8125rem; }
}

/* ---------------------------------------------------------------------------
   A profile's results are its posts, so the card is drawn as one: who posted
   it and when, what they said, the media, then how it was received.

   Only the chrome is added here. The card, its thumbnail and its save button
   are the ordinary ones, so a post card and a plain result still look like
   the same family.
--------------------------------------------------------------------------- */
.client-dl-post { display: flex; flex-direction: column; }

.client-post-head {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .75rem .875rem .5rem;
}

.client-post-face {
    flex: none;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    overflow: hidden;
    background: var(--line);
}

.client-post-face img { width: 100%; height: 100%; object-fit: cover; display: block; }

.client-post-by { display: grid; min-width: 0; }

.client-post-author {
    color: var(--ink);
    font-size: .8125rem;
    font-weight: 700;
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.client-post-date {
    color: var(--ink-3);
    font-size: .6875rem;
    line-height: 1.3;
}

/* The caption keeps the line breaks it was written with, but only three lines
   of them: a long one would push every thumbnail in the row out of line. */
.client-post-caption {
    margin: 0 0 .625rem;
    padding: 0 .875rem;
    color: var(--ink);
    font-size: .8125rem;
    line-height: 1.5;
    white-space: pre-line;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* How the post was received: an icon and a number, three across. */
.client-post-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem;
    margin: 0;
    padding: .625rem .875rem 0;
    color: var(--ink-3);
    font-size: .75rem;
    font-weight: 600;
}

.client-post-count {
    display: inline-flex;
    align-items: center;
    gap: .3125rem;
    /* The number is the message, so it is read at the page's own colour while
       the icon stays quieter beside it. */
    color: var(--ink-2, var(--ink-3));
}

.client-post-count svg {
    width: 1rem;
    height: 1rem;
    flex: none;
    opacity: .75;
}

@media (max-width: 480px) {
    .client-post-head { padding: .625rem .75rem .375rem; }
    .client-post-caption { padding: 0 .75rem; font-size: .78125rem; }
    .client-post-meta { padding: .5rem .75rem 0; }
}

/* ---------------------------------------------------------------------------
   A feed: one post to a row.

   Facebook's Posts section asks for this. A post is read rather than scanned —
   the name, the date and the caption all want a line of their own — and three
   abreast leaves none of them room. The Media section stays a grid, where
   seeing many things at once is the point.
--------------------------------------------------------------------------- */
.client-dl-grid.is-feed {
    grid-template-columns: minmax(0, 560px);
    justify-content: center;
    gap: 1rem;
}

/* Beats the single-result rule above, which would otherwise narrow a feed
   holding one post to a portrait card. */
.client-dl-grid.is-feed:has(> :only-child) {
    grid-template-columns: minmax(0, 560px);
}

/*
   The media keeps its own shape here instead of being cropped to a card: a
   post is shown as it was posted. A fixed height keeps a tall video from
   pushing the next post off the screen, and the dark ground is what fills the
   space either side of anything that is not the same shape.
*/
.client-dl-grid.is-feed .client-dl-thumb {
    aspect-ratio: auto;
    height: min(70vh, 32rem);
    background: #100f0d;
}

.client-dl-grid.is-feed .client-dl-thumb img { object-fit: contain; }

/* With room to spare, the caption need not be clipped to three lines. */
.client-dl-grid.is-feed .client-post-caption { -webkit-line-clamp: 8; }

@media (max-width: 600px) {
    .client-dl-grid.is-feed .client-dl-thumb { height: min(60vh, 24rem); }
}
