/* juris for chambers: the practitioner marketing site (4 pages).

   Shared by /chambers/, /chambers/product/, /chambers/grounding/ and
   /chambers/hosting/. Built on tokens.css + styles.css's band system
   (.band / .bandhead / .h2 / .lede / .steps / .stepcard / .panel / .split /
   .pillcta / .proofband / .faq / .iconrail) rather than a parallel layout: the
   one-off .ch-* layout this page used to carry shipped three desktop-only
   geometry bugs to production, and rebuilding it on the shared primitives is
   what fixed them (docs/DESIGN.md, "Second chambers defect").

   Only what the shared sheet has no vocabulary for lives here: the sub-nav
   across the four pages, and the screenshot frame. */

/* ---- hero ---- */
.ch-hero{max-width:760px; margin:0 auto}
.ch-hero h1{font-size:clamp(2rem,4.4vw,3.2rem)}
.ch-hero .sub{max-width:600px}
.ch-cta-row{display:flex; gap:12px; justify-content:center; flex-wrap:wrap; margin-top:26px}

/* ---- enquiry form ----
   The practitioner funnel. Reuses the existing panel/pillcta system rather than
   introducing a parallel form style, per the second-chambers-defect precedent
   (rebuild on the band system, do not patch a one-off layout). */
.ch-enq{margin-top:28px; text-align:left}
.ch-enq-grid{display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:14px}
.ch-enq-field{display:block; margin-top:14px}
.ch-enq-grid .ch-enq-field{margin-top:0}
.ch-enq-field > span{
  display:block; font-size:.82rem; letter-spacing:.02em;
  color:var(--muted); margin-bottom:6px;
}
.ch-enq-field input, .ch-enq-field textarea{
  width:100%; box-sizing:border-box; font:inherit; font-size:var(--fs-md);
  color:var(--ink); background:var(--canvas);
  border:1px solid var(--hair); border-radius:var(--r-md);
  padding:10px 12px; transition:border-color .18s ease, box-shadow .18s ease;
}
.ch-enq-field textarea{resize:vertical; min-height:76px}
.ch-enq-field input:focus-visible, .ch-enq-field textarea:focus-visible{
  outline:none; border-color:var(--accent);
  box-shadow:0 0 0 3px var(--accent-soft);
}
/* Honeypot: off-screen rather than display:none, because some bots skip hidden
   inputs. Not announced to assistive tech either (aria-hidden on the wrapper). */
.ch-enq-hp{position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden}
.ch-enq-actions{display:flex; align-items:center; gap:14px; flex-wrap:wrap; margin-top:18px}
.ch-enq-actions button{border:0; cursor:pointer; font:inherit}
.ch-enq-actions button[disabled]{opacity:.6; cursor:default}
.ch-enq-status{font-size:.88rem; color:var(--muted)}
@media (max-width:640px){
  .ch-enq-grid{grid-template-columns:1fr; gap:14px}
  .ch-enq-grid .ch-enq-field + .ch-enq-field{margin-top:0}
}

/* ---- sub-nav across the four chambers pages ---- */
.subnav{display:flex; gap:6px; flex-wrap:wrap; align-items:center}
.subnav a{
  font-size:var(--fs-xs); font-weight:500; color:var(--muted); text-decoration:none;
  padding:0 13px; min-height:var(--tap); display:inline-flex; align-items:center;
  border-radius:999px; white-space:nowrap;
}
/* On a phone the four links used to wrap into a column inside .nav-right
   (styles.css keeps that row nowrap, so the sub-nav took the width it was left
   and stacked), overlapping the brand. Now the bar wraps, and the sub-nav is a
   second row of chips that scrolls sideways if it must. Found by the qa/
   harness at 393px on WebKit. */
@media(max-width:860px){
  .navshell .nav{flex-wrap:wrap; row-gap:4px}
  .navshell .nav-right{flex-wrap:wrap; justify-content:flex-end; row-gap:4px}
  .subnav{order:3; flex:1 0 100%; flex-wrap:nowrap; overflow-x:auto; -webkit-overflow-scrolling:touch;
    scrollbar-width:none; margin:0 -20px; padding:0 20px}
  .subnav::-webkit-scrollbar{display:none}
}
.subnav a:hover{color:var(--ink); background:var(--panel-2)}
.subnav a[aria-current="page"]{color:var(--ink); background:var(--panel); box-shadow:var(--shadow-1)}

/* ---- screenshot frame ----
   The captures already carry the app's own flag ribbon along their top edge, so
   the frame stays a plain rounded card and does not fake browser chrome. */
.shot{
  display:block; border-radius:var(--r-xl); overflow:hidden;
  border:1px solid var(--hair); background:var(--panel); box-shadow:var(--shadow-2);
}
.shot img{display:block; width:100%; height:auto}
/* Full-page captures run several thousand pixels tall. Show the top of the
   screen at full width and let the rest fall away, rather than scaling the
   whole thing down until the text is unreadable. */
.shot.crop img{max-height:520px; object-fit:cover; object-position:top center}
.shot.crop-tall img{max-height:760px; object-fit:cover; object-position:top center}
/* Some captures carry their point in one region: a dialog over a dimmed page,
   a member list above half a screen of empty canvas. .focus zooms onto that
   region. The figure sets the crop as fractions of the full image (--cx, --cy
   from the top left, --cw of its width) and the crop's own --ar; the image
   keeps its intrinsic width and height attributes, so nothing shifts on load. */
.shot.focus{position:relative; aspect-ratio:var(--ar)}
.shot.focus img{position:absolute; left:0; top:0; max-width:none; width:calc(100% / var(--cw)); height:auto;
  translate:calc(-100% * var(--cx)) calc(-100% * var(--cy))}

.shotnote{font-size:var(--fs-xs); color:var(--muted); margin:12px 0 0; line-height:1.5}
.shotnote.center{text-align:center}

/* ---- copy above a full-width screenshot ----
   For the wide, dense screens. A five-column Review Grid or a full research
   thread is illegible in the ~560px column a .shotsplit leaves for it, so those
   put their copy above and take the full 1040px wrap instead. */
.shotwide{max-width:720px; margin:0 auto 28px; text-align:center}
.shotwide h3{font-family:var(--font-display); font-weight:400; font-size:clamp(1.25rem,2.4vw,1.6rem); margin:0 0 10px; color:var(--ink)}
.shotwide p{font-size:14.5px; color:var(--muted); margin:0; line-height:1.6}
.shotwide .ch-list{max-width:560px; margin:16px auto 0; text-align:left}
.shotblock + .shotblock{margin-top:56px}

/* ---- copy beside a screenshot, alternating down the page ---- */
.shotsplit{display:grid; grid-template-columns:1fr; gap:26px; align-items:center}
@media(min-width:900px){
  /* The screenshot always takes the wider column. Reordering the copy alone
     would leave a flipped row's screenshot in the narrow 0.85fr track, so the
     track widths swap with it. */
  .shotsplit{grid-template-columns:0.85fr 1.15fr; gap:40px}
  .shotsplit.flip{grid-template-columns:1.15fr 0.85fr}
  .shotsplit.flip .copy{order:2}
}
.shotsplit + .shotsplit{margin-top:56px}
.shotsplit .copy h3{font-family:var(--font-display); font-weight:400; font-size:clamp(1.25rem,2.4vw,1.6rem); margin:0 0 10px; color:var(--ink)}
.shotsplit .copy p{font-size:14.5px; color:var(--muted); margin:0 0 12px; line-height:1.6}
.shotsplit .copy p:last-child{margin-bottom:0}
.shotsplit .copy .eyebrow{margin-bottom:10px}

/* A tight list of what a surface does, under the copy. */
.ch-list{list-style:none; margin:14px 0 0; padding:0}
.ch-list li{position:relative; padding-left:18px; font-size:13.5px; color:var(--muted); line-height:1.55; margin-bottom:7px}
.ch-list li:before{content:""; position:absolute; left:0; top:8px; width:5px; height:5px; border-radius:50%; background:var(--accent); opacity:.75}

/* ---- eval stat cards ---- */
.ch-stats{display:grid; grid-template-columns:repeat(3,1fr); gap:14px}
@media(max-width:820px){ .ch-stats{grid-template-columns:1fr} }
.ch-stat{background:var(--panel); border:1px solid var(--hair); border-radius:var(--r-md); padding:18px 20px}
.ch-stat .v{font-family:var(--font-display); font-weight:400; font-size:34px; line-height:1; color:var(--ink)}
.ch-stat .l{font-size:10.5px; font-weight:700; letter-spacing:.09em; text-transform:uppercase; color:var(--muted); margin-top:8px}
.ch-stat .n{font-size:12.5px; color:var(--faint); margin-top:8px; line-height:1.5}
.ch-proof{max-width:660px; margin:28px auto 0; text-align:center; font-size:14.5px; color:var(--muted); line-height:1.65}

/* ---- accent callout ---- */
.ch-note{display:flex; gap:14px; align-items:flex-start; padding:14px 16px; border-radius:var(--r-md); background:var(--accent-soft); margin-top:14px}
.ch-note .dotv{width:9px; height:9px; border-radius:50%; background:var(--accent); margin-top:6px; flex:none}
.ch-note p{margin:0; font-size:13.5px; line-height:1.55; color:var(--ink)}

/* ---- citation legend (grounding page) ---- */
.ch-legend{display:grid; grid-template-columns:1fr; gap:12px; margin-top:20px}
@media(min-width:760px){ .ch-legend{grid-template-columns:repeat(3,1fr)} }
.ch-legend .row{display:flex; gap:12px; align-items:flex-start; background:var(--panel); border:1px solid var(--hair); border-radius:var(--r-md); padding:16px 18px}
.ch-legend .row p{margin:6px 0 0; font-size:12.5px; color:var(--muted); line-height:1.5}
.ch-legend .row strong{display:block; font-size:13.5px; color:var(--ink); font-weight:600; margin-top:10px}
/* The chips are the real .cite spec from styles.css, not a drawing of it: the
   page claims each state carries its own glyph, so it should show them. */
.ch-legend .cite{margin-bottom:2px}

.steps .panel p:last-child{margin-bottom:0}
.ch-cta{text-align:center}

/* ---- footer note ---- */
.ch-foot-note{font-size:11.5px; color:var(--faint); margin:10px 0 0}


/* ==================================================================
   MOTION
   ==================================================================
   Everything below was added in the eighth pass, mapping novera.framer.ai's
   motion design onto our own tokens. The reference's values were read out of
   its shipped Framer config rather than guessed, so the durations, distances
   and delay ladder here are its actual numbers.

   One thing the reference does that we deliberately do not: it ships with its
   reduced-motion flag set to false, so it animates regardless. Ours degrades
   properly, and so does the JavaScript-off case, which matters more here
   because these pages are authored to be complete without script. */

/* A second easing, scoped to these pages. tokens.css keeps --ease for short UI
   feedback (a hover, an :active press) and states the rule as one easing. An
   entrance running for a full second needs a far longer tail than a 200ms
   button press: reusing --ease at that duration reads as sluggish rather than
   smooth. Two curves, each with a stated job, is the smallest honest change. */
:root{ --ease-long:cubic-bezier(.12,.23,.17,.99) }

/* ---- scroll reveal ----
   The hidden start state is scoped to .js-motion, which chambers-motion.js
   puts on <html> only when it is actually going to animate. This is not
   defensive habit, it is load bearing twice over:

   1. styles.css:323 kills every transition under prefers-reduced-motion with
      `*{transition:none!important}`. It cannot undo an opacity:0 start state,
      so an unscoped rule here would leave those users on a blank page.
   2. If the script fails to load, these pages currently still render complete.
      An unscoped rule would silently turn that into a blank page too.

   Both cases resolve the same way: no class, no hidden state. */
.js-motion [data-reveal]{
  opacity:0; transform:translateY(40px); will-change:transform, opacity;
  transition:opacity 1s var(--ease-long), transform 1s var(--ease-long);
  transition-delay:var(--d, 0s);
}
.js-motion [data-reveal].in{opacity:1; transform:none; will-change:auto}

