/* ==========================================================================
   Persistent UI that floats over every section: custom cursor, boot loader,
   top bar, mobile nav sheet, scroll-progress hairline, section readout.
   ========================================================================== */

/* ---------- cursor ---------- */
/* The custom pointer only replaces the native one after cursor.js confirms it
   is running. Previously body carried cursor:none unconditionally, so a blocked
   CDN left the page rendering perfectly with no visible pointer at all. */
:root.cursor-live body,
:root.cursor-live a,
:root.cursor-live button,
:root.cursor-live summary,
:root.cursor-live select,
:root.cursor-live [data-cursor]{ cursor:none; }
.cursor,.cursor-ring{ display:none; }
:root.cursor-live .cursor,
:root.cursor-live .cursor-ring{ display:block; }
.cursor,.cursor-ring{ position:fixed; top:0; left:0; z-index:90; pointer-events:none; mix-blend-mode:difference; will-change:transform; }
.cursor{ width:6px; height:6px; background:var(--blend-ink); margin:-3px 0 0 -3px; }
.cursor-ring{ width:38px; height:38px; border:1px solid var(--blend-ink); margin:-19px 0 0 -19px; opacity:.55; }
@media (pointer:coarse){ .cursor,.cursor-ring{ display:none; } }

/* ---------- boot loader ---------- */
#loader{ position:fixed; inset:0; z-index:100; background:var(--bg); display:flex; align-items:flex-end; justify-content:space-between; gap:30px; padding:6vw; }
#loader .bl-log{ font-size:var(--fs-sm); line-height:2.1; letter-spacing:.06em; color:var(--muted); text-transform:uppercase; }
#loader .bl-log b{ color:var(--accent); font-weight:500; }
#loader .bl-count{ font-family:var(--display); font-weight:800; font-size:clamp(4rem,18vw,15rem); line-height:.8; letter-spacing:-.04em; }
#loader .bl-count i{ font-family:var(--mono); font-style:normal; font-size:14px; color:var(--accent); vertical-align:super; }

/* ---------- chrome ---------- */
/* padding-right reserves room for .nav-cta and .topbar-toggles, both fixed
   siblings positioned independently below — .topbar has no idea they exist,
   it just leaves the same gap it always would have for its own last child
   (nav, ending in the self-sized .nav-cta-space) to stop short of. */
.topbar{ position:fixed; top:0; left:0; right:0; z-index:60; display:flex; align-items:center; justify-content:space-between; padding:22px calc(5vw + 44px + 26px) 22px 5vw; mix-blend-mode:difference; color:var(--blend-ink); }
.topbar .brand{ display:inline-flex; align-items:center; min-height:44px; font-family:var(--display); font-weight:800; font-size:19px; letter-spacing:.01em; white-space:nowrap; }
.topbar .brand sup{ font-family:var(--mono); font-weight:400; font-size:10px; letter-spacing:.2em; margin-left:8px; opacity:.7; }
.topbar nav{ display:flex; gap:22px; font-size:var(--fs-sm); letter-spacing:.22em; text-transform:uppercase; }
  .topbar nav a{ display:inline-flex; align-items:center; min-height:44px; }
.topbar nav a{ opacity:.75; transition:opacity .4s var(--ease-out); }
.topbar nav a:hover{ opacity:1; }
/* Same box model as .nav-cta below, invisible: reserves the width and gap the
   fixed button needs so nav-group does not collapse into its place. */
.nav-cta-space{
  visibility:hidden; margin-left:4px;
  display:inline-flex; align-items:center; min-height:44px;
  font-size:var(--fs-sm); letter-spacing:.22em; text-transform:uppercase;
  padding:0 15px; border:1px solid transparent;
}

/* .nav-cta is a SIBLING of .topbar in the markup, not a descendant, and that
   is load-bearing, not stylistic. Two things were each confirmed by direct
   browser test before landing on this:
   - a descendant cannot opt out of an ancestor's mix-blend-mode by setting
     its own to normal — the ancestor's blend applies to the whole flattened
     subtree as one unit, so a nested CTA could never show a real colour.
   - mix-blend-mode on a position:fixed element blends correctly against the
     page; the identical blend-mode on a normal child nested inside an
     *unblended* fixed wrapper washes out to near-invisible — measured, not
     theoretical: a bold black label over a white card rendered pale grey
     once the blend moved from the fixed parent onto a nested child, with no
     other change. This ruled out every restructure that kept .nav-cta
     somewhere inside .topbar, blended-group boundaries or not.
   So .topbar keeps its blend exactly as it always has (nothing above this
   comment changed), and .nav-cta is its own independent position:fixed
   element, positioned to land in the same spot the flex layout used to put
   it: the 44px theme-toggle is the only thing to its right at any width
   where this is visible (.nav-toggle stays display:none until nav-cta itself
   hides at 1023px), so the offset is a fixed sum, not a guess. */
