/* Matthew House - one-time guided tour (coach-marks) for the "Display resolution"
   feature. Shown ONCE per user on their next sign-in (see tour.js MHTour.maybeStart).

   The whole overlay is built + positioned in JS (tour.js) and appended to <body>. It
   MUST stay aligned to live targets even while the app applies a root `zoom` (Display
   resolution): tour.js divides every target coordinate by the current zoom, so this CSS
   only styles the pieces - it never assumes an unscaled viewport.

   Visual language matches the first-login coach-mark (scrim + arrow bubble), but the
   highlight is a RECTANGLE ring around the exact target, per request. */

/* Root: fixed, above everything (MudBlazor popovers sit ~1300; the boot splash ~2000).
   pointer-events:none so only the explicit interactive children (panels/bubble) catch. */
.mht{position:fixed;inset:0;z-index:100000;pointer-events:none;font-family:var(--mh-font-body,'Hanken Grotesk',ui-sans-serif,system-ui,sans-serif);}

/* ---- dimming ---- */
/* Four panels box the target on all sides so everything EXCEPT the target rectangle is
   dimmed AND click-blocked (keeps the user on-rails); the target gap stays fully live. */
/* NO backdrop-filter ON THESE FOUR. REMOVED Aug 14 2026 (CEO: "a white line appears
   across the database when I click the User Menu").

   THE FOUR PANELS TILE THE VIEWPORT, so each one is a SEPARATE backdrop root. The top
   and bottom panels are tall; the left and right ones are only as tall as the target
   (54px on the user-menu step). Blurring a 54px strip has almost no backdrop to sample
   vertically, so Chromium clamps the edge pixels and smears them across the whole
   strip - it renders as a flat, lighter wash that does not match the tall panels above
   and below. The result is a bright horizontal band running the full width of the app
   at exactly the target's height. It appeared on EVERY target step, not just this one.

   The dim itself is a flat rgba and tiles seamlessly, so it stays. Only the blur is
   removed, and at 1.5px it was doing almost nothing the .55 dim was not already doing.

   IF THE BLUR IS EVER WANTED BACK it cannot go on these four - it needs ONE
   full-viewport element with the target punched out (clip-path, evenodd), so there is a
   single continuous backdrop root and therefore no seam. .mht-scrim below keeps its
   blur precisely because it IS one full-viewport element. */

/* THE WHITE LINE CAME BACK, AND THE DIM ITSELF WAS THE SECOND CAUSE (CEO, Aug 17 2026:
   "I am getting that white line again"). Removing the blur on Aug 14 fixed one of two
   independent faults. The note above then claimed "the dim itself is a flat rgba and
   tiles seamlessly" - THAT IS NOT TRUE ON A FRACTIONAL EDGE, and it is what was left.

   MEASURED on the live tour rather than reasoned about: left panel bottom 269.5, bottom
   panel top 269.5, gap between them exactly 0 - they abut perfectly, at a HALF pixel.
   Chromium then antialiases that shared row in BOTH panels at ~50% coverage, so instead
   of one solid .55 fill the row composites to roughly .47. Lighter than its neighbours,
   the full width of the viewport. Device pixel ratio was 1, so this is not a HiDPI
   quirk - and the app's root zoom makes fractional edges the normal case, not the rare
   one, because every rect is divided by the zoom before it is written.

   Snapping to integers was rejected: with an arbitrary root zoom and DPR there is no
   rounding that guarantees a whole DEVICE pixel, so it would move the seam rather than
   remove it. TWO TRANSLUCENT FILLS MUST NEVER SHARE AN EDGE - that is the actual rule.

   So the dim is now painted by ONE element, .mht-hole, using a 9999px box-shadow spread
   around the target. One element, one rasterised layer, no shared edge anywhere, at any
   zoom or DPR. The four panels stay for CLICK-BLOCKING only and paint nothing.

   The spread is px, NOT vmax: the app carries a root zoom and bare viewport units are
   banned app-wide for that reason. 9999px clears any real screen.

   .mht-hole is NOT the ring: the ring's mhtpulse keyframes animate box-shadow, so a dim
   parked there would be overwritten on every frame of the pulse. */
.mht-hole{position:fixed;pointer-events:none;
  box-shadow:0 0 0 9999px rgba(18,28,33,.55);}
.mht-panel{position:fixed;background:transparent;pointer-events:auto;
  transition:opacity .18s ease;}
