/* =====================================================================
   Leitco — shared chrome  (the slate house style)
   ---------------------------------------------------------------------
   LAYER 2 of 3. The masthead, the tab bar, the sub-nav, the theme switch
   and the drafting grid: the parts that make four applications read as
   one.

   EVERY class here is lc- prefixed, deliberately. viewer.html and
   tool.html already own .tabs, .wrap, .btn, .panel, .card, .pill and
   .mark, so the prefix is what lets this file go anywhere.

   Requires style/tokens.css.
   ===================================================================== */

/* The icon sprite leitco_chrome() emits. Zero-sized, so it takes no
   layout, but position:absolute as well because Safari has been known
   to reserve a line box for it. */
.lc-sprite{position:absolute;width:0;height:0;overflow:hidden}

/* --------------------------------------------------------- the sheet
   The plan grid pattern (assets/plan-grid-pattern.js), replacing the
   16/80 dot grid here 28 September 2026 — same brand device the
   sign-in page now uses, reshuffling to a new layout every five
   minutes (leitco.js, 29 September 2026).
   leitco.js mounts it into #lc-grid-bg (emitted by leitco_chrome(),
   so tool.html and viewer.html get it too — see nav.php) at the live
   --accent colour, and redraws it on resize and on a theme change.
   Fading toward the bottom of the screen, fixed, so content slides
   over it like paper on a board.

   .lc-nogrid opts out. (The point cloud studio does not use it: it wears the grid on its drop screen
   as .lc-darkgrid and hides it with body.has-cloud while a scan is on screen, see viewer.html.) The
   scan itself is a full-bleed WebGL canvas on a dark ground; a pattern behind it would be nonsense. */