/* Shorter travel for items that reveal inside an already-revealed block. */
.js-motion [data-reveal="sm"]{transform:translateY(24px)}
.js-motion [data-reveal="lg"]{transform:translateY(48px)}

/* ---- scroll-linked helpers ----
   The script writes custom properties and never touches style.transform, so a
   drift value can never blow away a CSS transform that is also carrying a
   centring translate, a rotation or a hover lift. Anything with its own
   transform (the hero layers below) folds var(--py) into its own chain
   instead, and wins on source order. */
[data-parallax]{transform:translate3d(0,var(--py,0px),0)}
[data-slide]{transform:translate3d(var(--sx,0px),0,0); opacity:var(--sop,1)}

/* The stagger is a delay ladder authored in the markup as `style="--d:.2s"`,
   not a JS loop. The observer only ever adds .in, so the rhythm of a section
   stays readable and editable in the HTML next to the content it belongs to.
   The reference's ladder is eyebrow 0, heading .2s, subcopy .4s, and grid
   children 0 / .2s / .4s. */

/* Belt and braces. If .js-motion is ever set while reduced motion is on, this
   guarantees nothing is left invisible. The guard test asserts this rule
   exists so the trap above cannot quietly regress. */
@media (prefers-reduced-motion: reduce){
  .js-motion [data-reveal],
  .js-motion [data-reveal].in{opacity:1; transform:none; transition:none}
}


/* ==================================================================
   SECTION HEADS, LEFT ALIGNED
   ==================================================================
   styles.css centres .bandhead for the citizen surface, where a short marketing
   line over a photograph wants to be centred. These pages are long-form and
   editorial, and the reference's flush-left eyebrow, heading and subcopy is
   most of why it reads as organised rather than as a stack of cards.

   Overriding here rather than in styles.css keeps the change to the four
   chambers pages: this sheet is only linked by them, and it loads last. */
.bandhead{max-width:640px; margin:0 0 36px; text-align:left}

/* The eyebrow is a plain line of muted, sentence-case text. It used to carry a
   terracotta lozenge; the shape meant nothing and read as template decoration,
   so it went, and the per-section labels above headings that already name
   their section went with it (2026-09-25). What remains is the hero line on
   each page and two feature names on the product page. */
.eyebrow{
  display:block; font-size:var(--fs-sm); font-weight:500; letter-spacing:0; text-transform:none;
  color:var(--muted); margin-bottom:14px;
}

/* Visually hidden but still read aloud. The live hero types its question into
   an aria-hidden span one character at a time, which is nonsense to a screen
   reader, so the real sentence is carried here instead. Clip rather than
   display:none, because display:none also removes it from the a11y tree. */
.ch-sr{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); clip-path:inset(50%);
  white-space:nowrap; border:0;
}


/* ==================================================================
   NAV, THREE CANDIDATES
   ==================================================================
   Toggled on body[data-cnav] for the bake-off. `static` is what these pages
   ship today. */
.navshell{position:relative; z-index:40}
.navcta{display:none; padding:0 15px; min-height:var(--tap); align-items:center; font-size:var(--fs-xs)}
@media(min-width:760px){ .navcta{display:inline-flex} }

/* condense: the bar stays in flow but gains a blur, a hairline and a slight
   tightening once you leave the hero. */
body[data-cnav="condense"] .navshell{
  position:sticky; top:0;
  transition:background .4s var(--ease-long), box-shadow .4s var(--ease-long);
}
body[data-cnav="condense"] .navshell .nav{transition:padding .4s var(--ease-long)}
body[data-cnav="condense"][data-scrolled] .navshell{
  background:color-mix(in srgb, var(--canvas) 82%, transparent);
  backdrop-filter:blur(14px) saturate(1.3); -webkit-backdrop-filter:blur(14px) saturate(1.3);
  box-shadow:0 1px 0 var(--hair);
}
body[data-cnav="condense"][data-scrolled] .navshell .nav{padding:11px 0}

/* float: the bar detaches into a rounded pill sitting over the content. */
body[data-cnav="float"] .navshell{position:fixed; top:14px; left:0; right:0}
body[data-cnav="float"] .navshell .wrap{max-width:1100px}
body[data-cnav="float"] .navshell .nav{
  padding:9px 10px 9px 18px; border-radius:var(--r-pill);
  background:color-mix(in srgb, var(--canvas) 74%, transparent);
  backdrop-filter:blur(16px) saturate(1.35); -webkit-backdrop-filter:blur(16px) saturate(1.35);
  border:1px solid var(--hair);
  transition:box-shadow .4s var(--ease-long), background .4s var(--ease-long);
}
body[data-cnav="float"][data-scrolled] .navshell .nav{
  background:color-mix(in srgb, var(--canvas) 90%, transparent);
  box-shadow:var(--shadow-2);
}
/* The fixed bar is out of flow, so the first section has to make its own room. */
body[data-cnav="float"] main{padding-top:74px}
body[data-cnav="float"][data-chero="photo"] main{padding-top:0}


/* ==================================================================
   HERO, FIVE CANDIDATES
   ==================================================================
   All five share one copy block, so the headline exists exactly once and the
   word splitter, the i18n walker and the reveal ladder each have a single
   target. The variants differ in what sits around and beneath it. */
.ch-hero{position:relative; padding:56px 0 44px; text-align:left; max-width:none; margin:0}
/* width:100% matters twice over. It keeps .wrap's own max-width and auto
   margins doing the centring, and under the photo variant the hero is a flex
   column, where a child with auto cross-axis margins does not stretch: without
   an explicit width it shrink-to-fits its text and then centres itself. */
.ch-hero-copy, .ch-hero-stage{position:relative; z-index:2; width:100%}
.ch-hero h1{font-size:clamp(2rem,4.4vw,3.2rem); margin:0; max-width:15ch}
.ch-hero .sub{margin:20px 0 0; max-width:52ch}
.ch-cta-row{justify-content:flex-start; margin-top:28px}

/* Per-word and per-line entrance. The reference splits its headline into one
   span per word and its subcopy into lines, each arriving from a small blur and
   lift. chambers-motion.js writes the spans and rebuilds them after every
   language switch, because chambers.js restores innerHTML wholesale. */
.js-motion .ch-hero h1 .w,
.js-motion .ch-hero .sub .w{
  display:inline-block; opacity:.001; filter:blur(4px); transform:translateY(12px);
  transition:opacity .8s var(--ease-long), filter .8s var(--ease-long), transform .8s var(--ease-long);
  transition-delay:var(--d, 0s);
}
.js-motion .ch-hero .sub .w{filter:blur(10px); transform:translateY(20px); transition-duration:.7s}
.js-motion .ch-hero h1.in .w,
.js-motion .ch-hero .sub.in .w{opacity:1; filter:blur(0); transform:none}
@media (prefers-reduced-motion: reduce){
  .js-motion .ch-hero h1 .w,
  .js-motion .ch-hero .sub .w{opacity:1; filter:none; transform:none; transition:none}
}

/* Only the selected variant renders, and only its images are ever fetched. */
.chv{display:none; position:relative}
body[data-chero="layers"] .chv-layers,
body[data-chero="frame"]  .chv-frame,
body[data-chero="live"]   .chv-live,
body[data-chero="text"]   .chv-text{display:block}

/* ---- A: layers ---- */
.chv-layers{max-width:1000px; margin:44px auto 0; height:clamp(300px,40vw,480px)}
.cl{
  position:absolute; left:50%; top:0; width:76%;
  border-radius:var(--r-lg); overflow:hidden;
  border:1px solid var(--hair); background:var(--panel); box-shadow:var(--shadow-2);
  transform-origin:50% 18%;
  /* Order matters. The centring and drift translates sit before the rotate, so
     the cards move in screen space rather than along their own tilted axes.
     --py is the scroll parallax and --mx/--my the pointer drift, both written
     as custom properties by chambers-motion.js so they compose with the
     rotation and scale instead of replacing them. */
  transform:
    translate(-50%,0)
    translate3d(var(--mx,0px), calc(var(--py,0px) + var(--my,0px)), 0)
    translate(var(--tx), var(--ty))
    rotate(var(--rz))
    scale(var(--sc));
  transition:transform .5s var(--ease-long);
}
.cl img{display:block; width:100%; height:auto; max-height:420px; object-fit:cover; object-position:top center}
.cl-front{z-index:3} .cl-mid{z-index:2} .cl-back{z-index:1}
.cl-back, .cl-mid{filter:saturate(.92) brightness(1.02)}
.cl-back:after, .cl-mid:after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(180deg, rgba(245,239,230,.16), rgba(245,239,230,.5));
}

/* ---- B: frame ---- */
.chv-frame{max-width:1000px; margin:44px auto 0}
.cf-glow{
  position:absolute; inset:-9% -7% -16%; z-index:0; border-radius:44px; pointer-events:none;
  background:
    radial-gradient(58% 58% at 50% 26%, rgba(209,118,44,.30), transparent 72%),
    radial-gradient(70% 50% at 50% 90%, rgba(90,94,51,.16), transparent 74%);
  filter:blur(34px);
}
.cf-shot{
  position:relative; z-index:1; margin:0; overflow:hidden;
  border-radius:var(--r-xl); border:1px solid var(--hair);
  background:var(--panel); box-shadow:var(--shadow-2);
}
.cf-shot img{display:block; width:100%; height:auto; max-height:520px; object-fit:cover; object-position:top center}

/* ---- C: live ---- */
.chv-live{max-width:660px; margin:44px auto 0}
.cv-card{
  border-radius:var(--r-xl); overflow:hidden; background:var(--panel);
  border:1px solid var(--hair); box-shadow:var(--shadow-2);
}
.cv-pad{padding:24px 26px 26px}
.cv-label{font-size:10.5px; font-weight:700; letter-spacing:.09em; text-transform:uppercase; color:var(--faint); margin:0 0 8px}
.cv-q{font-family:var(--font-display); font-size:19px; line-height:1.35; color:var(--ink); margin:0 0 18px; min-height:2.7em}
/* Hidden by default: the caret means "a cursor is typing here", and without the
   typing script that is a lie sitting next to a finished sentence. */
.cv-caret{
  display:none; width:2px; height:1em; margin-left:2px; vertical-align:-.12em;
  background:var(--accent); animation:cvblink 1s steps(1) infinite;
}
.js-motion .cv-caret{display:inline-block}
@keyframes cvblink{50%{opacity:0}}
.cv-a{font-size:14.5px; line-height:1.6; color:var(--muted); margin:0 0 14px}
.cv-chips{display:flex; flex-wrap:wrap; gap:7px}
/* `live` won the bake-off and is now the shipping hero, so the hidden start
   state moved behind .js-motion exactly as the note that stood here required.
   Without script, under reduced motion, or on an engine without
   IntersectionObserver, nothing is hidden and the card renders complete: the
   question is authored in the markup and the answer and its citations are
   visible. That matters more here than anywhere else on the site, because this
   card IS the claim that every answer cites a real source, and an empty card
   under the caption "the Act, the judgment and the article are real" argues
   against the product. Locked by tests/test_frontend_static_guards.py. */
.js-motion .cv-a, .js-motion .cv-chips .cite{
  opacity:0; transform:translateY(8px);
  transition:opacity .5s var(--ease-long), transform .5s var(--ease-long);
  transition-delay:calc(var(--i, 0) * 130ms);
}
.js-motion .cv-answer.in .cv-a, .js-motion .cv-answer.in .cite{opacity:1; transform:none}

/* ---- E: photo, the reference's own hero ----
   Full bleed image, the copy hugging the bottom left under a scrim that is
   invisible at the top and full at the bottom, so the text always lands on the
   darkest part of the picture whatever the crop does. */
.chp-bg{display:none}
body[data-chero="photo"] .chp-bg{display:block; position:absolute; inset:0; overflow:hidden; z-index:0}
/* The photograph runs to the very top and the bar sits over it, which is what
   makes this read as a hero rather than as a picture pasted under a header.
   Taking the nav out of flow is what lets the hero start at y=0, so this rule
   deliberately overrides whichever nav variant is selected. */