/* Full-screen scrim for message-only steps (welcome / final) - blocks all clicks. */
.mht-scrim{position:fixed;inset:0;background:rgba(18,28,33,.58);pointer-events:auto;
  -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);}

/* ---- rectangle highlight ring around the target (sharp corners, flashing) ---- */
.mht-ring{position:fixed;pointer-events:none;border-radius:0;
  border:2.5px solid #fff;
  box-shadow:0 0 0 2px rgba(78,124,114,.55), 0 0 0 6px rgba(156,198,207,.30), 0 10px 30px rgba(0,0,0,.28);
  animation:mhtpulse 2.2s ease-in-out infinite;}
@keyframes mhtpulse{
  0%,100%{box-shadow:0 0 0 2px rgba(78,124,114,.50), 0 0 0 5px rgba(156,198,207,.22), 0 10px 28px rgba(0,0,0,.26);}
  50%{box-shadow:0 0 0 2px rgba(78,124,114,.75), 0 0 0 9px rgba(156,198,207,.40), 0 12px 34px rgba(0,0,0,.32);}}
body.reduce-motion .mht-ring{animation:none;}

/* ---- speech bubble (arrow + message) ---- */
/* Same floor as .mht-modal below, for the same reason: a 0 token must not collapse
   the bubble to the width of its button. */
