/* =========================================================================
   LIQUID GLASS — material dressing
   =========================================================================
   js/liquid-glass.js owns the optics (SVG refraction filter, backdrop blur,
   frosted fallback) and tags each surface with .lg / .lg-fallback / .lg-solid.
   This file owns the material: surface transparency, tint, specular, rim,
   drop shadow.

   The single most important thing here is SURFACE ALPHA. Refraction can only
   be seen through the glass, so an opaque surface reads as frosted no matter
   how the filter is tuned. The reference implementation sits at 18-32% alpha;
   dark-mode.css had several of these surfaces at 60-82%, which is why they
   looked frosted. Buttons and bars go transparent; frames that carry body
   text stay a little denser, because legibility beats optics there.

   Composition rules:

     - The tint rides on background-IMAGE over an explicit background-COLOR,
       so both are controlled here rather than inherited from a shorthand.
     - The specular highlight and 1px glass rim are inset box-shadows on the
       element itself. Both nav pseudo-elements are already spoken for:
       ::before carries the tint (set !important in dark mode) and ::after is
       the notch bar.
     - Selectors double .lg to reach specificity (0,3,0). css/dark-mode.css
       styles these same surfaces at `html[data-theme="dark"] .x` = (0,2,1),
       which would otherwise win — and its `background` shorthands would reset
       our background-image. (0,3,0) clears those while still losing to the
       :hover / .active state rules at (0,3,1), so interaction states keep
       their existing design.

   Loaded after css/dark-mode.css.
   ========================================================================= */

:root {
    /* Light theme: bright specular, cool near-white tint. */
    --lg-tint-top: rgba(255, 255, 255, 0.14);
    --lg-tint-bottom: rgba(255, 255, 255, 0.03);
    --lg-specular: rgba(255, 255, 255, 0.72);
    --lg-underglow: rgba(255, 255, 255, 0.07);
    --lg-rim: rgba(255, 255, 255, 0.30);

    /* Surface alpha per role — the clarity dial. Keep these low: every point
       of alpha is a point of frost. Frames are denser only because they carry
       body text over the backdrop. */
    /* The nav pill carries NO backdrop blur, so its readability comes entirely
       from this tint — an overlay sitting on top of a sharp refracted image,
       the way the Apple Music player reads. Raise this, never the blur. */
    --lg-surface-nav: rgba(255, 255, 255, 0.17);
    --lg-surface-button: rgba(255, 255, 255, 0.10);
    --lg-surface-frame: rgba(255, 255, 255, 0.34);

    --lg-shadow-nav: 0 2px 10px rgba(0, 0, 0, 0.05);
    --lg-shadow-button: 0 8px 22px rgba(0, 0, 0, 0.12);
    --lg-shadow-frame: 0 20px 56px rgba(0, 0, 0, 0.14);

    /* In-page controls (the "control" preset). These sit on a flat page, so the
       glass has to be carried by the material. Note the rim is faintly DARK:
       a white inner rim is invisible against a white page, which is what made
       the pills lose their edge and read as indented instead of lifted. */
    --lg-ctl-surface: rgba(255, 255, 255, 0.58);
    --lg-ctl-highlight: rgba(255, 255, 255, 0.95);
    /* The edge is a GRADIENT, bright at the top and shaded at the bottom, so it
       reads as one curved glass rim. A flat ring plus a separate inset
       highlight drew two concentric lines — the "weird double outline". */
    --lg-ctl-edge-top: rgba(255, 255, 255, 0.98);
    --lg-ctl-edge-bottom: rgba(0, 0, 0, 0.10);
    --lg-ctl-gloss-top: rgba(255, 255, 255, 0.55);
    --lg-ctl-gloss-bottom: rgba(255, 255, 255, 0.04);
    /* Panels are tall, so their gloss must be near-flat or the top reads
       frosted while the bottom reads clear. */
    --lg-panel-gloss-top: rgba(255, 255, 255, 0.13);
    --lg-panel-gloss-bottom: rgba(255, 255, 255, 0.02);
    --lg-exif-surface: rgba(255, 255, 255, 0.48);
    --lg-menu-surface: rgba(255, 255, 255, 0.42);
    --lg-ctl-shadow: 0 6px 16px rgba(0, 0, 0, 0.10), 0 1px 3px rgba(0, 0, 0, 0.06);
    --lg-ctl-shadow-hover: 0 10px 24px rgba(0, 0, 0, 0.13), 0 2px 5px rgba(0, 0, 0, 0.07);
}

