/* ──────────────────────────────────────────────────────────────────────────
   SITE CHROME — shared across every detail page
   ──────────────────────────────────────────────────────────────────────────
   Loaded AFTER each page's inline <style>, so the rules here intentionally
   win over the per-page defaults they replace.

   Three things live here:
     1. The bottom dock — prev/next + footer, frozen to the viewport over a
        soft gradient instead of a hard bar, so scrolling content dissolves
        into it rather than colliding with an edge.
     2. Scroll reveal — sections fade/rise into place as they enter view.
     3. Lightbox + auto-scrolling gallery for photography blocks.

   site-chrome.js does the DOM work; nothing here requires markup changes.
   ────────────────────────────────────────────────────────────────────────── */

/* ── 0. CURSOR Z-INDEX FIX ────────────────────────────────────────────────
   Every page hides the real OS cursor site-wide (`* { cursor: none }`) and
   draws its own dot + ring instead, at z-index 10001. That's lower than the
   lightbox (15000, below) and lower than Tokyo's entry gate (also 15000) —
   so with the real cursor off and the fake one hidden behind either overlay,
   there is no visible cursor at all while they're open. Loaded after each
   page's inline <style>, so this wins on source order without needing
   !important. Placed above #page-fade (20000) too, since that also briefly
   covers the whole viewport on load. */
#cursor-dot, #cursor-ring { z-index: 20001; }

/* ── 1. FROZEN BOTTOM DOCK ────────────────────────────────────────────────
   .cs-next and .site-foot are moved into this wrapper by the JS. The
   gradient is tall and multi-stop on purpose: a two-stop fade still reads
   as a visible edge, because the eye catches the point where it starts.
   Easing it across four stops makes the transition itself invisible. */
.site-dock {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 3000;
    pointer-events: none;
    padding-top: 90px;
    /* --dock-rgb lets a page whose background isn't the usual #080808 (the
       Chair Phone page runs true black) tint the fade to match, so the
       gradient never reads as a lighter panel sitting on the page. */
    background: linear-gradient(
        to top,
        rgba(var(--dock-rgb, 8,8,8), 0.98) 0%,
        rgba(var(--dock-rgb, 8,8,8), 0.94) 32%,
        rgba(var(--dock-rgb, 8,8,8), 0.78) 55%,
        rgba(var(--dock-rgb, 8,8,8), 0.42) 76%,
        rgba(var(--dock-rgb, 8,8,8), 0.12) 90%,
        rgba(var(--dock-rgb, 8,8,8), 0)   100%
    );
}
/* The dock itself must not eat clicks — only its actual controls do. */
.site-dock > * { pointer-events: auto; }

/* Pulled in off the page corners and centered. At the far edges of a wide
   monitor these sat outside where anyone is actually reading and went
   unnoticed entirely. */
.site-dock .cs-next {
    border-top: none;
    max-width: 900px; margin: 0 auto;
    padding: 0 22px 12px;
    display: flex; justify-content: center; align-items: flex-start;
    gap: clamp(80px, 14vw, 220px);
}
.site-dock .cs-next a {
    font-size: 11.5px; font-weight: 700; letter-spacing: 0.14em;
    color: var(--text-primary);
    border-bottom: 1px solid rgba(237,235,230,0.28);
    padding-bottom: 4px;
    transition: color 0.2s ease, border-color 0.2s ease;
}
.site-dock .cs-next a:hover {
    color: var(--accent);
    border-bottom-color: var(--accent);
}
.site-dock .cs-next .nx-label {
    color: var(--text-muted); font-weight: 400; letter-spacing: 0.2em;
}
.site-dock .site-foot {
    border-top: none;
    padding: 0 40px 14px;
}

/* Content needs room to clear the dock at the end of the document. */
body.has-site-dock { padding-bottom: 132px; }

@media (max-width: 900px) {
    .site-dock { padding-top: 70px; }
    .site-dock .cs-next  { padding: 0 22px 8px; }
    .site-dock .site-foot { padding: 0 22px 12px; flex-direction: column; gap: 4px; }
    body.has-site-dock { padding-bottom: 150px; }
}

/* ── 2. SCROLL REVEAL ─────────────────────────────────────────────────────
   Short travel and a long ease. The point is to make the page feel like it
   has depth as it assembles, not to draw attention to the animation. */