#lc-grid-bg{
  position:fixed;inset:0;z-index:0;pointer-events:none;
  -webkit-mask-image:var(--grid-fade);
          mask-image:var(--grid-fade);
}
#lc-grid-bg svg{display:block;width:100%;height:100%}
body.lc-nogrid #lc-grid-bg{display:none}
@media print{ #lc-grid-bg{display:none} }

/* ---------------------------------------------------------- masthead */
/* z-index 3, above the tab bar's 2, and it has to be. The theme menu
   hangs out of the bottom of this header, and z-index inside a stacking
   context cannot climb out of it: with both at 2 the tab bar — later in
   the document — painted straight over the first menu item. */
.lc-hdr{display:flex;align-items:center;gap:var(--sp-3);height:64px;padding:0 var(--sp-4);
  background:var(--surface);border-bottom:1px solid var(--hair);position:relative;z-index:3}
/* The Android app (and an installed PWA on a notched phone) draws the page under the status bar. The
   inset is 0 in an ordinary browser tab, so this border is 0 high there and nothing changes. In the
   app it is a slate band, the height of the status bar, above the white masthead: the app turns the
   bar's icons light (capacitor.config.json). --safe-area-inset-top is set by Capacitor's own script.
   The masthead is border-box, so its height grows by the same amount (here and in the phone rule). */
:root{--lc-safe-top:var(--safe-area-inset-top, env(safe-area-inset-top, 0px))}
.lc-hdr{border-top:var(--lc-safe-top) solid var(--slate);height:calc(64px + var(--lc-safe-top))}
.lc-brand{display:flex;align-items:center;gap:12px;color:var(--accent);text-decoration:none;flex:none}
.lc-brand svg{width:28px;height:28px;fill:currentColor;display:block}
.lc-brand b{font-size:19px;font-weight:bold;letter-spacing:.02em}
.lc-div{width:1px;height:24px;background:var(--hair);flex:none}
.lc-hdr h1{margin:0;font-size:16px;font-weight:normal;color:var(--ink-2);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.lc-who{margin-left:auto;display:flex;align-items:center;gap:var(--sp-2);
  font-size:14px;color:var(--ink-2);white-space:nowrap}
.lc-me{white-space:nowrap}
.lc-who a{color:var(--accent);font-weight:bold;text-decoration:none;
  padding:var(--sp-1) var(--sp-2);border-radius:var(--r-sm);
  transition:background var(--dur-fast) var(--ease)}
@media (hover:hover){ .lc-who a:hover{background:var(--sunk)} }
.lc-who a:active{background:var(--accent-soft)}

/* the theme switch: system, light or dark, remembered on this device */
.lc-theme{position:relative;display:inline-flex}
.lc-theme-btn{width:36px;height:36px;display:grid;place-items:center;
  border:1px solid var(--hair);border-radius:var(--r-sm);background:transparent;
  color:var(--ink-2);cursor:pointer;
  transition:color var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease),
             background var(--dur-fast) var(--ease),transform var(--dur-fast) var(--ease)}
@media (hover:hover){ .lc-theme-btn:hover{color:var(--ink);border-color:var(--line)} }
.lc-theme-btn[aria-expanded="true"]{color:var(--ink);border-color:var(--line)}
.lc-theme-btn:active{transform:translateY(1px);background:var(--sunk)}
.lc-theme-btn svg{width:16px;height:16px;display:none}
/* Which of the three icons the button shows is decided here, in CSS,
   from the data-theme-pref the boot script writes on <html> before the
   stylesheets are applied. The alternative — render one icon in PHP and
   correct it in JavaScript — flickers on every page load, and PHP cannot
   know the answer anyway: the choice lives in localStorage. */
:root[data-theme-pref="system"] .lc-theme-btn .i-system,
:root[data-theme-pref="light"]  .lc-theme-btn .i-light,
:root[data-theme-pref="dark"]   .lc-theme-btn .i-dark,
:root:not([data-theme-pref])    .lc-theme-btn .i-system{display:block}

.lc-theme-menu{position:absolute;right:0;top:calc(100% + 8px);z-index:40;display:grid;
  min-width:168px;padding:var(--sp-1);background:var(--surface-2);
  border:1px solid var(--hair);border-radius:var(--r-md);box-shadow:var(--shadow-float);
  transform-origin:top right}
.lc-theme-menu:not([hidden]){animation:lc-pop var(--dur-fast) var(--ease)}
.lc-theme-menu[hidden]{display:none}
.lc-theme-menu button{display:flex;align-items:center;gap:12px;padding:var(--sp-2) 12px;
  border:0;border-radius:var(--r-sm);background:transparent;color:var(--ink);
  font-family:inherit;font-size:14px;text-align:left;cursor:pointer;
  transition:background var(--dur-fast) var(--ease)}
@media (hover:hover){ .lc-theme-menu button:hover{background:var(--accent-soft)} }
.lc-theme-menu button[aria-checked="true"]{color:var(--accent);font-weight:bold}
.lc-theme-menu svg{width:16px;height:16px;flex:none}
@keyframes lc-pop{from{opacity:0;transform:translateY(-4px) scale(.98)}to{opacity:1;transform:none}}
/* The theme swap crossfades where the browser can do it. The API opts
   itself out under prefers-reduced-motion, and leitco.js skips it too. */
::view-transition-old(root),::view-transition-new(root){
  animation-duration:var(--dur-base);animation-timing-function:var(--ease)}

/* -------------------------------------------------------------- tabs */
/* overscroll-behavior-x:contain — without it, a touch swipe that hits
   the end of this row's own scroll (an admin account has enough tools
   to need one) hands off to the page itself: the whole viewport
   rubber-bands sideways, briefly showing blank space past the edge.
   Found on a real phone, 22 September 2026 — no overflow on the page
   itself (confirmed: document.body.scrollWidth === window.innerWidth
   in a real test), so it was this, not a layout bug. contain stops the
   handoff without touching the row's own scroll. */
.lc-tabs{display:flex;gap:var(--sp-1);padding:0 var(--sp-3);background:var(--surface);
  border-bottom:1px solid var(--hair);overflow-x:auto;scrollbar-width:none;
  overscroll-behavior-x:contain;position:relative;z-index:2}
.lc-tabs::-webkit-scrollbar{display:none}
.lc-tabs a{flex:0 0 auto;display:flex;align-items:center;height:48px;padding:0 12px;
  font-family:var(--f-ui);font-size:14px;color:var(--ink-2);text-decoration:none;
  border-bottom:2px solid transparent;white-space:nowrap;
  transition:color var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease),
             background var(--dur-fast) var(--ease)}