html[data-theme="dark"] {
    /* Dark theme: the specular has to drop hard or it reads as a drawn white
       line rather than a lit edge. */
    --lg-tint-top: rgba(255, 255, 255, 0.07);
    --lg-tint-bottom: rgba(255, 255, 255, 0.015);
    --lg-specular: rgba(255, 255, 255, 0.22);
    --lg-underglow: rgba(255, 255, 255, 0.03);
    --lg-rim: rgba(255, 255, 255, 0.14);

    --lg-surface-nav: rgba(28, 28, 30, 0.30);
    --lg-surface-button: rgba(28, 28, 30, 0.16);
    --lg-surface-frame: rgba(28, 28, 30, 0.40);

    --lg-shadow-nav: 0 2px 12px rgba(0, 0, 0, 0.40);
    --lg-shadow-button: 0 8px 24px rgba(0, 0, 0, 0.45);
    --lg-shadow-frame: 0 24px 60px rgba(0, 0, 0, 0.55);

    --lg-ctl-surface: rgba(72, 72, 74, 0.52);
    --lg-ctl-highlight: rgba(255, 255, 255, 0.16);
    --lg-ctl-edge-top: rgba(255, 255, 255, 0.30);
    --lg-ctl-edge-bottom: rgba(255, 255, 255, 0.05);
    --lg-ctl-gloss-top: rgba(255, 255, 255, 0.10);
    --lg-ctl-gloss-bottom: rgba(255, 255, 255, 0.02);
    --lg-panel-gloss-top: rgba(255, 255, 255, 0.06);
    --lg-panel-gloss-bottom: rgba(255, 255, 255, 0.015);
    --lg-exif-surface: rgba(28, 28, 30, 0.54);
    --lg-menu-surface: rgba(28, 28, 30, 0.48);
    --lg-ctl-shadow: 0 6px 18px rgba(0, 0, 0, 0.45), 0 1px 3px rgba(0, 0, 0, 0.30);
    --lg-ctl-shadow-hover: 0 12px 26px rgba(0, 0, 0, 0.52), 0 2px 5px rgba(0, 0, 0, 0.35);
}

/* SAFARI / FIREFOX / ALL iOS BROWSERS LAND HERE.
   WebKit and Gecko can't run an SVG filter through backdrop-filter, so these
   engines get no refraction — that part is a hard engine limit, not a setting.
   What they must NOT get is heavy frost as a consolation prize: an earlier
   version pushed this path to 55-68% alpha with a 12-16px blur to "compensate",
   which is precisely the milky look we're trying to kill, and it's what ships
   to every iPhone and every Safari visitor.
   So: stay clear. Carry the surface with an edge-only rim and the lit top edge,
   keep alpha within a few points of the Chromium values, and use just enough
   blur to keep text off busy photos. Frames get more because they hold body
   text; scrims keep their deep blur because hiding content is their job.
   Custom-property declarations don't collide with `background` shorthands, so
   these need no specificity bump. */
.lg-fallback {
    --lg-surface-nav: rgba(255, 255, 255, 0.12);
    --lg-surface-button: rgba(255, 255, 255, 0.18);
    --lg-surface-frame: rgba(255, 255, 255, 0.42);
    /* Edge-only, so a firmer rim buys definition without hazing the face. */
    --lg-rim: rgba(255, 255, 255, 0.40);
}

html[data-theme="dark"] .lg-fallback {
    --lg-surface-nav: rgba(28, 28, 30, 0.26);
    --lg-surface-button: rgba(28, 28, 30, 0.24);
    --lg-surface-frame: rgba(28, 28, 30, 0.48);
    --lg-rim: rgba(255, 255, 255, 0.20);
}

/* -------------------------------------------------------------------- nav */

/* A FLOATING PILL, after the Apple Music player.

   Pulling the bar off the top edge and rounding it fully is what puts the
   refracted rim on all four sides — as a full-bleed strip its left and right
   edges are simply off-screen, so only the top and bottom bands could ever be
   seen. Centred with margin-inline rather than translateX because .main-nav
   runs a fadeDown animation that owns `transform`; using it here would make the
   pill jump sideways for the duration of the entrance. */