.reveal {
    opacity: 0;
    transform: translateY(46px);
    transition: opacity 1.25s cubic-bezier(0.16, 1, 0.3, 1),
                transform 1.25s cubic-bezier(0.16, 1, 0.3, 1);
    will-change: opacity, transform;
}
.reveal.is-visible { opacity: 1; transform: none; }

/* Never let a reveal permanently hide content for someone who can't run the
   observer (no JS, reduced motion) — both paths land on fully visible. */
@media (prefers-reduced-motion: reduce) {
    .reveal { transition: none; opacity: 1; transform: none; }
}

/* ── 2b. STILLS BLOCK ─────────────────────────────────────────────────────
   The shared "these are Jeff's own photographs" pattern: eyebrow, context
   note, gallery, and a link out to the wider photography work. Defined here
   so any case-study page can use it without duplicating the CSS inline. */
.cs-stills { margin-bottom: 64px; }
.cs-gallery-note {
    font-size: 12.5px; line-height: 1.7; color: var(--text-secondary);
    max-width: 620px; margin: 0 0 24px;
}
.cs-more {
    display: inline-block; font-family: 'Space Mono', monospace; font-weight: 700;
    font-size: 9px; letter-spacing: 0.18em; text-transform: uppercase;
    color: var(--text-secondary); text-decoration: none;
    border: 1px solid var(--border-mid); padding: 12px 20px;
    margin-top: 30px;
    transition: color 0.22s ease, border-color 0.22s ease;
}
.cs-more:hover { color: var(--accent); border-color: var(--accent); }

/* Credits carry occasional inline qualifiers ("varies by campaign") that
   should read as an aside, not as part of the credit itself. */
.credit i { font-style: normal; color: var(--text-muted); }

/* ── 3. AUTO-SCROLLING GALLERY ────────────────────────────────────────────
   Opt in per page with class="cs-gallery cs-marquee". The track is cloned
   once by the JS and translated exactly -50%, so the seam lands on an
   identical frame and the loop is invisible. */
.cs-marquee {
    display: block; overflow: hidden;
    max-width: none; width: 100%;
    -webkit-mask-image: linear-gradient(to right, transparent 0, #000 5%, #000 95%, transparent 100%);
            mask-image: linear-gradient(to right, transparent 0, #000 5%, #000 95%, transparent 100%);
}
.cs-marquee .marquee-track {
    display: flex; gap: 18px; width: max-content;
    animation: cs-marquee-scroll 90s linear infinite;
}
.cs-marquee:hover .marquee-track,
.cs-marquee:focus-within .marquee-track { animation-play-state: paused; }
.cs-marquee img {
    flex: 0 0 auto;
    width: 300px; aspect-ratio: 4 / 3;
    height: auto; object-fit: cover; display: block;
    opacity: 0.86; transition: opacity 0.3s ease;
}
.cs-marquee img:hover { opacity: 1; }

@keyframes cs-marquee-scroll {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
    .cs-marquee .marquee-track { animation: none; }
    .cs-marquee { overflow-x: auto; }
}
@media (max-width: 900px) {
    .cs-marquee img { width: 210px; }
}

/* Dock-style proximity magnification lives on photography.html only, inline
   in that page — it's the index/slat rail, not a detail page, and it doesn't
   load this file. See that page's own <style>/<script> for the .dock-img
   rules and the pointermove handler. */

/* ── 4. LIGHTBOX ──────────────────────────────────────────────────────────
   Click any gallery image to bring it up; click anywhere that isn't the
   image (or press Escape) to dismiss. */
.cs-gallery img, .cs-marquee img { cursor: none; }

/* The photo lifts out of the page from exactly where it was sitting, rather
   than cross-fading in from nowhere. The JS measures the thumbnail, drops the
   full-size image on top of it at matching size, then releases it to its
   final position — so the movement has a start point you can follow.

   The easing is the whole point of the feel: a long duration with a curve that
   overshoots almost imperceptibly and settles, which reads as mass. The
   backdrop takes longer to darken than the image takes to travel, so the room
   dims around the photo instead of with it. */
#cs-lightbox {
    position: fixed; inset: 0; z-index: 15000;
    display: flex; align-items: center; justify-content: center;
    padding: 5vh 5vw;
    background: rgba(3,3,3,0);
    -webkit-backdrop-filter: blur(0px); backdrop-filter: blur(0px);
    opacity: 1; visibility: hidden;
    transition: background 0.66s cubic-bezier(0.22, 1, 0.28, 1),
                backdrop-filter 0.66s cubic-bezier(0.22, 1, 0.28, 1),
                -webkit-backdrop-filter 0.66s cubic-bezier(0.22, 1, 0.28, 1),
                visibility 0s linear 0.62s;
}
#cs-lightbox.is-open {
    visibility: visible;
    background: rgba(3,3,3,0.94);
    -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px);
    transition: background 0.66s cubic-bezier(0.22, 1, 0.28, 1),
                backdrop-filter 0.66s cubic-bezier(0.22, 1, 0.28, 1),
                -webkit-backdrop-filter 0.66s cubic-bezier(0.22, 1, 0.28, 1);
}
#cs-lightbox img {
    display: block; width: auto; height: auto;
    max-width: 100%; max-height: 88vh; max-height: 88svh;
    object-fit: contain;
    transform-origin: top left;
    /* Two shadows: a tight contact shadow that keeps the photo attached to
       something, and a long soft one that puts real height under it. */
    box-shadow: 0 6px 18px rgba(0,0,0,0.55), 0 60px 140px -20px rgba(0,0,0,0.9);
    will-change: transform;
}
/* Applied by the JS for the duration of the flight. */
#cs-lightbox img.lb-flying {
    transition: transform 0.72s cubic-bezier(0.19, 1.04, 0.22, 1);
}

