/* ==========================================================================
   SINEMILL — site chrome ("berlin"): corner nav, loader, entrance, toast

   Replaces header.css. The prototype's dev switches (SOUND / CALM) are not
   ported — they were instrumentation, and the handoff says so explicitly.
   ========================================================================== */

/* ==========================================================================
   1. THE NAV
   --------------------------------------------------------------------------
   Two corners. No bar, no rule, no background, no reserved column. The mark
   sits top-left and the words stack top-right, floating directly on the page
   so content bleeds underneath them.

   The whole thing is `mix-blend-mode: difference`. That is not a stylistic
   choice — with no plate behind it the nav has to stay legible over black
   ground, over an accent band and over a plugin screenshot, and difference
   is the only thing that guarantees contrast against all three. It also
   means the nav inverts as images pass under it, which is the one moment the
   chrome acknowledges the page at all.

   CAUTION: any ancestor with a z-index or a transform becomes a stacking
   context, and this then composites against THAT instead of the page — at
   which point it silently stops inverting. See base.css on #page-container.
   ========================================================================== */

/* THE NAV'S REAL OCCUPIED HEIGHT, for anything that must clear it.

   --nav-h in tokens.css is EDITORIAL clearance and is deliberately SMALLER
   than this between roughly 1000 and 1300px — editorial content is allowed to
   bleed under the two corners, which is the whole point of a nav with no bar.
   Interactive chrome is not allowed to: the plugin-docs route put a PDF
   viewer's own toolbar (page number, zoom, download, print) directly under the
   link stack, so two sets of controls occupied the same pixels and the nav's
   difference blend inverted over them.

   The link stack is three lines of mono. It is FLAT across the viewport,
   because that type deliberately does not scale with the viewport (see
   .nav__link), and it is always taller than .nav__mark, which tops out at
   40px. So the only variable is the nav's own padding.

   4.875rem, NOT 78px, AND THAT IS NOT A TIDY-UP. The two are identical at a
   16px root — this changes nothing about how the site renders today — but the
   nav's type is set in `--t-micro`, which is 0.6875rem, so it DOES scale when
   a reader raises their browser's text size even though it ignores the
   viewport. Hard-coded at 78px this token silently under-reported the nav by
   half its height at 200% text zoom, and every page that trusted it ran its
   title straight through SUPPORT / ACCOUNT / CART. Measured at a 32px root:
   the stack is 156px, which is exactly 4.875rem.

   The gutter stays in px: it is spatial, not typographic, and should not grow
   because someone made the text bigger.

   If a fourth link is ever added to .nav__links, this is the number that has
   to move — 1.625rem per line. */
:root {
    --nav-occupied: calc(var(--gutter) + 4.875rem);

    /* WHAT ANY PAGE SHOULD CLEAR, at any width and any zoom.

       --nav-h is editorial clearance and --nav-occupied is the nav's real
       height, and WHICH ONE IS LARGER CHANGES WITH THE VIEWPORT: --nav-h wins
       above roughly 1300px, --nav-occupied wins below it. Every route that
       picked one picked wrong at some width — the commerce routes collided at
       1000-1300 until they were moved to --nav-occupied, and the document
       routes collided only at 175% zoom and above, where a centred measure
       grows to nearly the full page and reaches the right corner.

       `max()` asks the question instead of answering it once. */
    --nav-clear: max(var(--nav-h), calc(var(--nav-occupied) + var(--s-4)));
}

.nav {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 60;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    padding: var(--gutter);
    /* The bar itself catches nothing — only the two corners do — so the page
       underneath stays clickable across the whole top edge. */
    pointer-events: none;
    mix-blend-mode: difference;
}
.nav > * { pointer-events: auto; }

/* ON A TASK ROUTE THE NAV SCROLLS AWAY.

   The nav has no bar and no background — it is two marks that blend into
   whatever is under them — and a document is allowed to run beneath it. That
   is the look, and it works on the homepage and on a product page.

   It does not work on a form. `mix-blend-mode: difference` over a display-size
   white heading renders the mark BLACK, so scrolling a checkout put what looks
   like a hole punched through "billing details", and the same over the total's
   paper band. Not a collision that reads as a design; one that reads as a
   printing fault, on the two pages where a customer must not misread anything.

   This is the rule stated at the top of this file — editorial content may
   bleed under the corners, interactive chrome may not — applied to the routes
   that are a task rather than a document. `absolute` rather than `static`:
   the nav is a direct child of a static `body`, so it resolves against the
   page, stays exactly where it is at rest, takes up no space in the flow, and
   simply leaves with the scroll. Nothing about the resting layout moves. */
body.woocommerce-cart .nav,
body.woocommerce-checkout .nav,
body.woocommerce-order-received .nav,
body.woocommerce-account .nav {
    position: absolute;
}

.nav__mark {
    display: block;
    width: clamp(26px, 2.6vw, 40px);
    color: var(--paper);
}
.nav__mark svg { width: 100%; height: auto; fill: currentColor; }

.nav__links {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.15em;
    text-align: right;
}

.nav__link {
    font-family: var(--f-mono);
    /* 12px, not 11. These are the only interactive words on the page and they
       sit over arbitrary content in difference blend — the one place the type
       cannot afford to be at the small end of the scale. */
    font-size: var(--t-label);
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--paper);
    padding: 0.35em 0;
    transition: opacity var(--d-snap) var(--e-hard);
}
.nav__link:hover { opacity: 0.45; }
.nav__link[aria-current="page"] { opacity: 0.45; }