@media (hover:hover){ .lc-tabs a:hover{color:var(--ink);border-bottom-color:var(--hair)} }
.lc-tabs a:active{background:var(--sunk)}
.lc-tabs a:focus-visible{outline:2px solid var(--accent);outline-offset:-4px}
.lc-tabs a[aria-current="page"]{color:var(--accent);font-weight:bold;border-bottom-color:var(--accent)}
/* Skip link (3 October 2026, WCAG 2.4.1): the first thing a keyboard user tabs to, hidden until it is. */
.lc-skip{position:absolute;left:var(--sp-3);top:-60px;z-index:100;padding:10px 16px;border-radius:var(--r-sm);
  background:var(--accent);color:var(--on-accent);font-weight:bold;text-decoration:none;transition:top var(--dur-fast) var(--ease)}
.lc-skip:focus{top:var(--sp-2)}
#main:focus{outline:none}
@media print{ .lc-skip{display:none} }

/* The list under "Settings" in the header (3 October 2026): Account details, Inbox, Change password and,
   for an administrator, Accounts. */
.lc-acct{position:relative;display:inline-flex}
.lc-who a.lc-acct-btn{display:inline-flex;align-items:center;gap:6px}
.lc-acct-chev{width:6px;height:6px;margin:-3px 0 0 2px;border-right:2px solid currentColor;border-bottom:2px solid currentColor;
  transform:rotate(45deg);transition:transform var(--dur-fast) var(--ease)}
.lc-who a.lc-acct-btn[aria-current="page"]{background:var(--sunk)}
.lc-acct-sep{height:1px;margin:var(--sp-1) 6px;background:var(--hair)}
.lc-acct-btn[aria-expanded="true"] .lc-acct-chev{transform:rotate(-135deg);margin-top:3px}
.lc-acct-menu{position:absolute;right:0;top:calc(100% + 8px);z-index:40;display:grid;min-width:190px;padding:var(--sp-1);
  background:var(--surface-2);border:1px solid var(--hair);border-radius:var(--r-md);box-shadow:var(--shadow-float);
  transform-origin:top right}
.lc-acct-menu:not([hidden]){animation:lc-pop var(--dur-fast) var(--ease)}
.lc-acct-menu[hidden]{display:none}
.lc-who .lc-acct-menu a{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:var(--sp-2) 12px;
  color:var(--ink);font-size:14px;font-weight:normal;border-radius:var(--r-sm)}
@media (hover:hover){ .lc-who .lc-acct-menu a:hover{background:var(--accent-soft)} }
.lc-who .lc-acct-menu a:focus-visible{outline:2px solid var(--accent);outline-offset:-2px;background:var(--accent-soft)}
/* How many answers wait in the Inbox, on the Settings link (3 October 2026). */
.lc-count{display:inline-block;min-width:1.4em;margin-left:.35em;padding:0 .4em;border-radius:999px;
  background:var(--accent);color:var(--on-accent);font-size:.78em;font-weight:bold;line-height:1.5;text-align:center}

/* ----------------------------------------------------------- pop-up boxes
   Dropdown lists and confirm / alert / prompt boxes (3 October 2026, Tyler: "make all pop up boxes the
   same style as the app"). Drawn by leitco.js in place of the browser's own, which a page cannot style.
   Tokens only, so they follow the theme. Never printed. */
.lc-pop{position:fixed;z-index:10000;box-sizing:border-box;overflow-y:auto;overscroll-behavior:contain;
  scrollbar-width:thin;scrollbar-color:var(--line) transparent;
  background:var(--surface);color:var(--ink);border:1px solid var(--line);border-radius:var(--r-md);
  box-shadow:0 10px 32px rgba(0,0,0,.35);font-size:15px}