.main-nav.lg.lg {
    top: 10px;
    left: 12px;
    right: 12px;
    margin-inline: auto;
    max-width: 1160px;
    border-radius: 999px;
    /* A pill has no bottom edge to underline. */
    border-bottom: 0;
    background-color: transparent;
    background-image: none;
    /* Lift it off the page, then a full inset ring — on a pill the rim reads
       as the glass edge all the way round, where on a full-width strip it
       looked like a text field. No underglow: `inset 0 -10px 24px` washes 24px
       into a 52px bar, which is most of its height, and that is haze. */
    box-shadow:
        0 8px 24px rgba(0, 0, 0, 0.12),
        0 1px 3px rgba(0, 0, 0, 0.06),
        inset 0 1px 0 var(--lg-specular),
        inset 0 0 0 1px var(--lg-rim);
}

html[data-theme="dark"] .main-nav.lg.lg {
    box-shadow:
        0 8px 26px rgba(0, 0, 0, 0.5),
        0 1px 3px rgba(0, 0, 0, 0.35),
        inset 0 1px 0 var(--lg-specular),
        inset 0 0 0 1px var(--lg-rim);
}

/* The nav's tint lives on ::before (dark mode sets it !important), so the
   surface alpha has to be applied there rather than on the element. It also has
   to follow the pill's corners, and lose the -20px top overhang that existed to
   hide the old filter's distorted edge. */
.main-nav.lg::before {
    top: 0;
    border-radius: inherit;
    background: var(--lg-surface-nav);
    /* The old distortion layer displaced a flat 5% white fill: a no-op on the
       backdrop that still cost a GPU pass and warped the tint rect's own
       edges — the artifact `overflow: hidden` was there to mask. Refraction
       now comes from backdrop-filter on the element itself. */
    filter: none;
}

html[data-theme="dark"] .main-nav.lg::before {
    background: var(--lg-surface-nav) !important;
}

/* Mobile-only black bar that covered the notch behind a full-bleed nav. A
   floating pill doesn't touch the status bar, and `overflow: hidden` was
   clipping it out of existence anyway. */
.main-nav.lg::after {
    display: none;
}

@media (max-width: 700px) {
    .main-nav.lg.lg {
        top: 8px;
        left: 8px;
        right: 8px;
    }
}

/* No halo on the pill's text. A light glow behind the wordmark read as a smear
   rather than as contrast, and the site's own dark shadow on .nav-text-light
   fought it. Contrast comes from the tint layer plus the adaptive colour that
   app.js toggles — nothing painted around the glyphs. */
.main-nav.lg .nav-brand,
.main-nav.lg .nav-menu a,
.main-nav.lg .theme-toggle,
.main-nav.lg .mobile-menu-btn,
.main-nav.lg .nav-brand.nav-text-light,
.main-nav.lg .nav-menu a.nav-text-light {
    text-shadow: none;
}

.main-nav.lg .nav-icon svg,
.main-nav.lg .theme-toggle svg,
.main-nav.lg .mobile-menu-btn svg,
.main-nav.lg .nav-brand svg {
    filter: none;
}

/* ------------------------------------------------- adaptive nav colour --- */

/* The label colour must follow the BACKDROP, not the theme.
   `html[data-theme="dark"] .nav-menu a` in dark-mode.css is (0,2,0) and loads
   after the inline `.nav-menu a.nav-text-light` (also (0,2,0)), so in dark mode
   the adaptive class was silently overruled and never did anything. Worse,
   there was no dark-text state at all, so a bright photograph passing under the
   bar in dark mode left near-white labels on it.

   These reach (0,3,0) / (0,4,0) so both states win in either theme. app.js sets
   exactly one of them whenever imagery is behind the bar, and neither when it
   isn't — in which case the theme's own colour applies, which is correct. */
.main-nav.lg .nav-brand.nav-text-light,
.main-nav.lg .nav-menu a.nav-text-light,
.main-nav.lg .theme-toggle.nav-text-light,
.main-nav.lg .mobile-menu-btn.nav-text-light {
    color: #fff;
}

.main-nav.lg .nav-brand.nav-text-dark,
.main-nav.lg .nav-menu a.nav-text-dark,
.main-nav.lg .theme-toggle.nav-text-dark,
.main-nav.lg .mobile-menu-btn.nav-text-dark {
    color: #1D1D1F;
}