body[data-chero="photo"] .navshell{position:absolute; top:0; left:0; right:0; background:none; box-shadow:none}
body[data-chero="photo"] .navshell .nav{background:none; border:0; box-shadow:none}
body[data-chero="photo"] .navshell .brand,
body[data-chero="photo"] .navshell .navlink,
body[data-chero="photo"] .navshell .subnav a{color:#F2EADD}
body[data-chero="photo"] .navshell .subnav a[aria-current="page"]{background:rgba(242,234,221,.16); box-shadow:none}
body[data-chero="photo"] .navshell .langs{background:rgba(242,234,221,.14); border-color:rgba(242,234,221,.2); box-shadow:none}
body[data-chero="photo"] .navshell .lang{color:rgba(242,234,221,.75)}
body[data-chero="photo"] .navshell .lang.active{background:#F2EADD; color:var(--ink)}
body[data-chero="photo"] .ch-hero{
  min-height:100svh; display:flex; flex-direction:column; justify-content:flex-end;
  padding:0 0 64px;
}
body[data-chero="photo"] .ch-hero-stage{display:none}
body[data-chero="photo"] .ch-hero h1{color:#F2EADD}
/* No max-width or margin here: .ch-hero-copy is a .wrap, and constraining it
   would re-centre the whole column inside the page. The headline and subcopy
   carry their own measure, so the copy stays flush with the nav's left edge. */
body[data-chero="photo"] .ch-hero .sub{color:rgba(242,234,221,.84); max-width:44ch}
body[data-chero="photo"] .ch-hero .eyebrow{color:rgba(242,234,221,.82)}
.chp-img{
  position:absolute; inset:0; display:block;
  background-image:url("/img/hero-mauritius.jpg");
  background-size:cover; background-position:center 58%;
  transform:scale(1.05);
  animation:chpsettle 2s var(--ease-long) forwards;
}
/* Same image-set upgrade styles.css uses, but with an absolute path: this sheet
   lives at /chambers/, so a relative url() would resolve to /chambers/img/. */
@supports (background-image: image-set(url("/img/hero-mauritius.webp") type("image/webp"))){
  .chp-img{ background-image:image-set(url("/img/hero-mauritius.webp") type("image/webp"), url("/img/hero-mauritius.jpg") type("image/jpeg")); }
}
@keyframes chpsettle{from{transform:scale(1.05)} to{transform:scale(1)}}
/* Bottom-weighted, and weighted harder than it looks like it needs to be. The
   only photograph we own is a bright turquoise lagoon, so pale display type
   over its lower third fails contrast at anything gentler. The top stays light
   enough that the picture still reads as a picture. */
.chp-scrim{
  position:absolute; inset:0; display:block;
  background:linear-gradient(180deg,
    rgba(10,9,5,.34) 0%, rgba(10,9,5,.30) 28%, rgba(10,9,5,.56) 58%,
    rgba(10,9,5,.80) 82%, rgba(10,9,5,.90) 100%);
}
@media(max-width:640px){
  .chp-scrim{background:linear-gradient(180deg, rgba(10,9,5,.45) 0%, rgba(10,9,5,.62) 40%, rgba(10,9,5,.92) 100%)}
}


/* ==================================================================
   SCREENSHOT BACKDROP, FOUR CANDIDATES
   ==================================================================
   .shotstage wraps an existing .shot without changing it, so the winning
   treatment can later be swapped for real photography by editing background
   values here and touching no markup at all. */
.shotstage{position:relative; border-radius:26px; padding:clamp(12px,2.6vw,30px); isolation:isolate}
.shotstage > .shot, .shotstage > .sc-shot{position:relative; z-index:1}

/* paint: a warm canvas built entirely in CSS. Four gradient washes for the
   pigment, one fine turbulence for paper tooth and one coarse low-frequency
   turbulence for the uneven brush, both desaturated and multiplied so they
   darken the wash without adding a hue the palette does not have.

   This is a simulation. The reference's warmth comes from art-directed
   photography and there is no CSS anywhere in its stylesheet doing this; real
   images are being sourced separately, and this rule is where they land. */
body[data-cbd="paint"] .shotstage{
  border:1px solid rgba(36,30,20,.07);
  background:
    radial-gradient(120% 90% at 12% 4%,    rgba(209,118,44,.16), transparent 58%),
    radial-gradient(100% 80% at 88% 0%,    rgba(90,94,51,.13),   transparent 62%),
    radial-gradient(140% 120% at 50% 118%, rgba(36,30,20,.10),   transparent 64%),
    linear-gradient(168deg, #F2E7D8 0%, #EADFCF 42%, #E3D6C4 74%, #DBCCB7 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.55), inset 0 -1px 0 rgba(36,30,20,.06);
}
body[data-cbd="paint"] .shotstage:before,
body[data-cbd="paint"] .shotstage:after{
  content:""; position:absolute; inset:0; z-index:0;
  border-radius:inherit; pointer-events:none; mix-blend-mode:multiply;
}
body[data-cbd="paint"] .shotstage:before{
  opacity:.40; background-size:220px 220px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23g)' opacity='0.55'/%3E%3C/svg%3E");
}
body[data-cbd="paint"] .shotstage:after{
  opacity:.28; background-size:560px 560px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='560' height='560'%3E%3Cfilter id='w'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.011 0.019' numOctaves='3' seed='7' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='560' height='560' filter='url(%23w)'/%3E%3C/svg%3E");
}

/* photo: the one photographic asset we own, blurred hard enough to read as
   texture rather than as a picture of a mountain. */
body[data-cbd="photo"] .shotstage{overflow:hidden; border:1px solid rgba(36,30,20,.07)}
body[data-cbd="photo"] .shotstage:before{
  content:""; position:absolute; inset:-12%; z-index:0;
  background-image:url("/img/hero-mauritius.jpg");
  background-size:cover; background-position:center 58%;
  filter:blur(26px) saturate(1.1) sepia(.30) brightness(1.06) contrast(.9);
}
@supports (background-image: image-set(url("/img/hero-mauritius.webp") type("image/webp"))){
  body[data-cbd="photo"] .shotstage:before{
    background-image:image-set(url("/img/hero-mauritius.webp") type("image/webp"), url("/img/hero-mauritius.jpg") type("image/jpeg"));
  }
}
body[data-cbd="photo"] .shotstage:after{
  content:""; position:absolute; inset:0; z-index:0; border-radius:inherit;
  background:linear-gradient(180deg, rgba(245,239,230,.5), rgba(245,239,230,.78));
}

/* wash: a terracotta bloom fading into the band. No asset, no noise. */
body[data-cbd="wash"] .shotstage{
  border:1px solid var(--hair);
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--accent) 9%, var(--canvas)) 0%,
    var(--panel-2) 100%);
}

/* clean: today's look, the frame on bare canvas. */
body[data-cbd="clean"] .shotstage{padding:0; background:none; border:0; box-shadow:none}
body[data-cbd="clean"] .shotstage:before,
body[data-cbd="clean"] .shotstage:after{display:none}

/* The frames themselves lift very slightly on hover. The reference has no
   hover state on its imagery at all; a small one reads as responsive without
   turning the page into a set of buttons. */
.shot{transition:transform .35s var(--ease-long), box-shadow .35s var(--ease-long)}



/* ==================================================================
   SCROLL-PINNED SHOWCASE
   ==================================================================
   Six screenshots stacked in one frame on the left, a sticky rail of six steps
   on the right. As each sentinel band crosses the viewport midline its step
   opens and the previous one closes, reversibly, exactly one at a time.

   Everything outside the pin media query is the fallback, and it is also what
   a phone, a reduced-motion visitor and a visitor with JavaScript off get: a
   plain stacked list with every step readable. */
/* position:relative is load bearing: the sentinel bands are absolutely
   positioned and must resolve against the runway, not against the viewport.
   Without it every band sat near the top of the document and the active index
   pinned to the last step the moment you scrolled at all. */
.sc-pin{position:relative}
.sc-grid{display:grid; grid-template-columns:1fr; gap:26px}
.sc-track{display:none}
.sc-frame{margin:0}
.sc-shot{position:relative; margin:0; border-radius:var(--r-lg); overflow:hidden;
  border:1px solid var(--hair); background:var(--panel); box-shadow:var(--shadow-2)}
.sc-shot + .sc-shot{margin-top:14px}
.sc-shot img{display:block; width:100%; height:auto; max-height:420px; object-fit:cover; object-position:top center}

.sc-steps{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:8px}
/* White on the tan band. The reference uses tan cards on a light page; ours
   sits in a .band.alt, which is already tan, so taking the card the other way
   is what keeps the rows readable as cards at all. */
.sc-step{background:var(--panel); border-radius:var(--r-md); overflow:hidden;
  border:1px solid transparent; transition:background .4s var(--ease-long), border-color .4s var(--ease-long)}