.lc-pop-row{position:relative;box-sizing:border-box;height:44px;line-height:43px;padding:0 40px 0 14px;
  overflow:hidden;white-space:nowrap;text-overflow:ellipsis;cursor:pointer;border-bottom:1px solid var(--hair)}
.lc-pop-row:last-child{border-bottom:0}
.lc-pop-row[data-active]{background:var(--sunk)}
.lc-pop-row[aria-selected="true"]{background:var(--accent-soft);font-weight:bold}
.lc-pop-row[aria-selected="true"]::after{content:"\2713";position:absolute;right:14px;top:0;color:var(--accent)}
.lc-pop-row[aria-disabled="true"]{color:var(--ink-3);cursor:default}
.lc-pop-grp{padding:8px 14px 4px;font-size:11.5px;font-weight:bold;letter-spacing:.4px;color:var(--ink-2);background:var(--sunk)}
dialog.lc-dlg{width:min(400px,calc(100vw - 32px));padding:0;border:1px solid var(--line);border-radius:var(--r-md);
  background:var(--surface);color:var(--ink);box-shadow:0 12px 40px rgba(0,0,0,.35)}
dialog.lc-dlg::backdrop{background:rgba(0,0,0,.55)}
.lc-dlg form{display:grid;gap:16px;padding:22px 22px 18px}
.lc-dlg-msg{margin:0;font-size:15px;line-height:1.5;white-space:pre-line;overflow-wrap:anywhere}
.lc-dlg input{font:inherit;font-size:15px;padding:9px 10px;width:100%;box-sizing:border-box;color:var(--ink);
  background:var(--paper);border:1px solid var(--line);border-radius:var(--r-sm)}
.lc-dlg input:focus{outline:none;border-color:var(--accent)}
.lc-dlg-acts{display:flex;gap:10px;justify-content:flex-end}
.lc-dlg-acts button{font:inherit;font-size:14px;font-weight:bold;padding:8px 18px;cursor:pointer;border-radius:999px;
  border:1px solid var(--line);background:transparent;color:var(--ink)}
.lc-dlg-acts button.lc-dlg-yes{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}
.lc-dlg-acts button:focus-visible,.lc-pop:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
@media print{ .lc-pop,dialog.lc-dlg{display:none!important} }

/* ------------------------------------------------------------- footer
   Copyright, 30 September 2026 — leitco_copyright() in nav.php, the
   one place every page (including tool.html/viewer.html, which never
   load style/ui.css) gets it from. Lives here rather than ui.css so it
   works everywhere without exception. Not hidden for print — the
   point is that it prints too. */
.foot{text-align:center;margin-top:var(--sp-5);font-size:12px;color:var(--ink-2)}

/* ----------------------------------------------------------- sub-nav
   A tool's own views — Scans: Studio / Library. Lighter than the tab bar
   above it, so the hierarchy reads at a glance. */
.lc-sub{display:flex;gap:var(--sp-1);padding:var(--sp-2) var(--sp-4);
  overflow-x:auto;scrollbar-width:none;overscroll-behavior-x:contain;
  position:relative;z-index:2}
.lc-sub::-webkit-scrollbar{display:none}
.lc-sub a{flex:0 0 auto;display:inline-flex;align-items:center;height:32px;padding:0 var(--sp-3);
  border-radius:999px;border:1px solid transparent;
  font-family:var(--f-ui);font-size:14px;color:var(--ink-2);text-decoration:none;white-space:nowrap;
  transition:background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease),
             color var(--dur-fast) var(--ease)}
@media (hover:hover){ .lc-sub a:hover{background:var(--surface);border-color:var(--hair);color:var(--ink)} }
.lc-sub a:active{background:var(--sunk)}
.lc-sub a[aria-current="page"]{background:var(--surface);border-color:var(--hair);
  color:var(--accent);font-weight:bold;box-shadow:var(--shadow-raised)}

/* ---------------------------------------------------------- install
   The button always renders hidden — see leitco_install_button()'s own
   comment for why — and leitco.js reveals it once it knows the
   browser can actually do something. */