/* Icons are fill/stroke="currentColor", so colour alone drives them — but the
   Instagram glyph sets an explicit fill in places, so pin it to currentColor. */
.main-nav.lg .nav-text-light svg,
.main-nav.lg .nav-text-dark svg {
    fill: currentColor;
}

/* ------------------------------------------------------- slideshow nav */

/* Solid black, no glass — the slideshow is meant to be immersive, and a
   translucent bar over full-bleed imagery fights the photograph. The module
   excludes this element from glass entirely (see EXCLUDE in liquid-glass.js),
   so there is no .lg class to hang these off; .main-nav.slideshow-nav reaches
   (0,2,0) to beat the base .main-nav rules regardless of source order. */
.main-nav.slideshow-nav,
.slideshow-nav {
    background: #000;
    background-image: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    box-shadow: none;
}

.main-nav.slideshow-nav::before,
.slideshow-nav::before {
    background: #000 !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    filter: none;
}

html[data-theme="dark"] .slideshow-nav,
html[data-theme="dark"] .slideshow-nav::before {
    background: #000 !important;
}

/* Everything in the bar is white. The bar used to be translucent over the
   photograph, so app.js sampled slide brightness and toggled .nav-dark-mode /
   .nav-text-light to keep the label readable — over a permanently black bar
   that logic can only make icons darker than they should be. The theme toggle
   and hamburger are <button>s, so the old `.slideshow-nav .nav-menu a` rule
   never reached them, which is why they read dimmer than the wordmark.
   Icons are fill/stroke="currentColor", so colour alone drives them. */
.slideshow-nav.slideshow-nav .nav-brand,
.slideshow-nav.slideshow-nav .nav-menu a,
.slideshow-nav.slideshow-nav .nav-icon,
.slideshow-nav.slideshow-nav .theme-toggle,
.slideshow-nav.slideshow-nav .mobile-menu-btn,
.slideshow-nav.slideshow-nav .mobile-instagram,
.slideshow-nav.slideshow-nav .mobile-theme-toggle,
.slideshow-nav.slideshow-nav.nav-dark-mode .nav-brand,
.slideshow-nav.slideshow-nav.nav-dark-mode .nav-menu a,
.slideshow-nav.slideshow-nav.nav-dark-mode .theme-toggle,
.slideshow-nav.slideshow-nav.nav-dark-mode .mobile-menu-btn {
    color: #fff !important;
    text-shadow: none;
    opacity: 1;
}

/* The wordmark logo is stroked at width 11, so stroke has to follow colour
   too; the icon glyphs inherit a dark stroke from the base nav rules that
   would show on any stroked path. */
.slideshow-nav.slideshow-nav .nav-icon svg,
.slideshow-nav.slideshow-nav .mobile-menu-btn svg,
.slideshow-nav.slideshow-nav .mobile-instagram svg,
.slideshow-nav.slideshow-nav .nav-brand svg {
    fill: currentColor;
    stroke: currentColor;
    opacity: 1;
}

/* The moon/sun glyphs are stroked, not filled. */
.slideshow-nav.slideshow-nav .theme-toggle svg {
    fill: none;
    stroke: currentColor;
}

/* ---------------------------------------------------------------- buttons */

.back-to-top.lg.lg,
.slideshow-control-btn.lg.lg,
.lightbox-nav.lg.lg,
.lightbox-print-availability.lg.lg,
.lightbox .close.lg.lg,
.btn--play.lg.lg,
.map-filter-pill.lg.lg,
.map-fullscreen-btn.lg.lg,
.map-pin-card-close.lg.lg,
.map-tray-close.lg.lg,
.map-tray-nav-btn.lg.lg,
.map-tray-country-pill.lg.lg,
.map-film-region-chip.lg.lg,
.map-tray-exif-chip.lg.lg,
#jmap-lightbox .jlb-close.lg.lg,
#jmap-lightbox .jlb-nav.lg.lg,
.leaflet-control-zoom a.lg.lg {
    background-color: var(--lg-surface-button);
    /* No tint gradient and no underglow: on a ~50px control both cover most of
       the face and turn the lens milky. The lit top edge plus the 1px rim are
       enough to read the bead as glass. */
    background-image: none;
    box-shadow:
        var(--lg-shadow-button),
        inset 0 1px 1px var(--lg-specular),
        inset 0 0 0 1px var(--lg-rim);
}

