/* ============================================================
   HMB shared stylesheet
   Design tokens + shared chrome (nav, footer, toast, offline
   banner, install prompt). Extracted from the page <style>
   blocks so the palette lives in exactly one place.
   Page-specific CSS still lives inline and overrides this file.
   ============================================================ */

:root{
    --parchment:oklch(95.0% 0.016 73.7);--parchment-light:oklch(95.0% 0.016 73.7);
    --wine:oklch(26.2% 0.064 5.4);--wine-mid:oklch(34.3% 0.087 4.6);
    --terra:oklch(53% 0.128 36.7);--terra-soft:oklch(75.6% 0.070 52.5);--terra-glow:var(--terra-a12);
    --gold:oklch(70.2% 0.055 84.8);--gold-soft:oklch(70.2% 0.087 84.8 / 0.15);
    --ink:oklch(20.8% 0.016 356.7);--stone:oklch(52% 0.019 50.3);--mist:oklch(46.0% 0.021 45);
    --blush:oklch(84.8% 0.044 39.3);--cream-card:oklch(99.2% 0.006 75.4);--green:oklch(68.1% 0.120 158.7);--amber:oklch(77.4% 0.143 77.0);
    
    /* Text-safe variants. Same hue and chroma, lightness lowered until the
       pair clears WCAG AA 4.5:1. Use these for small text and for fills
       that carry light text; the originals stay for decoration. */
    --terra-fill:oklch(53.0% 0.128 36.7);
    --gold-text:oklch(52.0% 0.055 84.8);
    --green-text:oklch(52.0% 0.103 156.2);
    --amber-text:oklch(52.0% 0.110 77.0);

    --cream:oklch(95.0% 0.016 73.7);--rose:oklch(53% 0.128 36.7);--deep-rose:oklch(51.4% 0.119 31.5);--burgundy:oklch(26.2% 0.064 5.4);--charcoal:oklch(20.8% 0.016 356.7);--warm-grey:oklch(52% 0.019 50.3);--light-blush:oklch(97.6% 0.013 53.4);
    }
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0;}
html{scroll-behavior:smooth;}
body::after{
    content:'';position:fixed;inset:0;z-index:9998;pointer-events:none;
    opacity:0.025;
    background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    background-size:200px 200px;
}
.nav-logo span{color:var(--blush);}
#premium-nav-badge{display:none;}
#premium-nav-badge.visible{display:inline-flex;}
.hamburger.open span:nth-child(2){opacity:0;}
.footer-links ul{list-style:none;}
.footer-links a:hover{color:var(--blush);}
.footer-bottom{display:flex;justify-content:space-between;align-items:center;}
@keyframes spin{to{transform:rotate(360deg);}}
.premium-badge{display:none;align-items:center;gap:4px;background:linear-gradient(135deg,var(--gold),oklch(57.0% 0.068 82.4));color:var(--cream-card);font-size:9px;font-weight:700;letter-spacing:2px;text-transform:uppercase;padding:3px 9px;border-radius:2px;white-space:nowrap;}
.premium-badge.visible{display:inline-flex;}
.hamburger{display:none;background:none;border:none;cursor:pointer;flex-direction:column;justify-content:center;align-items:center;gap:5px;padding:8px;min-width:44px;min-height:44px;}
@media(min-width:861px){.hamburger{display:none!important;}}
.paywall-view-plans:hover{color:var(--deep-rose);}
.paywall-cta:hover{background:var(--deep-rose);transform:translateY(-1px);}
@media(max-width:600px){.paywall-trust{gap:8px;font-size:10px;}.paywall-pricing{flex-direction:column;}}
body[data-premium="yes"] .adsbygoogle,
body[data-premium="yes"] ins.adsbygoogle,
body[data-premium="yes"] .ad-container,
body[data-premium="yes"] [data-ad-block]{display:none!important;}
/* Reduced motion, applied once for every page that links this sheet.
   Durations are near-zeroed rather than removed so animation-fill-mode
   still resolves -- a reveal that ends at opacity:1 must not be left
   stranded at opacity:0. */
