/* ============================================================================
   fw-city-mist.css — Ask MIST states + the mobile slide deck on Cité Fluid.

   Loads AFTER fw-world-2.css so it wins specificity ties. Deliberately NOT
   render-blocking: everything it styles is absent or hidden at first paint, so
   it must not join the critical path the Safari FOUC gate protects.

   Surface rules inherited from the page's paper restyle (fw-world-2.css §1, §4,
   §7, §8), not reinvented here:
     · white paper = two procedural noise layers multiplied over #fff
     · buttons: 4px radius, hard 2-3px offset shadow with NO blur, slight tilt
     · one accent only: --wefw2-blue (#42b1ff)
     · district pins are BLACK paper — light type inside them
   Everything new is prefixed we-mist- / we-dmist- / fw2-stage so it can never
   collide with the page's generic class names (bare .ic/.tt have bitten us).

   ── LAYOUT MODEL ────────────────────────────────────────────────────────────
   DESKTOP (§5): Ask MIST is a RIGHT RAIL, not a modal. The city is never
   covered — #scene narrows to `100vw - --mist-rail` and re-frames itself
   (fw-city-mist.js watches it with a ResizeObserver and re-fires the bundle's
   own resize handler).

   MOBILE (§9): the scroll story is a SLIDE DECK. The city is pinned to the top
   of the viewport and the content is a FULL-BLEED bottom stage with a torn top
   edge — no floating tilted cards. Every stage is the same height with content
   top-aligned, and the next stage slides up OVER the previous one. Ask MIST
   opens as a full-screen sheet, then minimises to a bottom tab the moment a
   request is sent so the district labels play over an uncovered city.
   ========================================================================== */

:root {
  /* one number controls the desktop rail AND how far the city shifts */
  --mist-rail: clamp(340px, 27vw, 440px);

  /* Mobile deck. city + stage MUST total 100 and both MUST be dvh: svh would
     leave a strip of bare paper between them whenever iOS collapses the URL
     bar (that strip is the "black showing up behind" in the field report). */
  --fw2-city-h: 52dvh;
  --fw2-stage-h: 48dvh;
  /* MUST be the tear tile's natural 48px. The rag in --tx1..4 spans only ~5 of
     the tile's 48 viewBox units, so squashing the strip squashes the rag with
     it: at 22px it renders as a ~2px wobble, i.e. a straight line. */
  --fw2-tear-h: 48px;
}

/* ---------- 1. Suggestion chips ------------------------------------------- */
/* Sit on the white card under the composer. Same chassis as .control, smaller.
   Hidden until the JS has a pool, so an empty rail never reserves space. */

.we-mist-suggest { margin: 12px 3px 0; text-align: left; }
.we-mist-suggest[hidden] { display: none; }