/* Press state: the bead flattens and the specular dims, like glass pushed
   against its backing. */
.back-to-top.lg.lg:active,
.slideshow-control-btn.lg.lg:active,
.lightbox-nav.lg.lg:active,
.map-filter-pill.lg.lg:active,
.map-fullscreen-btn.lg.lg:active {
    box-shadow:
        0 3px 10px rgba(0, 0, 0, 0.12),
        inset 0 1px 1px rgba(255, 255, 255, 0.30),
        inset 0 0 0 1px var(--lg-rim);
}

/* --------------------------------------------------------------- controls */

/* In-page pills and buttons, styled to read like an iOS control: bright top
   edge, faint dark rim for definition, real drop shadow so it lifts off the
   page, and a light frost. Refraction still runs underneath and shows itself
   whenever one of these passes over imagery — but on a white page the material
   is doing all the work, which is why these look the same in Safari.

   :not(.active) keeps selected states (.filter-btn.active, .journal-tab-btn.active)
   entirely on their original design — those are solid on purpose. */
.cta-btn--secondary.lg.lg:not(.active),
.contact-direct-btn.lg.lg:not(.active),
.service-pill.lg.lg:not(.active),
.filter-btn.lg.lg:not(.active),
.journal-tab-btn.lg.lg:not(.active),
.lightbox-info-btn.lg.lg:not(.active),
.lightbox .close.lg.lg:not(.active),
.prints-modal-close.lg.lg:not(.active) {
    /* The edge is painted by the border box layer and the face by the padding
       box layers, which is the gradient-border technique. It gives ONE edge that
       runs bright at the top into shade at the bottom — a curved glass rim.
       Previously a flat inset ring sat 1px inside a transparent border while a
       separate inset highlight drew the top, so the two lines read as a double
       outline. No inset ring here at all. */
    background:
        linear-gradient(180deg, var(--lg-ctl-gloss-top), var(--lg-ctl-gloss-bottom)) padding-box,
        linear-gradient(var(--lg-ctl-surface), var(--lg-ctl-surface)) padding-box,
        linear-gradient(180deg, var(--lg-ctl-edge-top), var(--lg-ctl-edge-bottom)) border-box;
    /* .cta-btn--secondary carries a hard 1.5px dark border; make it transparent
       so the border-box gradient above becomes the edge. */
    border-color: transparent;
    box-shadow: var(--lg-ctl-shadow);
}

/* Hover has to be restated here: the originals set a solid dark background and
   white text, which over a glass surface would leave white-on-near-white. */
.cta-btn--secondary.lg.lg:hover:not(.active),
.contact-direct-btn.lg.lg:hover:not(.active),
.service-pill.lg.lg:hover:not(.active),
.filter-btn.lg.lg:hover:not(.active),
.journal-tab-btn.lg.lg:hover:not(.active),
.lightbox-info-btn.lg.lg:hover:not(.active),
.lightbox .close.lg.lg:hover:not(.active),
.prints-modal-close.lg.lg:hover:not(.active) {
    background:
        linear-gradient(180deg, var(--lg-ctl-highlight), var(--lg-ctl-gloss-top)) padding-box,
        linear-gradient(var(--lg-ctl-surface), var(--lg-ctl-surface)) padding-box,
        linear-gradient(180deg, var(--lg-ctl-edge-top), var(--lg-ctl-edge-bottom)) border-box;
    color: var(--text-primary);
    box-shadow: var(--lg-ctl-shadow-hover);
    transform: translateY(-1px);
}

.cta-btn--secondary.lg.lg:active:not(.active),
.service-pill.lg.lg:active:not(.active),
.filter-btn.lg.lg:active:not(.active),
.journal-tab-btn.lg.lg:active:not(.active) {
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
    transform: translateY(0);
}

/* ----------------------------------------------------------------- frames */