#cs-lightbox .lb-hint {
    position: absolute; bottom: 26px; left: 0; right: 0;
    text-align: center;
    font-family: 'Space Mono', monospace; font-size: 8px;
    letter-spacing: 0.2em; text-transform: uppercase;
    color: #55524e;
    pointer-events: none;
    opacity: 0; transition: opacity 0.4s ease 0.5s;
}
#cs-lightbox.is-open .lb-hint { opacity: 1; }

/* Everything behind the lightbox eases back a fraction and loses a touch of
   contrast, so the photo reads as being lifted off the page rather than
   overlaid on it. */
body.lightbox-open .lb-recede {
    transform: scale(0.988);
    filter: saturate(0.9);
    transition: transform 0.7s cubic-bezier(0.22,1,0.28,1), filter 0.7s ease;
}
.lb-recede { transition: transform 0.7s cubic-bezier(0.22,1,0.28,1), filter 0.7s ease; }

@media (prefers-reduced-motion: reduce) {
    #cs-lightbox, #cs-lightbox.is-open,
    #cs-lightbox img, #cs-lightbox img.lb-flying,
    .lb-recede, body.lightbox-open .lb-recede { transition: none; }
    body.lightbox-open .lb-recede { transform: none; filter: none; }
}

/* The dock would otherwise float on top of the lightbox. */
body.lightbox-open .site-dock { opacity: 0; transition: opacity 0.25s ease; }

/* ── 6. TOUCH DEVICES ─────────────────────────────────────────────────────
   Loaded by all 33 detail pages, so this is the one place the phone/tablet
   pass needs to happen for them. The 900px collapse each page already
   carries handles width; what's left is everything keyed to a pointer.

   The fake record-dot cursor is the big one. Every page sets
   `* { cursor: none }` for it, and on touch that rule survives while the
   cursor itself never appears — harmless visually, but it also strips the
   pointer affordance from anything a hybrid device does hover. Put the real
   cursor back and hide the fake one. This file is linked after each page's
   inline <style>, so equal-specificity rules here win. */
@media (hover: none) {
    * { cursor: auto; }
    a, button, [role="button"], .cs-gallery img, .cs-marquee img { cursor: pointer; }
    #cursor-dot, #cursor-ring { display: none !important; }

    /* Content scrolls under the fixed menu button, which on desktop had the
       page's own dark chrome behind it. Give it a backdrop of its own. */
    #menu-toggle, .back-pill {
        top: 12px !important; left: 12px !important;
        padding: 11px 14px !important;
        background: rgba(8,8,8,0.82);
        backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
        border: 1px solid rgba(255,255,255,0.09);
    }

    /* Prev/next were sized for a mouse. 44px is the minimum comfortable tap
       target, and the desktop gap of up to 220px pushes them off a phone. */
    .site-dock .cs-next { gap: 28px; }
    .site-dock .cs-next a {
        display: inline-block; padding: 12px 0; font-size: 12px;
    }
}