.sc-step:hover{background:#fff; border-color:var(--hair)}
.sc-step.open{border-color:var(--hair); box-shadow:var(--shadow-1)}
.sc-head{display:flex; align-items:center; gap:12px; padding:15px 16px; cursor:pointer;
  text-decoration:none; color:var(--ink)}
.sc-n{font-size:var(--fs-xs); font-weight:700; letter-spacing:.06em; color:var(--accent-ink); flex:none}
.sc-t{font-family:var(--font-display); font-size:16.5px; flex:1}
.sc-ic{position:relative; width:16px; height:16px; flex:none; color:var(--muted);
  transition:transform .4s var(--ease-long)}
.sc-ic:before, .sc-ic:after{content:""; position:absolute; left:50%; top:50%; background:currentColor}
.sc-ic:before{width:11px; height:1.5px; margin:-.75px 0 0 -5.5px}
.sc-ic:after{width:1.5px; height:11px; margin:-5.5px 0 0 -.75px}
.sc-step.open .sc-ic{transform:rotate(45deg)}
.sc-body{padding:0 16px 15px}
.sc-body p{margin:0; font-size:13.5px; line-height:1.6; color:var(--muted)}

@media(min-width:900px){
  /* height:auto does not interpolate; 0fr to 1fr does. Collapsed only under
     .js-motion so an engine that cannot interpolate fr units, or a visitor
     without script, sees all six paragraphs rather than none. */
  .js-motion .sc-body{display:grid; grid-template-rows:1fr; padding:0 16px;
    transition:grid-template-rows .42s var(--ease-long), opacity .3s var(--ease-long), padding .42s var(--ease-long)}
  .js-motion .sc-body > *{overflow:hidden; min-height:0}
  .js-motion .sc-step:not(.open) .sc-body{grid-template-rows:0fr; opacity:0; padding-bottom:0}
  .js-motion .sc-step.open .sc-body{padding-bottom:15px}

  .js-motion .sc-pin{height:calc(100vh + var(--sc-n, 6) * var(--sc-step-h, 58vh))}
  /* min-height plus centring rather than height:100vh, so a 1280x720 laptop
     does not clip the sixth step off the bottom of the pinned stage. */
  .js-motion .sc-stage{position:sticky; top:0; min-height:100svh; display:flex; align-items:center}
  /* The visual carries the section, so it takes the larger share of the row and
     the stage padding tightens to give it back some width. */
  .js-motion .sc-grid{grid-template-columns:1.28fr .72fr; gap:48px; align-items:center; width:100%}
  .js-motion .sc-shot{position:absolute; inset:0; opacity:0; transform:scale(1.03);
    transition:opacity .5s var(--ease-long), transform .8s var(--ease-long)}
  .js-motion .sc-shot + .sc-shot{margin-top:0}
  .js-motion .sc-shot.current{opacity:1; transform:none}
  .js-motion .sc-shot img{height:100%; max-height:none}
  .js-motion .sc-visual{position:relative; aspect-ratio:1760/1200; max-height:min(68vh,580px)}
  .js-motion .sc-frame{position:absolute; inset:0; padding:clamp(10px,1.4vw,18px)}

  /* Sentinels: full-height bands, one per step, stacked down the runway. */
  .js-motion .sc-track{display:block; position:absolute; inset:0; opacity:0; pointer-events:none}
  .js-motion .sc-track i{position:absolute; left:0; right:0; display:block;
    height:var(--sc-step-h,58vh); top:calc(50vh + var(--k) * var(--sc-step-h,58vh))}
  /* The anchor target must land where the band starts, not at the page top. */
  .js-motion .sc-track i{scroll-margin-top:50vh}
}

/* The pinned stage is only as tall as heading plus showcase, not a full
   viewport. A 100svh stage centring its content left half a screen of empty
   band under the section heading on a tall monitor. The heading now sits inside
   the stage (see the pages), and centring moves to the sticky offset: the block
   holds mid-viewport, never higher than just under the sticky nav. --sc-half is
   about half the block; the page sets it (six steps make chambers taller). */
@media(min-width:900px){
  .js-motion .sc-stage{min-height:0; flex-direction:column; align-items:stretch;
    top:max(72px, calc(50vh - var(--sc-half, 300px)))}
  /* A .wrap with auto margins in a flex column shrinks to fit and centres; the
     same trap as the photo hero above. */
  .js-motion .sc-stage > .wrap{width:100%}
  .sc-stage .bandhead{margin-bottom:24px}
}
/* A short laptop screen (1280x720) cannot hold heading, lede, screenshot and a
   six-step rail at once; the lede is the line that can go. */
@media(min-width:900px) and (max-height:780px){
  .js-motion .sc-stage .bandhead .lede{display:none}
  .js-motion .sc-stage .bandhead{margin-bottom:16px}
}


/* ==================================================================
   COURT HIERARCHY
   ==================================================================
   The Mauritian courts as a tree, top of the system first, drawn when it
   scrolls in: each tier's connector grows down from the tier above, then its
   courts rise in, then chambers-courts.js counts each court's judgments up from
   the live index. The hidden start state is scoped to html.js-motion, so
   JavaScript off, reduced motion and a missing IntersectionObserver all render
   the finished tree. The counts are never in the markup. */
.ct{--gap:14px; --drop:26px; --ease-draw:cubic-bezier(.12,.23,.17,.99)}
.ct-tree{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; align-items:center}
.ct-tier{position:relative; display:grid; width:100%; gap:var(--gap);
  grid-template-columns:repeat(var(--n), minmax(0, 1fr)); padding-top:calc(var(--drop) * 2)}
.ct-tier:first-child{padding-top:0}
/* Narrow tiers stay narrow, so the tree reads as a tree and not a table. */
.ct-tier[style*="--n:1"]{max-width:340px}
.ct-tier[style*="--n:2"]{max-width:620px}

/* The spine from the tier above, and the bar the tier's courts hang from. */
.ct-tier:not(:first-child):before{content:""; position:absolute; top:0; left:50%;
  width:1px; height:var(--drop); background:var(--muted); opacity:.45;
  transform-origin:top}
.ct-tier:not(:first-child):after{content:""; position:absolute; top:var(--drop); height:1px;
  left:calc((100% - (var(--n) - 1) * var(--gap)) / var(--n) / 2);
  right:calc((100% - (var(--n) - 1) * var(--gap)) / var(--n) / 2);
  background:var(--muted); opacity:.45; transform-origin:center}
.ct-tier:not(:first-child) > .ct-node:before{content:""; position:absolute; bottom:100%; left:50%;
  width:1px; height:var(--drop); background:var(--muted); opacity:.45; transform-origin:top}

.ct-node{position:relative; display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:4px; min-height:84px; padding:16px 14px; text-align:center;
  background:var(--panel); border:1px solid var(--hair); border-radius:var(--r-lg)}
.ct-top{border-color:color-mix(in srgb, var(--accent) 40%, var(--hair)); box-shadow:var(--shadow-1)}
.ct-name{font-family:var(--font-display); font-size:17px; line-height:1.25; color:var(--ink)}
.ct-n{font-size:var(--fs-sm); color:var(--accent-ink); font-variant-numeric:tabular-nums; font-weight:600}
.ct-n:empty{display:none}
.ct-sub{font-size:var(--fs-xs); line-height:1.5; color:var(--muted); max-width:46ch}

.ct-side{display:grid; gap:var(--gap); grid-template-columns:1fr; margin-top:calc(var(--drop) * 1.5);
  padding-top:calc(var(--drop) * 1.5); border-top:1px dashed var(--hair)}
@media(min-width:760px){ .ct-side{grid-template-columns:1fr 1fr} }
.ct-wide{min-height:0; padding:18px 20px}
.ct-law{background:var(--panel-2)}
.ct-note{margin:18px 0 0; text-align:center; font-size:var(--fs-xs); color:var(--faint)}

/* Phones: four courts across do not fit, and connectors to a wrapped row would
   point at the wrong boxes, so the bars go and a single spine remains. */
@media(max-width:699px){
  .ct-tier{grid-template-columns:1fr 1fr}
  .ct-tier[style*="--n:1"]{grid-template-columns:1fr}
  .ct-tier:not(:first-child):after,
  .ct-tier:not(:first-child) > .ct-node:before{display:none}
  .ct-tier{padding-top:var(--drop)}
}

/* The drawing. Tier t starts at t * .32s: spine, then bar, then stubs, then the
   courts. Transform and opacity only. */
.js-motion .ct-tier:before{transform:scaleY(0); transition:transform .45s var(--ease-draw) calc(var(--t) * .32s)}
.js-motion .ct-tier:after{transform:scaleX(0); transition:transform .5s var(--ease-draw) calc(var(--t) * .32s + .18s)}
.js-motion .ct-tier > .ct-node:before{transform:scaleY(0); transition:transform .35s var(--ease-draw) calc(var(--t) * .32s + .38s)}
.js-motion .ct-node{opacity:0; transform:translateY(14px);
  transition:opacity .6s var(--ease-draw), transform .8s var(--ease-draw);
  transition-delay:calc(var(--t) * .32s + .3s)}
.js-motion .ct-side .ct-node{transition-delay:calc(var(--t) * .32s + .1s)}
.js-motion .ct-side .ct-node + .ct-node{transition-delay:calc(var(--t) * .32s + .25s)}
.js-motion .ct.in .ct-tier:before, .js-motion .ct.in .ct-tier > .ct-node:before{transform:scaleY(1)}
.js-motion .ct.in .ct-tier:after{transform:scaleX(1)}
.js-motion .ct.in .ct-node{opacity:1; transform:none}
/* Tier variables reach the courts through inheritance; the side panel sets its own. */


/* ==================================================================
   NUMBERED HOW IT WORKS
   ==================================================================
   The .steps grid with a numeral, rather than a new layout. */
.howsteps{grid-template-columns:1fr}
@media(min-width:641px){ .howsteps{grid-template-columns:1fr 1fr} }
@media(min-width:1000px){ .howsteps{grid-template-columns:repeat(4,1fr)} }
.howstep{padding-top:18px; border-top:1px solid var(--hair)}
.hn{display:block; font-family:var(--font-display); font-size:13px; font-weight:500;
  letter-spacing:.06em; color:var(--accent-ink); margin-bottom:10px}
.howstep h3{font-family:var(--font-display); font-weight:400; font-size:18px; margin:0 0 8px; color:var(--ink)}
.howstep p{font-size:13.5px; line-height:1.6; color:var(--muted); margin:0}


/* ==================================================================
   ODDS AND ENDS
   ================================================================== */
/* Tabular figures so a counting stat does not jitter its own width. The
   min-width is belt and braces: it is not certain the self-hosted Spectral
   subset carries the tnum feature, and a reserved box is cheap. */
.ch-stat .v{display:inline-block; min-width:3.4ch; font-variant-numeric:tabular-nums}

/* The FAQ marker already rotates; it just did so instantly. */
.faqrow .ic{transition:transform .4s var(--ease-long)}
/* styles.css centres the FAQ column, which reads as a mistake once the section
   head above it is flush left. */
.faq{margin:0}

/* The founder quote on the photo band. These rules lived in styles.css for the
   citizen landing's dark band; PR #95 removed that band and deleted them as
   unused, but this page still uses the class, so from that deploy the quote
   rendered unstyled: edge to edge, no padding, dark text on the photograph.
   Kept here, beside the only page that uses it. The .photo backdrop and its
   .dark-overlay scrim still come from styles.css. */
.proofband{position:relative; overflow:hidden; padding:56px 28px; color:#F5EFE6;
  border-radius:22px; margin:0 20px}
@media(min-width:640px){ .proofband{margin-left:28px; margin-right:28px; padding:64px 48px} }
@media(min-width:1024px){ .proofband{margin-left:auto; margin-right:auto; max-width:calc(1040px - 64px)} }
.proofband .inner{position:relative; z-index:1; max-width:760px}
.proofband .quote{font-family:var(--font-display); font-weight:400;
  font-size:clamp(1.2rem,2.6vw,1.65rem); line-height:1.35; margin:0; color:#F5EFE6}
.proofband .who{font-size:var(--fs-sm); color:rgba(245,239,230,.8); margin:14px 0 0}

/* Hover lifts and the marquee pause only where a pointer can hover; on a touch
   screen :hover sticks after the tap (see styles.css, same block). */
@media (hover:hover) and (pointer:fine){
  .shotstage:hover > .shot{transform:translateY(-3px); box-shadow:var(--shadow-2), 0 30px 60px -22px rgba(36,30,20,.22)}
}

/* Inline links in running prose keep their line; the tap area reaches the 44px
   floor through a pseudo-element, as the citizen surface's citation chips do. */
main p > a{position:relative}
/* Fixed offsets, not a percentage: a plain inline element has no box height for
   a percentage to resolve against (the citizen chips are inline-flex, so theirs
   does). A 16 to 20px line plus 2 x 13px reaches 42 to 46px. */
main p > a::after{content:""; position:absolute; left:0; right:0; top:-13px; bottom:-13px}
/* A link standing alone in its paragraph is a control, not running prose. */
.ch-prooflink a{display:inline-flex; align-items:center; min-height:var(--tap)}

/* ---------------------------------------------- drawn back office (.bo) ---
   The showcase used to be six screenshots. They went stale whenever the back
   office changed and could not translate. Each surface is now drawn in HTML
   (index.html) in the live app's own chrome: the sidebar and its icons, the
   serif page titles, the green and amber status chips, the "1 source" pills.

   Motion runs only where the pinned showcase runs (.js-motion, >= 900px) and
   only on the .current scene, so a scene replays each time the reader scrolls
   back to it. Every rule outside that block is the finished frame, which is
   what a phone, reduced motion and JavaScript off all show. Anything that only
   exists mid-scene (the typed question, the "searching" row, the pointer, the
   file being dropped, the "processing" labels) is hidden in the finished frame.

   Borrowed from motion.dev, rebuilt without a library: springs for arrivals
   (linear(), with a cubic-bezier fallback), a blur-in for cards, staggered
   lists, a status label that swaps in place, a pointer that travels to what it
   opens. Icons are masks over currentColor, drawn after the Lucide set the
   back office uses. */
.bo{--bo-spring:cubic-bezier(.2,.9,.25,1.15); --bo-amber:#B7791F; container-type:inline-size;
  background:var(--canvas); font-size:12px; line-height:1.45; color:var(--ink); text-align:left}
@supports (transition-timing-function:linear(0,1)){
  .bo{--bo-spring:linear(0, .006, .025 2.8%, .101 6.1%, .539 18.9%, .721 25.3%, .849 31.5%,
       .937 38.1%, .968 41.8%, .991 45.7%, 1.006 50.1%, 1.015 55%, 1.017 63.9%, 1.001 85.6%, 1)}
}
.bo p, .bo ul, .bo ol, .bo dl, .bo dd{margin:0}
.bo ul, .bo ol{list-style:none; padding:0}
.bo-ni:before{content:""}
.bo-ni:before, .bo-brand i, .bo-search i, .bo-tool i{display:inline-block; flex:none; width:14px; height:14px;
  background:currentColor; -webkit-mask:var(--ic) center/contain no-repeat; mask:var(--ic) center/contain no-repeat}
.bo-i-today{--ic:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22black%22 stroke-width=%221.8%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Ccircle cx=%2212%22 cy=%2212%22 r=%224%22/%3E%3Cpath d=%22M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M6.3 17.7l-1.4 1.4M19.1 4.9l-1.4 1.4%22/%3E%3C/svg%3E")}
.bo-i-matters{--ic:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22black%22 stroke-width=%221.8%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.7-.9L9.6 3.9A2 2 0 0 0 7.9 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z%22/%3E%3C/svg%3E")}
.bo-i-assistant{--ic:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22black%22 stroke-width=%221.8%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z%22/%3E%3C/svg%3E")}
.bo-i-library{--ic:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22black%22 stroke-width=%221.8%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M2 4h6a4 4 0 0 1 4 4v13a3 3 0 0 0-3-3H2zM22 4h-6a4 4 0 0 0-4 4v13a3 3 0 0 1 3-3h7z%22/%3E%3C/svg%3E")}
.bo-i-vault{--ic:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22black%22 stroke-width=%221.8%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z%22/%3E%3C/svg%3E")}
.bo-i-review{--ic:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22black%22 stroke-width=%221.8%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Crect x=%223%22 y=%223%22 width=%2218%22 height=%2218%22 rx=%222%22/%3E%3Cpath d=%22M3 9h18M3 15h18M9 3v18M15 3v18%22/%3E%3C/svg%3E")}
.bo-i-workflows{--ic:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22black%22 stroke-width=%221.8%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Ccircle cx=%2218%22 cy=%225%22 r=%223%22/%3E%3Ccircle cx=%226%22 cy=%2212%22 r=%223%22/%3E%3Ccircle cx=%2218%22 cy=%2219%22 r=%223%22/%3E%3Cpath d=%22m8.6 13.5 6.8 4M15.4 6.5l-6.8 4%22/%3E%3C/svg%3E")}
.bo-i-admin{--ic:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22black%22 stroke-width=%221.8%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Ccircle cx=%2212%22 cy=%2212%22 r=%223%22/%3E%3Cpath d=%22M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1A1.7 1.7 0 0 0 9 19.4a1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1A1.7 1.7 0 0 0 4.6 9a1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z%22/%3E%3C/svg%3E")}
.bo-i-scale{--ic:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22black%22 stroke-width=%221.8%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22m16 16 3-8 3 8c-.9.6-1.9 1-3 1s-2.1-.4-3-1ZM2 16l3-8 3 8c-.9.6-1.9 1-3 1s-2.1-.4-3-1ZM7 21h10M12 3v18M3 7h2c2 0 5-1 7-2 2 1 5 2 7 2h2%22/%3E%3C/svg%3E")}
.bo-i-search{--ic:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22black%22 stroke-width=%221.8%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Ccircle cx=%2211%22 cy=%2211%22 r=%227%22/%3E%3Cpath d=%22m20 20-3.5-3.5%22/%3E%3C/svg%3E")}
.bo-i-plus{--ic:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22black%22 stroke-width=%221.8%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M12 5v14M5 12h14%22/%3E%3C/svg%3E")}
.bo-i-down{--ic:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22black%22 stroke-width=%221.8%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M12 4v12M7 11l5 5 5-5M5 20h14%22/%3E%3C/svg%3E")}
.bo-i-send{--ic:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22black%22 stroke-width=%221.8%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M12 19V5M5 12l7-7 7 7%22/%3E%3C/svg%3E")}
.bo-i-file{--ic:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22black%22 stroke-width=%221.8%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z%22/%3E%3Cpath d=%22M14 2v6h6%22/%3E%3C/svg%3E")}
.bo-i-check{--ic:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22black%22 stroke-width=%223%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22%3E%3Cpath d=%22M20 6 9 17l-5-5%22/%3E%3C/svg%3E")}

/* the app shell */
.bo-app{position:relative; display:flex; height:100%; min-height:360px}
.bo-app:before{content:""; position:absolute; left:0; right:0; top:0; height:3px; z-index:3;
  background:linear-gradient(90deg, var(--flag-red) 0 25%, var(--flag-blue) 25% 50%, var(--flag-yellow) 50% 75%, var(--flag-green) 75%)}
.bo-side{flex:none; width:128px; display:flex; flex-direction:column; gap:2px; padding:16px 8px 10px;
  background:var(--panel); border-right:1px solid var(--hair)}
.bo-brand{display:flex; align-items:center; gap:6px; padding:0 6px; font-family:var(--font-display); font-size:15px; line-height:1}
.bo-brand i{width:15px; height:15px; color:var(--accent)}
.bo-brand .dot{color:var(--accent)}
.bo-firm{padding:3px 6px 10px; font-size:9px; color:var(--muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.bo-ni{display:flex; align-items:center; gap:7px; padding:5px 6px; border-radius:6px; font-size:11px; color:var(--ink); white-space:nowrap}
.bo-ni:before{width:13px; height:13px; color:var(--muted)}
.bo-ni.on{background:var(--accent-soft); color:var(--accent-ink); font-weight:600; box-shadow:inset 2px 0 0 var(--accent)}
.bo-ni.on:before{color:var(--accent)}
.bo-sec{padding:10px 6px 3px; font-size:8.5px; font-weight:600; letter-spacing:.08em; text-transform:uppercase; color:var(--muted)}
.bo-me{margin-top:auto !important; display:flex; align-items:center; gap:6px; padding:8px 4px 0; border-top:1px solid var(--hair); font-size:10px; font-weight:600; white-space:nowrap}
.bo-me i, .bo-people i{flex:none; display:grid; place-items:center; width:22px; height:22px; border-radius:50%;
  font-style:normal; font-size:8.5px; font-weight:700; color:var(--accent-ink); background:var(--accent-soft)}
.bo-me em{display:block; font-style:normal; font-weight:400; font-size:9px; color:var(--muted)}
.bo-main{flex:1; min-width:0; overflow:hidden; display:flex; flex-direction:column; gap:9px; padding:16px 18px 16px}

/* type and chips shared by the scenes */
.bo-eyebrow{display:flex; gap:6px; font-size:9.5px; font-weight:600; letter-spacing:.07em; text-transform:uppercase; color:var(--muted)}
.bo-eyebrow span:first-child{color:var(--accent-ink)}
.bo-h{display:flex; align-items:center; gap:10px; margin-top:-4px !important; font-family:var(--font-display); font-size:18px; line-height:1.2; letter-spacing:-.01em}
.bo-k{margin:0 0 5px !important; font-size:9.5px; font-weight:600; letter-spacing:.07em; text-transform:uppercase; color:var(--accent-ink)}
.bo-btn{display:inline-flex; align-items:center; padding:5px 11px; border-radius:var(--r-pill); background:var(--primary-fill); color:var(--primary-fg);
  font-family:var(--font-body); font-size:10.5px; font-weight:600; letter-spacing:0; white-space:nowrap}
.bo-btn-r{margin-left:auto}
.bo-guard{display:flex; align-items:center; gap:6px; font-size:11px; font-weight:600; color:var(--verified-ink)}
.bo-guard:before{content:"\2713"; flex:none; display:grid; place-items:center; width:14px; height:14px; border-radius:50%;
  background:var(--verified-ink); color:#fff; font-size:8.5px; font-weight:800}
.bo .cite{padding:1px 7px; border-radius:var(--r-pill); font-size:10px; white-space:nowrap; vertical-align:1px}
.bo mark{color:inherit; background:color-mix(in srgb, var(--accent) 24%, transparent); border-radius:3px; padding:0 2px}
.bo-chips{display:flex; flex-wrap:wrap; align-items:center; gap:6px}
.bo-tag, .bo-status, .bo-open, .bo-org, .bo-lock, .bo-okchip{display:inline-grid; padding:2px 8px; border-radius:var(--r-pill); font-size:9.5px; font-weight:600; white-space:nowrap}
.bo-tag{color:var(--accent-ink); background:var(--accent-soft)}
.bo-status{color:var(--verified-ink); background:color-mix(in srgb, var(--verified) 13%, transparent)}
/* a label that swaps in place: both words share one grid cell, so the chip is
   always as wide as the longer one and nothing beside it moves */
.bo-status b, .bo-st b{grid-area:1/1; font-weight:inherit}
.bo-was{visibility:hidden}
.bo-tool{display:inline-flex; align-items:center; gap:5px; padding:3px 9px; border:1px solid var(--hair); border-radius:6px; background:var(--panel); font-size:10px; font-weight:600}
.bo-tool i{width:11px; height:11px}

/* 0. research thread */
.bo-thread{position:relative; flex:1; min-height:0; display:flex; flex-direction:column; gap:8px}
.bo-q{align-self:flex-end; max-width:82%; padding:7px 12px; border-radius:14px 14px 4px 14px; background:var(--accent-soft); color:var(--accent-ink); font-weight:500}
.bo-think{display:none}
.bo-ans{display:flex; flex-direction:column; gap:7px; padding:11px 13px; background:var(--panel); border:1px solid var(--hair); border-radius:var(--r-md); box-shadow:var(--shadow-1);
  font-family:var(--font-display); font-size:13px; line-height:1.5}
.bo-ans .bo-guard{font-family:var(--font-body)}
.bo-cite{position:relative}
.bo-cursor{display:none}
.bo-pop{position:absolute; right:0; bottom:0; z-index:2; width:min(236px,64%); padding:11px 13px; background:var(--panel);
  border:1px solid var(--hair); border-radius:var(--r-md); box-shadow:0 18px 40px -14px rgba(36,30,20,.35), var(--shadow-1)}
.bo-pop-t{font-family:var(--font-display); font-size:13.5px; line-height:1.3}
.bo-pop-m{margin:3px 0 9px !important; font-size:10px; color:var(--muted)}
.bo-compose{display:flex; align-items:center; gap:8px; padding:7px 7px 7px 12px; background:var(--panel); border:1px solid var(--hair); border-radius:var(--r-md); color:var(--muted)}
.bo-typed{display:none}
.bo-ph{flex:1}
.bo-send{position:relative; flex:none; width:22px; height:22px; border-radius:50%; background:var(--primary-fill)}
.bo-send:after{content:""; position:absolute; inset:5px; background:var(--primary-fg); -webkit-mask:var(--ic) center/contain no-repeat; mask:var(--ic) center/contain no-repeat}

/* 1. vault */
.bo-drop{position:relative; display:grid; place-items:center; padding:9px; border:1.5px dashed color-mix(in srgb, var(--accent) 40%, var(--hair)); border-radius:var(--r-md);
  background:color-mix(in srgb, var(--accent) 4%, var(--panel)); color:var(--muted); font-size:10.5px}
.bo-fly{display:none}
.bo-docs{display:grid; gap:5px}
.bo-docs li{display:flex; align-items:center; gap:8px; padding:6px 10px; background:var(--panel); border:1px solid var(--hair); border-radius:var(--r-sm)}
.bo-fi{flex:none; width:13px; height:13px; background:var(--muted); -webkit-mask:var(--ic) center/contain no-repeat; mask:var(--ic) center/contain no-repeat}
.bo-doc{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.bo-st{flex:none; display:inline-grid; justify-items:end; font-size:9.5px; font-weight:600}
.bo-st b{padding:2px 8px; border-radius:var(--r-pill)}
.bo-st .bo-now{color:var(--verified-ink); background:color-mix(in srgb, var(--verified) 13%, transparent)}
.bo-st .bo-was{color:var(--bo-amber); background:color-mix(in srgb, var(--flag-yellow) 22%, transparent)}
.bo-search{display:flex; align-items:center; gap:7px; padding:7px 11px; background:var(--panel); border:1px solid var(--hair); border-radius:var(--r-md)}
.bo-search i{width:13px; height:13px; color:var(--muted)}
.bo-hit{padding:9px 12px; background:var(--panel); border:1px solid var(--hair); border-left:3px solid var(--accent); border-radius:var(--r-sm); box-shadow:var(--shadow-1)}
.bo-hit-t{font-family:var(--font-display); font-size:13px}
.bo-hit2{margin-top:-3px}
.bo-acts{gap:8px}
.bo-foot{font-size:10.5px; color:var(--muted)}

/* 2. workflow run */
.bo-inputs{display:flex; gap:18px; padding:7px 11px; background:var(--panel); border:1px solid var(--hair); border-radius:var(--r-sm)}
.bo-inputs dt{font-size:9px; font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--muted)}
.bo-inputs dd{font-size:11px}
.bo-prog{height:4px; border-radius:4px; background:var(--panel-2); overflow:hidden}
.bo-prog i{display:block; height:100%; width:100%; border-radius:inherit; background:var(--verified)}
.bo-steps{display:grid; gap:5px}
.bo-steps li{display:flex; align-items:center; gap:9px; padding:7px 10px; background:var(--panel); border:1px solid var(--hair); border-radius:var(--r-sm)}
.bo-steps li > span:nth-child(2){flex:1; min-width:0; font-weight:500}
.bo-dot{position:relative; flex:none; width:16px; height:16px}
.bo-dot:before, .bo-dot:after{content:""; position:absolute; inset:0; border-radius:50%}
.bo-dot:before{display:none; border:2px solid var(--hair); border-top-color:var(--accent)}
.bo-dot:after{content:"\2713"; display:grid; place-items:center; background:var(--verified-ink); color:#fff; font-size:9px; font-weight:800}
.bo-src{flex:none; padding:1px 8px; border-radius:var(--r-pill); background:var(--panel-2); color:var(--muted); font-size:9.5px; font-weight:600}

/* 3. review grid, drawn after the live table: tinted header, row labels on
   the left, and a cell that carries its value and its source pill */
.bo-grid{display:grid; grid-template-columns:minmax(74px,.9fr) repeat(3,1fr); border:1px solid var(--hair); border-radius:var(--r-md); overflow:hidden; background:var(--panel); font-size:11px}
.bo-gh{padding:6px 8px; background:var(--panel-2); font-size:9px; font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); border-bottom:1px solid var(--hair)}
.bo-gr{padding:8px; font-weight:600; font-size:10.5px; background:color-mix(in srgb, var(--panel-2) 45%, var(--panel)); border-bottom:1px solid var(--hair)}
.bo-c{position:relative; display:flex; flex-wrap:wrap; align-items:center; align-content:flex-start; gap:3px 4px; padding:7px 8px; border-left:1px solid var(--hair); border-bottom:1px solid var(--hair)}
.bo-grid > :nth-last-child(-n+4){border-bottom:0}
.bo-c .bo-v{flex:0 0 100%}
.bo-pill{white-space:nowrap; padding:0 7px; border-radius:var(--r-pill); background:var(--panel-2); color:var(--muted); font-size:9px; font-weight:600}
.bo-c.bo-flag:after{content:""; position:absolute; left:-1px; top:0; bottom:0; width:3px; background:var(--flag-yellow)}
.bo-watch{padding:0 6px; border-radius:var(--r-pill); font-style:normal; font-size:8.5px; font-weight:700; letter-spacing:.05em; text-transform:uppercase;
  color:var(--bo-amber); background:color-mix(in srgb, var(--flag-yellow) 24%, transparent)}

/* 4. matters */
.bo-matters{display:grid; gap:5px}
.bo-matters li{display:flex; align-items:center; gap:6px; padding:7px 10px; background:var(--panel); border:1px solid var(--hair); border-radius:var(--r-sm)}
.bo-matters li > span:first-child{flex:1; min-width:0}
.bo-matters strong{display:block; font-weight:600; color:var(--accent-ink); white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.bo-matters small{display:block; font-size:9.5px; color:var(--muted)}
.bo-matters li.bo-m-on{border-color:color-mix(in srgb, var(--accent) 45%, var(--hair)); box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 10%, transparent)}
.bo-open{color:var(--verified-ink); background:color-mix(in srgb, var(--verified) 13%, transparent)}
.bo-org{color:var(--muted); background:var(--panel-2)}
.bo-lock{color:#B42318; background:color-mix(in srgb, var(--flag-red) 12%, transparent)}
.bo-people{padding:10px 12px; background:var(--panel); border:1px solid var(--hair); border-radius:var(--r-md); box-shadow:var(--shadow-1)}
.bo-people p{display:flex; align-items:center; gap:8px; margin:0 0 5px !important}
.bo-people p span{flex:1}
.bo-people p.bo-k{display:block}
.bo-people p em{padding:1px 8px; border:1px solid var(--hair); border-radius:6px; font-style:normal; font-size:10px; color:var(--muted)}
.bo-people p.bo-note{margin:7px 0 0 !important; font-size:10.5px; color:var(--accent-ink)}

/* 5. admin */
.bo-tabs{display:flex; gap:14px; border-bottom:1px solid var(--hair); font-size:10.5px; font-weight:600; color:var(--muted); white-space:nowrap; overflow:hidden}
.bo-tabs span{padding:0 0 6px}
.bo-tabs span.on{color:var(--accent-ink); box-shadow:inset 0 -2px 0 var(--accent)}
.bo-kpis{display:grid; grid-template-columns:repeat(3,1fr); gap:8px}
.bo-kpis > p{display:flex; flex-direction:column; align-items:flex-start; gap:4px; padding:9px 11px; background:var(--panel); border:1px solid var(--hair); border-radius:var(--r-md); box-shadow:var(--shadow-1)}
.bo-kpis small{font-size:8.5px; font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--muted)}
.bo-kpis strong{font-family:var(--font-display); font-size:19px; font-weight:400; line-height:1.1; font-variant-numeric:tabular-nums}
.bo-meter{align-self:stretch; height:4px; border-radius:4px; background:var(--panel-2); overflow:hidden}
.bo-meter i{display:block; height:100%; width:calc(var(--v) * 100%); border-radius:inherit; background:var(--accent)}
.bo-okchip{color:var(--verified-ink); background:color-mix(in srgb, var(--verified) 13%, transparent); font-size:9px; white-space:normal}
.bo-audit{padding:10px 12px; background:var(--panel); border:1px solid var(--hair); border-radius:var(--r-md); box-shadow:var(--shadow-1)}
.bo-audit p:not(.bo-k){display:flex; gap:10px; padding:4px 0; border-top:1px solid var(--hair)}
.bo-audit time{flex:none; color:var(--muted); font-variant-numeric:tabular-nums}

/* Narrow frames (a phone, or the stacked list under 900px): the sidebar keeps
   its icons and loses its words, as the live app's does. */
@container (max-width:520px){
  .bo-side{width:44px; padding:14px 6px 10px; align-items:center}
  .bo-brand .wordmark, .bo-firm, .bo-sec, .bo-me span{display:none}
  .bo-brand{padding:0 0 12px}
  .bo-ni{padding:6px; justify-content:center}
  .bo-ni span{display:none}
  .bo-sec + .bo-nav{margin-top:10px; padding-top:10px; border-top:1px solid var(--hair)}
  .bo-me{padding:8px 0 0; justify-content:center}
  .bo-main{padding:14px 12px}
  .bo-inputs{flex-direction:column; gap:4px}
  .bo-kpis{grid-template-columns:1fr 1fr}
  .bo-kpis > p:last-child{grid-column:1 / -1; flex-direction:row; flex-wrap:wrap; align-items:center}
  .bo-grid{grid-template-columns:minmax(0,.85fr) repeat(3,minmax(0,1fr)); font-size:10px}
  .bo-gh, .bo-gr{padding:6px 5px}
  .bo-gh{text-transform:none; letter-spacing:0; font-size:9.5px; hyphens:auto}
  .bo-watch{letter-spacing:0; white-space:nowrap}
  .bo-c{padding:6px 5px}
  .bo-pill{padding:0 5px; font-size:8.5px}
  .bo-matters li{flex-wrap:wrap}
  .bo-matters li > span:first-child{flex:1 0 100%}
}

/* Stacked (under 900px): each scene is in the page flow at its natural height,
   and the popover joins the flow under the answer. */
@media(max-width:899.98px){
  .bo-app{min-height:0}
  .bo-pop{position:static; width:auto}
  .bo-thread{flex:none}
}

/* ---- motion: the pinned showcase only ----
   Each scene is one timeline in seconds from the moment it becomes .current.
   `both` fill everywhere, so before its delay an element holds its first
   keyframe and after it holds its last, and the last is always the finished
   frame above. */
@media(min-width:900px){
  .js-motion .sc-visual:has(.bo){aspect-ratio:1.34}
  .js-motion [data-showcase]:not(.sc-live) .bo *,
  .js-motion [data-showcase]:not(.sc-live) .bo *:before,
  .js-motion [data-showcase]:not(.sc-live) .bo *:after{animation-play-state:paused !important}
  .js-motion .bo .bo-app{min-height:0}
  .js-motion .bo.current .bo-main > *{animation:bo-rise .5s var(--ease-long) both}
  .js-motion .bo.current .bo-main > :nth-child(2){animation-delay:.06s}

  /* 0. thread: the question is typed and sent, juris searches, the answer
        streams with its chips, the guard confirms, and the pointer opens the
        first judgment. */
  .js-motion .bo-s0.current .bo-typed{display:block; flex:1; overflow:hidden; white-space:nowrap; color:var(--ink);
    animation:bo-type 1.1s steps(34) .2s both, bo-out .15s linear 1.45s both}
  .js-motion .bo-s0.current .bo-typed:after{content:""; display:inline-block; width:1.5px; height:1.1em; margin-left:1px; vertical-align:-2px; background:var(--accent)}
  .js-motion .bo-s0.current .bo-ph{animation:bo-late 1.6s step-end both}
  .js-motion .bo-s0.current .bo-typed + .bo-ph{position:absolute; opacity:0}
  .js-motion .bo-s0 .bo-compose{position:relative}
  .js-motion .bo-s0.current .bo-send{animation:bo-press .35s var(--bo-spring) 1.35s both}
  .js-motion .bo-s0.current .bo-q{animation:bo-pop .55s var(--bo-spring) 1.5s both}
  .js-motion .bo-s0.current .bo-think{display:flex; align-items:center; gap:8px; height:22px; margin-bottom:-30px; color:var(--muted); font-size:11px;
    animation:bo-life 1.2s var(--ease-long) 1.85s both}
  .js-motion .bo-s0.current .bo-think i{width:36px; height:6px; border-radius:6px;
    background:linear-gradient(90deg, var(--panel-2) 0 30%, var(--accent) 50%, var(--panel-2) 70% 100%) 0 0/300% 100%; animation:bo-sheen 1s linear infinite}
  .js-motion .bo-s0.current .bo-ans{animation:bo-rise .55s var(--ease-long) 2.95s both}
  .js-motion .bo-s0.current .bo-line{animation:bo-stream .6s var(--ease-long) both; animation-delay:calc(3.05s + var(--k) * .35s)}
  .js-motion .bo-s0.current .bo-line .cite{animation:bo-chip .5s var(--bo-spring) both; animation-delay:calc(3.45s + var(--k) * .35s)}
  .js-motion .bo-s0.current .bo-guard{animation:bo-rise .45s var(--ease-long) 4.15s both}
  .js-motion .bo-s0.current .bo-cursor{display:block; position:absolute; left:55%; top:62%; z-index:4; width:16px; height:20px; pointer-events:none;
    background:no-repeat center/contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 20'%3E%3Cpath d='M1 1v15l4-3.5 2.6 6 2.6-1.1-2.6-5.9H13z' fill='%23241E14' stroke='white' stroke-width='1.3' stroke-linejoin='round'/%3E%3C/svg%3E");
    animation:bo-point .9s cubic-bezier(.3,.7,.2,1) 4.5s both, bo-click .25s ease-in-out 5.45s both, bo-out .3s linear 6.4s forwards}
  .js-motion .bo-s0.current .bo-line .cite.bo-cite{animation:bo-chip .5s var(--bo-spring) 3.45s both, bo-ring 1s ease-out 5.5s both}
  .js-motion .bo-s0.current .bo-pop{animation:bo-card .7s var(--bo-spring) 5.6s both}

  /* 1. vault: a scan is dropped in, each file is processed in turn (the scan
        through OCR), then a search finds the clause and marks it. */
  .js-motion .bo-s1.current .bo-fly{display:block; position:absolute; right:14%; top:-6px; padding:5px 10px; border-radius:6px;
    background:var(--panel); border:1px solid var(--hair); box-shadow:0 14px 30px -12px rgba(36,30,20,.4); font-size:10.5px; color:var(--ink);
    animation:bo-drop 1.1s cubic-bezier(.3,.7,.2,1) .35s both}
  .js-motion .bo-s1.current .bo-drop{animation:bo-rise .5s var(--ease-long) both, bo-glow 1s ease-out .9s both}
  .js-motion .bo-s1.current .bo-docs li{animation:bo-rise .45s var(--ease-long) both; animation-delay:calc(.15s + var(--k) * .1s)}
  .js-motion .bo-s1.current .bo-docs li.bo-new{animation:bo-pop .55s var(--bo-spring) 1.3s both}
  .js-motion .bo-s1.current .bo-st .bo-was{visibility:visible; animation:bo-swapout .3s var(--ease-long) both}
  .js-motion .bo-s1.current .bo-st .bo-now{animation:bo-swapin .45s var(--bo-spring) both}
  .js-motion .bo-s1.current .bo-docs li:nth-child(1) .bo-st b{animation-delay:1.1s}
  .js-motion .bo-s1.current .bo-docs li:nth-child(2) .bo-st b{animation-delay:1.55s}
  .js-motion .bo-s1.current .bo-docs li:nth-child(3) .bo-st b{animation-delay:2.6s}
  .js-motion .bo-s1.current .bo-hit2{animation-delay:4.35s}
  .js-motion .bo-s1.current .bo-hit2 mark{animation-delay:4.9s}
  .js-motion .bo-s1.current .bo-st .bo-was:before{content:""; display:inline-block; width:5px; height:5px; margin-right:5px; border-radius:50%; vertical-align:1px;
    background:currentColor; animation:bo-blink .8s ease-in-out infinite}
  .js-motion .bo-s1.current .bo-search{animation:bo-rise .45s var(--ease-long) 2.8s both}
  .js-motion .bo-s1.current .bo-search span{display:inline-block; overflow:hidden; white-space:nowrap; vertical-align:bottom; animation:bo-type .8s steps(14) 3.1s both}
  .js-motion .bo-s1.current .bo-hit{animation:bo-card .7s var(--bo-spring) 4s both}
  .js-motion .bo-s1.current .bo-hit mark{background:linear-gradient(color-mix(in srgb, var(--accent) 24%, transparent), color-mix(in srgb, var(--accent) 24%, transparent)) no-repeat 0 0/100% 100%;
    animation:bo-mark .9s var(--ease-long) 4.6s both}

  /* 2. workflow: the run steps through its plan one at a time, each step
        spinning until it lands with its sources, the bar keeping pace, and
        the status turns from running to succeeded. */
  .js-motion .bo-s2.current .bo-prog i{animation:bo-fill 4s var(--ease-long) .5s both}
  .js-motion .bo-s2.current .bo-steps li{animation:bo-rise .4s var(--ease-long) both; animation-delay:calc(.2s + var(--k) * .07s)}
  .js-motion .bo-s2.current .bo-steps li > span:nth-child(2){animation:bo-dim .3s linear both; animation-delay:calc(.5s + var(--k) * 1s)}
  .js-motion .bo-s2.current .bo-dot:before{display:block;
    animation:bo-arc .01s step-end both, bo-spin .7s linear infinite, bo-out .2s linear both;
    animation-delay:calc(.5s + var(--k) * 1s), calc(.5s + var(--k) * 1s), calc(1.5s + var(--k) * 1s)}
  .js-motion .bo-s2.current .bo-dot:after{animation:bo-chip .45s var(--bo-spring) both; animation-delay:calc(1.5s + var(--k) * 1s)}
  .js-motion .bo-s2.current .bo-src{animation:bo-chip .4s var(--bo-spring) both; animation-delay:calc(1.6s + var(--k) * 1s)}
  .js-motion .bo-s2.current .bo-status .bo-was{visibility:visible; animation:bo-swapout .3s var(--ease-long) 4.6s both}
  .js-motion .bo-s2.current .bo-status .bo-now{animation:bo-swapin .45s var(--bo-spring) 4.6s both}
  .js-motion .bo-s2.current .bo-status{animation:bo-tint .3s linear 4.6s both}
  .js-motion .bo-s2.current .bo-done{animation:bo-rise .5s var(--ease-long) 4.85s both}
  .js-motion .bo-s2.current .bo-acts{animation:bo-rise .5s var(--ease-long) 5.05s both}

  /* 3. review grid: every cell starts as a shimmer and fills with its value
        and its source, row by row; one is flagged for a person to look at. */
  .js-motion .bo-s3.current .bo-c:before{content:""; position:absolute; left:8px; right:12px; top:9px; height:18px; border-radius:4px;
    background:linear-gradient(90deg, var(--panel-2) 0 30%, color-mix(in srgb, var(--panel-2) 40%, var(--panel)) 50%, var(--panel-2) 70% 100%) 0 0/300% 100%;
    animation:bo-sheen 1.1s linear infinite, bo-out .2s linear both; animation-delay:0s, calc(.55s + var(--k) * .2s)}
  .js-motion .bo-s3.current .bo-c > *{animation:bo-rise-s .4s var(--ease-long) both; animation-delay:calc(.6s + var(--k) * .2s)}
  .js-motion .bo-s3.current .bo-foot{animation:bo-rise .45s var(--ease-long) 4.2s both}
  .js-motion .bo-s3.current .bo-c.bo-flag{animation:bo-ring-y 1.2s ease-out 3.8s both}
  .js-motion .bo-s3.current .bo-c.bo-flag:after{transform-origin:top; animation:bo-grow-y .45s var(--ease-long) 3.8s both}
  .js-motion .bo-s3.current .bo-c .bo-watch{animation:bo-chip .5s var(--bo-spring) 3.85s both}
  .js-motion .bo-s3.current .bo-status .bo-was{visibility:visible; animation:bo-swapout .3s var(--ease-long) 3.6s both}
  .js-motion .bo-s3.current .bo-status .bo-now{animation:bo-swapin .45s var(--bo-spring) 3.6s both}
  .js-motion .bo-s3.current .bo-status{animation:bo-tint .3s linear 3.6s both}

  /* 4. matters: the restricted matter is picked out, its member list opens,
        and a viewer is added to it. */
  .js-motion .bo-s4.current .bo-matters li{animation:bo-rise .45s var(--ease-long) both; animation-delay:calc(.15s + var(--k) * .09s)}
  .js-motion .bo-s4.current .bo-matters li.bo-m-on{animation:bo-rise .45s var(--ease-long) .15s both, bo-sel .5s var(--ease-long) .9s both}
  .js-motion .bo-s4.current .bo-lock{animation:bo-chip .5s var(--bo-spring) 1.1s both}
  .js-motion .bo-s4.current .bo-people{animation:bo-card .7s var(--bo-spring) 1.45s both}
  .js-motion .bo-s4.current .bo-people p{animation:bo-rise .4s var(--ease-long) both; animation-delay:calc(1.8s + var(--k,0) * .12s)}
  .js-motion .bo-s4.current .bo-people p.bo-join{animation:bo-slide .5s var(--bo-spring) 2.7s both, bo-flash 1.4s ease-out 2.9s both}
  .js-motion .bo-s4.current .bo-people p.bo-note{animation-delay:3.2s}

  /* 5. admin: the meters fill, the health checks come back normal, and the
        audit log writes itself a line at a time. */
  .js-motion .bo-s5.current .bo-kpis > p{animation:bo-rise .5s var(--ease-long) both; animation-delay:calc(.2s + var(--k) * .1s)}
  .js-motion .bo-s5.current .bo-meter i{animation:bo-grow 1.1s var(--ease-long) both; animation-delay:calc(.6s + var(--k) * .15s)}
  .js-motion .bo-s5.current .bo-okchip{animation:bo-chip .5s var(--bo-spring) 1.1s both}
  .js-motion .bo-s5.current .bo-okchip + .bo-okchip{animation-delay:1.3s}
  .js-motion .bo-s5.current .bo-audit{animation:bo-rise .5s var(--ease-long) 1.4s both}
  .js-motion .bo-s5.current .bo-audit p:not(.bo-k){animation:bo-slide .45s var(--bo-spring) both; animation-delay:calc(1.8s + var(--k) * .5s)}
  .js-motion .bo-s5.current .bo-audit p:last-child{animation:bo-slide .45s var(--bo-spring) 2.8s both, bo-flash 1.4s ease-out 3s both}
}
@keyframes bo-rise{from{opacity:0; transform:translateY(10px)} to{opacity:1; transform:none}}
@keyframes bo-rise-s{from{opacity:0; transform:translateY(4px)} to{opacity:1; transform:none}}
@keyframes bo-pop{from{opacity:0; transform:translateY(8px) scale(.94)} to{opacity:1; transform:none}}
@keyframes bo-chip{from{opacity:0; transform:scale(.5)} to{opacity:1; transform:none}}
@keyframes bo-card{from{opacity:0; transform:translateY(16px) scale(.95); filter:blur(4px)} to{opacity:1; transform:none; filter:none}}
@keyframes bo-stream{from{opacity:0; filter:blur(3px); transform:translateY(4px)} to{opacity:1; filter:none; transform:none}}
@keyframes bo-slide{from{opacity:0; transform:translateX(-14px)} to{opacity:1; transform:none}}
@keyframes bo-out{from{opacity:1} to{opacity:0}}
@keyframes bo-late{from{opacity:0} to{opacity:1}}
@keyframes bo-type{from{max-width:0} to{max-width:100%}}
@keyframes bo-press{0%{transform:scale(1)} 40%{transform:scale(.8)} 100%{transform:scale(1)}}
@keyframes bo-life{0%{opacity:0; transform:translateY(6px)} 18%{opacity:1; transform:none} 82%{opacity:1} 100%{opacity:0}}
@keyframes bo-sheen{from{background-position:100% 0} to{background-position:0 0}}
@keyframes bo-point{from{opacity:0; transform:translate(150px,90px)} 30%{opacity:1} to{opacity:1; transform:none}}
@keyframes bo-click{50%{transform:scale(.8)}}
@keyframes bo-ring{from{box-shadow:0 0 0 0 color-mix(in srgb, var(--accent) 45%, transparent)} to{box-shadow:0 0 0 9px transparent}}
@keyframes bo-drop{0%{opacity:0; transform:translate(70px,-46px) rotate(8deg)} 25%{opacity:1} 70%{opacity:1; transform:translate(0,4px) rotate(0) scale(1)} 100%{opacity:0; transform:translate(0,14px) scale(.8)}}
@keyframes bo-glow{0%{box-shadow:0 0 0 0 color-mix(in srgb, var(--accent) 35%, transparent)} 100%{box-shadow:0 0 0 10px transparent}}
@keyframes bo-swapout{from{opacity:1; transform:none} to{opacity:0; transform:translateY(-6px)}}
@keyframes bo-swapin{from{opacity:0; transform:translateY(6px)} to{opacity:1; transform:none}}
@keyframes bo-blink{50%{opacity:.25}}
@keyframes bo-mark{from{background-size:0 100%} to{background-size:100% 100%}}
@keyframes bo-fill{0%{width:0} 25%{width:25%} 50%{width:50%} 75%{width:75%} 100%{width:100%}}
@keyframes bo-grow{from{width:0}}
@keyframes bo-dim{from{color:var(--muted)} to{color:var(--ink)}}
@keyframes bo-arc{from{border-top-color:var(--hair)} to{border-top-color:var(--accent)}}
@keyframes bo-spin{to{transform:rotate(360deg)}}
@keyframes bo-tint{from{color:var(--bo-amber); background:color-mix(in srgb, var(--flag-yellow) 22%, transparent)}}
@keyframes bo-grow-y{from{transform:scaleY(0)}}
@keyframes bo-ring-y{from{box-shadow:inset 0 0 0 40px color-mix(in srgb, var(--flag-yellow) 30%, transparent)} to{box-shadow:inset 0 0 0 40px transparent}}
@keyframes bo-sel{from{border-color:var(--hair); box-shadow:none}}
@keyframes bo-flash{0%{background:color-mix(in srgb, var(--accent) 16%, transparent)} 100%{background:transparent}}

/* ------------------------------------------ where the work runs (.dep) ---
   Four options, four rows, three places. chambers-deploy.js sets --col and
   data-col on each pill from its data-at table; the pill slides on a spring to
   its column and takes that place's colour. A row whose work goes to a supplier
   draws the line leaving Mauritius, with a dot running along it. With
   JavaScript off the board is hidden and the four descriptions are a list. */
.dep{--dep-lab:210px; --dep-spring:cubic-bezier(.2,.9,.25,1.15)}
@supports (transition-timing-function:linear(0,1)){
  .dep{--dep-spring:linear(0, .006, .025 2.8%, .101 6.1%, .539 18.9%, .721 25.3%, .849 31.5%,
       .937 38.1%, .968 41.8%, .991 45.7%, 1.006 50.1%, 1.015 55%, 1.017 63.9%, 1.001 85.6%, 1)}
}
.dep-opts, .dep-board{display:none}
.dep.is-live .dep-opts{display:flex; flex-wrap:wrap; gap:8px; margin:0 0 18px}
.dep.is-live .dep-board{display:block}
.dep-opt{display:inline-flex; align-items:center; gap:10px; min-height:var(--tap); padding:0 18px 0 8px;
  border-radius:var(--r-pill); border:1px solid var(--hair); background:var(--panel); color:var(--muted);
  font:inherit; font-size:var(--fs-sm); font-weight:600; cursor:pointer;
  transition:background .3s var(--ease-long), color .3s var(--ease-long), border-color .3s var(--ease-long)}
.dep-opt:focus-visible{outline:2px solid var(--focus); outline-offset:2px}
.dep-opt[aria-selected="true"]{background:var(--primary-fill); color:var(--primary-fg); border-color:var(--primary-fill)}
.dep-l{display:inline-grid; place-items:center; width:28px; height:28px; border-radius:50%; flex:none;
  font-size:var(--fs-xs); font-weight:700; background:var(--accent-soft); color:var(--accent-ink)}
.dep-opt[aria-selected="true"] .dep-l{background:var(--accent); color:#fff}
@media (hover:hover) and (pointer:fine){ .dep-opt:not([aria-selected="true"]):hover{color:var(--ink); border-color:color-mix(in srgb, var(--ink) 22%, var(--hair))} }

.dep-board{padding:20px; background:var(--panel); border:1px solid var(--hair); border-radius:var(--r-xl); box-shadow:var(--shadow-2)}
.dep-zones, .dep-row{display:grid; grid-template-columns:var(--dep-lab) 1fr 1fr 1fr; align-items:center}
.dep-z{margin:0; padding:10px 12px; display:flex; flex-direction:column; gap:1px; border-radius:var(--r-md) var(--r-md) 0 0}
.dep-z strong{font-size:var(--fs-sm); color:var(--ink)}
.dep-z span{font-size:var(--fs-xs); color:var(--muted)}
.dep-z0{background:color-mix(in srgb, var(--flag-red) 7%, transparent)}
.dep-z1{background:var(--accent-soft)}
.dep-z2{background:color-mix(in srgb, var(--verified) 10%, transparent)}
.dep-row{border-top:1px solid var(--hair)}
.dep-rl{margin:0; padding:14px 12px 14px 0; font-size:var(--fs-sm); color:var(--ink)}
.dep-track{grid-column:2 / span 3; position:relative; height:58px;
  background:linear-gradient(90deg, color-mix(in srgb, var(--flag-red) 7%, transparent) 0 33.333%,
    var(--accent-soft) 33.333% 66.666%, color-mix(in srgb, var(--verified) 10%, transparent) 66.666%)}
.dep-pill{position:absolute; top:0; bottom:0; left:0; width:33.333%; display:grid; place-items:center; z-index:1;
  transform:translateX(calc(var(--col, 1) * 100%));
  transition:transform .8s var(--dep-spring), opacity .35s var(--ease-long)}
.dep-pill i{font-style:normal; padding:6px 14px; border-radius:var(--r-pill); font-size:var(--fs-xs); font-weight:600;
  background:var(--panel); color:var(--ink); border:1px solid var(--hair); box-shadow:var(--shadow-1);
  transition:background .4s var(--ease-long), color .4s var(--ease-long), border-color .4s var(--ease-long)}
.dep-pill[data-col="0"] i{border-color:color-mix(in srgb, var(--flag-red) 40%, var(--hair))}
.dep-pill[data-col="1"] i{background:var(--accent); color:#fff; border-color:var(--accent)}
.dep-pill[data-col="2"] i{background:var(--verified-ink); color:#fff; border-color:var(--verified-ink)}
.dep-pill.off{opacity:0; pointer-events:none}
/* On option C a row carries two pills, the firm's ordinary work and a
   restricted matter's. They never share a column (the restricted one is always
   in chambers), so both sit on the row's centre line. */
.dep-rx i{background:var(--verified-ink); color:#fff}
.dep-rx i:before{content:"\25CF  "; font-size:8px; vertical-align:1px}

/* the line leaving Mauritius, from your instance to the suppliers */
.dep-track:before{content:""; position:absolute; top:50%; left:16.666%; width:33.333%; height:8px; margin-top:-4px;
  --dep-line:color-mix(in srgb, var(--flag-red) 55%, transparent);
  background:radial-gradient(circle, var(--panel) 2px, var(--dep-line) 2.5px 3.5px, transparent 4px) right center/8px 8px no-repeat,
    repeating-linear-gradient(90deg, var(--dep-line) 0 5px, transparent 5px 9px) left center/calc(100% - 8px) 1.5px no-repeat;
  opacity:0; transition:opacity .4s ease}
.dep-row.is-out .dep-track:before{opacity:1}
.dep-track:after{content:""; position:absolute; top:50%; left:50%; width:7px; height:7px; margin:-3.5px 0 0 -3.5px;
  border-radius:50%; background:var(--flag-red); opacity:0}
.dep.is-anim .dep-row.is-out .dep-track:after{animation:dep-leave 1.8s cubic-bezier(.45,0,.55,1) infinite}
@keyframes dep-leave{0%{opacity:0; left:50%} 15%{opacity:1} 85%{opacity:1} 100%{opacity:0; left:16.666%}}

.dep-guard{margin:16px 0 0; display:flex; align-items:center; gap:10px; padding:12px 14px; border-radius:var(--r-md);
  background:color-mix(in srgb, var(--verified) 9%, transparent); color:var(--verified-ink); font-size:var(--fs-sm); font-weight:600}
.dep-guard:before{content:"\2713"; flex:none; display:grid; place-items:center; width:22px; height:22px; border-radius:50%;
  background:var(--verified-ink); color:#fff; font-size:12px}

.dep-descs{display:grid; gap:14px; margin-top:18px}
.dep-desc h3{display:flex; align-items:center; gap:10px; margin:0 0 6px; font-family:var(--font-display); font-weight:400; font-size:var(--fs-lg)}
.dep-desc p{margin:0; color:var(--muted); line-height:1.6; max-width:70ch}
.dep.is-live .dep-descs{gap:0}
.dep.is-live .dep-desc{grid-area:1/1; opacity:0; visibility:hidden; transform:translateY(6px);
  transition:opacity .35s var(--ease-long), transform .5s var(--ease-long), visibility 0s .35s}
/* out first, then in: two paragraphs crossfading in one cell read as a smear */
.dep.is-live .dep-desc.on{opacity:1; visibility:visible; transform:none; transition-delay:.18s, .18s, 0s}

@media(max-width:760px){
  .dep{--dep-lab:0px}
  .dep-board{padding:14px}
  .dep-zones{grid-template-columns:1fr 1fr 1fr}
  .dep-zones > span:first-child{display:none}
  .dep-z{padding:8px 6px}
  .dep-z strong{font-size:var(--fs-xs)}
  .dep-z span{display:none}
  .dep-row{grid-template-columns:1fr 1fr 1fr}
  .dep-rl{grid-column:1 / -1; padding:10px 0 6px; font-size:var(--fs-xs); font-weight:600}
  .dep-track{grid-column:1 / -1; height:46px}
  .dep-pill i{padding:5px 9px}
  .dep-opt{padding:0 14px 0 8px}
}
.dep-band{scroll-margin-top:80px}
@media(max-width:760px){
  .dep.is-live .dep-opts{display:grid; grid-template-columns:1fr 1fr; gap:6px}
  .dep-opt{justify-content:flex-start; padding:6px 10px 6px 6px; font-size:var(--fs-xs); line-height:1.25; text-align:left}
  .dep-l{width:24px; height:24px}
}
/* Phone nav: the wordmark, the language pill and the sub-nav took three rows,
   because .nav-right carries the full-width sub-nav and so always wrapped below
   the brand as a block. Under 560px its children join the bar directly: brand
   and language pill share the first row, the sub-nav chips take the second.
   "Citizen research" goes; the wordmark already links to the citizen surface. */
@media(max-width:559.98px){
  .navshell .nav-right{display:contents}
  .navshell .nav-right > .navlink{display:none}
  .navshell .langs{order:2; margin-left:auto}
  .navshell .subnav{order:3}
}

/* Section headings inherited body line-height (about 1.55), so every heading
   that ran to two lines opened a gap as tall as a third. Display type sits
   tight; balance keeps a lone word off the second line. */
.h2{line-height:1.12; text-wrap:balance}
.lede, .sc-body p, .dep-desc p{text-wrap:pretty}

/* The hosting page's audit log, drawn in the same chrome as the showcase. The
   captured one listed a development database: hashed user ids, loopback IPs
   and a column of auth.login. Its rows write themselves in once the frame is
   revealed; with no motion they are simply there. */
.bo-host .bo-app{min-height:0}
.bo-audit-full p{display:grid !important; grid-template-columns:40px minmax(0,.9fr) minmax(0,2fr); gap:10px; align-items:baseline}
.bo-audit-full .bo-k{letter-spacing:.06em}
.bo-who{font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
@container (max-width:520px){
  .bo-audit-full p{grid-template-columns:34px minmax(0,1fr)}
  .bo-audit-full .bo-who{grid-column:2}
  .bo-audit-full p > span:last-child{grid-column:2; margin-top:-4px; color:var(--muted)}
  .bo-audit-full .bo-k span:nth-child(3){display:none}
}
.js-motion .shotstage .bo-host .bo-audit p:not(.bo-k){opacity:0}
.js-motion .shotstage.in .bo-host .bo-audit p:not(.bo-k){animation:bo-slide .45s var(--bo-spring) both}
.js-motion .shotstage.in .bo-host .bo-audit p:nth-child(2){animation-delay:.5s}
.js-motion .shotstage.in .bo-host .bo-audit p:nth-child(3){animation-delay:.7s}
.js-motion .shotstage.in .bo-host .bo-audit p:nth-child(4){animation-delay:.9s}
.js-motion .shotstage.in .bo-host .bo-audit p:nth-child(5){animation-delay:1.1s}
.js-motion .shotstage.in .bo-host .bo-audit p:nth-child(6){animation-delay:1.3s}
.js-motion .shotstage.in .bo-host .bo-audit p:nth-child(7){animation:bo-slide .45s var(--bo-spring) 1.5s both, bo-flash 1.4s ease-out 1.8s both}