.exif-overlay.lg.lg,
.highlight-card.lg.lg,
.location-cta.lg.lg,
.prints-modal.lg.lg,
.map-legend.lg.lg,
.map-stats-bar.lg.lg,
.map-tray.lg.lg,
.map-pin-card.lg.lg,
.map-cluster-bubble.lg.lg,
.sticky-cta-bar.lg.lg,
.about-hero-container.lg.lg,
.social-tag.lg.lg,
#jmap-lightbox .jlb-caption.lg.lg {
    background-color: var(--lg-surface-frame);
    background-image: linear-gradient(180deg, var(--lg-tint-top), var(--lg-tint-bottom));
    box-shadow:
        var(--lg-shadow-frame),
        inset 0 1px 1px var(--lg-specular),
        inset 0 -8px 20px var(--lg-underglow),
        inset 0 0 0 1px var(--lg-rim);
}

/* The EXIF panel is a data table, so it gets glass but noticeably denser than
   the other frames — camera/lens/shutter values have to stay crisply readable
   over whatever photograph is behind them. Its 1px hard border is handed to the
   same gradient edge the controls use, so it reads as glass rather than a
   bordered card. */
.lightbox-exif-panel.lg.lg {
    background:
        linear-gradient(180deg, var(--lg-panel-gloss-top), var(--lg-panel-gloss-bottom)) padding-box,
        linear-gradient(var(--lg-exif-surface), var(--lg-exif-surface)) padding-box,
        linear-gradient(180deg, var(--lg-ctl-edge-top), var(--lg-ctl-edge-bottom)) border-box;
    border-color: transparent;
    box-shadow: var(--lg-shadow-frame);
}

/* ----------------------------------------------------- mobile menu panel */

/* An iOS-style floating menu rather than a full-page sheet. The overlay used to
   be a 100vw x 100vh surface at 98% opacity, which hid the site entirely; it is
   now just an invisible tap-catcher, and the <ul> inside it is the glass panel.
   Being a small panel is also what makes refraction worth having here — it is
   affordable, and the rim reads on all four sides.

   Scoped to the mobile breakpoint because .mobile-nav-overlay is display:none on
   desktop and display:flex inside the same query; changing display unscoped
   would reveal the menu on desktop. */
@media (max-width: 768px) {
    .mobile-nav-overlay.mobile-nav-overlay {
        display: block;
        background: transparent !important;
        backdrop-filter: none !important;
        -webkit-backdrop-filter: none !important;
        padding-top: 0;
        /* Load-bearing. dark-mode.css slides the overlay with
           `transform: translateX(100%) !important` from when it was a full-page
           sheet, and a transformed ancestor becomes the containing block for
           position:fixed descendants — which threw the panel a full viewport
           off-screen to the right. The panel does the animating now, so the
           tap-catcher must not be transformed at all. */
        transform: none !important;
    }

    /* Faint dim so the panel reads as modal and the tap target is obvious,
       without hiding the photography behind it. */
    .mobile-nav-overlay.mobile-nav-overlay::before {
        background: rgba(0, 0, 0, 0.12);
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
    }

    .mobile-nav-overlay.mobile-nav-overlay ul {
        position: fixed;
        top: 68px;
        right: 8px;
        width: min(258px, calc(100vw - 16px));
        max-height: min(70vh, 620px);
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        /* Vertical padding only. Horizontal padding would inset each row and
           make it read as a separate chip; vertical padding keeps the first and
           last rows off the panel's rounded ends — the Instagram row was
           sitting hard against the bottom edge. */
        padding: 6px 0 14px;
        gap: 0;
        text-align: left;
        border-radius: 22px;
        /* Springs out of the hamburger it was opened from. Animating the panel
           rather than the overlay sidesteps the !important transform rules
           dark-mode.css sets on .mobile-nav-overlay itself. */
        transform: scale(0.92);
        transform-origin: top right;
        opacity: 0;
        transition:
            transform 0.34s cubic-bezier(0.22, 1, 0.36, 1),
            opacity 0.2s ease;
    }

    .mobile-nav-overlay.mobile-nav-overlay.active ul {
        transform: scale(1);
        opacity: 1;
    }

    /* Same single gradient rim the controls use, over a surface denser than the
       generic frame — these are text rows and have to stay readable over
       whatever photograph is behind them. */
    .mobile-nav-overlay.mobile-nav-overlay ul.lg {
        border: 1px solid transparent;
        background:
            linear-gradient(180deg, var(--lg-panel-gloss-top), var(--lg-panel-gloss-bottom)) padding-box,
            linear-gradient(var(--lg-menu-surface), var(--lg-menu-surface)) padding-box,
            linear-gradient(180deg, var(--lg-ctl-edge-top), var(--lg-ctl-edge-bottom)) border-box;
        box-shadow:
            0 18px 44px rgba(0, 0, 0, 0.22),
            0 3px 10px rgba(0, 0, 0, 0.10);
    }

    html[data-theme="dark"] .mobile-nav-overlay.mobile-nav-overlay ul.lg {
        box-shadow:
            0 18px 48px rgba(0, 0, 0, 0.6),
            0 3px 10px rgba(0, 0, 0, 0.4);
    }

    .mobile-nav-overlay.mobile-nav-overlay li {
        display: block;
    }

    /* Plain rows, not buttons. A radius here (plus a rounded press state) made
       the menu read as a stack of chips; a system menu is flat full-width rows
       divided by hairlines, with the panel's own corners doing the rounding. */
    .mobile-nav-overlay.mobile-nav-overlay a {
        display: flex;
        align-items: center;
        gap: 10px;
        /* Down from 28px: menu rows, not a full-page list. */
        font-size: 17px;
        font-weight: 500;
        line-height: 1.2;
        padding: 14px 18px;
        border-radius: 0;
        text-align: left;
    }

    /* Press highlight spans the whole row edge to edge — no rounded chip. */
    .mobile-nav-overlay.mobile-nav-overlay a:active {
        background: rgba(0, 0, 0, 0.06);
        border-radius: 0;
    }

    html[data-theme="dark"] .mobile-nav-overlay.mobile-nav-overlay a:active {
        background: rgba(255, 255, 255, 0.10);
    }

    .mobile-nav-overlay.mobile-nav-overlay .nav-icon svg {
        width: 20px;
        height: 20px;
    }
}