@media(prefers-reduced-motion:reduce){
    html{scroll-behavior:auto;}
    *,*::before,*::after{
        animation-duration:0.01ms !important;
        animation-iteration-count:1 !important;
        transition-duration:0.01ms !important;
        scroll-behavior:auto !important;
    }
}
.skip-link{
    position:absolute;top:-40px;left:0;z-index:999;
    background:var(--burgundy);color:var(--cream);
    padding:10px 18px;font-size:12px;font-weight:600;
    letter-spacing:1px;text-decoration:none;
    transform:translateY(-100%);transition:transform 0.2s;
}
.skip-link:focus{transform:translateY(140%);}
/* Focus ring. Terracotta sits at L=61%, so it separates from both the
   parchment ground (L=95%) and the wine nav (L=26%) -- gold no longer
   would, now that it has been pulled back to a support tone. */
:focus-visible{
    outline:2px solid var(--terra);
    outline-offset:3px;
    border-radius:2px;
}
button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{
    outline:2px solid var(--terra);
    outline-offset:2px;
}
/* On a terracotta-filled control the ring would vanish into the fill,
   so those switch to wine. */
.btn-primary:focus-visible,
.paywall-cta:focus-visible,
.btn-upgrade-inline:focus-visible,
.nav-cta:focus-visible{
    outline-color:var(--wine);
    outline-offset:3px;
}
#hmb-toast-container{
    position:fixed;bottom:24px;left:50%;transform:translateX(-50%);
    z-index:9999;display:flex;flex-direction:column;gap:10px;
    pointer-events:none;align-items:center;
}
.hmb-toast{
    background:var(--charcoal);color:var(--cream);
    padding:13px 22px;font-size:13px;font-weight:500;
    letter-spacing:0.3px;border-radius:2px;
    box-shadow:var(--lift-md);
    display:flex;align-items:center;gap:10px;
    transform:translateY(20px);opacity:0;
    transition:transform 0.3s cubic-bezier(0.16,1,0.3,1),opacity 0.25s;
    pointer-events:auto;max-width:90vw;
}
.hmb-toast.show{transform:translateY(0);opacity:1;}
.hmb-toast svg{width:18px;height:18px;flex-shrink:0;}
.hmb-toast.success svg{color:oklch(76.7% 0.130 145.3);}
.hmb-toast.error svg{color:oklch(75.4% 0.101 20.5);}
.hmb-toast.info svg{color:var(--gold);}
@media(max-width:480px){
    #hmb-toast-container{bottom:80px;left:16px;right:16px;transform:none;}
    .hmb-toast{font-size:12px;padding:11px 16px;}
}
button.is-loading{
    position:relative;color:transparent!important;pointer-events:none;
}
button.is-loading::after{
    content:'';position:absolute;left:50%;top:50%;
    width:18px;height:18px;margin:-9px 0 0 -9px;
    border:2.5px solid oklch(99.2% 0.006 75 / 0.3);
    border-top-color:currentColor;color:var(--cream-card);
    border-radius:50%;animation:hmb-spin 0.7s linear infinite;
}
button.is-loading.btn-outline::after,
button.is-loading.btn-secondary::after{color:var(--rose);}
@keyframes hmb-spin{to{transform:rotate(360deg);}}
#back-to-top{
    position:fixed;bottom:24px;right:24px;z-index:200;
    width:46px;height:46px;border-radius:50%;
    background:var(--burgundy);color:var(--cream);
    border:none;cursor:pointer;
    display:flex;align-items:center;justify-content:center;
    box-shadow:var(--lift-md);
    opacity:0;transform:translateY(20px) scale(0.85);pointer-events:none;
    transition:opacity 0.3s,transform 0.3s;
}
#back-to-top.visible{opacity:1;transform:translateY(0) scale(1);pointer-events:auto;}
#back-to-top:hover{background:var(--charcoal);transform:translateY(-2px) scale(1.05);}
#back-to-top svg{width:20px;height:20px;}
@media(max-width:480px){
    #back-to-top{width:42px;height:42px;bottom:18px;right:18px;}
}
@media (display-mode: standalone) {
    body{padding-bottom:env(safe-area-inset-bottom);}
}
.bottom-nav{display:none;}
@media(max-width:860px){
    .bottom-nav{
        display:flex;position:fixed;left:0;right:0;bottom:0;z-index:198;
        height:60px;
        background:oklch(26.2% 0.064 5.4);
        border-top:1px solid var(--cream-a08);
        padding-bottom:env(safe-area-inset-bottom);
    }
    .bottom-nav-tab{
        flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
        gap:3px;text-decoration:none;color:var(--cream-a55);
        font-size:9px;font-weight:600;letter-spacing:0.5px;text-transform:uppercase;
        transition:color 0.15s;background:none;border:none;cursor:pointer;
        padding:6px 4px;min-height:54px;
    }
    .bottom-nav-tab svg{width:22px;height:22px;}
    .bottom-nav-tab.active{color:var(--blush);}
    .bottom-nav-tab.active svg{filter:drop-shadow(0 0 8px oklch(86.0% 0.053 18.2 / 0.4));}
    .bottom-nav-tab:active{background:var(--cream-a05);}
    
    /* Only reserve space when the page actually renders a bottom tab bar.
       Pages without one (contact, terms, diagnostic) got 60px of dead
       space when these rules were shared. */
    body:has(.bottom-nav){padding-bottom:calc(60px + env(safe-area-inset-bottom)) !important;}

    body:has(.bottom-nav) #back-to-top{bottom:calc(78px + env(safe-area-inset-bottom)) !important;}

    body:has(.bottom-nav) .mobile-signout-fab{bottom:calc(78px + env(safe-area-inset-bottom)) !important;}

    body:has(.bottom-nav) #hmb-toast-container{bottom:calc(76px + env(safe-area-inset-bottom)) !important;}
}
#ios-install-banner{
    display:none;position:fixed;left:12px;right:12px;bottom:76px;z-index:300;
    background:var(--cream);color:var(--charcoal);
    padding:14px 16px;border-radius:0;
    box-shadow:var(--lift-md), 0 0 0 1px oklch(26.2% 0.064 5 / 0.04);
    display:none;align-items:center;gap:12px;
    animation:slideUpBanner 0.4s cubic-bezier(0.16,1,0.3,1);
}
#ios-install-banner.visible{display:flex;}
#ios-install-banner .iib-icon{
    width:44px;height:44px;border-radius:9px;background:var(--burgundy);
    display:flex;align-items:center;justify-content:center;flex-shrink:0;
}
#ios-install-banner .iib-icon svg{width:26px;height:26px;color:var(--blush);}
#ios-install-banner .iib-text{flex:1;min-width:0;}
#ios-install-banner .iib-title{font-size:13px;font-weight:700;color:var(--charcoal);line-height:1.2;margin-bottom:3px;}
#ios-install-banner .iib-sub{font-size:11px;color:var(--warm-grey);line-height:1.35;}
#ios-install-banner .iib-sub strong{color:var(--rose);font-weight:600;}
#ios-install-banner .iib-close{
    background:none;border:none;cursor:pointer;color:var(--warm-grey);
    font-size:20px;padding:4px 8px;flex-shrink:0;line-height:1;
}
@keyframes slideUpBanner{from{transform:translateY(120%);opacity:0;}to{transform:translateY(0);opacity:1;}}
#offline-banner{
    display:none;position:fixed;top:0;left:0;right:0;z-index:400;
    background:var(--charcoal);color:var(--cream);
    padding:10px 16px;text-align:center;font-size:12px;font-weight:500;
    letter-spacing:0.3px;
}
#offline-banner.visible{display:block;animation:slideDownBanner 0.3s ease;}
#offline-banner svg{width:14px;height:14px;display:inline-block;vertical-align:middle;margin-right:6px;color:var(--gold);}
@keyframes slideDownBanner{from{transform:translateY(-100%);}to{transform:translateY(0);}}
body.is-offline nav{top:36px;}