.mht-pop{position:fixed;pointer-events:auto;width:300px;max-width:max(240px,calc(calc(100 * var(--mh-vw)) - 28px));
  background:var(--mh-surface,#fff);color:var(--mh-ink,#22303a);
  border:1px solid var(--mh-line,#D9DFE7);border-radius:16px;
  padding:16px 16px 14px;box-shadow:0 18px 48px rgba(20,32,38,.30);
  animation:mhtin .22s ease;}
@keyframes mhtin{from{opacity:0;transform:translateY(6px) scale(.98);}to{opacity:1;transform:none;}}
body.reduce-motion .mht-pop{animation:none;}
.mht-pop .mht-step{font-size:11px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  color:var(--mh-green-d,#4E7C72);margin-bottom:6px;}
.mht-pop .mht-title{font-family:var(--mh-font-head,inherit);font-size:16.5px;font-weight:700;
  color:var(--mh-ink,#22303a);margin-bottom:5px;line-height:1.25;}
.mht-pop .mht-msg{font-size:13.5px;line-height:1.55;color:var(--mh-muted,#5b6a72);}
.mht-pop .mht-row{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:14px;}
.mht-pop .mht-hintline{display:flex;align-items:center;gap:7px;font-size:12.5px;font-weight:700;color:var(--mh-green-d,#4E7C72);}
.mht-pop .mht-hintline svg{width:15px;height:15px;flex:none;}
/* A BUBBLE THAT CARRIES ITS OWN BUTTON (Aug 3 2026, the Program tour's last step).
   space-between above was written for a row holding a hint line AND a button; with a
   button alone it pinned it to the left edge, which reads as unfinished. A row whose
   only child is the button right-aligns it, exactly like the footer of every other
   surface in the app. The hint-line variant is untouched. */
.mht-pop .mht-row:has(> .mht-next:only-child){justify-content:flex-end;}
.mht-pop .mht-next{height:36px;padding:0 18px;font-size:13.5px;}

/* the little diamond arrow; JS sets .up/.down/.left/.right + inline offset */
.mht-arrow{position:absolute;width:16px;height:16px;background:var(--mh-surface,#fff);
  border:1px solid var(--mh-line,#D9DFE7);transform:rotate(45deg);}
.mht-arrow.up{top:-8px;border-right:none;border-bottom:none;}
.mht-arrow.down{bottom:-8px;border-left:none;border-top:none;}
.mht-arrow.left{left:-8px;border-top:none;border-right:none;}
.mht-arrow.right{right:-8px;border-bottom:none;border-left:none;}

/* ---- centered modal card (welcome / final) ---- */
/* THE max() IS A FLOOR, NOT A PREFERENCE (Aug 3 2026). --mh-vw is written by script
   from window.innerWidth; anywhere that reads 0 before the first real resize, the old
   `calc(100 * var(--mh-vw) - 32px)` resolved to 0 and this card collapsed to the width
   of its own button - a 58px column of wrapped text with the button off-screen. A
   floor makes that state merely narrow instead of unusable. Bare vw is still not used:
   the zoom-corrected token remains the source, per the --mh-vw law. */
.mht-modal{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);pointer-events:auto;
  width:440px;max-width:max(300px,calc(calc(100 * var(--mh-vw)) - 32px));background:var(--mh-surface,#fff);color:var(--mh-ink,#22303a);
  border:1px solid var(--mh-line,#D9DFE7);border-radius:22px;padding:30px 28px 24px;text-align:center;
  box-shadow:0 30px 80px rgba(16,26,32,.42);animation:mhtpop .26s cubic-bezier(.34,1.4,.5,1);}
@keyframes mhtpop{from{opacity:0;transform:translate(-50%,-50%) scale(.92);}to{opacity:1;transform:translate(-50%,-50%) scale(1);}}
body.reduce-motion .mht-modal{animation:none;}
.mht-modal .mht-badge{width:64px;height:64px;border-radius:20px;margin:0 auto 16px;display:grid;place-items:center;
  background:linear-gradient(135deg,#6E9B8E,#4E7C72 60%,#3C6258);color:#fff;box-shadow:0 12px 26px rgba(60,98,88,.36);}
.mht-modal .mht-badge svg{width:32px;height:32px;}
.mht-modal .mht-title{font-family:var(--mh-font-head,inherit);font-size:22px;font-weight:700;margin-bottom:9px;line-height:1.25;}
.mht-modal .mht-msg{font-size:14.5px;line-height:1.6;color:var(--mh-muted,#5b6a72);max-width:360px;margin:0 auto;}
.mht-modal .mht-row{justify-content:center;margin-top:22px;display:flex;align-items:center;gap:12px;}

/* ---- buttons ---- */
.mht-next{height:40px;padding:0 22px;border:none;border-radius:11px;cursor:pointer;font:inherit;font-size:14px;font-weight:700;color:#fff;
  background:linear-gradient(135deg,#6E9B8E,#4E7C72 60%,#3C6258);box-shadow:0 8px 18px rgba(60,98,88,.30);transition:filter .14s ease,transform .14s ease;}
.mht-next:hover{filter:brightness(1.06);transform:translateY(-1px);}
.mht-skip{border:none;background:none;cursor:pointer;font:inherit;font-size:12.5px;font-weight:600;color:var(--mh-muted,#8a97a0);padding:6px 4px;}
.mht-skip:hover{color:var(--mh-ink,#22303a);text-decoration:underline;}

/* ---- dark theme ---- */
/* Dark dim moves with it - the panels are transparent in both themes now. */
body.dark .mht-hole{box-shadow:0 0 0 9999px rgba(4,9,12,.66);}
body.dark .mht-panel{background:transparent;}
body.dark .mht-scrim{background:rgba(4,9,12,.68);}
body.dark .mht-pop,body.dark .mht-modal{background:var(--mh-surface,#16211f);border-color:var(--mh-line,#2b3a37);color:var(--mh-ink,#eaf1ee);}
body.dark .mht-arrow{background:var(--mh-surface,#16211f);border-color:var(--mh-line,#2b3a37);}
body.dark .mht-pop .mht-msg,body.dark .mht-modal .mht-msg{color:var(--mh-muted,#9fb0ac);}
body.dark .mht-ring{border-color:#eaf1ee;}

/* SKIP TOUR (CEO, Jul 31 2026). The tour masks the entire app - a full-viewport .mht-scrim on
   modal steps, four .mht-panel masks on target steps - and had no exit on any of them, so the
   only way back to work was to finish all five steps. This is the tour's visible way out, and
   it sits on the tour ROOT (not inside the modal) so it is reachable on target steps too.
   Bottom-LEFT and z-index 100095: bottom-right is the feedback FAB's corner (.fb-fab, z 100091),
   which hit-tested ON TOP of this button and swallowed the only exit the tour has - the exact
   bug being fixed, reintroduced one corner over. Verified by hit test, not by eye. */
.mht-skip{position:fixed;left:22px;bottom:22px;z-index:100095;pointer-events:auto;
  display:inline-flex;align-items:center;gap:8px;padding:9px 18px;border-radius:999px;
  border:1px solid rgba(255,255,255,.34);background:rgba(255,255,255,.14);color:#fff;
  font-family:inherit;font-size:13px;font-weight:700;cursor:pointer;
  -webkit-backdrop-filter:blur(8px) saturate(1.4);backdrop-filter:blur(8px) saturate(1.4);
  transition:background .15s ease,border-color .15s ease,transform .15s ease;}
.mht-skip:hover{background:rgba(255,255,255,.24);border-color:rgba(255,255,255,.5);transform:translateY(-1px);}
.mht-skip:focus-visible{outline:2px solid #fff;outline-offset:3px;}