/* -------------------------------------------------- lightbox chrome (mobile) */

@media (max-width: 768px) {
    /* The close button sat at right 32-68px and the info button at 68-108px,
       so they met at exactly 68 with no gap — and at 36px vs 40px their centres
       didn't line up either. Same size, same top, real gap between them. */
    .lightbox .close,
    .lightbox .lightbox-info-btn {
        top: 20px;
        width: 40px;
        height: 40px;
    }

    .lightbox .close {
        right: 20px;
    }

    .lightbox .lightbox-info-btn {
        right: 72px;
    }

    /* The EXIF panel is a bottom sheet on mobile (left/right 12px, bottom 12px,
       up to 50vh) while the print pill sits at bottom: 90px — squarely inside
       it. The panel's height varies with content, so there is no fixed offset
       that reliably clears it; yielding the pill while the panel is open is the
       honest fix, and it returns the moment the panel closes. */
    /* Lift it clear of the sheet rather than hiding it. The first attempt faded
       it to opacity 0, which read as the print link being REMOVED on iOS — and
       it's a conversion affordance, so it must never disappear. The panel is
       capped at 50vh with a 12px bottom offset, so sitting above that cap
       clears it whatever the panel's content height turns out to be. */
    .lightbox:has(.lightbox-exif-panel.visible) .lightbox-print-availability {
        bottom: calc(50vh + 26px);
        transition: bottom 0.3s cubic-bezier(0.22, 1, 0.36, 1);
    }
}

/* ----------------------------------------------------------------- scrims */

/* Full-viewport scrims get frost only — no rim, no specular, no refraction
   (the module's "scrim" preset sets scale 0). A lit edge on a full-screen
   overlay just draws a box around the viewport, and a scrim's whole job is to
   suppress what's behind it. */
.mobile-nav-overlay.lg.lg,
.lightbox.lg.lg,
#jmap-lightbox.lg.lg {
    background-image: none;
    box-shadow: none;
}

/* ------------------------------------------------------------ a11y / fallback */

/* Reduced transparency or increased contrast: stop pretending to be glass.
   The module applies .lg-solid and skips the optics entirely. */
.lg-solid {
    background-image: none !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    background-color: #fff;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12);
}

html[data-theme="dark"] .lg-solid {
    background-color: #1c1c1e;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.5);
}

/* Windows high-contrast strips backdrop effects; keep the surfaces readable
   rather than transparent. */
@media (forced-colors: active) {
    .lg,
    .lg-fallback {
        background-image: none;
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
        box-shadow: none;
        border: 1px solid CanvasText;
    }
}