/* ═══ Muted text and the accent need OPPOSITE adjustments by ground ═══
   The muted grey has to go darker to be legible on parchment and lighter
   to be legible on wine, and no single value does both: 4.5:1 on #f5ede3
   needs L <= 52%, 4.5:1 on #1e1518 needs L >= 62%, and the old 59.9% sat
   in the gap failing both. Same shape of problem for the accent — pulling
   it down to 53% fixes it as text on parchment and behind cream on a
   button, but takes it from 4.0 to 2.8 on the wine hero, where the
   headline only passes today because it is large.

   Custom properties inherit, so the ground decides. The base values below
   are tuned for light sections; the dark sections restate them. Nothing at
   a usage site changes — every existing var(--stone) and var(--terra)
   picks up the right one from whichever section it sits in. */
.v2-hero, .page-hero, .pricing-hero, .policy-hero, .account-hero, .contact-hero,
nav, footer, .legal-bar, .emergency, .v2-band, .v2-step-b,
.paywall-modal, .paywall-top, .saved-itin-modal, .apology-modal,
.tier-1, .tier-2, .tier-3, .mc-card, .lock-badge, .free-limit-bar,
/* #gift-quiz is a dark section that was never added to this list, so its
   accent stayed on the light-ground value and the heading measured 2.76:1
   against its own gradient — below even the 3.0 that large text is allowed.
   Membership of this list is the whole mechanism; being absent from it is
   silent. */