/* The count is the only nav element that ever carries a fill: it is the only
   one whose value changes. Hidden entirely at zero rather than showing a 0 —
   an empty cart does not need a badge. */
.nav__link b {
    font-weight: 400;
    background: var(--paper);
    color: var(--ink);
    padding: 0 0.3em;
    margin-left: 0.4em;
}

@media (max-width: 640px) {
    .nav__links { gap: 0; }
    /* Deliberately NOT smaller here. Shrinking the only tap targets on the
       page to 10px on the smallest screens is backwards. */
    .nav__link { font-size: var(--t-micro); padding: 0.45em 0; }
}

/* ==========================================================================
   2. THE LOADER
   --------------------------------------------------------------------------
   The mark is a hole punched in a black veil; plugin UIs strobe through the
   hole, the strobe accelerates to near-flicker, and then it CUTS.

   NOTHING SCALES AND NOTHING FADES. An earlier version zoomed the hole until
   it swallowed the screen, and a scaling vector shape reads as a transition
   effect rather than as a cut. The exit uses the same grammar as every frame
   before it, and the page assembles on the other side — see § 3.

   Homepage only, once per session, skippable by any input. It never runs on
   a route someone reached from a link — see loader.js.
   ========================================================================== */

.loader {
    position: fixed;
    inset: 0;
    z-index: 900;
    background: var(--ink);
    overflow: hidden;
    cursor: pointer;
}
.loader[hidden] { display: none; }

.loader__strobe { position: absolute; inset: 0; background: var(--ink); }
.loader__strobe img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    /* Every frame is a cut. There is deliberately no transition here. */
}
.loader__strobe img.is-on { opacity: 1; }

/* A hard accent wash on some frames — the strobe reads as a shutter rather
   than a slideshow. */
.loader__flash {
    position: absolute;
    inset: 0;
    background: var(--accent);
    mix-blend-mode: multiply;
    opacity: 0;
}
.loader__flash.is-on { opacity: 1; }

.loader__veil { position: absolute; inset: 0; width: 100%; height: 100%; }

.loader__hud {
    position: absolute;
    left: var(--gutter);
    bottom: var(--gutter);
    right: var(--gutter);
    z-index: 3;
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: var(--s-6);
    font-family: var(--f-pixel);
    font-size: var(--t-nano);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--paper-dim);
    mix-blend-mode: difference;
    pointer-events: none;
}
.loader__count { font-size: var(--t-label); color: var(--paper); }
.loader__file  { color: var(--paper-faint); }
.loader__skip  { color: var(--paper-dim); }

/* ==========================================================================
   3. THE ENTRANCE
   --------------------------------------------------------------------------
   After the cut the page assembles: each block arrives from whichever
   viewport edge it is nearest, at speed, and stops dead. The start offsets
   are derived by entrance.js from real geometry; the only thing CSS owns is
   making sure nothing is visible before it has been placed.

   Note what is NOT here: no `opacity: 0` start state and no blanket
   transition kill under reduced motion. Both are how a JS-driven reveal ends
   up permanently invisible — this theme shipped that bug once already.
   entrance.js no-ops under reduced motion and everything is simply visible.
   ========================================================================== */

html.is-entering [data-enter] { visibility: hidden; }
[data-enter].is-placed { visibility: visible; }

/* ==========================================================================
   4. TOAST
   --------------------------------------------------------------------------
   Live region for things that happen without a page load: added to cart,
   copied, subscribed. The one element allowed above the grain, because it
   carries information rather than atmosphere.
   ========================================================================== */

.toast {
    position: fixed;
    left: 50%;
    bottom: var(--s-12);
    transform: translateX(-50%);
    z-index: 960;
    background: var(--paper);
    color: var(--ink);
    padding: var(--s-3) var(--s-6);
    font-family: var(--f-mono);
    font-size: var(--t-micro);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    max-width: min(90vw, 640px);
    text-align: center;
}
.toast[hidden] { display: none; }
.toast--bad { background: var(--alarm); color: var(--ink); }

/* The explore and buy bars occupy the bottom edge; lift the toast clear of
   whichever one is up so it is never half-covered. */
/* .buybar has no is-up state any more — it is always on screen — so the toast
   clears it whenever the bar EXISTS, not when it happens to be shown. */
body:has(.explore.is-up) .toast,
body:has(.buybar) .toast { bottom: calc(var(--s-12) + var(--s-16)); }

/* THE COOKIE NOTICE CLEARS THEM TOO, for the same reason and by the same test.

   It is a corner card drawn by sinemill-core, and that plugin has no business
   knowing how tall this theme's furniture is — so it reads a lift from a
   variable and this is the file that sets it. Without this the notice sat on
   the bottom edge at a far higher z-index than either bar, and a visitor who
   had not answered it yet could not see the price or reach the buy button.

   `.explore` is tested WITH `.is-up` because it is only in the way when it is
   actually up; `.buybar` is tested bare because it has no up state and is on
   screen whenever it exists — the same asymmetry the toast rule above relies
   on, for the same reason. */
body:has(.explore.is-up),
body:has(.buybar) { --sinemill-consent-lift: calc(var(--s-12) + var(--s-16)); }