.nav-cta{
  position:fixed; top:22px; right:calc(5vw + 44px + 26px); z-index:61;
  display:inline-flex; align-items:center; min-height:44px;
  font-size:var(--fs-sm); letter-spacing:.22em; text-transform:uppercase;
  padding:0 15px; color:var(--accent); border:1px solid var(--accent);
  transition:background .35s var(--ease-out), color .35s var(--ease-out);
}
@media (hover:hover){
  .nav-cta:hover{ background:var(--accent); color:var(--on-accent); }
}
.nav-cta:focus-visible{ background:var(--accent); color:var(--on-accent); }
@media (max-width:1023px){ .nav-cta{ display:none; } }

/* Its own independent position:fixed + mix-blend-mode group (see the comment
   on .nav-cta above) — flush to the true right edge, unaffected by anything
   .topbar or .nav-cta reserve room for. */
.topbar-toggles{ position:fixed; top:22px; right:5vw; z-index:60; display:flex; align-items:center; gap:26px; mix-blend-mode:difference; color:var(--blend-ink); }

.theme-toggle{ background:none; border:none; padding:0; width:44px; height:44px; display:inline-flex; align-items:center; justify-content:center; cursor:pointer; -webkit-tap-highlight-color:transparent; transition:transform .5s var(--ease-out); }
.theme-toggle:hover{ transform:rotate(18deg); }
.theme-toggle svg{ width:18px; height:18px; display:block; }
.theme-toggle .i-moon{ display:none; }
[data-theme="light"] .theme-toggle .i-sun{ display:none; }
[data-theme="light"] .theme-toggle .i-moon{ display:block; }
@media (pointer:coarse){ .theme-toggle{ cursor:pointer; width:44px; height:44px; } }

.nav-toggle{ display:none; }
.mnav{ display:none; }
@media (max-width:1023px){
  .topbar nav{ display:none; }
  .nav-toggle{ display:inline-flex; flex-direction:column; justify-content:center; gap:6px; width:44px; height:44px; padding:0 10px; background:none; border:none; cursor:pointer; }
  .nav-toggle span{ display:block; height:1.5px; width:100%; background:currentColor; transition:transform .4s var(--ease-out), opacity .3s var(--ease-out); }
  .nav-toggle.is-open span:first-child{ transform:translateY(3.75px) rotate(45deg); }
  .nav-toggle.is-open span:last-child{ transform:translateY(-3.75px) rotate(-45deg); }
  /* safe center keeps the list centred when it fits and falls back to the top
     edge when it does not, so nothing is clipped on a landscape phone. */
  .mnav{ position:fixed; inset:0; z-index:55; display:flex; flex-direction:column; align-items:flex-start; justify-content:center; justify-content:safe center; gap:clamp(10px,1.9vh,22px); padding:96px 9vw 40px; background:var(--bg); overflow-y:auto; overscroll-behavior:contain; opacity:0; visibility:hidden; transform:translateY(-10px); transition:opacity .45s var(--ease-out), transform .45s var(--ease-out), visibility .45s; }
  .mnav.open{ opacity:1; visibility:visible; transform:none; }
  .mnav a{ display:flex; align-items:center; min-height:44px; font-family:var(--display); font-weight:700; text-transform:uppercase; font-size:clamp(1.35rem,6.2vw,2.3rem); line-height:1.05; letter-spacing:-.01em; color:var(--ink); flex:0 0 auto; }
  .mnav a .mi{ font-family:var(--mono); font-weight:400; font-size:var(--fs-sm); letter-spacing:.14em; color:var(--accent); margin-right:14px; vertical-align:middle; }
  .mnav a.mnav-cta{ margin-top:2vh; font-family:var(--mono); font-weight:500; text-transform:uppercase; font-size:var(--fs-base); letter-spacing:.18em; color:var(--accent); }
}