.lc-install{display:inline-flex;align-items:center;gap:var(--sp-2);height:36px;padding:0 12px;
  border:1px solid var(--hair);border-radius:var(--r-sm);background:transparent;color:var(--ink);
  font-family:var(--f-ui);font-size:14px;font-weight:bold;cursor:pointer;
  transition:border-color var(--dur-fast) var(--ease),background var(--dur-fast) var(--ease),
             transform var(--dur-fast) var(--ease)}
@media (hover:hover){ .lc-install:hover{border-color:var(--line)} }
.lc-install:active{transform:translateY(1px);background:var(--sunk)}
.lc-install svg{width:16px;height:16px;color:var(--accent);flex:none}
.lc-install[hidden]{display:none}

/* The dialog itself. <dialog> for the focus trap and Escape handling
   the element gives for free — the same reason the theme menu does not
   use one is that a menu is not modal, and this is. */
.lc-install-dlg{width:min(456px,calc(100% - 32px));max-height:calc(100% - 32px);padding:0;
  border:1px solid var(--hair);border-radius:var(--r-lg);background:var(--surface-2);
  color:var(--ink);box-shadow:var(--shadow-float);overflow:auto}
.lc-install-dlg[open]{animation:lc-pop var(--dur-slow) var(--ease)}
.lc-install-dlg::backdrop{background:rgba(0,0,0,.4)}
.lc-sd-head{display:flex;gap:var(--sp-3);align-items:center;padding:var(--sp-4) var(--sp-4) var(--sp-3)}
.lc-sd-icon{width:64px;height:64px;flex:none;border-radius:var(--r-lg);background:var(--slate);
  color:var(--white);display:grid;place-items:center}
.lc-sd-icon svg{width:36px;height:36px;fill:currentColor}
.lc-sd-head h2{margin:0;font-size:19px}
.lc-sd-head p{margin:var(--sp-1) 0 0;font-size:14px;color:var(--ink-2)}
.lc-sd-body{display:grid;gap:var(--sp-3);padding:0 var(--sp-4)}
/* Its own class, not .seg — viewer.html and tool.html both already
   define a bare .seg for their own toggles (colour/height, screen
   size...), and this dialog appears on every page including those two.
   A more specific selector would still win inside the dialog either
   way, but a name of its own is one less thing to reason about. */
.lc-sd-seg{display:flex;gap:4px}
.lc-sd-seg button{flex:1;font-family:inherit;font-size:12px;font-weight:bold;
  padding:8px 6px;border:1px solid var(--line);border-radius:var(--r-sm);
  background:var(--surface);color:var(--ink-2);cursor:pointer;
  transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.lc-sd-seg button[aria-pressed="true"]{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}
.lc-sd-list{list-style:none;margin:0;padding:0;display:grid;gap:12px}
.lc-sd-list li{display:grid;grid-template-columns:24px minmax(0,1fr);gap:12px;font-size:14px;line-height:1.5}
.lc-sd-list svg{width:20px;height:20px;color:var(--accent);margin-top:2px}
.lc-sd-steps{margin:0;padding:var(--sp-3) var(--sp-3) var(--sp-3) var(--sp-5);
  display:grid;gap:var(--sp-2);font-size:14px;background:var(--sunk);border-radius:var(--r-md)}
.lc-sd-steps svg{width:16px;height:16px;vertical-align:-3px;color:var(--accent)}
.lc-sd-acts{display:flex;justify-content:flex-end;flex-wrap:wrap;gap:var(--sp-2);
  padding:var(--sp-3) var(--sp-4);margin-top:var(--sp-4);border-top:1px solid var(--hair)}
/* Not .btn/.btn-2 — both are already spoken for, differently, on
   tool.html and viewer.html, which draw this same dialog. */
.lc-sd-btn{display:inline-flex;align-items:center;gap:var(--sp-2);min-height:40px;
  padding:0 var(--sp-4);border:1px solid var(--line);border-radius:var(--r-sm);
  background:var(--surface);color:var(--ink);font-family:var(--f-ui);font-size:14px;
  font-weight:bold;cursor:pointer;
  transition:background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease)}
