/* ============================================================================
   shared/chrome.css  ·  the sitewide navigation chrome: a.backlink, the pill
   in the top-left corner that goes back to the portfolio. Fixed, not
   fixed-until-you-scroll, so it persists over every section, dark panel or
   glass diagram included. No script dependency.

   Link it after shared/scroll.css, or near the end of <head> on a page with
   no scroll.css:
     <link rel="stylesheet" href="shared/chrome.css">

   SPECIFICITY CONTRACT
   --------------------
   The pill's identity, that it is fixed top-left, sized as a comfortable hit
   area, and set in the rail's own label typeface, is stated at normal
   specificity: several pages still carry an older in-flow .backlink rule
   (mono, inline, no background) in their own <style> block, and this file is
   linked after it precisely so it wins. Anything a page might reasonably want
   to reshape without a fight, the wash colour, the blur, the radius, the
   offsets, sits inside :where() or reads a token with a fallback, exactly as
   shared/scroll.css does for .vp-mark.
   ========================================================================== */

:root{
  --chrome-back-top: 18px;
  --chrome-back-left: 22px;
}

a.backlink{
  position: fixed;
  top: var(--chrome-back-top);
  left: var(--chrome-back-left);
  z-index: 90;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  text-decoration: none;
  cursor: pointer;
  /* same label voice as shared/scroll.css .vp-mark-label */
  font-family: var(--display, var(--font-display, ui-sans-serif, system-ui, sans-serif));
  font-weight: 500;
  font-size: 10.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink, #111517);
  transition: color 160ms ease, border-color 160ms ease, background-color 160ms ease, box-shadow 160ms ease;
}

/* the pill: reads over any section, light, dark or glass, because the wash
   pulls it toward --paper and the blur mutes whatever sits behind it. A page
   is free to restate any of these; none of it fights the page's own rule. */