.we-mist-suggest__label {
  display: block;
  margin-bottom: 8px;
  color: var(--wefw2-ink-3, #6b6a63);
  font-family: var(--wefw2-fl, "FLBold", "Arial Black", sans-serif);
  font-weight: 400;
  font-size: 12px;
  line-height: 1;
  letter-spacing: .05em;
  text-transform: uppercase;
}

.we-mist-suggest__row { display: flex; flex-wrap: wrap; gap: 7px; }

.we-mist-chip {
  max-width: 100%;
  padding: 7px 11px;
  border: 1.5px solid rgba(20, 17, 9, .2);
  border-radius: 4px;
  background: #fff;
  color: #07101a;
  box-shadow: 2px 2px 0 rgba(0, 0, 0, .38);
  font-family: Inter, -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI", sans-serif;
  font-weight: 700;
  font-size: 12px;
  line-height: 1.25;
  letter-spacing: -.01em;
  text-align: left;
  cursor: pointer;
  transform: rotate(-.5deg);
  transition: transform .16s ease, box-shadow .16s ease;
}
.we-mist-chip:nth-child(even) { transform: rotate(.6deg); }
.we-mist-chip:hover,
.we-mist-chip:focus-visible {
  transform: translateY(-2px) rotate(-.5deg);
  box-shadow: 3px 3px 0 rgba(0, 0, 0, .46);
}
.we-mist-chip:nth-child(even):hover,
.we-mist-chip:nth-child(even):focus-visible { transform: translateY(-2px) rotate(.6deg); }

/* a route chip is the kind that lights the city — flag it with the one accent */
.we-mist-chip.is-route { border-color: rgba(66, 177, 255, .55); }
.we-mist-chip.is-route::before {
  content: '';
  display: inline-block;
  width: 6px; height: 6px;
  margin-right: 7px;
  background: var(--wefw2-blue, #42b1ff);
  rotate: 45deg;
  vertical-align: middle;
}

/* ---------- 2. The character counter ------------------------------------- */

.we-mist-count {
  margin-left: auto;
  color: var(--wefw2-ink-3, #6b6a63);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10px;
  letter-spacing: .04em;
  white-space: nowrap;
}
.we-mist-count[hidden] { display: none; }

/* ---------- 3. Answer / thinking / error states -------------------------- */
/* .mist-command-result is black paper (fw-world-2.css:1967). The pulse used to
   animate forever because there was no terminal state; now it only runs while
   we are genuinely waiting, and stops the moment a payload lands. */

.we-mist-result__body { min-width: 0; }
.mist-command-result .we-mist-result__body > strong {
  display: block; font-size: 12px; letter-spacing: .03em;
}

.mist-command-result[data-state='thinking'] .mist-command-result__pulse {
  animation: activity-pulse 1.25s ease-in-out infinite;
}
.mist-command-result[data-state='answer'] .mist-command-result__pulse,
.mist-command-result[data-state='routing'] .mist-command-result__pulse,
.mist-command-result[data-state='error'] .mist-command-result__pulse { animation: none; }
.mist-command-result[data-state='routing'] .mist-command-result__pulse { background: var(--wefw2-blue, #42b1ff); }
.mist-command-result[data-state='error'] .mist-command-result__pulse { background: #e0644f; }

/* the echoed prompt while thinking reads as quoted input, not as an answer */
.mist-command-result[data-state='thinking'] #mist-command-result-copy {
  font-style: italic; opacity: .82;
}

.we-mist-note {
  display: block;
  margin-top: 7px;
  color: #8f98a4;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 9.5px;
  letter-spacing: .05em;
  text-transform: uppercase;
}
.we-mist-note[hidden] { display: none; }

/* ---------- 4. Follow-up chips (inside the black result card) ------------- */

.we-mist-followups { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.we-mist-followups[hidden] { display: none; }

.we-mist-chip--followup {
  padding: 6px 9px;
  border: 1px solid rgba(255, 255, 255, .26);
  background: none;
  color: #e7eaef;
  box-shadow: none;
  font-size: 11px;
  font-weight: 600;
  transform: none;
}
.we-mist-chip--followup:nth-child(even) { transform: none; }
.we-mist-chip--followup:hover,
.we-mist-chip--followup:focus-visible {
  border-color: var(--wefw2-blue, #42b1ff);
  background: rgba(66, 177, 255, .12);
  color: #fff;
  box-shadow: none;
  transform: none;
}
.we-mist-chip--followup:nth-child(even):hover,
.we-mist-chip--followup:nth-child(even):focus-visible { transform: none; }

/* ---------- 5. DESKTOP: Ask MIST as a right rail -------------------------- */
/* a) .mist-command-shell becomes a right-edge column. It KEEPS
      pointer-events:none (fw-world-2.css:589) so the city stays draggable and
      the bundle's `t.target === Je` backdrop-close cannot misfire on padding.
   b) .we-fw2-sh--mist — already pointer-events:auto — is the rail itself.
   c) #scene narrows by exactly the rail width so the city re-centres in the
      visible column. District pins follow for free: the bundle anchors them
      off `#scene.getBoundingClientRect()`. */

.mist-command-shell { place-items: stretch end; padding: 0; }

.we-fw2-sh--mist {
  display: flex;
  flex-direction: column;
  width: var(--mist-rail);
  max-width: 100%;
  height: 100%;
  padding: 86px 18px 24px;
  overflow-y: auto;
  overscroll-behavior: contain;
  transform: translateX(101%);
  transition: transform .34s cubic-bezier(.2, .8, .2, 1);
}
.mist-command-shell.is-open .we-fw2-sh--mist { transform: none; }
/* position:relative is load-bearing — without it #we-mist-close resolves against
   .mist-command-shell (position:fixed, inset 0) and lands in the top-right of the
   VIEWPORT, behind the site nav, instead of the card's own corner. */
.mist-command-card { width: 100%; position: relative; }

/* The topbar spans the full viewport and centres its controls, so with the rail
   open "Reset view" lands on top of the rail — covering #we-mist-close entirely.
   Reserving the rail's width re-centres the controls over the visible city. */
body.mist-command-active .topbar {
  padding-right: var(--mist-rail);
  transition: padding-right .34s cubic-bezier(.2, .8, .2, 1);
}

/* The city is the star now, so stop dimming it. #scene keeps its own
   `transition: filter .28s` from fw-world-2.css:580 — we add width to it. */
#scene { transition: filter .28s ease, width .34s cubic-bezier(.2, .8, .2, 1); }
body.mist-command-active #scene { filter: none; width: calc(100vw - var(--mist-rail)); }

/* Undo the bundle's modal-dodging pin offsets --------------------------------
   fw-world-2.js nudges three districts when the dialog is open (its `Xa` map:
   fairshare [-62,80], droplets [62,80], repapp [0,170]) and hides their pins,
   because the centred modal used to sit on top of them. With a rail there is
   nothing to dodge, so we cancel each nudge with the standalone `translate`
   property — it composes with the bundle's per-frame
   `transform: translate3d(var(--activity-x), var(--activity-y), 0)`, and pure
   translations commute, so this is exact cancellation rather than a fudge. */
body.mist-command-active .district-activity[data-district="fairshare"] { translate: 62px -80px; }
body.mist-command-active .district-activity[data-district="droplets"]  { translate: -62px -80px; }
body.mist-command-active .district-activity[data-district="repapp"]    { translate: 0 -170px; }
body.mist-command-active .district-activity[data-district="fairshare"] .district-activity__pin,
body.mist-command-active .district-activity[data-district="droplets"] .district-activity__pin,
body.mist-command-active .district-activity[data-district="repapp"] .district-activity__pin { display: block; }

/* ---------- 5b. Rail controls: close + minimise -------------------------- */
/* The card had NO close affordance — the only way out was the topbar toggle or
   Escape, and on a full-screen mobile sheet the topbar is covered.
   #we-mist-close forwards to #toggle-mist-command so the bundle's own state
   and aria-pressed stay authoritative. */

.we-mist-close {
  position: absolute;
  z-index: 3;
  top: 12px; right: 12px;
  width: 32px; height: 32px;
  padding: 0;
  display: grid;
  place-items: center;
  border: 1.5px solid rgba(20, 17, 9, .2);
  border-radius: 4px;
  background: #fff;
  color: #07101a;
  box-shadow: 2px 2px 0 rgba(0, 0, 0, .34);
  font: 700 17px/1 Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  cursor: pointer;
  transform: rotate(-1deg);
}
.we-mist-close:hover,
.we-mist-close:focus-visible {
  transform: rotate(-1deg) translateY(-1px);
  box-shadow: 3px 3px 0 rgba(0, 0, 0, .42);
}

/* Mobile-only expand/minimise toggle. The desktop rail never collapses. */
.we-mist-expand { display: none; }

/* ---------- 6. The MIST block inside a district pin ---------------------- */
/* Additive: the live-metric markup stays in the DOM and keeps being updated by
   the bundle's timer. CSS just swaps which half is visible, so normal browsing
   is completely unaffected. */

.we-dmist { display: none; }

.district-activity.is-mist-work { width: 178px; }
.district-activity.is-mist-work .we-dmist { display: block; }
.district-activity.is-mist-work .district-activity__live,
.district-activity.is-mist-work .district-activity__primary,
.district-activity.is-mist-work .district-activity__details { display: none; }

.district-activity.is-mist-work[data-lod='far'] .we-dmist,
.district-activity.is-mist-work[data-lod='medium'] .we-dmist,
.district-activity.is-mist-work[data-lod='detail'] .we-dmist { display: block; }

.we-dmist__label {
  display: block;
  margin: 7px 0 3px;
  color: var(--wefw2-blue, #42b1ff);
  font-family: var(--wefw2-fl, "FLBold", "Arial Black", sans-serif);
  font-weight: 400;
  font-size: 9px;
  line-height: 1;
  letter-spacing: .09em;
  text-transform: uppercase;
}

.we-dmist__head {
  display: block;
  margin-bottom: 6px;
  color: #fff;
  font-family: var(--wefw2-haas, "WeHaas", "Helvetica Neue", sans-serif);
  font-weight: 800;
  font-size: 12px;
  line-height: 1.15;
  letter-spacing: -.015em;
}

.we-dmist__items { margin: 0; padding: 0; list-style: none; display: grid; gap: 4px; }
.we-dmist__items li {
  position: relative;
  padding-left: 9px;
  color: #c2c8d2;
  font-family: var(--wefw2-fl, "FLBold", "Arial Black", sans-serif);
  font-weight: 400;
  font-size: 9.5px;
  line-height: 1.25;
  letter-spacing: .02em;
  opacity: 0;
  animation: we-dmist-in .34s ease forwards;
  animation-delay: calc(var(--i, 0) * 90ms + 130ms);
}
.we-dmist__items li::before {
  content: '';
  position: absolute;
  left: 0; top: 4px;
  width: 4px; height: 4px;
  background: rgba(66, 177, 255, .8);
  rotate: 45deg;
}
@keyframes we-dmist-in {
  from { opacity: 0; transform: translateY(3px); }
  to   { opacity: 1; transform: none; }
}

/* districts MIST is not touching recede, so the lit ones read as the answer */
body.mist-work-active .district-activity:not(.is-mist-work) {
  opacity: .24;
  transition: opacity .3s ease;
}

/* ---------- 7. SDK floating widgets: off on this page -------------------- */
/* The chat + cart bubbles are injected into <body> at runtime by the FairShare
   SDK as <fluid-cart-widget> / <fluid-lead-capture-widget> (light DOM, so CSS
   reaches them). On a full-bleed 3D marketing page they sit on top of the
   content — bottom-right, 60px, margin 16px and 84px 16px.

   Scoped to `html.fw2-site-scroll`, which sections/fluid_world_2 adds during
   parse and NOTHING ever removes (the bundle only strips `fw2-scroll-mode`),
   so this is Cité Fluid only — every other page keeps its cart and chat.
   Hiding the widget UI does not touch the SDK: #fluid-cdn-script still loads
   and rep attribution still runs. There is no add-to-cart on this page. */

html.fw2-site-scroll fluid-cart-widget,
html.fw2-site-scroll fluid-lead-capture-widget,
html.fw2-site-scroll [data-fluid-widget="true"] { display: none !important; }

/* ---------- 8. Reduced motion -------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .we-mist-chip { transition: none; }
  .we-dmist__items li { animation: none; opacity: 1; }
  .mist-command-result[data-state='thinking'] .mist-command-result__pulse { animation: none; }
  body.mist-work-active .district-activity:not(.is-mist-work) { transition: none; }
  .we-fw2-sh--mist { transition: none; }
  #scene { transition: none; }
}

/* ============================================================================
   9. MOBILE — the scroll story as a slide deck
   ============================================================================
   760px matches the page's own story breakpoint (fw-world-2.css:1245 block).

   ⚠ content-visibility is load-bearing here, not a perf tweak.
   `.fw2-scroll-step` ships `content-visibility:auto` +
   `contain-intrinsic-size: auto 94svh` (fw-world-2.css:1132-1133), which:
     1. applies `contain: paint`, making each step A CONTAINING BLOCK FOR FIXED
        DESCENDANTS — a fixed bottom stage would be pinned to the step, not the
        viewport, so the whole deck is impossible while it is on; and
     2. under-estimates the real step height, so the document kept growing as
        the reader scrolled. That is why "Explore Fluid City" felt dead: the
        finale slid out from under the thumb between touchstart and touchend.
   ========================================================================== */

@media (max-width: 760px) {

  /* -- 9a. City pinned to the top ----------------------------------------- */
  /* #scene is fixed inset:0 in scroll mode (fw-world-2.css:948). The ortho
     camera centres the city inside whatever box it gets, so the city reads as
     vertically centred in the window above the paper. fw-city-mist.js re-fires
     the bundle's resize handler when this box changes; without that the
     drawing buffer would stay 100vh tall and the city would render stretched. */
  body.fw2-scroll-mode #scene { inset: 0 0 auto 0; height: var(--fw2-city-h); }

  /* -- 9b. Native scroll snapping ----------------------------------------- */
  /* The bundle snaps chapters from a `wheel` handler — and phones never fire
     `wheel`, so mobile had NO snapping at all: free-scrolling ~13 tall sections
     while a WebGL city repaints. That is the "swipe and it didn't swipe" and
     the choppiness. CSS scroll-snap is driven on the compositor by iOS, so it
     costs no main-thread work. `scroll-snap-stop: always` forbids flinging
     past a slide, which is what made swipes feel non-deterministic. */
  html.fw2-scroll-mode { scroll-snap-type: y mandatory; }

  body.fw2-scroll-mode .fw2-scroll-intro,
  body.fw2-scroll-mode .fw2-scroll-step,
  body.fw2-scroll-mode .fw2-scroll-step[data-side='right'],
  body.fw2-scroll-mode .fw2-scroll-finale {
    display: block;
    height: 100svh;          /* stable spacer — svh so URL-bar motion cannot
                                resize every slide and shift the scroll offset */
    min-height: 100svh;
    padding: 0;
    scroll-snap-align: start;
    scroll-snap-stop: always;
    content-visibility: visible;   /* see the warning above */
    contain-intrinsic-size: none;
  }

  /* -- 9c. The bottom stage ------------------------------------------------ */
  /* Full-bleed, edge to edge, same paper as everything else, always the same
     height. Replaces the floating tilted card. */
  body.fw2-scroll-mode .we-fw2-sh--intro,
  body.fw2-scroll-mode .we-fw2-sh--card,
  body.fw2-scroll-mode .we-fw2-sh--finale {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    width: auto;
    height: var(--fw2-stage-h);
    margin: 0;
    z-index: 8;
    filter: none;              /* drop-shadow is for a floating card, not a wall */
    transform: translateY(100%);
    transition: transform .42s cubic-bezier(.22, .61, .36, 1);
    pointer-events: none;
    visibility: hidden;
  }

  /* Torn top edge, dividing the graphic above from the content below.
     The tear tiles (--tx1..4) are authored solid-on-top / torn-on-bottom, so
     the strip is flipped with scaleY(-1) to put the rag at the TOP. The paper
     is procedural noise, so flipping it is imperceptible. Sits on the wrapper,
     not the card, because the card scrolls its own overflow and would clip it. */
  body.fw2-scroll-mode .we-fw2-sh--intro::before,
  body.fw2-scroll-mode .we-fw2-sh--card::before,
  body.fw2-scroll-mode .we-fw2-sh--finale::before {
    content: '';
    position: absolute;
    left: 0; right: 0;
    top: calc(1px - var(--fw2-tear-h));   /* 1px overlap kills a hairline seam */
    height: var(--fw2-tear-h);
    background:
      var(--pp-speck-w) 0 0/var(--pp-s-size) repeat,
      var(--pp-grain-w) 0 0/var(--pp-g-size) repeat #fff;
    background-blend-mode: multiply, multiply;
    transform: scaleY(-1);
    -webkit-mask-image: var(--wefw2-tile, var(--tx1));
            mask-image: var(--wefw2-tile, var(--tx1));
    -webkit-mask-repeat: repeat-x;  mask-repeat: repeat-x;
    -webkit-mask-size: 300px 48px;  mask-size: 300px 48px;  /* natural tile height */
    -webkit-mask-position: bottom left; mask-position: bottom left;
    pointer-events: none;
  }

  /* Hand-torn variety: the page gives every card its own tile so no two edges
     repeat. The tile var lives on the CARD, which is a child of the wrapper the
     tear is drawn on, so it cannot inherit upward — restate it on the wrapper. */
  body.fw2-scroll-mode .we-fw2-sh--intro  { --wefw2-tile: var(--tx2); }
  body.fw2-scroll-mode .we-fw2-sh--finale { --wefw2-tile: var(--tx4); }
  body.fw2-scroll-mode .fw2-scroll-step:nth-of-type(4n+1) .we-fw2-sh--card { --wefw2-tile: var(--tx1); }
  body.fw2-scroll-mode .fw2-scroll-step:nth-of-type(4n+2) .we-fw2-sh--card { --wefw2-tile: var(--tx3); }
  body.fw2-scroll-mode .fw2-scroll-step:nth-of-type(4n+3) .we-fw2-sh--card { --wefw2-tile: var(--tx2); }
  body.fw2-scroll-mode .fw2-scroll-step:nth-of-type(4n+4) .we-fw2-sh--card { --wefw2-tile: var(--tx4); }

  /* Deck state. fw-city-mist.js sets data-slide on each slide section from an
     IntersectionObserver pinned to the viewport midline, so exactly one slide
     is `current`. Only three stages are ever rendered — the incoming one slides
     up OVER the outgoing one, which is the "swiping to the next section" feel. */
  body.fw2-scroll-mode [data-slide='before'] .we-fw2-sh--intro,
  body.fw2-scroll-mode [data-slide='before'] .we-fw2-sh--card,
  body.fw2-scroll-mode [data-slide='before'] .we-fw2-sh--finale { transform: translateY(0); }

  body.fw2-scroll-mode [data-slide='prev'] .we-fw2-sh--intro,
  body.fw2-scroll-mode [data-slide='prev'] .we-fw2-sh--card,
  body.fw2-scroll-mode [data-slide='prev'] .we-fw2-sh--finale {
    transform: translateY(0); visibility: visible; z-index: 8;
  }

  body.fw2-scroll-mode [data-slide='current'] .we-fw2-sh--intro,
  body.fw2-scroll-mode [data-slide='current'] .we-fw2-sh--card,
  body.fw2-scroll-mode [data-slide='current'] .we-fw2-sh--finale {
    transform: translateY(0); visibility: visible; z-index: 10;
    pointer-events: auto; will-change: transform;
  }

  body.fw2-scroll-mode [data-slide='next'] .we-fw2-sh--intro,
  body.fw2-scroll-mode [data-slide='next'] .we-fw2-sh--card,
  body.fw2-scroll-mode [data-slide='next'] .we-fw2-sh--finale {
    transform: translateY(100%); visibility: visible; z-index: 9;
    will-change: transform;
  }

  /* -- 9d. The card inside the stage -------------------------------------- */
  /* Same height every slide, content top-aligned, no tilt, no floating card
     chrome. Selectors carry an extra class so they outrank
     `.fw2-scroll-step[data-side='left'] .fw2-scroll-card` (0,3,0). */
  body.fw2-scroll-mode .fw2-scroll-step .fw2-scroll-card,
  body.fw2-scroll-mode .fw2-scroll-intro .fw2-scroll-intro__card,
  body.fw2-scroll-mode .fw2-scroll-finale .fw2-scroll-finale__card {
    display: flex;
    flex-direction: column;
    justify-content: flex-start;    /* content at the TOP of the section */
    width: 100%;
    max-width: none;
    height: 100%;
    margin: 0;
    padding: 20px 18px calc(16px + env(safe-area-inset-bottom));
    border: 0;
    border-radius: 0;
    rotate: none;
    opacity: 1;
    transform: none;
    overflow-y: auto;
    overscroll-behavior: contain;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    /* full-bleed: the torn bottom edge is a paper-slip idiom and would only
       clip against the screen edge. The tear now lives on the wrapper's top. */
    -webkit-mask-image: none;
            mask-image: none;
  }

  /* the intro headline is the only block that can outgrow the stage */
  body.fw2-scroll-mode .fw2-scroll-intro h1 { font-size: clamp(26px, 7.4vw, 34px); }
  body.fw2-scroll-mode .fw2-scroll-finale h2 { font-size: clamp(24px, 6.6vw, 32px); }
  body.fw2-scroll-mode .fw2-scroll-card h2 { font-size: clamp(21px, 5.8vw, 26px); }

  /* -- 9d2. Kill the invisible tap-blocker over the CTA -------------------- */
  /* THE "Explore Fluid City does nothing on mobile" BUG.
     fw-world-2.css:958-966 force-hides `.story-panel` in scroll mode, but NOT
     its fixed wrapper `.we-fw2-sh--story` (:1806, mobile override :2051):

         .we-fw2-sh--story{position:fixed;z-index:9;bottom:26px;…}
         @media(max-width:680px){…left:10px;bottom:10px;width:calc(100vw - 20px)}

     `visibility:hidden` on the panel still OCCUPIES LAYOUT, so the wrapper is a
     full-width, ~200px-tall, totally invisible box pinned to the bottom of the
     phone — with pointer-events defaulting to auto.

     Raising the CTA's z-index cannot help: my stages live inside
     `.fw2-scroll-story`, which is `z-index:8` + `isolation:isolate`, so every
     z-index in there is CONFINED to that stacking context. This wrapper is a
     sibling at z-index 9 in the ROOT context, so it outranks the whole subtree.
     The blocker itself has to be neutralised.

     Desktop escapes because the wrapper is only `min(510px, …)` wide on the
     left, while the finale card is centred — the overlap misses the button.

     pointer-events only: no layout or paint change, and it lapses the moment
     `fw2-scroll-mode` is removed, so the real story dialog is untouched. */
  body.fw2-scroll-mode .we-fw2-sh--story { pointer-events: none; }

  /* -- 9e. The exit CTA has to be impossible to miss ----------------------- */
  /* .fw2-scroll-story is pointer-events:none (fw-world-2.css:978) with only
     specific cards opting back in, so state this explicitly rather than
     inheriting. touch-action:manipulation drops the 300ms double-tap-zoom wait
     and 52px is the minimum comfortable target. */
  body.fw2-scroll-mode #fw2-explore-city {
    position: relative;
    z-index: 12;
    pointer-events: auto;
    display: flex;
    width: 100%;
    min-height: 52px;
    margin-top: auto;               /* pinned to the bottom of the stage */
    touch-action: manipulation;
  }

  /* -- 9f. Ask MIST: full-screen sheet ------------------------------------ */
  .mist-command-shell { place-items: stretch; padding: 0; }

  .we-fw2-sh--mist {
    width: 100%;
    height: 100%;
    padding: 0;
    transform: translateY(100%);
  }
  .mist-command-shell.is-open .we-fw2-sh--mist { transform: none; }

  .mist-command-card {
    height: 100%;
    /* clears the fixed site nav + its torn strip; the kicker used to sit
       underneath it */
    padding: calc(env(safe-area-inset-top) + 92px) 16px calc(18px + env(safe-area-inset-bottom));
    border-radius: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-mask-image: none;
            mask-image: none;
    rotate: none;
  }
  .we-mist-close { top: calc(env(safe-area-inset-top) + 62px); right: 14px; }

  /* the sheet covers the city, so let it dim behind — but never narrow it */
  body.mist-command-active:not(.we-mist-min) #scene { filter: brightness(.94) saturate(.96); }
  body.mist-command-active #scene { width: 100vw; }

  /* The six live-metric chips float over the sheet and cover the textarea and
     the suggestion chips. Hide the whole layer while the sheet is up; it comes
     back the moment the sheet minimises, which is when the MIST work labels
     are the point. */
  body.mist-command-active:not(.we-mist-min) .district-activity-layer { display: none; }

  /* -- 9g. Minimised tab (body.we-mist-min) ------------------------------- */
  /* Set the moment a prompt is sent, so the thinking pulse and then the answer
     summary live in a thumb-height tab while the labels play over a completely
     uncovered city. */
  body.we-mist-min .mist-command-shell { place-items: end stretch; }
  body.we-mist-min .we-fw2-sh--mist { height: auto; }
  body.we-mist-min .mist-command-card {
    height: auto;
    padding: 11px 13px calc(11px + env(safe-area-inset-bottom));
  }
  body.we-mist-min .mist-command-kicker,
  body.we-mist-min .mist-command-card > h2,
  body.we-mist-min .mist-command-lede,
  body.we-mist-min .mist-composer,
  body.we-mist-min .we-mist-suggest,
  body.we-mist-min .we-mist-followups,
  body.we-mist-min .we-mist-close { display: none; }
  body.we-mist-min .mist-command-result { margin: 0; }
  body.we-mist-min #mist-command-result-copy {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  /* the whole tab is the expand target while minimised */
  .we-mist-expand {
    display: block;
    position: absolute;
    z-index: 4;
    border: 0;
    background: none;
    cursor: pointer;
    padding: 0;
  }
  body.we-mist-min .we-mist-expand { inset: 0; width: 100%; color: transparent; font-size: 0; }

  /* expanded: a small "minimise" pill so the reader can get back to the city */
  body.mist-command-active:not(.we-mist-min) .we-mist-expand {
    top: calc(env(safe-area-inset-top) + 62px);
    left: 14px;
    width: auto;
    height: 32px;
    padding: 0 11px;
    border: 1.5px solid rgba(20, 17, 9, .2);
    border-radius: 4px;
    background: #fff;
    color: #07101a;
    box-shadow: 2px 2px 0 rgba(0, 0, 0, .34);
    font: 700 11px/1 Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    letter-spacing: -.01em;
  }
  /* Nothing to minimise before a prompt has been sent — fw-city-mist.js owns
     the `hidden` attribute. REQUIRED, not redundant: `display:block` above
     outranks the UA's `[hidden] { display: none }`. */
  .we-mist-expand[hidden] { display: none; }

  /* -- 9h. District labels at 390px --------------------------------------- */
  /* Six anchored panels cannot coexist on a phone, so the ones MIST is not
     touching are removed outright rather than faded. */
  body.mist-work-active .district-activity:not(.is-mist-work) { display: none; }
  .district-activity.is-mist-work { width: 152px; padding: 7px 8px 8px; }
  .we-dmist__head { font-size: 11px; }
  .we-dmist__items li { font-size: 9px; line-height: 1.2; }

  /* -- 9i. Chips ----------------------------------------------------------- */
  .we-mist-suggest__row { gap: 6px; }
  .we-mist-chip { font-size: 11.5px; padding: 6px 9px; }

  /* -- 9j. Reduced motion on the deck -------------------------------------- */
  @media (prefers-reduced-motion: reduce) {
    body.fw2-scroll-mode .we-fw2-sh--intro,
    body.fw2-scroll-mode .we-fw2-sh--card,
    body.fw2-scroll-mode .we-fw2-sh--finale { transition: none; }
  }
}