@media (hover:hover){ .lc-sd-btn:hover{background:var(--sunk)} }
.lc-sd-btn:active{transform:translateY(1px)}
.lc-sd-btn svg{width:16px;height:16px;flex:none}
.lc-sd-btn-primary{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}
@media (hover:hover){ .lc-sd-btn-primary:hover{background:var(--accent-hover);border-color:var(--accent-hover)} }
.lc-sd-btn[aria-busy="true"]{cursor:progress;pointer-events:none}
.lc-sd-spin{display:inline-block;width:14px;height:14px;flex:none;border-radius:50%;
  border:2px solid currentColor;border-right-color:transparent;
  animation:lc-sd-spin 700ms linear infinite}
@keyframes lc-sd-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion: reduce){ .lc-sd-spin{animation-duration:1.6s} }

@media (max-width:720px){
  .lc-hdr{padding:0 var(--sp-3);height:calc(56px + var(--lc-safe-top));gap:var(--sp-2)}
  .lc-me,.lc-div{display:none}
  /* The page's one <h1>: off the screen on a phone, but still there for a screen reader (display:none
     removed it, and the page had no heading at all; WCAG 1.3.1, 2.4.6). */
  .lc-hdr h1{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0)}
  /* The right-hand group (theme, Settings, Sign out) is tight on a 360-375 px phone: less gap and padding
     so the page never scrolls sideways (3 October 2026). */
  .lc-who{gap:2px}
  .lc-who a{padding:var(--sp-1) 6px}
  .lc-tabs{padding:0 var(--sp-2)}
  .lc-sub{padding:var(--sp-2) var(--sp-3)}
  .lc-install span{display:none}
  .lc-install{width:36px;padding:0;justify-content:center}
}
@media (max-width:400px){
  .lc-hdr{padding:0 var(--sp-2);gap:var(--sp-1)}
  .lc-brand{gap:8px}
  .lc-brand b{font-size:17px}
  .lc-theme-btn{width:32px;height:32px}
}
@media print{ .lc-tabs,.lc-sub,.lc-who,.lc-install{display:none} }

/* ========================================================== start-up
   The block mark draws itself once, on arrival, then flies into place
   in the header while the page fades in behind it. Once per browser
   session (sessionStorage, not localStorage — a new tab gets it
   again, the same tab reloading the same page does not), about 4.8s
   to landing at the 2.5x speed Tyler chose, skippable with a click or
   any key, and a plain fade under reduced motion.

   Self-contained here rather than split across chrome.css and ui.css:
   tool.html and viewer.html show this too — every page with a
   .lc-brand mark to land in does — and neither loads ui.css. .sp-rise
   and .visually-hidden below are ui.css's own lc-rise keyframe and
   utility class in every way but name; a shared name across two files
   that might disagree later seemed worse than one small duplication.
   (Tyler, 16 September 2026: "come up with an animated start up",
   2.5x speed, grid waves from the logo, Faint, Slow, start-up only.) */
.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
@keyframes sp-rise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

.splash{--k:2.5;position:fixed;inset:0;z-index:100;display:grid;place-items:center;
  background-color:var(--paper);color:var(--accent);cursor:progress;
  transition:background-color var(--dur-slow) var(--ease),opacity var(--dur-slow) var(--ease)}
.splash.leaving-splash{background-color:transparent;pointer-events:none}
.splash.leaving-splash .splash-grid{opacity:0;transition:opacity var(--dur-slow) var(--ease)}
.splash.gone{opacity:0}
/* The plan grid pattern, same as the rest of the app (28 September
   2026) — mounted by runSplash() in leitco.js, not CSS, since it's the
   same JS-generated SVG everywhere else. Sits behind .sp-stage. */
.splash-grid{position:absolute;inset:0;z-index:0;pointer-events:none}
.splash-grid svg{display:block;width:100%;height:100%}
.sp-stage{position:relative;z-index:1;display:grid;justify-items:center;gap:var(--sp-4)}