#gift-quiz {
    --stone:oklch(66% 0.019 50.3);
    --warm-grey:oklch(66% 0.019 50.3);
    --mist:oklch(66% 0.021 45);
    /* the accent keeps its present lightness on dark grounds */
    --terra:oklch(61.3% 0.128 36.7);
    /* Measured against the real gradient rather than assumed: rose at 61.3%
       gives the tier-3 label 4.26:1 and green at 68.1% gives the tier-1
       buttons 4.07-4.14:1, both short of the 4.5 that 10-13px text needs.
       Nothing had ever measured these because axe declines to judge text on a
       gradient and reports it as undecided rather than failing. */
    --rose:oklch(64.5% 0.128 36.7);
    --green:oklch(72.5% 0.120 158.7);
}

/* Islands inside a dark section that paint their own ground. The section
   sets the dark-ground values for everything beneath it, but a parchment
   chip or a solid terracotta button supplies its own background, so the
   text on it needs the light-ground values back. Without this the hero
   chip inherited the 66% grey onto parchment (2.7:1) and the primary
   button kept the 61.3% terracotta under cream text (3.86:1). */
.v2-hero-chip, .v2-shot, .paywall-body {
    --stone:oklch(52% 0.019 50.3);
    --warm-grey:oklch(52% 0.019 50.3);
}
.v2-btn, .btn, .btn-primary, .cta-btn {
    --terra:oklch(53% 0.128 36.7);
    --rose:oklch(53% 0.128 36.7);
}

/* Paywall: the free hour.
   Secondary to the buy button on purpose — it is the fallback for someone
   not ready to pay, not the thing being sold. Outlined rather than filled so
   it reads as the quieter of the two without disappearing into the "Maybe
   later" text link below it. */
.paywall-demo{display:block;width:100%;margin-top:10px;padding:13px;
    background:none;color:var(--terra-fill);border:1px solid var(--terra-fill);
    font-family:'Outfit',sans-serif;font-size:13px;font-weight:600;letter-spacing:0.5px;
    cursor:pointer;transition:background 0.2s,color 0.2s;min-height:44px;}
.paywall-demo:hover{background:var(--terra-fill);color:var(--cream-card);}

/* Icons.
   Sized in em so an icon matches the text it sits beside rather than needing a
   rule per context, and nudged down so its optical centre lands on the
   baseline. currentColor is inherited, which is the whole reason these
   replaced emoji: they take the colour of the tier, button or ground around
   them instead of whatever the operating system decided. */
.hmb-icon{width:1.15em;height:1.15em;vertical-align:-0.22em;flex:0 0 auto;display:inline-block;}
.hmb-icon-lg{width:28px;height:28px;vertical-align:middle;}

/* Elevation.
   Thirty-seven distinct box-shadows were in use, nearly all of them one-offs
   eyeballed a few pixels apart: 0.30 and 0.35 of the same terracotta, four
   neutral lifts between 0.07 and 0.12, five modal shadows. Nobody could have
   told them apart side by side, and together they made the site look assembled
   rather than designed. These five are the whole vocabulary; each keeps the
   value the majority of the site was already using, so the common case is
   unchanged and only the strays move. */