:where(a.backlink){
  padding: 9px 15px 9px 13px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--line, #C3CCD1) 65%, transparent);
  background: color-mix(in srgb, var(--paper, #F9FAFA) 86%, transparent);
  -webkit-backdrop-filter: blur(11px) saturate(1.3);
  backdrop-filter: blur(11px) saturate(1.3);
  box-shadow: 0 1px 3px color-mix(in srgb, var(--ink, #111517) 10%, transparent);
}

/* browsers without backdrop-filter get a near-opaque wash instead of a
   half-transparent one, so contrast never depends on the effect landing. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))){
  :where(a.backlink){ background: color-mix(in srgb, var(--paper, #F9FAFA) 96%, transparent); }
}

a.backlink:hover,
a.backlink:focus-visible{
  color: var(--page-accent, var(--ink, #111517));
}
:where(a.backlink:hover),
:where(a.backlink:focus-visible){
  border-color: color-mix(in srgb, var(--page-accent, var(--ink, #111517)) 45%, var(--line, #C3CCD1));
  background: color-mix(in srgb, var(--paper, #F9FAFA) 96%, transparent);
}
a.backlink:focus-visible{
  outline: 2px solid var(--link, #4D687A);
  outline-offset: 2px;
}
a.backlink:active{ transform: translateY(1px); }

/* the arrow glyph stays each page's own: .backlink i / i::before are drawn
   per page against --line/--ink. Nothing here touches it. */

@media (max-width: 640px){
  :root{ --chrome-back-top: 12px; --chrome-back-left: 12px; }
}

/* Short viewports: several pages squeeze a tall mid-page section's own top
   padding down to ~10px so its content still fits one screen (see each
   page's own "SHORT VIEWPORTS" block). The pill shrinks here too, so the
   band it actually needs a page to keep clear is as small as this contract
   can make it: a smaller hit area, not a smaller z-index or a dodge, since
   there is no horizontal room to sidestep into in the same top-left corner a
   kicker also opens in. Pages still carry the last few pixels themselves, the
   same way a fixed navbar's height becomes a page's own padding-top. */
@media (max-height: 860px){
  :root{ --chrome-back-top: 12px; }
  a.backlink{ font-size: 9.5px; letter-spacing: .1em; gap: 6px; }
  :where(a.backlink){ padding: 6px 12px 6px 11px; }
}

@media (prefers-reduced-motion: reduce){
  a.backlink{ transition: none; }
  a.backlink:active{ transform: none; }
}

/* THE FICTION FLAG IS GONE (round 6). Oliver: "I would remove what says 'Real
   rules, fake data' from every page. That just looks bad."

   Removed here rather than page by page, so it is gone from every page the
   moment this file loads and cannot come back through a page that still has the
   markup. The disclosure itself is not lost: the pages that need it say it once
   as a plain sentence in their own exit row. Pages may drop the <p> whenever
   they are next touched; this rule costs them nothing until they do. */
p.fiction-flag{ display: none !important; }

/* ---------- unified page ambient: accent blobs (Pin 1) ----------
   Usage: <div class="ambient" aria-hidden="true"><i></i><i></i><i></i></div>
   Page sets --page-accent on :root or body. Business pages keep default blends;
   personal pages may raise --ambient-boost (e.g. 1.6). */
.ambient{position:fixed;inset:0;z-index:-2;pointer-events:none;overflow:hidden;--ambient-boost:1}
.ambient i{position:absolute;border-radius:50%;filter:blur(30px);will-change:transform}
.ambient i:nth-child(1){width:46vw;height:40vw;left:-8%;top:6%;
  background:radial-gradient(closest-side,color-mix(in srgb,var(--page-accent) calc(6% * var(--ambient-boost)),transparent),transparent 70%);
  animation:ambDriftA 44s ease-in-out infinite alternate}
.ambient i:nth-child(2){width:38vw;height:34vw;right:-6%;top:48%;
  background:radial-gradient(closest-side,color-mix(in srgb,var(--page-accent) calc(5% * var(--ambient-boost)),transparent),transparent 72%);
  animation:ambDriftB 52s ease-in-out infinite alternate}
.ambient i:nth-child(3){width:30vw;height:26vw;left:38%;bottom:-8%;
  background:radial-gradient(closest-side,color-mix(in srgb,var(--page-accent) calc(4% * var(--ambient-boost)),transparent),transparent 70%);
  animation:ambDriftA 60s ease-in-out infinite alternate}
@keyframes ambDriftA{to{transform:translate3d(2.2%,1.6%,0) scale(1.05)}}
@keyframes ambDriftB{to{transform:translate3d(-2%,2.2%,0) scale(1.03)}}
@media (prefers-reduced-motion: reduce){.ambient i{animation:none}}

/* ============================================================================
   THE EXIT ROW  ·  D10-a, per Oliver ("there doesn't need to be any text above
   the lines and use the app colors for the text"). The last thing on every
   page. One hairline, then one or two lines of links, and nothing else.

   MARKUP CONTRACT (page lanes paste this; shared owns the CSS):
     <footer class="exit" aria-label="Exit">
       <nav class="exit-stack">              <-- business pages only
         <a href="replenish.html" style="--acc:#1D5B47">Replenish</a>
         ...hub order, this page omitted...
       </nav>
       <p class="exit-row">
         <a href="mailto:hi@oliverschwartz.me">hi@oliverschwartz.me</a>
         <a href="https://github.com/o-liverschwartz">GitHub</a>
         <a href="index.html">Portfolio</a>
       </p>
     </footer>

   COLOUR IS THE SENTENCE. The deleted label ("Part of the same stack") is
   carried by colour instead: four different accents on the first line are four
   other products; one repeated accent on the second line is the page you are
   standing on. Every sibling colour is stated below, keyed by href, so a page
   lane pastes links and no colours; the exits read --page-accent-ink, the
   page's text-safe accent, and fall back to
   --page-accent for a page whose raw accent is already readable.

   The middots are drawn by CSS between siblings, so a page pastes bare <a>
   elements and a wrap can never strand a separator on its own line.
   ========================================================================== */

.exit{
  margin-top: clamp(22px, 3.4vh, 38px);
  padding-top: 14px;
  border-top: 1px solid var(--line, #C3CCD1);
  display: flex;
  flex-direction: column;
  gap: 7px;
}
:where(.exit){ font-family: var(--mono, var(--font-mono, ui-monospace, monospace)); }

.exit-stack,
.exit-row{
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 25px;
  row-gap: 4px;
  /* 12.5px is the site's quiet-mono floor; the exits never go under it. */
  font-family: var(--mono, var(--font-mono, ui-monospace, monospace));
  font-size: 12.5px;
  letter-spacing: .02em;
  line-height: 1.7;
}

/* SIBLING COLOURS LIVE HERE, NOT IN THE MARKUP. Each product's accent as TEXT
   is that page's own text-safe ink, never its raw accent: raw yellow #F2C230
   is 1.6:1 on paper and raw #4A86DB is 3.5:1, so neither is a text colour.
   Keyed by href so a page lane pastes the links and no colours at all.
   Measured against --paper #F9FAFA:
     replenish         #1D5B47  7.61:1
     metrics-registry  #2F5D8C  6.55:1
     build-assemble    #8A6A12  4.84:1   (that page's own --yellowText)
     composer          #C2410C  4.95:1
     ops-portal        #1E7A45  5.12:1
     drive-organizer   #8A6A12  4.84:1
     screenshot-triage #3568C4  5.11:1   (that page's own --t-accent-ink)
   Every one clears 4.5:1. These win over an inline --acc, so a page that still
   carries one from an earlier paste cannot put a raw accent back on paper. */
.exit a[href$="replenish.html"]        { --exit-ink: #1D5B47 }
.exit a[href$="metrics-registry.html"] { --exit-ink: #2F5D8C }
.exit a[href$="build-assemble.html"]   { --exit-ink: #8A6A12 }
.exit a[href$="composer.html"]         { --exit-ink: #C2410C }
.exit a[href$="ops-portal.html"]       { --exit-ink: #1E7A45 }
.exit a[href$="drive-organizer.html"]  { --exit-ink: #8A6A12 }
.exit a[href$="screenshot-triage.html"]{ --exit-ink: #3568C4 }

/* The three exits take THIS page's own ink, --page-accent-ink. Where a page
   has not declared one, shared/scroll.js stamps it onto the root from its own
   table (see PAGE_INK there), so build-assemble, whose ink lives in a token
   only that page can read, still gets a text colour rather than raw #F2C230.
   With no script at all the chain ends at --ink, which is always readable. */

.exit-stack a,
.exit-row a{
  /* The last resort is INK, never the raw --page-accent: an accent that has
     not been declared text-safe is not a text colour, and falling through to
     it is exactly how #F2C230 landed on paper at 1.6:1. */
  --exit-ink: var(--acc, var(--page-accent-ink, var(--ink, #111517)));
  position: relative;
  color: var(--exit-ink);
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--exit-ink) 28%, transparent);
  padding-bottom: 1px;
  transition: border-color 150ms ease;
}
.exit-stack a:hover,
.exit-row a:hover{ border-bottom-color: var(--exit-ink); }
.exit-stack a:focus-visible,
.exit-row a:focus-visible{
  outline: 2px solid var(--link, #4D687A);
  outline-offset: 3px;
  border-radius: 2px;
}

/* The separator belongs to the GAP, not to either link, so it is taken out of
   flow and parked in the middle of the flex gap. Left in flow it would sit
   inside the second link's box and the link's own underline would run under
   it, which is why it is positioned rather than margined. */
.exit-stack a + a::before,
.exit-row a + a::before{
  content: "\00B7";
  position: absolute;
  right: calc(100% + 11px);
  top: 0;
  color: var(--line, #C3CCD1);
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce){
  .exit-stack a, .exit-row a{ transition: none; }
}

/* ============================================================================
   THE HERO ECHO  ·  C11-b, under the tint policy Oliver picked in D8-a.

   Behind each page's OPENING, and nowhere else, sits one very faint, very
   large echo of that product's own working surface: the week the Composer
   runs, the registry's rows, the wall of saved charts, the rule that files a
   folder, the heap of screenshots. A vertical mask takes it to nothing before
   the opening ends, so the second section starts on plain paper.

   Replenish keeps its per-part bands and Ops Portal keeps its seven rooms, so
   neither takes an echo; every other page gets one instead of a section tint.

   MARKUP: <div class="hero-echo" aria-hidden="true"></div> as the FIRST child
   of the opening section. shared/scroll.js draws the SVG into it, choosing the
   drawing from body[data-page] (falling back to the file name).

   z-index:-1 keeps the echo behind every glyph on the page, so body contrast
   is a blank page's contrast and nothing here can be read as a background
   behind text.
   ========================================================================== */

.hero-echo{
  position: absolute;
  inset: -4% -3% 0 -3%;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 16%, #000 46%, rgba(0,0,0,.5) 74%, transparent 96%);
  mask-image: linear-gradient(180deg, transparent 0, #000 16%, #000 46%, rgba(0,0,0,.5) 74%, transparent 96%);
}
.hero-echo svg{ display: block; width: 100%; height: 100%; }
/* every shape reads one token: the page's text-safe accent where it has one,
   because a raw yellow at 8% is not a colour, it is nothing. */
.hero-echo svg .a{ fill: var(--page-accent-ink, var(--page-accent, var(--ink, #111517))); }
.hero-echo svg .w{ stroke: var(--page-accent-ink, var(--page-accent, var(--ink, #111517))); fill: none; }

@media (max-width: 760px){ .hero-echo{ display: none } }

/* ============================================================================
   FRAME SWITCHES  ·  C10-a. The handoff between two sections is one ground
   colour cutting at the section edge. No rule, no gradient, no cross fade, no
   motion: the colour changing IS the seam, and shared CSS draws no line at it.

   A page states its bands by setting --band on a section (and --bandc for the
   marks that agree with it). A section that sets neither is paper, which is
   what makes the cut visible where it is meant to be.
   ========================================================================== */

:where(.vp){ background: var(--band, transparent); }
/* Belt and braces: nothing shared draws a seam between two sections. Stated at
   zero specificity, per this file's contract, so a page that genuinely wants a
   line somewhere still wins without a fight. */
:where(.vp + .vp){ border-top: 0; }