.progress{ position:fixed; top:0; left:0; right:0; height:2px; z-index:80; pointer-events:none; }
.progress i{ display:block; height:100%; width:100%; transform:scaleX(0); transform-origin:left; background:linear-gradient(90deg, var(--accent), var(--amber)); }
#sysread{ position:fixed; left:5vw; bottom:26px; z-index:50; pointer-events:none; font-size:var(--fs-xs); letter-spacing:.24em; text-transform:uppercase; color:var(--faint); }
#sysread b{ color:var(--accent); font-weight:500; }
/* Stands down over the contact panel, which is the one solid block that
   reaches this corner — see initSysRead() in nav.js. */
#sysread{ opacity:1; transition:opacity .35s var(--ease-out); }
#sysread.is-hidden{ opacity:0; }
@media (max-width:900px){ #sysread{ display:none; } }

/* ---------- floating scroll-to-top ----------
   Fixed bottom-right. The SVG ring is a read-progress meter driven from
   nav.js; the button itself only appears once there is a meaningful amount
   of page behind you, and steps aside while the case-file reel is pinned
   (the reel runs its own progress bar along the same edge). */
.totop{
  position:fixed; right:clamp(16px,5vw,52px); bottom:clamp(16px,4.5vh,46px); z-index:70;
  width:56px; height:56px; display:grid; place-items:center;
  padding:0; border:none; border-radius:50%;
  background:color-mix(in oklab, var(--bg) 82%, transparent);
  -webkit-backdrop-filter:blur(9px); backdrop-filter:blur(9px);
  color:var(--ink); cursor:pointer;
  opacity:0; visibility:hidden; transform:translateY(14px) scale(.86);
  transition:opacity .5s var(--ease-out), transform .5s var(--ease-out),
             visibility .5s, background .4s var(--ease-out), color .4s var(--ease-out);
}
.totop.show{ opacity:1; visibility:visible; transform:none; }
.totop.stow{ opacity:0; visibility:hidden; transform:translateY(14px) scale(.86); }

.totop-ring{ position:absolute; inset:0; width:100%; height:100%; transform:rotate(-90deg); }
.totop-ring circle{ fill:none; stroke-width:1.5; }
.tt-track{ stroke:var(--line); }
.tt-bar{
  stroke:var(--accent); stroke-linecap:round;
  /* 2πr for r=26 ≈ 163.36; nav.js drives the dashoffset from scroll position */
  stroke-dasharray:163.36; stroke-dashoffset:163.36;
  transition:stroke-dashoffset .12s linear;
}
.totop-arrow{ position:relative; width:19px; height:19px; fill:none; stroke:currentColor; stroke-width:1.6; stroke-linecap:round; stroke-linejoin:round; transition:transform .45s var(--ease-out); }

@media (hover:hover){
  .totop:hover{ background:var(--accent); color:var(--on-accent); }
  .totop:hover .totop-arrow{ transform:translateY(-3px); }
  .totop:hover .tt-track{ stroke:transparent; }
}
.totop:focus-visible{ outline:2px solid var(--accent); outline-offset:4px; }
@media (pointer:coarse){ .totop{ cursor:pointer; } }

/* The reel owns the bottom edge while it is pinned. */
.reel-pinned .totop{ opacity:0; visibility:hidden; transform:translateY(14px) scale(.86); pointer-events:none; }

@media (prefers-reduced-motion:reduce){
  .totop{ transition:opacity .2s linear, visibility .2s; transform:none; }
  .totop.show{ transform:none; }
  .totop.stow, .reel-pinned .totop{ transform:none; }
  .tt-bar{ transition:none; }
  .totop-arrow{ transition:none; }
}

/* ---------- very small handsets (≤400px) ----------
   The brand lockup plus two 44px controls does not fit 320px at full size,
   so the wordmark steps down and the control gap tightens. */
@media (max-width:400px){
  .topbar{ padding:12px 4vw; }
  .topbar .brand{ font-size:15.5px; }
  .topbar .brand sup{ margin-left:5px; letter-spacing:.12em; }
  /* These were shrunk to 40px to fit the narrow bar, which put both controls
     under the 44px minimum. Dropping the gap instead buys back the width at
     the same total footprint, and the targets stay 44px and non-overlapping. */
  .topbar-toggles{ top:12px; right:4vw; gap:0; }
}

/* ---------- skip link ----------
   Off-screen until focused, then lands in the top-left as a normal button. */
.skip-link{
  position:fixed; top:0; left:0; z-index:200;
  padding:14px 20px; background:var(--accent); color:var(--on-accent);
  font-size:var(--fs-sm); letter-spacing:.16em; text-transform:uppercase;
  transform:translateY(-120%); transition:transform .25s var(--ease-out);
}
.skip-link:focus{ transform:none; outline:2px solid var(--ink); outline-offset:2px; }

/* ---------- mobile contact bar ----------
   Phone-only. Below 1023px .nav-cta is display:none, so without this there is
   no persistent way to reach us from a phone at all. Three equal targets, each
   comfortably over 44px, sitting on the safe-area inset so it clears the iOS
   home indicator. */
.mobile-bar{
  position:fixed; left:0; right:0; bottom:0; z-index:75;
  display:none; align-items:stretch;
  background:color-mix(in oklab, var(--panel) 94%, transparent);
  -webkit-backdrop-filter:blur(14px); backdrop-filter:blur(14px);
  border-top:1px solid var(--line);
  padding-bottom:env(safe-area-inset-bottom,0);
  transform:translateY(102%); transition:transform .4s var(--ease-out);
}
.mobile-bar.show{ transform:none; }
.mobile-bar .mb-item{
  flex:1 1 0; min-width:0; min-height:58px;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px;
  padding:9px 6px; color:var(--ink);
  font-size:var(--fs-2xs); letter-spacing:.11em; text-transform:uppercase;
  border-left:1px solid var(--line);
}
.mobile-bar .mb-item:first-child{ border-left:none; }
.mobile-bar .mb-item svg{ width:19px; height:19px; flex:0 0 auto; }
.mobile-bar .mb-item span{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100%; }
.mobile-bar .mb-whats{ color:#25d366; }
[data-theme="light"] .mobile-bar .mb-whats{ color:#128c4a; }   /* 4.6:1 on the light panel */
.mobile-bar .mb-cta{ background:var(--accent); color:var(--on-accent); border-left-color:var(--accent); }
.mobile-bar .mb-item:active{ filter:brightness(1.15); }

@media (max-width:1023px){
  .mobile-bar{ display:flex; }
  /* The bar owns the bottom edge, so the round controls move up above it. */
  .totop{ bottom:calc(66px + env(safe-area-inset-bottom,0) + 12px); }
  /* The reel's own progress bar would sit underneath it otherwise. */
  .reel-progress{ bottom:calc(66px + env(safe-area-inset-bottom,0) + 12px); }
}
/* Nothing should sit on top of the form the bar points at. */
.mobile-bar.stow{ transform:translateY(102%); }

/* ---------- floating WhatsApp (desktop) ----------
   Desktop only: on a phone the same channel is already one of three equal
   targets in .mobile-bar, and two WhatsApp buttons on one screen is noise. */
.wa-float{
  position:fixed; right:clamp(16px,5vw,52px); bottom:calc(clamp(16px,4.5vh,46px) + 68px);
  z-index:70; width:56px; height:56px; display:grid; place-items:center;
  border-radius:50%; background:#25d366; color:#04110c;
  box-shadow:0 12px 34px -12px rgba(0,0,0,.55);
  opacity:0; visibility:hidden; transform:translateY(14px) scale(.86);
  transition:opacity .5s var(--ease-out), transform .5s var(--ease-out), visibility .5s;
}
.wa-float.show{ opacity:1; visibility:visible; transform:none; }
.wa-float svg{ width:27px; height:27px; }
.wa-float .wa-tip{
  position:absolute; right:calc(100% + 12px); top:50%; transform:translateY(-50%) translateX(6px);
  padding:9px 14px; white-space:nowrap; background:var(--elev); color:var(--ink);
  border:1px solid var(--line); font-size:var(--fs-2xs); letter-spacing:.14em; text-transform:uppercase;
  opacity:0; pointer-events:none; transition:opacity .35s var(--ease-out), transform .35s var(--ease-out);
}
@media (hover:hover){
  .wa-float:hover{ filter:brightness(1.08); }
  .wa-float:hover .wa-tip{ opacity:1; transform:translateY(-50%); }
}
.wa-float:focus-visible{ outline:2px solid var(--accent); outline-offset:4px; }
.wa-float:focus-visible .wa-tip{ opacity:1; transform:translateY(-50%); }
@media (max-width:1023px){ .wa-float{ display:none; } }
.reel-pinned .wa-float{ opacity:0; visibility:hidden; pointer-events:none; }

@media (prefers-reduced-motion:reduce){
  .skip-link,.mobile-bar,.wa-float,.wa-float .wa-tip{ transition:none; }
  .wa-float{ transform:none; }
  .wa-float.show{ transform:none; }
}