/* The heartbeat: while the mark draws, a faint wave of lit grid pulses
   out from behind it. A copy of the grid, drawn stronger, shows only
   through a soft ring whose radius (--wr, registered so it can
   animate) grows and fades. Start-up only — page changes do not wave.
   Without @property support there is simply no wave; nothing breaks,
   the mark still draws and lands. */
@property --wr{syntax:"<length>";inherits:false;initial-value:0px}
.sp-wave{position:absolute;inset:0;z-index:0;pointer-events:none;
  /* The wash alone stays a CSS gradient — a flat tint, not a grid, so
     there's nothing in it to swap. The grid itself is a second, denser
     plan-grid-pattern mount (runSplash()'s beat()), a sibling of this
     background, both cut by the same mask below. */
  background-image:linear-gradient(var(--wave-wash),var(--wave-wash));
  --ww:120px;
  -webkit-mask-image:radial-gradient(circle at var(--wx) var(--wy),transparent calc(var(--wr) - var(--ww)),#000 var(--wr),transparent calc(var(--wr) + var(--ww)));
          mask-image:radial-gradient(circle at var(--wx) var(--wy),transparent calc(var(--wr) - var(--ww)),#000 var(--wr),transparent calc(var(--wr) + var(--ww)));
  animation:sp-wave var(--wd) cubic-bezier(.25,.6,.3,1) both}
.sp-wave svg{position:absolute;inset:0;display:block;width:100%;height:100%}
@keyframes sp-wave{from{--wr:0px;opacity:1}70%{opacity:.7}to{--wr:var(--wmax);opacity:0}}
.built .sp-wave{opacity:0;transition:opacity var(--dur-slow) var(--ease)}
@media (prefers-reduced-motion: reduce){ .sp-wave{display:none} }

.sp-mark{width:112px;height:112px;overflow:visible;display:block}
.sp-block,.sp-c{transform-box:fill-box}
.sp-block{transform-origin:50% 100%;animation:sp-y calc(380ms * var(--k)) var(--ease) calc(140ms * var(--k)) backwards}
.sp-room{transform-origin:0 50%;animation:sp-x calc(220ms * var(--k)) var(--ease) calc(480ms * var(--k)) backwards}
.sp-stem{transform-origin:50% 0;animation:sp-y calc(200ms * var(--k)) var(--ease) calc(640ms * var(--k)) backwards}
.sp-notch{transform-origin:50% 100%;animation:sp-y calc(220ms * var(--k)) var(--ease) calc(780ms * var(--k)) backwards}
.sp-slot{transform-origin:100% 50%;animation:sp-x calc(200ms * var(--k)) var(--ease) calc(920ms * var(--k)) backwards}
.sp-word{display:grid;justify-items:center;gap:var(--sp-2);transition:opacity var(--dur-fast) var(--ease)}
.sp-word b{display:flex;font-family:var(--f-ui);font-size:28px;font-weight:bold;letter-spacing:.04em;line-height:1;color:var(--accent)}
.sp-word b span{display:inline-block;animation:sp-rise calc(260ms * var(--k)) var(--ease) backwards}
.sp-word small{font-size:14px;color:var(--ink-2);animation:sp-fade calc(300ms * var(--k)) var(--ease) calc(1100ms * var(--k)) backwards}
.sp-load{width:120px;height:2px;border-radius:2px;background:var(--hair);overflow:hidden;
  animation:sp-fade calc(200ms * var(--k)) var(--ease) calc(300ms * var(--k)) backwards}
.sp-load i{display:block;height:100%;background:var(--accent);transform-origin:left;
  animation:sp-x calc(1100ms * var(--k)) var(--ease) calc(300ms * var(--k)) backwards}
.leaving-splash .sp-word,.leaving-splash .sp-load{opacity:0}
@keyframes sp-x{from{transform:scaleX(0)}}
@keyframes sp-y{from{transform:scaleY(0)}}
@keyframes sp-fade{from{opacity:0}}
@media (prefers-reduced-motion: reduce){ .splash *{animation-delay:0s!important} }
@media print{ .splash{display:none} }