:root{
    --lift-sm:0 4px 16px oklch(26.2% 0.064 5.4 / 0.08);
    --lift-md:0 8px 24px oklch(26.2% 0.064 5.4 / 0.35);
    --lift-lg:0 32px 80px oklch(26.2% 0.064 5 / 0.35);
    --lift-terra:0 8px 24px var(--terra-a30);
    /* Negative spread pulls the shadow in under the element instead of
       haloing it — a different effect from the lifts above, so it gets its own
       two steps rather than being forced into them. */
    --lift-tight:0 18px 40px -18px oklch(26.2% 0.064 5.4 / 0.3);
    --lift-hero:0 26px 60px -18px oklch(26.2% 0.064 5.4 / 0.7);
    /* The settled nav wants a tight, dark edge rather than a halo — it sits
       against the page rather than floating over it, so it keeps its own step
       instead of being folded into the lifts. */
    --lift-nav:0 10px 30px -16px oklch(20.8% 0.016 357 / 0.85);
    --focus-ring:0 0 0 3px var(--terra-glow);
}

/* Cream at a stated opacity.
   Thirty-four different alphas of this one colour were in use across 173
   declarations — 0.62, 0.65, 0.66, 0.70, 0.72, 0.74 and 0.75 all within
   thirteen points of each other, none of them distinguishable from its
   neighbours. Nine steps replace them, each anchored on the value the most
   declarations already used, so the common cases do not move at all and only
   the strays snap into line. Named by their alpha rather than by a role,
   because the same step is text on one ground and a border on another. */
:root{
    --cream-a95:oklch(95.0% 0.016 73.7 / 0.95);
    --cream-a85:oklch(95.0% 0.016 73.7 / 0.85);
    --cream-a72:oklch(95.0% 0.016 73.7 / 0.72);
    --cream-a62:oklch(95.0% 0.016 73.7 / 0.62);
    --cream-a55:oklch(95.0% 0.016 73.7 / 0.55);
    --cream-a35:oklch(95.0% 0.016 73.7 / 0.35);
    --cream-a25:oklch(95.0% 0.016 73.7 / 0.25);
    --cream-a14:oklch(95.0% 0.016 73.7 / 0.14);
    --cream-a08:oklch(95.0% 0.016 73.7 / 0.08);
    --cream-a05:oklch(95.0% 0.016 73.7 / 0.05);
}

/* Terracotta at a stated opacity.
   Twenty-two different alphas of the accent across 149 declarations, with
   0.12 and 0.13 and 0.15 and 0.18 all in use and none of them distinguishable
   from its neighbours. Nine steps, each anchored on the value the most
   declarations already used. Written after the substitution pass, not before:
   defining them first is how the cream tokens ended up assigned to themselves
   and took seven pages down to unreadable. */
:root{
    --terra-a05:oklch(61.3% 0.128 36.7 / 0.05);
    --terra-a10:oklch(61.3% 0.128 36.7 / 0.10);
    --terra-a12:oklch(61.3% 0.128 36.7 / 0.12);
    --terra-a15:oklch(61.3% 0.128 36.7 / 0.15);
    --terra-a20:oklch(61.3% 0.128 36.7 / 0.20);
    --terra-a25:oklch(61.3% 0.128 36.7 / 0.25);
    --terra-a30:oklch(61.3% 0.128 36.7 / 0.30);
    --terra-a45:oklch(61.3% 0.128 36.7 / 0.45);
    --terra-a80:oklch(61.3% 0.128 36.7 / 0.80);
}

/* Entitlement is a network round trip, so for the first fraction of a second
   the page does not know who it is talking to. It used to guess "not premium"
   and paint the gates, which meant a paying subscriber watched a paywall
   appear and disappear on every single page load — measured at 230-260ms.
   visibility rather than display: the space stays reserved, so nothing below
   jumps when the answer lands. Keyed on an attribute that only JavaScript
   sets, so with JavaScript off it is never applied and the gates just show. */
html[data-ent="pending"] .lock-overlay[data-auto],
html[data-ent="pending"] .free-limit-bar[data-auto]{visibility:hidden;}
