/* ============================================================
   ASCENIX — the light site.

   This is the stylesheet the homepage was designed in. It came
   off demo-site/exacare-layout.html on 2026-08-19, unchanged,
   when Owen moved that page onto the live site: "keep the exact
   demo site landing page and transition it to the website
   folder."

   PART 1 is that file's own <style> block, verbatim. Every
   comment in it is the record of a decision and none of them
   were rewritten on the way across.

   PART 2 is new — the same vocabulary extended to the six
   interior pages, which were near-black and are now on this
   ground. It is at the bottom of the file, under its own banner.

   The ground is #F8FAFC, the one dark surface is navy
   #1C3F6E, display type is Newsreader and everything else is
   Plus Jakarta Sans. Module colour is fixed: falls orange,
   behaviours green, hydration blue, skin violet.
   ============================================================ */

/* ============================================================
   ASCENIX HOMEPAGE — the exacare.com layout, our palette
   Built 2026-08-17. Revised 2026-08-18. Shipped to the live
   site 2026-08-19; everything below this line is as it was
   written in the demo folder.

   Owen asked for the exacare.com homepage rebuilt "exactly like
   this except our product and our colours". So the section
   order, the proportions and every layout device are theirs;
   every word, figure, colour and mockup is ours.

   ---- 2026-08-18 pass, from Owen's notes ----------------------

   1. Eyebrows are gone. Every one of them — the hero pill, the
      closing pill, the mono micro-caps over the logo strip.
      His words: "the eyebrows look super ChatGPT".

   2. The logo-strip line is set in our own display serif at a
      readable size and carries the real footprint figure from
      company/overview.md, instead of 10px letterspaced mono.

   3. The dark surfaces are no longer ink #0B1220. They are
      navy #1C3F6E — rgb(28, 63, 110) — for any area that carries
      text. The bright blue is #0CC7ED, for buttons and CTAs.

   4. Every mockup is now a real product surface built from
      dashboard.css: the falls ring, the non-compliance chart,
      a nurse's note, the incident table with its why-flag, the
      twelve-week severity heatmap and the Risk Radar rank list.
      Figures agree with the product page — 13 falls in February
      against a 20 cap, 4 non-compliant, 35 over three months.

   5. Proof is the case-studies treatment: the three figures with
      a count-up, then Marion in display type with her portrait.
      The photo carousel is out. It is also the fix for the
      uncleared-photograph problem the old version carried.

   6. "Across every incident type" is now "What it covers", with
      the site's own subline, real boards, and the segments
      dimming in and out as they pass the middle of the screen.

   7. The tail is ours: the dark blue hands over to a white sheet
      with a radius on its top corners and a shadow cast upward,
      then the footer is a card floating on that sheet. Same
      recipe as .d-lightband / .d-foot in website/_src/dark.css,
      light-themed here, with the partner badge and the three
      compliance acts that footer carries.

   ---- 2026-08-18, second pass from Owen ----------------------

   8. A new section under the hero, where he drew a ring on the
      empty space: copy left, and on the right a plane tilted off
      head-on carrying the notes going in, a clean line with slow
      lumps of information on it, the A reading them, and the same
      line spitting the results out the far side. See "3b · the
      line" below for how it is built.

   9. The case-study section is back, with the photographs. The
      "Time your teams can feel" heading and the free-floating
      quote are gone INTO it: the quote is the left card and the
      three figures are the right one. Two cards because there is
      one customer on record and one set of figures.

  10. "Checked against your policy" is out of the headline. Owen,
      2026-08-12: having non-compliant paperwork is horrible and
      they want compliant paperwork; leading on whose policy it is
      makes a real survey finding sound like a preference setting.
      The customisation is still true and still said — second, in
      one clause, in the step body.

   TYPE: Newsreader for display, Plus Jakarta Sans for everything
   else — the light-theme pairing already in tokens.css.
   ============================================================ */

:root{
  --serif:var(--font-display);
  --sans:var(--font-ui);
  --mono:var(--font-mono);

  /* The page ground and the one dark surface. */
  --page:var(--subtle);
  --deep:var(--cyan-900);          /* #1C3F6E */
  --deep-2:#070E1C;                /* far stop: darker navy, not a third blue */
  --deep-hi:color-mix(in srgb,var(--brand) 18%,var(--deep));
  --sheet:#FAFAFA;                 /* the white tail, same as the site */

  /* Module colour is fixed and has been corrected once already:
     falls orange, behaviours green, hydration blue, skin violet.
     These are the light-ground steps of the site's four. */
  --falls:#F97316; --behav:#17B26A; --hydr:#0CC7ED; --skin:#8B5CF6;

  --maxw:1200px;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;background:var(--page);color:var(--text);font-family:var(--sans);
  font-size:16px;line-height:1.6;-webkit-font-smoothing:antialiased}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
.wrap{width:min(var(--maxw),calc(100% - 48px));margin-inline:auto}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* motion.js hides a below-the-fold reveal by setting this. Without
   the rule the page still reads; it just does not animate. */
[data-reveal-pending]{opacity:0}

/* ---------- type ---------- */
.display{font-family:var(--serif);font-weight:400;letter-spacing:-.02em;line-height:1.04;
  color:var(--text-strong)}
h1.display{font-size:clamp(40px,5.6vw,78px)}
h2.display{font-size:clamp(32px,4.2vw,58px)}
.it{font-style:italic}
/* The highlight swipe that used to sit under this word was the
   reference's, down to the rounded ends. Owen, 2026-08-18: "it's
   exactly like the ExaCare, which is a scary look — remove it."
   The italic is ours and stays; the bar is gone.

   What replaced it is a fill. "Our platform connects" sits grey and
   fills to blue as the statement comes up the screen — so the
   emphasis arrives on the phrase rather than sitting under it
   waiting. The subject and the verb fill together because they are
   one claim; splitting the fill off onto the verb alone left the
   name of the thing looking like the part that didn't matter. --p is written by the page script from this
   element's own position in the viewport, not from scrollY, because
   the statement is halfway down the page and a scroll-from-zero
   figure would have finished long before anyone saw it. */
.mark{--p:0%;white-space:nowrap;
  /* Grey rather than black underneath. Against near-black the blue
     was arriving on a word that already looked finished; against a
     grey the fill is the thing you notice, which is the point of it. */
  background-image:linear-gradient(90deg,var(--cyan-700) 0%,var(--cyan-700) var(--p),
    #A6B1BE var(--p),#A6B1BE 100%);
  -webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent}
.mark i{font-style:italic}
/* nowrap holds the phrase together so the fill crosses it in one
   sweep. Below this the type has hit its clamp floor while the
   column keeps narrowing, so the phrase is let go rather than
   allowed to run off the edge; clone gives each line its own ramp
   instead of one gradient stretched across both. */
@media(max-width:520px){.mark{white-space:normal;
  -webkit-box-decoration-break:clone;box-decoration-break:clone}}
@media(prefers-reduced-motion:reduce){.mark{--p:100%}}
.sub{font-size:clamp(16px,1.3vw,18.5px);line-height:1.62;color:var(--text-2);max-width:60ch}

/* ---------- buttons ----------
   MOTION, settled 2026-08-20 out of _proposals/2026-08-20-button-
   motion.html. Owen asked whether the primary and the secondary
   should match or each have their own vibe, and the answer the
   page argued for is MATCH THE PHYSICS, SPLIT THE FINISH.

     - the physics are identical on both, in both families: a 1px
       lift on hover and scale(.97) on press. They sit side by side
       in every closing band, and two different presses would read
       as two components that arrived from different places.
     - the primary carries one layer the secondary does not — the
       pointer light below. A ghost button with a glow on it stops
       being a ghost.

   Three things were broken rather than merely absent, and the
   transition list is the first: it named transform and box-shadow
   only, so .btn--ghost's background change — its one animation —
   was snapping. The other two are the press state and the hover
   gate, both below. */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;
  padding:15px 26px;border-radius:var(--r-pill);font-family:var(--sans);font-size:15px;font-weight:600;
  border:1px solid transparent;cursor:pointer;
  transform:translateZ(0);
  transition:transform .16s var(--ease-out),box-shadow .2s ease,
             background .2s ease,border-color .2s ease}
.btn--cta{background:var(--brand);color:#04222A;box-shadow:0 8px 22px -12px rgba(12,199,237,.9)}
.btn--ghost{background:rgba(11,18,32,.05);color:var(--text-strong)}
.btn--sm{padding:10px 18px;font-size:14px}
.btn--onink{background:rgba(255,255,255,.10);color:#fff;border-color:rgba(255,255,255,.20)}

/* The site's own text link, arrow and all. */
.tlink{display:inline-flex;align-items:center;gap:8px;font-size:16px;font-weight:500;
  color:var(--text);transition:color .2s ease}
.tlink:hover{color:var(--text-strong)}
.tlink svg{width:14px;height:14px;transition:transform .2s var(--ease-out)}
.tlink:hover svg{transform:translateX(4px)}

/* ---------- 2 · the header ----------
   Owen, 2026-08-18, pointing at archive-site/: the site's own
   header, the one that "kind of comes together when you scroll",
   instead of a pill that is a pill the whole way down.

   The recipe is `.d-nav` out of website/_src/dark.css, light-themed
   for this page. At rest it is a full-width bar with nothing behind
   it; on scroll `.d-nav__in` contracts from 1240 to 1000 and picks
   up liquid glass. At rest there is no fill, same as before.

   `data-scrolled` is already set by initNav() in motion.js, which
   looks for '.nav, .d-nav'. The demo never needed a second scroll
   listener — it needed the CSS that reads the attribute.

   THE ITEMS ARE THE LIVE SITE'S, not the reference's: Product,
   About with its dropdown, Case Studies, FAQ, Book a Demo. Product
   / Modules / Customers / Company were ExaCare's information
   architecture, which is not ours. "Sign in" went out with them —
   it pointed nowhere, and the live site does not have one, which
   closes the third open question at the bottom of this README.

   One deliberate difference from the live shell: the logo goes to
   #top rather than index.html, so clicking it does not walk you out
   of the demo. Every other item does leave, the same way the footer
   already does. */
.d-nav{position:fixed;top:0;left:0;right:0;z-index:100;padding-block:16px;
  transition:padding .25s ease;transform:translateZ(0);isolation:isolate}
.d-nav[data-scrolled='true']{padding-block:10px}
.d-nav__in{max-width:1240px;margin-inline:auto;padding-inline:24px;
  display:flex;align-items:center;justify-content:space-between;gap:24px;
  border:1px solid transparent;border-radius:var(--r-pill);
  position:relative;isolation:isolate;transform:translateZ(0);
  transition:max-width .42s var(--ease-out),padding .42s var(--ease-out)}
.d-nav__in > *{position:relative;z-index:1}
/* Glass lives on a pinned pseudo, not on the pill that also
   contracts. backdrop-filter on that pill recast the logo and the
   demo button whenever anything behind it redrew — hovering the
   flow cards or the logo strip. The filter stays on this layer;
   it is not in a transition. */
.d-nav[data-scrolled='true'] .d-nav__in::before{
  content:'';position:absolute;inset:-1px;z-index:0;border-radius:inherit;
  pointer-events:none;transform:translateZ(0);
  background:linear-gradient(180deg,rgba(255,255,255,.82),rgba(236,249,252,.74));
  border:1px solid rgba(28,63,110,.12);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.95),0 12px 36px rgba(28,63,110,.08);
  backdrop-filter:saturate(180%) blur(22px);-webkit-backdrop-filter:saturate(180%) blur(22px)}
@media(min-width:900px){
  .d-nav__in{padding-inline:40px}
  .d-nav[data-scrolled='true'] .d-nav__in{max-width:1000px;padding:9px 14px}
  .d-nav[data-scrolled='true'] .d-nav__logo{padding-left:16px}
}
/* Below the pill breakpoint it stays a plain frosted bar, same as
   the site: a 1000px pill on a 390px screen is just a bar with the
   corners cut off. */
@media(max-width:899px){
  .d-nav[data-scrolled='true'] .d-nav__in{padding-block:8px}
  .d-nav[data-scrolled='true'] .d-nav__in::before{
    box-shadow:inset 0 1px 0 rgba(255,255,255,.95);
    backdrop-filter:saturate(180%) blur(20px);-webkit-backdrop-filter:saturate(180%) blur(20px)}
}
.d-nav__logo img{height:24px;width:auto;display:block}
.d-nav__links{display:flex;align-items:center;gap:34px;font-size:15px}
.d-nav__links a{color:var(--text);transition:color .2s ease}
.d-nav__links a:hover{color:var(--text-strong)}
.d-nav__act{display:flex;align-items:center;gap:10px}

/* About carries Security and Careers, exactly as the live nav does.
   There is no Contact item: the details are in the footer and
   anyone who wants to talk to us books a demo. */
.d-nav__has{position:relative;display:inline-flex}
.d-nav__has > a{display:inline-flex;align-items:center;gap:5px}
.d-nav__has > a svg{width:11px;height:11px;transition:transform .2s ease}
.d-nav__has:hover > a svg{transform:rotate(180deg)}
.d-nav__menu{position:absolute;top:100%;left:50%;translate:-50% 12px;min-width:212px;
  display:flex;flex-direction:column;gap:2px;padding:8px;border-radius:16px;
  background:rgba(255,255,255,.72);border:1px solid rgba(255,255,255,.8);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9),0 22px 50px -26px rgba(11,18,32,.28);
  backdrop-filter:saturate(180%) blur(20px);-webkit-backdrop-filter:saturate(180%) blur(20px);
  opacity:0;visibility:hidden;
  transition:opacity .18s ease,translate .18s var(--ease-out),visibility .18s}
.d-nav__has:hover .d-nav__menu,.d-nav__has:focus-within .d-nav__menu{
  opacity:1;visibility:visible;translate:-50% 6px}
.d-nav__menu a{padding:9px 12px;border-radius:10px;font-size:14.5px;color:var(--text)}
.d-nav__menu a:hover{background:var(--n-100);color:var(--text-strong)}

.d-nav__toggle{display:none;width:38px;height:38px;align-items:center;justify-content:center;
  padding:0;background:0;border:0;cursor:pointer}
.d-nav__toggle span,.d-nav__toggle span::before,.d-nav__toggle span::after{
  display:block;width:15px;height:1.5px;background:var(--text-strong)}
.d-nav__toggle span{position:relative}
.d-nav__toggle span::before,.d-nav__toggle span::after{content:'';position:absolute;left:0}
.d-nav__toggle span::before{top:-5px}
.d-nav__toggle span::after{top:5px}
.d-nav__drawer{display:none;margin:10px 16px 0;padding:10px 16px 14px;border-radius:20px;
  background:rgba(255,255,255,.95);border:1px solid var(--border);
  backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px);
  box-shadow:0 22px 50px -26px rgba(11,18,32,.45)}
.d-nav[data-open='true'] .d-nav__drawer{display:block}
.d-nav__drawer a{display:block;padding:10px 4px;font-size:16px;color:var(--text)}
.d-nav__drawer a.d-nav__sub{padding-left:16px;font-size:14.5px;color:var(--text-2)}
@media(max-width:899px){.d-nav__links{display:none}.d-nav__toggle{display:flex}}

/* ---------- 3 · hero ---------- */
/* The header is fixed rather than in the flow, so the hero owns the
   space it used to take. */
.hero{position:relative;text-align:center;padding:clamp(148px,15vw,208px) 0 clamp(50px,6vw,80px);
  overflow:hidden}
/* The sunburst behind the headline is gone at Owen's direction —
   it was the reference's most recognisable device and the first
   thing on our page. The headline now carries the fold on its own,
   which is why it needed something to do.

   translateZ(0) pins the circuit and the copy to their own
   compositor layers. Without that split, hovering the demo
   button recasts the masked, filtered SVG every frame
   and the fold flickers. */
.hero__in{position:relative;z-index:1;transform:translateZ(0)}

/* ---- the circuit behind the fold -----------------------------
   Packets travel navy-adjacent into brand cyan. Three overlapping
   dashes, each a step closer in hue, with a blur on the tail so
   the join is a fade rather than a hard edge. */
.hero__vitals{position:absolute;inset:0;z-index:0;overflow:hidden;pointer-events:none;
  transform:translateZ(0);isolation:isolate;contain:paint;
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 8%,#000 82%,transparent 97%);
  mask-image:linear-gradient(180deg,transparent 0,#000 8%,#000 82%,transparent 97%)}
.hero__bloom{position:absolute;inset:18% 20% 26%;
  background:radial-gradient(ellipse 55% 46% at 50% 50%,rgba(12,199,237,.18),transparent 70%);
  filter:blur(32px)}
.hero__vitals svg{position:absolute;inset:0;width:100%;height:100%;
  shape-rendering:geometricPrecision}
.hero-tr{opacity:.38;stroke-width:.9}
.hero-pads{opacity:.72;filter:drop-shadow(0 0 2.5px rgba(12,199,237,.5))}
.hero-flow path{fill:none;animation:hero-out 5.6s linear infinite}
/* Blur lives on the group, not on every travelling path. A filter
   on an animating stroke is a new bitmap every frame; fourteen of
   those under a sibling hover is the flicker. */
.hero-flow--navy{filter:blur(.6px);opacity:.72}
.hero-flow--navy path{stroke:#0F9EC4;stroke-width:1.35;stroke-dasharray:14 86}
.hero-flow--mid{filter:blur(.25px);opacity:.85}
.hero-flow--mid path{stroke:#0BB4DC;stroke-width:1.15;stroke-dasharray:0 4 10 86}
.hero-flow--cyan path{stroke:#0CC7ED;stroke-width:1.05;stroke-dasharray:0 8 6 86}
.hero-flow--soft{filter:blur(2.2px);opacity:.22}
.hero-flow--soft path{stroke:#0CC7ED;stroke-width:3.6;stroke-dasharray:0 3 11 86}
@keyframes hero-out{to{stroke-dashoffset:-100}}
@media(prefers-reduced-motion:reduce){
  .hero-flow path{animation:none}
  .hero-flow{display:none}}
/* THE CLEARING gets its own box - inset:0, so it is exactly the hero -
   because it has to be sized in PERCENTAGES and the drawing it masks is
   a fixed 3400x800. Percentages on the svg would resolve against 3400
   and mean nothing. Two boxes, one mask each, rather than stacking both
   on .hero__vitals and reaching for mask-composite: nesting multiplies
   the masks on its own and there is no compositing operator to get
   wrong.
   The numbers are measured, not guessed. The copy's centre sits at 59%
   of the hero's height at every width tested (390 to 1920 - it barely
   moves, because the top padding and the type scale together). Its half
   width wants min(46%, 420px): on a phone the copy fills the screen, on
   a desktop max-width caps it and the percentage would keep growing past
   what it needs. Its half height wants 37%, measured max 32.4%. Those
   are the SOLID radii; the gradient is stated at 1/0.7 of each because
   the fill runs clear to 70% and then feathers, which is what stops the
   clearing reading as a drawn circle.
   min(46%, 420px) is what the width wants and min() is what we cannot
   have: Chrome rejects a math function in a gradient's ending-shape
   size, and it rejects it silently - the whole declaration computes to
   none and the clearing just is not there. The two arms cross at 913px,
   so one breakpoint draws the same curve in two rules that parse. */
.hero__vitals-clear{position:absolute;inset:0;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-image:radial-gradient(ellipse 52% 44% at 50% 56%,transparent 0 70%,#000 94%);
  mask-image:radial-gradient(ellipse 52% 44% at 50% 56%,transparent 0 70%,#000 94%)}
@media (min-width:900px){
  .hero__vitals-clear{
    -webkit-mask-image:radial-gradient(ellipse 540px 44% at 50% 56%,transparent 0 70%,#000 94%);
    mask-image:radial-gradient(ellipse 540px 44% at 50% 56%,transparent 0 70%,#000 94%)}
}


/* The headline is one colour and does not animate. The fill it used
   to carry moved down to "connects" in the statement — see .mark.

   Proof-line under the sub: a filled brand-cyan circle and a white
   tick, then the sentence. No pill, no glass, no glow — the old
   eyebrow treatment sat above the headline and read as chrome. */
.hero__trust{display:flex;align-items:center;justify-content:center;gap:8px;
  width:max-content;margin:20px auto 0;padding:0;
  color:#3F3A34;
  font-size:14.5px;font-weight:500;letter-spacing:-.005em;line-height:1.2}
.hero__trust-pip{width:16px;height:16px;border-radius:50%;flex:0 0 auto;
  display:grid;place-items:center;background:var(--brand)}
.hero__trust-pip svg{display:block;width:16px;height:16px}
@media (max-width:520px){
  .hero__trust{font-size:13.5px;margin-top:16px}}
.hero h1{margin:0 auto;max-width:17ch}
.hero .sub{margin:24px auto 0;text-align:center;max-width:56ch}
.hero .btn{margin-top:28px}

/* ---------- 3b · the line ----------
   Copy left, a tilted plane right. Study A out of
   _proposals/2026-08-18-flow-3d.html, carrying Rishi's flow: every
   module the home charts on the left, the A, five outcomes out.

   ---- rebuilt in CSS rather than SVG, 2026-08-18 ---------------
   Owen: "make the 3D element a lot cleaner and more modern — right
   now it looks super HTML-y." It did, and the reason was the
   drawing surface. An SVG rect can carry a fill, a 1px stroke and a
   flat offset copy of itself; that is the whole vocabulary, and it
   is exactly the vocabulary that reads as a div. What sells a solid
   is the stuff SVG makes expensive: an inset top highlight, a
   hairline that is a shadow rather than a stroke, a side face that
   DARKENS as it descends, a tight contact shadow under the near
   edge and a wide ambient one under the whole object.

   So the cards are HTML and the wires stayed SVG. The plane holds
   `aspect-ratio:900/520` and the overlay uses the same viewBox at
   xMidYMid meet, which means a percentage in the markup and a user
   unit in the path resolve to the same point at every width. That
   is the only reason the wires meet the cards.

   ---- the lift ------------------------------------------------
   The side face is a stack of six box-shadows whose offsets double
   in the lit state. Both states declare the SAME NUMBER of shadows,
   which is what lets the browser interpolate them — the edge grows
   as a document lands, instead of a rectangle sliding under a
   static shadow.

   The cards do not translate. A 7px lift over animated, filtered
   wires recasts that SVG on every hover, which is the flicker.
   Colour on the hairline and the bar is the pop.

   ONLY THE RIGHT SIDE LIGHTS, at Owen's direction: the outputs
   flash as a document lands. The input card holds still, because it is
   the thing being read rather than the thing being produced. */
.flow{padding:clamp(8px,1.6vw,22px) 0 clamp(16px,2.4vw,34px);
  transform:translateZ(0);isolation:isolate}
.flow__grid{display:grid;grid-template-columns:minmax(0,.8fr) minmax(0,1.2fr);
  gap:clamp(28px,4.2vw,60px);align-items:center}
@media(max-width:980px){.flow__grid{grid-template-columns:minmax(0,1fr);gap:30px}}
.flow h2{margin:0;max-width:16em;font-size:clamp(28px,3.3vw,44px)}
.flow .sub{margin-top:18px;max-width:42ch;font-size:16px}
.flow .tlink{margin-top:22px}

/* The tilt, and the floor it sits on. perspective-origin is off to
   the right so the plane turns away from the copy. */
.flow__stage{perspective:1700px;perspective-origin:74% 46%}
@media(min-width:981px){
  .flow__stage{position:relative;left:clamp(56px,7vw,120px)}
}
/* Every position on the plane is a percentage and the wires are a
   viewBox, so the geometry already scaled with the column. The type
   did not — it was in px — and below about 700px of plane that is
   the whole failure: at 390px the plane is 340px wide, an output
   card is 131x29, and "Ranked risk, projected forward" at 14px runs
   clean out of it. The aspect ratio cannot move (the wires are drawn
   against 900x520 at xMidYMid meet, so the cards would come off the
   ends of their own lines), which means the answer is to shrink the
   diagram as one object: the plane is a query container and every
   size inside it is cqw, capped at the value it has always had. The
   cap holds down to a plane of about 520px, which is roughly where a
   14px label genuinely stops fitting an output card, so nothing
   shrinks before it has to; below that the whole diagram scales down
   together instead of coming apart. The input card starts a little
   earlier, at about 620px — it is a title, seven rows and a footer
   inside a box 29% wide, so it runs out of room before the one-line
   outputs do. */
.flow__plane{position:relative;aspect-ratio:900/520;container-type:inline-size;
  transform:rotateY(-16deg) rotateX(7deg) rotate(-1deg);
  isolation:isolate}
@media(max-width:980px){
  .flow__stage{perspective:1700px;perspective-origin:50% 50%}
  .flow__plane{transform:rotateY(-8deg) rotateX(3.5deg)}
}
/* There is deliberately no ground shadow under the plane. One used
   to sit here — a blurred ellipse spanning the whole thing — and it
   read as a grey smear rather than as light, because the plane is
   not a solid object. It is a scatter of cards with a gap down the
   middle, so a single shadow beneath it was casting the silhouette
   of a body that isn't there. Each card carries its own contact
   shadow instead; that is what puts them in the scene. */
.flow__wires{position:absolute;inset:0;width:100%;height:100%;overflow:visible;z-index:1;
  pointer-events:none;transform:translateZ(0);isolation:isolate;contain:paint}

/* ---- the card ----
   Six side steps, a hairline that is a shadow so it never doubles
   with the highlight, and two grounds: a tight contact shadow at
   the near edge and a wide ambient one. */
/* ---- depth ----
   Owen, 2026-08-18: "almost too 3D now." Six steps at 12px deep is a
   plinth, not a card, and on the tall input card that made the
   bottom edge a long grey band. Four steps at 6px, and the ramp now
   ENDS near the page ground (#E4EAF1) instead of well below it —
   the last step was reading as a hard line under everything, which
   is what "the bottom looks iffy" was.

   The lit state grows the edge from 6px to 9px rather than doubling
   it. Both states still declare the same number of shadows, which
   is what lets the browser interpolate between them. */
.fc{--fc-c:var(--brand);--fc-s:rgba(12,199,237,.30);
  position:absolute;z-index:2;border-radius:min(16px,3.08cqw);
  background:linear-gradient(177deg,#FFFFFF 0%,#FCFDFE 64%,#F8FBFD 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    0 0 0 1px rgba(16,32,48,.07),
    1px 1.5px 0 #F6F8FB, 2px 3px 0 #F0F4F8, 3px 4.5px 0 #EAEFF5, 4px 6px 0 #E4EAF1,
    0 10px 14px -10px rgba(11,18,32,.20),
    0 26px 38px -26px rgba(11,18,32,.24);
  transition:box-shadow .38s cubic-bezier(.2,.9,.25,1);
  transform:translateZ(0)}
.fc.is-lit{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    0 0 0 1px var(--fc-s),
    1.5px 2.3px 0 #F6F8FB, 3px 4.5px 0 #F0F4F8, 4.5px 6.8px 0 #EAEFF5, 6px 9px 0 #E4EAF1,
    0 15px 18px -11px rgba(11,18,32,.22),
    0 34px 46px -28px var(--fc-s)}

/* ---- the input card ---- */
/* Same recipe as the outputs, at their popped depth. Six pixels
   of edge on a 66px pill reads as a slab; the same six on this
   tall face reads as a hairline. The lit 9px ramp is what makes
   the two objects agree. */
.fc--in{left:0;top:5%;width:29%;height:86%;padding:6% 6.5% 5%;
  display:flex;flex-direction:column;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    0 0 0 1px rgba(16,32,48,.07),
    1.5px 2.3px 0 #F6F8FB, 3px 4.5px 0 #F0F4F8, 4.5px 6.8px 0 #EAEFF5, 6px 9px 0 #E4EAF1,
    0 10px 14px -10px rgba(11,18,32,.20),
    0 26px 38px -26px rgba(11,18,32,.24)}
/* A third bigger, 2026-08-20 at Owen's direction — 14.5px and
   2.34cqw both went up by the same factor, so the card scales the
   way it always did and only the title's share of it changed. The
   cqw half is not decoration: the whole plane is a container query
   and a px-only title stops shrinking with everything else, which
   is the bug that put four output labels outside their own pills
   on a phone. Move one, move both. */
.fc__ttl{font-size:min(19.5px,3.15cqw);font-weight:600;line-height:1.28;letter-spacing:-.01em;
  color:var(--text-strong)}
/* Falls through Wounds sit lower, same direction, same day: "move
   the falls all the way down to wound slightly lower, because it's
   a little too high." The bigger title takes some of it and this
   takes the rest. There is room — the card runs to a footer pinned
   at the bottom, and the space this eats was empty. */
.fc__list{margin:15% 0 0;padding:0;list-style:none;display:flex;flex-direction:column;gap:4.2%}
.fc__list li{display:flex;align-items:center;gap:min(9px,1.45cqw);font-size:min(13.5px,2.18cqw);
  font-weight:500;color:var(--text);line-height:1.2}
.fc__list i{width:min(6px,.97cqw);height:min(6px,.97cqw);flex:0 0 auto;border-radius:50%;
  background:var(--brand);box-shadow:0 0 0 min(3px,.48cqw) rgba(12,199,237,.14)}
.fc__foot{margin-top:auto;padding-top:7%;border-top:1px solid var(--border);
  font-size:min(10.5px,1.69cqw);line-height:1.4;font-weight:500;color:var(--text-muted);
  letter-spacing:-.005em}

/* ---- the outputs ---- */
.fc--out{right:0;width:38%;height:14%;display:flex;align-items:center;gap:min(12px,2.31cqw);
  padding:0 5% 0 3.5%}
.fc--out b{font-size:min(14px,2.69cqw);font-weight:600;letter-spacing:-.014em;line-height:1.26;
  color:var(--text-strong)}
/* Each output owns a colour, and its wire and its packet carry the
   same one — so the line you follow out of the A tells you where it
   lands before you read the label. Every colour is already in the
   token set; none of them is invented for this. */
.fc__bar{width:min(4px,.77cqw);height:56%;align-self:center;border-radius:3px;background:var(--fc-c);
  flex:0 0 auto;transition:box-shadow .38s ease}
.fc.is-lit .fc__bar{box-shadow:0 0 12px var(--fc-s),0 0 3px var(--fc-c)}

/* ---- the A ----
   The disc is in the file. Extra depth is a hard edge under the
   PNG (drop-shadow follows the knockout) plus a dark puck sat
   just behind it, so the mark reads as a token rather than a
   sticker. One hard step, not two — two stacked on the PNG's own
   rim and it read as a thick puck. */
/* 45.5%, not 50%: the gap the A sits in runs from the input
   card's edge to the outputs' edge, and the middle of that gap is
   not the middle of the plane. At 50% it read as pushed toward the
   outcomes. */
.flow__hub{position:absolute;z-index:3;left:45.5%;top:50%;width:13.4%;aspect-ratio:1;
  translate:-50% -50%;display:grid;place-items:center;
  background:none;border-radius:0;overflow:visible;
  transform:translateZ(0);isolation:isolate;pointer-events:none}
.flow__hub img{width:100%;height:auto;position:relative;z-index:1;display:block;
  filter:
    drop-shadow(1.2px 1.6px 0 #0E1520)
    drop-shadow(0 10px 14px rgba(5,12,20,.30))
    drop-shadow(0 18px 26px rgba(5,12,20,.20))}
.flow__hub::after{content:'';position:absolute;z-index:0;inset:8%;border-radius:50%;
  background:#070C13;translate:1px 2px;
  box-shadow:0 8px 12px -8px rgba(5,12,20,.34)}
.flow__hub::before{content:'';position:absolute;inset:-18%;border-radius:50%;
  border:1px solid var(--brand);opacity:0;animation:fxping 3.2s cubic-bezier(.2,.7,.2,1) infinite}
@keyframes fxping{0%{transform:scale(.88);opacity:.55}72%,100%{transform:scale(1.34);opacity:0}}

/* ---- the wires ----
   Stroked with a gradient so they are strongest at the A and fade
   into the cards, which is what stops six lines reading as a
   circuit board. */
.fx-wire{fill:none;stroke:url(#fxgrad);stroke-width:1.6;stroke-linecap:round}
/* The flow. A dash that travels the wire, in the wire's own colour:
   a wide soft pass under a narrow bright one so the leading edge has
   some bloom to it. pathLength="100" on every path means one
   dasharray works for all eight lanes and they stay in step.

   The period is the pathLength exactly (14 + 86), so the loop is
   seamless — a dash leaves the far end as the next one enters. */
/* The bright pass is EXACTLY the wire's own width. At 3.2 over a
   1.6 wire it read as a snake riding the line — a separate object
   gliding along a rail. At the same width it reads as the line
   itself lighting up, which is what it is meant to be. The glow is
   a halo around that, not a tube under it: narrow enough that it
   never looks thicker than the wire. */
.fx-flow{fill:none;stroke-width:1.6;stroke-linecap:round;
  stroke-dasharray:16 84;animation:fxflow 3.2s linear infinite}
.fx-glow{filter:blur(2.5px)}
.fx-flow--soft{stroke-width:4.5;opacity:.22;stroke-dasharray:16 84}
@keyframes fxflow{to{stroke-dashoffset:-100}}
@media(prefers-reduced-motion:reduce){
  .fx-flow,.flow__hub::before{animation:none}
  .fc{transition:none}
}

/* The depth has to come down with everything else. Four hard steps
   at 6px under a 29px-tall card is the "almost too 3D" note all over
   again at a third of the size, and a 16deg turn on a diagram this
   small only foreshortens labels that are already tiny. Two steps and
   a shallower tilt. Both states still declare six shadows, which is
   what keeps the lit transition interpolating. */
@media(max-width:700px){
  .flow__plane{transform:rotateY(-5deg) rotateX(2deg)}
  /* THE LIST MARGIN COMES BACK DOWN HERE, and this is not a taste
     call. It is a percentage, so it resolves against the card's
     WIDTH, while the room it is eating is the card's HEIGHT — and
     on a narrow plane the card is proportionally much shorter than
     it is wide. At 15% the last row, Wounds, landed under the
     footer's hairline at 390px. It does not overflow the box
     (.fc__foot has margin-top:auto, so the flex column absorbs it
     by overlapping rather than by scrolling) which means a page
     that measures clean and still looks broken. Screenshot the
     card, do not trust scrollHeight. */
  .fc__list{margin-top:8%}
  .fc{box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    0 0 0 1px rgba(16,32,48,.07),
    1px 1.5px 0 #F1F5F9, 2px 3px 0 #E7EDF4,
    0 6px 9px -6px rgba(11,18,32,.20),
    0 14px 20px -14px rgba(11,18,32,.24)}
  .fc.is-lit{
    box-shadow:
      inset 0 1px 0 rgba(255,255,255,.95),
      0 0 0 1px var(--fc-s),
      1.5px 2.3px 0 #F1F5F9, 3px 4.5px 0 #E7EDF4,
      0 9px 11px -7px rgba(11,18,32,.22),
      0 18px 24px -15px var(--fc-s)}
  .fc--in{box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    0 0 0 1px rgba(16,32,48,.07),
    1.5px 2.3px 0 #F1F5F9, 3px 4.5px 0 #E7EDF4,
    0 6px 9px -6px rgba(11,18,32,.20),
    0 14px 20px -14px rgba(11,18,32,.24)}
}

/* ---------- 4 · logo strip ----------
   The line above the marks used to be 10px letterspaced mono in
   micro-caps. It is now our display serif at a size a person
   actually reads, and it carries the real number from
   company/overview.md instead of a shrug.

   Our client marks are knocked out to WHITE for the dark site, so
   on a light ground they are invisible. invert() flips a pure
   white knockout to black, which costs nothing and is reversible.
   Do not re-export a second set of dark PNGs for a demo. */
/* The fade belongs on the section, not on the row. The row is
   width:max-content — several viewports wide and translating — so
   percentage mask stops resolved against the whole marquee and put
   the right-hand ramp somewhere off past the edge of the screen.
   Masking the overflow:hidden section instead measures the stops
   against what is actually visible, so both edges dissolve the same
   way and stay put while the marks travel through them. */
.logos{padding:clamp(34px,4.4vw,58px) 0 clamp(56px,7vw,86px);overflow:hidden;
  transform:translateZ(0);isolation:isolate;
  -webkit-mask-image:linear-gradient(90deg,transparent 0%,#000 14%,#000 86%,transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0%,#000 14%,#000 86%,transparent 100%)}
.logos__row{display:flex;gap:64px;align-items:center;width:max-content;
  animation:slide 52s linear infinite;filter:invert(1) grayscale(1)}
.logos__row img{height:auto;width:calc(var(--w) * 1px);opacity:.42}
@keyframes slide{to{transform:translateX(-50%)}}

/* ---------- 5 · the statement ---------- */
.say{padding:clamp(56px,7vw,96px) 0}
.say p{font-family:var(--serif);font-weight:400;font-size:clamp(28px,3.5vw,48px);line-height:1.12;
  letter-spacing:-.02em;color:var(--text-strong);max-width:20ch;margin:0}
.say .btn{margin-top:34px}

/* ---------- 6 · the card pair ---------- */
.pair{display:grid;grid-template-columns:1fr 1fr;gap:22px;padding-bottom:clamp(56px,7vw,96px)}
@media(max-width:900px){.pair{grid-template-columns:1fr}}
.pcard{border-radius:24px;padding:30px;min-height:430px;position:relative;overflow:hidden;
  display:flex;flex-direction:column}
.pcard--dark{color:rgba(255,255,255,.76);
  background:radial-gradient(120% 100% at 12% 0%,var(--deep-hi) 0%,var(--deep) 52%,var(--deep-2) 100%)}
.pcard--light{background:var(--white);border:1px solid var(--border)}
.pcard__tag{display:flex;align-items:center;gap:10px;font-size:15px;font-weight:600;
  color:var(--text-strong)}
.pcard--dark .pcard__tag{color:#fff}
.pcard__sw{width:11px;height:11px;border-radius:3px;background:var(--sw,var(--brand))}
.pcard__say{font-family:var(--serif);font-size:26px;line-height:1.16;letter-spacing:-.02em;
  margin:14px 0 0;max-width:24ch;color:var(--text-strong)}
.pcard--dark .pcard__say{color:#fff}
.pcard__art{margin-top:auto;padding-top:26px}
/* A board on the blue keeps its own white surface and gets a
   deeper shadow so it lifts off the colour rather than sitting in
   it. Everything inside is still dashboard.css. */
.pcard--dark .dpanel{box-shadow:0 30px 60px -34px rgba(0,0,0,.85)}
/* A board keeps the light theme's ink whatever it is sitting on.
   dashboard.css leaves colour to inherit on a few elements
   (.dcard__value, .dchart__avg), and on a dark ground those
   inherit white and vanish into the white panel. */
.pcard--dark .dpanel,.jshot{color:var(--text)}
/* A specific gap, edge to edge of the board. The chart is counts
   by home; this is the reason one of those bars is red in the
   product. Negative margin cancels .dpanel's 14px pad so the
   wash hits the radius rather than floating as a chip. */
.dpanel:has(.dflag){overflow:hidden;padding-bottom:0}
.dflag{display:flex;align-items:center;gap:10px;margin:14px -14px 0;
  padding:11px 14px;background:var(--danger-bg);color:#B42318;
  font-size:12px;font-weight:600;line-height:1.3;
  border-top:1px solid rgba(180,35,24,.14)}
.dflag__mark{display:inline-flex;align-items:center;justify-content:center;
  width:22px;height:22px;flex:0 0 auto;border-radius:50%;
  background:#fff;color:#B42318}
.dflag__mark svg{width:12px;height:12px}
.dflag__home{color:var(--text-strong)}
.dflag__gap{margin-left:auto;text-align:right}
.pcard[data-imod='falls'] .pcard__sw{--sw:var(--falls)}
.pcard[data-imod='behav'] .pcard__sw{--sw:var(--behav)}
.pcard[data-imod='hydr'] .pcard__sw{--sw:var(--hydr)}
.pcard[data-imod='skin'] .pcard__sw{--sw:var(--skin)}
.imod{display:flex;flex-wrap:wrap;gap:7px;margin:18px 0 0}
.imod button{appearance:none;cursor:pointer;border:1px solid rgba(255,255,255,.16);
  background:rgba(255,255,255,.06);color:rgba(255,255,255,.78);
  border-radius:999px;padding:6px 12px;font:inherit;font-size:12.5px;font-weight:600}
.imod button:hover,.imod button:focus-visible{border-color:rgba(255,255,255,.34);color:#fff;outline:none}
.imod button[aria-selected='true']{color:#fff;border-color:color-mix(in srgb,var(--m,#0CC7ED) 60%,#fff);
  background:color-mix(in srgb,var(--m,#0CC7ED) 32%,transparent);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--m,#0CC7ED) 18%,transparent)}
.imod__stage{margin-top:16px}
.imod__stage .dpanel[hidden],.imod__grid tbody[hidden]{display:none}
.imod__stage .dpanel{min-height:0}
.imod__go{display:inline-flex;align-items:center;gap:6px;margin:14px auto 0;
  padding:0;border:0;background:none;cursor:pointer;font:inherit;font-size:13px;font-weight:600;
  color:#1C3F6E}
.imod__go svg{width:14px;height:14px}
.imod__go:hover,.imod__go:focus-visible{color:#0CC7ED;outline:none}
.imod__stats{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin-top:8px}
.imod__stats div{padding:12px 10px;border:1px solid var(--border);border-radius:12px;text-align:center}
.imod__stats b{display:block;font-size:22px;line-height:1;color:var(--ink);letter-spacing:-.03em}
.imod__stats b.ok{color:#067647}
.imod__stats b.warn{color:#B54708}
.imod__stats span{display:block;margin-top:6px;font-size:11.5px;color:var(--text-2);line-height:1.25}
.imod__tablehead{display:flex;align-items:center;gap:12px;margin-bottom:4px}
.imod__back{display:inline-flex;align-items:center;gap:4px;padding:4px 8px 4px 4px;
  border:1px solid var(--border);border-radius:999px;background:#fff;cursor:pointer;
  font:inherit;font-size:12px;font-weight:600;color:var(--text)}
.imod__back svg{width:14px;height:14px}
.imod__back:hover,.imod__back:focus-visible{border-color:#1C3F6E;color:#1C3F6E;outline:none}
.imod__tablesub{margin:0 0 12px;font-size:12.5px;color:var(--text-2)}
.imod__table .dtable--track{min-width:0}
.imod__table .dtable-wrap{max-height:280px}
@media(max-width:520px){.imod__stats{grid-template-columns:1fr}}

/* ---------- 6c · Glenn, across both cards ----------
   Owen, 2026-08-18: a card under the pair, running the full width
   of both and about a third of their height — the AI layer sitting
   on top of everything, and the point that anything in the
   platform can be asked about.

   So it is one grid child spanning 1 / -1 rather than a section of
   its own. A separate section would have put a gap and a ground
   change between the layer and the thing it sits on, which is the
   opposite of what a layer is.

   The tint is the brand at 10% over white with a brand hairline,
   because the two cards under it are already a dark one and a
   plain one; a third solid ground would read as a third product
   rather than as something over the first two.

   THE EXAMPLE IS THE CARE-PLAN CHECK, on purpose. "Suggests
   interventions" is what every AI feature in the category claims.
   Checking the care plan first and leaving out what is already
   charted is the part competitors do not do, it is in
   company/product.md, and it is one line.

   ---- revised the same day, from Owen -----------------------
   The module chips came off: the four names were already said in
   section 9 and the card is about the layer, not the list. The
   question types itself into the composer and Glenn answers like a
   chatbot, which is the real panel's order (type, send, think,
   answer) compressed to one exchange — a finished answer that just
   appears reads as a screenshot. The sample-data line moved out
   from under the answer to under the whole card, because it is a
   note about the page rather than part of the conversation. */
.gcard{grid-column:1 / -1;display:grid;grid-template-columns:minmax(0,.82fr) minmax(0,1.18fr);
  gap:clamp(20px,2.6vw,40px);align-items:center;
  padding:clamp(20px,2.2vw,28px);border-radius:24px;
  background:linear-gradient(112deg,rgba(12,199,237,.13) 0%,rgba(12,199,237,.05) 44%,var(--white) 100%);
  border:1px solid rgba(12,199,237,.32)}
@media(max-width:820px){.gcard{grid-template-columns:minmax(0,1fr);gap:22px}}
.gcard__say{font-family:var(--serif);font-size:clamp(21px,2vw,26px);line-height:1.16;
  letter-spacing:-.02em;margin:12px 0 0;max-width:22ch;color:var(--text-strong)}
.gspark{width:22px;height:22px;flex:0 0 auto;border-radius:7px;display:grid;place-items:center;
  background:var(--brand);color:#04222A}
.gspark svg{width:13px;height:13px}
/* The sample-data line sits UNDER the card, not inside the panel —
   it is a note about the page, not part of the conversation. */
.gsamp{grid-column:1 / -1;margin:0;text-align:center;font-size:12px;color:var(--text-muted)}

/* --- the thread ---
   Type into the composer, send, think, answer. Same order as the
   real panel in website/_src/dashboards.js, compressed to one
   exchange: a finished answer that simply appears reads as a
   screenshot, and watching the question get asked is the whole
   reason this card is not a static quote. */
.gchat{background:var(--white);border:1px solid var(--border);border-radius:18px;
  padding:14px;box-shadow:0 14px 34px -26px rgba(11,18,32,.5);
  display:flex;flex-direction:column;gap:10px;min-height:158px}
/* .gmsg and .gthink both set display, and a CSS display rule beats
   the hidden attribute's user-agent style — without this the empty
   bubbles show from the start and the thinking row never leaves. */
.gchat [hidden]{display:none}
.gmsg{display:flex;gap:10px;align-items:flex-start}
.gmsg--me{justify-content:flex-end}
.gmsg--me span{max-width:88%;padding:9px 14px;border-radius:14px 14px 4px 14px;
  background:rgba(12,199,237,.14);border:1px solid rgba(12,199,237,.22);
  font-size:14px;line-height:1.45;font-weight:500;color:var(--text-strong)}
.gmsg--ai p{margin:0;font-size:14.5px;line-height:1.56;color:var(--text-2)}
.gmsg--ai b{font-weight:600;color:var(--text-strong)}
/* The caret only shows while something is being typed. */
.is-typing::after{content:'';display:inline-block;width:1.5px;height:1em;margin-left:2px;
  translate:0 .16em;background:var(--cyan-700);animation:gcaret .9s steps(1) infinite}
@keyframes gcaret{50%{opacity:0}}
.gthink{display:flex;align-items:center;gap:10px;font-size:13.5px;color:var(--text-muted)}
.gthink i{width:5px;height:5px;border-radius:50%;background:var(--n-300);
  animation:gdot 1.1s ease-in-out infinite}
.gthink i:nth-child(2){animation-delay:.15s}
.gthink i:nth-child(3){animation-delay:.3s}
@keyframes gdot{0%,100%{opacity:.35;transform:translateY(0)}50%{opacity:1;transform:translateY(-3px)}}
.gcomp{margin-top:auto;display:flex;align-items:center;gap:10px;padding:9px 9px 9px 14px;
  border:1px solid var(--border);border-radius:var(--r-pill);background:var(--n-100);
  font-size:13.5px;color:var(--text-muted);min-height:42px}
.gcomp span{flex:1;min-width:0;overflow:hidden;white-space:nowrap;color:var(--text-strong)}
.gcomp span:empty::before{content:'Ask Glenn a follow-up\2026';color:var(--text-muted)}
.gcomp button{width:26px;height:26px;flex:0 0 auto;border:0;border-radius:50%;cursor:default;
  background:var(--brand);color:#04222A;display:grid;place-items:center}
.gcomp button svg{width:13px;height:13px}


/* ---------- tags: the two dashboard.css does not carry ---------- */
.tag--ok{background:var(--success-bg);color:#067647}
.tag--cy{background:var(--info-bg);color:var(--cyan-700)}
.tag--warn{background:var(--warning-bg);color:#B54708}

/* ---------- compact tables ----------
   .dtable is built for a full-width board and sets min-width:620px
   so its six columns never crush. Inside a card or a 470px mockup
   there are three columns and no reason for a scrollbar, so these
   two relax that and nothing else. Same table, same type scale,
   same red row. */
/* .jseg centres its text and td has no text-align of its own, so
   a table dropped into a centred section quietly centres too. */
.dtable td{text-align:left}
.dtable--mini{min-width:0}
.dtable--mini th,.dtable--mini td{padding:8px 10px}
/* On a phone the mini table gives back its slack instead of
   spilling its chips past the card edge: the columns are all
   nowrap, so every saved pixel of padding is a pixel of chip. */
@media(max-width:560px){
  .dtable--mini{font-size:11px}
  .dtable--mini th,.dtable--mini td{padding:8px 7px}
  .dtable--mini .tag{font-size:9.5px;padding:3px 7px}
}
.dtable--kv{min-width:0}
.dtable--kv td:last-child{text-align:right;font-weight:600;color:var(--ink);white-space:nowrap}
.whyflag__pop .tag{display:block;width:max-content}

/* ---------- 6b · what it's worth ----------
   Owen, 2026-08-18: the 20%, the $40K and the twelve weeks have to
   be on the page somewhere. They go HERE, between what it does and
   what one operator got out of it, because that is the only place
   the two kinds of number can sit near each other without being
   read as the same kind.

   They are not results. The 20% and the $40K are what the problem
   costs a home today as Ascenix sizes it, and the footnote under
   the row says so — the same separation website/_src/pages/
   index.html keeps. Do not move one of these into the case-study
   grid below, and do not put a count-up on them: a figure that
   spins up reads as something that was measured. */
.worth{padding:clamp(60px,7vw,96px) 0 clamp(34px,4.4vw,60px)}
.worth h2{text-align:center;max-width:14ch;margin:0 auto}
/* Option D out of _proposals/2026-08-18-worth-row.html, chosen
   2026-08-18. Four rounded cards each holding a big number and a
   paragraph was the shape every generator reaches for, and the
   reason it read as generic is that the container was doing no
   work: a box round a figure adds an edge and takes away air, and
   the figure was already the loudest thing in the block.

   So there is no container. The only ink spent on structure is a
   short rule under each figure, in that figure's own colour — the
   same device already running down the four outputs on the diagram
   in 3b, which is what makes this row read as part of a system
   rather than as a component that arrived from somewhere else.

   NO COUNT-UP HERE, and that is not just "no animation": a figure
   that spins up reads as something that was measured, and three of
   these four were not. */
.worth__grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(22px,3vw,46px);margin-top:clamp(40px,5vw,64px)}
@media(max-width:900px){.worth__grid{grid-template-columns:repeat(2,minmax(0,1fr));row-gap:40px}}
@media(max-width:520px){.worth__grid{grid-template-columns:minmax(0,1fr)}}
.wfig__n{display:block;font-family:var(--serif);font-weight:400;white-space:nowrap;
  font-size:clamp(38px,3.9vw,54px);line-height:.94;letter-spacing:-.045em;color:var(--text-strong)}
.wfig__r{display:block;width:46px;height:5px;border-radius:3px;margin:18px 0 16px;
  background:var(--c,var(--brand))}
.wfig__l{display:block;font-size:15px;font-weight:600;letter-spacing:-.01em;color:var(--text-strong)}
.wfig p{margin:9px 0 0;font-size:14.5px;line-height:1.58;color:var(--text-2)}

/* ---------- 6c · in their own words ----------
   Owen, 2026-08-20: a centre card with the quote we have, a second
   one to the right that scrolls in, and a third that asks for the
   next one.

   IT IS A REAL SCROLLER, not a slider that transforms a track. The
   rail is overflow-x with scroll-snap and the arrows call scrollTo,
   so a trackpad swipe, a touch drag, a keyboard arrow and the two
   buttons are all the same mechanic and none of them needed
   writing. What centres card one is the track's padding: half the
   leftover viewport on each side, which is also what leaves card
   two peeking at the edge rather than hard against it.

   The inactive cards are dimmed and stood back a little. That is
   the only thing marking the active card — no border, no ring —
   because the card is already a photograph with a scrim and one
   more edge on it would be one too many.

   DO NOT put data-reveal on a .vcard. motion.js animates transform
   with fill:both, which outranks the scale below, and every card
   would sit at 100% for good. */
.voices{padding:clamp(46px,6vw,80px) 0 clamp(52px,6.5vw,92px)}
.voices h2{text-align:center;max-width:16ch;margin:0 auto}

.voices__rail{--vcard-w:clamp(280px,58vw,700px);
  margin-top:clamp(32px,4.2vw,54px);
  overflow-x:auto;overflow-y:hidden;scroll-snap-type:x mandatory;
  scrollbar-width:none;-webkit-overflow-scrolling:touch}
.voices__rail::-webkit-scrollbar{display:none}
.voices__rail:focus-visible{outline:2px solid var(--brand);outline-offset:4px;border-radius:var(--r-lg)}
@media(prefers-reduced-motion:no-preference){.voices__rail{scroll-behavior:smooth}}

/* Percentage padding resolves against the rail's own width, so this
   is half the leftover viewport whatever the card clamps to. */
/* The rail clips: overflow-x:auto makes overflow-y:hidden a real
   clip, at the PADDING box. So the padding is not spacing, it is the
   room the card's shadow needs to finish in — 20px over the top of
   --sh-md's 18, 48px under its 38. Shrink either one and the shadow
   comes off against a straight horizontal edge under every card,
   which is the grey slab Owen caught on 2026-08-20. The inline
   padding is hundreds of pixels wide, so the sides were never at
   risk. */
.voices__track{display:flex;width:max-content;gap:clamp(14px,1.8vw,26px);
  padding-inline:calc((100% - var(--vcard-w)) / 2);padding-block:20px 48px}

.vcard{position:relative;flex:0 0 var(--vcard-w);width:var(--vcard-w);
  height:clamp(400px,33vw,470px);margin:0;overflow:hidden;
  border-radius:var(--r-xl);background:var(--ink);scroll-snap-align:center;
  box-shadow:none;opacity:.4;transform:scale(.945);
  transition:opacity .5s var(--ease-out),transform .5s var(--ease-out),
             box-shadow .5s var(--ease-out)}
/* --sh-md, not --sh-lg. A 60px blur under a card that is already a
   dark photograph on a near-white ground is the heavy end of the
   elevation scale doing work nothing asked for, and it is the one
   that would not fit the clip. The cards standing back have no
   shadow at all. */
.vcard.on{opacity:1;transform:none;box-shadow:var(--sh-md)}

.vcard__ph{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:50% 42%}
/* The scrim starts a quarter of the way down so the top of the photo
   is still a photo. Everything under it is type. */
.vcard--quote::after{content:'';position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(11,18,32,0) 24%,rgba(11,18,32,.58) 56%,
    rgba(11,18,32,.92) 100%)}

.vcard__body{position:relative;z-index:2;height:100%;display:flex;flex-direction:column;
  justify-content:flex-end;padding:clamp(22px,2.5vw,34px)}
.vcard blockquote{margin:0;font-family:var(--serif);font-weight:400;color:#fff;
  font-size:clamp(19px,1.7vw,25px);line-height:1.3;letter-spacing:-.015em;text-wrap:pretty}
.vcard blockquote em{font-style:italic;color:var(--cyan-200)}
.vcard--long blockquote{font-size:clamp(15.5px,1.35vw,20px);line-height:1.36}
.vcard figcaption{display:flex;align-items:center;gap:12px;margin-top:clamp(18px,2vw,26px)}
.vcard__face{width:46px;height:46px;flex:0 0 auto;border-radius:50%;object-fit:cover;
  border:1.5px solid rgba(255,255,255,.45)}
.vcard__who b{display:block;font-size:15px;font-weight:600;color:#fff;letter-spacing:-.01em}
.vcard__who i{display:block;font-style:normal;font-size:13px;margin-top:2px;
  color:rgba(255,255,255,.72)}

/* "View Case Study", pushed to the far end of the attribution row.
   It sits on the row rather than under it because a card that is
   already a photograph, a quote and a name does not need a fourth
   band of its own. Only a story with a `link` renders one — the
   partial is left out entirely otherwise, so a customer without a
   written-up case study is not a card with a dead link on it. */
.vcard__cs{display:inline-flex;align-items:center;gap:5px;margin-left:auto;
  flex:0 0 auto;padding:8px 12px 8px 14px;border-radius:var(--r-pill);
  font-size:13px;font-weight:600;letter-spacing:-.01em;text-decoration:none;
  color:#fff;background:rgba(255,255,255,.13);border:1px solid rgba(255,255,255,.28);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  transition:background var(--dur-fast) var(--ease-out),
             border-color var(--dur-fast) var(--ease-out)}
.vcard__cs svg{width:15px;height:15px;opacity:.8}
.vcard__cs:hover{background:rgba(255,255,255,.22);border-color:rgba(255,255,255,.45)}
/* Below the pill and the name cannot share a line without one of
   them wrapping mid-word, so the row stacks and the pill goes back
   to the left under the name. */
@media(max-width:620px){
  .vcard figcaption{flex-wrap:wrap}
  .vcard__cs{margin-left:58px;margin-top:14px}
}

/* --- the empty slot ---
   It has to read as a slot at a glance, from the label down to the
   ring where a face will go. See the note in the markup: nothing in
   here may be replaced with something that sounds like a customer
   until there IS one. */
.vcard--slot .vcard__lab{align-self:flex-start;margin-bottom:16px;
  font-family:var(--mono);font-size:10.5px;font-weight:500;
  letter-spacing:.14em;text-transform:uppercase;color:rgba(255,255,255,.9);
  padding:6px 11px;border-radius:var(--r-pill);
  background:rgba(255,255,255,.14);border:1px solid rgba(255,255,255,.28)}
.vcard--slot blockquote{color:rgba(255,255,255,.9)}
.vcard--slot .vcard__who b,.vcard--slot .vcard__who i{color:rgba(255,255,255,.6)}
.vcard__face--empty{display:block;background:rgba(255,255,255,.1);
  border-style:dashed;border-color:rgba(255,255,255,.4)}

/* --- the ask ---
   No photograph, so it does not read as a third testimonial. */
.vcard--ask{background:
  radial-gradient(120% 100% at 12% 0%,rgba(12,199,237,.16) 0%,rgba(12,199,237,0) 58%),
  linear-gradient(158deg,var(--cyan-800) 0%,var(--deep-2) 62%)}
.vcard--ask .vcard__body{justify-content:center}
.vcard--ask h3{margin:0;font-size:clamp(26px,2.5vw,36px);color:#fff;max-width:12ch}
.vcard--ask p{margin:16px 0 0;max-width:34ch;font-size:15.5px;line-height:1.6;
  color:rgba(255,255,255,.76)}
.vcard--ask .btn{align-self:flex-start;margin-top:clamp(22px,2.6vw,30px)}

/* --- the controls --- */
.voices__nav{display:flex;align-items:center;justify-content:center;
  gap:clamp(14px,1.6vw,20px);margin-top:clamp(22px,2.8vw,32px)}
.vbtn{width:44px;height:44px;flex:0 0 auto;display:inline-flex;align-items:center;
  justify-content:center;padding:0;border-radius:50%;cursor:pointer;
  border:1px solid var(--border);background:var(--white);color:var(--text-strong);
  transform:translateZ(0);
  transition:border-color var(--dur-fast) var(--ease-out),
             box-shadow var(--dur-fast) var(--ease-out),
             transform var(--dur-fast) var(--ease-out),opacity var(--dur-fast) linear}
.vbtn svg{width:20px;height:20px}
.vbtn:hover{border-color:var(--n-300);box-shadow:var(--sh-sm);transform:translate3d(0,-1px,0)}
.vbtn[disabled]{opacity:.3;pointer-events:none}
.vdots{display:flex;align-items:center;gap:8px}
.vdot{width:8px;height:8px;padding:0;border:0;border-radius:var(--r-pill);cursor:pointer;
  background:var(--n-300);transition:width var(--dur-fast) var(--ease-out),
             background var(--dur-fast) var(--ease-out)}
.vdot.on{width:24px;background:var(--brand)}

/* On a phone the card is nearly the whole screen, so it goes taller
   rather than wider: the quote is the same length either way and a
   280px-wide card at 3:2 has no room to set it. */
@media(max-width:620px){
  .voices__rail{--vcard-w:min(82vw,340px)}
  .vcard{height:clamp(400px,112vw,460px)}
  .vcard blockquote{font-size:19px}
  /* THE SCRIM HAS TO COME UP HERE, and it is not a taste call. The
     quote is the same length in a card two thirds the width, so it
     runs to four or five lines and its first line sits around 19% of
     the way down — above 24%, where the desktop scrim is still fully
     transparent. Measured on the couple photo, that put line one at
     2.3:1 against white, under the 4.5:1 floor, while the same card
     reads 7:1 on a desktop. With the wash below it is 7:1 on every
     line. Re-measure if the photograph or the quote length changes. */
  .vcard--quote::after{background:linear-gradient(180deg,rgba(11,18,32,.34) 0%,
    rgba(11,18,32,.6) 34%,rgba(11,18,32,.94) 100%)}
}

/* ---------- 7 · the case study ----------
   Owen, 2026-08-18, pointing at ExaCare's four-across figure row:
   *"include these four in the section like this, but obviously make
   it slightly different"* — same rhythm, our object.

   WHAT IS DIFFERENT, and why each one matters: theirs is bare on
   the ground, ours is a card with our radius and our border.
   Theirs are ink on cream, ours are cyan-700 on white. Their rules
   run the full height edge to edge; ours stop short at the top and
   bottom. And ours count up, which theirs do not. It reads as the
   same idea and not as the same asset.

   THE FOUR ARE ALL ONE OPERATOR'S — twelve homes, 80%, 15%, zero.
   A band strips the sentence off a number, so only numbers that
   survive without one can go in it, and one footnote then covers
   the whole row. That is why the 20% and the $40K are NOT here:
   they are what the problem costs a home today as Ascenix sizes
   it, they need their sentence, and dropped into a row of measured
   results nobody could tell which was which. They stay as prose
   cards in section 6b. Do not merge the two rows. */
.cases{padding:clamp(56px,7vw,100px) 0}
.cases__lede{text-align:center;margin:22px auto 0}
.cases__attrib{margin:clamp(26px,3vw,34px) auto 0;max-width:76ch;text-align:center;
  font-size:12.5px;line-height:1.55;color:var(--text-muted)}

/* --- the figure band --- */
.band{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  margin-top:clamp(38px,5vw,60px);background:var(--white);border:1px solid var(--border);
  border-radius:24px;box-shadow:0 1px 2px rgba(11,18,32,.04);overflow:hidden}
.band__i{position:relative;padding:clamp(28px,3.2vw,40px) clamp(20px,2.4vw,32px)}
/* The rule is a pseudo-element rather than a border so it can stop
   short of the card edge. A border cannot be inset, and running it
   the full height is the reference's move, not ours. */
.band__i::before{content:'';position:absolute;left:0;top:18%;bottom:18%;width:1px;
  background:var(--border)}
.band__i:first-child::before{display:none}
.band__n{display:block;font-family:var(--serif);font-weight:400;
  font-size:clamp(38px,4.4vw,60px);line-height:1;letter-spacing:-.04em;color:var(--cyan-700);
  white-space:nowrap}
.band__l{display:block;margin-top:clamp(14px,1.6vw,20px);max-width:22ch;
  font-size:14.5px;line-height:1.42;font-weight:500;color:var(--text-strong)}
@media(max-width:900px){
  .band{grid-template-columns:repeat(2,minmax(0,1fr))}
  .band__i:nth-child(2n+1)::before{display:none}
  .band__i:nth-child(n+3){border-top:1px solid var(--border)}
}
@media(max-width:460px){
  .band{grid-template-columns:minmax(0,1fr)}
  .band__i::before{display:none}
  .band__i:nth-child(n+2){border-top:1px solid var(--border)}
}

/* --- the story, under the band --- */
.story{display:grid;grid-template-columns:minmax(0,.82fr) minmax(0,1.18fr);
  margin-top:22px;background:var(--white);border:1px solid var(--border);
  border-radius:24px;overflow:hidden;box-shadow:0 1px 2px rgba(11,18,32,.04)}
@media(max-width:820px){.story{grid-template-columns:minmax(0,1fr)}}
.story__ph{position:relative;min-height:clamp(260px,30vw,380px);background:var(--n-100)}
.story__ph img{width:100%;height:100%;object-fit:cover;object-position:46% 50%}
.story__b{display:flex;flex-direction:column;justify-content:center;
  padding:clamp(30px,3.4vw,48px)}
/* A flex item in a column container stretches on the cross axis, so
   width:auto on an image means "as wide as the card" and the mark
   comes out squashed to its own height. align-self holds it to its
   aspect. Client marks are knocked out to white for the dark site,
   so they need the same invert as the strip up top. */
.story__logo{align-self:flex-start;width:78px;height:auto;margin-bottom:22px;
  filter:invert(1) grayscale(1);opacity:.5}
.story blockquote{margin:0;font-family:var(--serif);font-weight:400;
  font-size:clamp(21px,2.1vw,30px);line-height:1.24;letter-spacing:-.022em;color:var(--text-strong)}
.story blockquote em{font-style:italic;color:var(--cyan-700)}
.story figcaption{display:flex;align-items:center;gap:14px;margin-top:clamp(26px,3vw,36px)}
.story__face{width:52px;height:52px;flex:0 0 auto;border-radius:50%;object-fit:cover;
  box-shadow:0 0 0 1px var(--border),0 0 0 5px rgba(12,199,237,.12)}
.story__who b{display:block;font-size:16px;font-weight:600;color:var(--text-strong)}
.story__who i{display:block;font-style:normal;font-size:14px;color:var(--text-2);margin-top:3px}
.story .tlink{align-self:flex-start;margin-top:26px;font-size:15px}

/* ---------- 8 · the sticky split ----------
   GONE FROM THE SITE 2026-08-20. The section came off the homepage
   and it was the only page that ever carried it, so the rules went
   with it. Markup and CSS are archived together in
   _archive/homepage-sticky-split.html.

   site.js's split/rail sync is NOT dead and was not touched: the
   same block drives the module rail on the homepage and the product
   page, and it no-ops on a page with no [data-step]. What replaced
   this section is 8 · the integrations band, below. */

/* ---------- 8 · the integrations band ----------
   One row, full width, short. It sits between the quotes and the
   blue module band, which is exactly where the longest section on
   the page used to be — see the note in the markup.

   IT IS NOT THE CLIENT STRIP. Section 4 is a scrolling marquee of
   customer marks knocked back to grey and set at a shared optical
   size. This is three EHR marks, still, in their own colours, on a
   tinted band, with a sentence beside them. If the two ever start
   looking alike, this is the one that changes: the strip's job is
   volume and this one's job is naming three specific systems.

   --cap does the same work it does on the security page's cards:
   every logo has a different amount of air baked into its file, so
   the per-mark percentage is an optical match, not a measured one.
   Set it by eye against the row, never by making the boxes equal. */
.ints{position:relative;background:var(--cyan-50);
  border-block:1px solid rgba(7,132,161,.14);
  padding:clamp(26px,3vw,38px) 0}
.ints__row{display:flex;align-items:center;justify-content:space-between;
  gap:clamp(24px,4vw,64px);flex-wrap:wrap}
.ints__say h2{margin:0;font-family:var(--serif);font-weight:400;letter-spacing:-.02em;
  font-size:clamp(21px,2.1vw,29px);line-height:1.14;color:var(--text-strong);max-width:20ch}
.ints__say p{margin:9px 0 0;font-size:14.5px;line-height:1.6;color:var(--text-2);max-width:46ch}
.tlink--sm{font-size:14.5px;gap:5px;white-space:nowrap}
.tlink--sm svg{width:15px;height:15px}

.ints__marks{display:flex;align-items:center;gap:clamp(24px,3.4vw,52px);
  margin:0;padding:0;list-style:none;flex-wrap:wrap}
.ints__marks li{display:flex;align-items:center;justify-content:center;
  width:clamp(62px,6.6vw,88px);height:clamp(42px,4.6vw,58px)}
.ints__marks img{width:auto;height:auto;max-width:var(--cap,72%);max-height:var(--cap,72%);
  object-fit:contain;display:block}
/* "anything else" is type, not a drawn mark. On the security page
   the generic entry earns an icon because it is a card in a row of
   cards; here it is one line at the end of a row of logos, and a
   fourth glyph would read as a fourth vendor. */
.ints__marks .ints__more{width:auto;font-size:12.5px;line-height:1.35;font-weight:600;
  letter-spacing:-.005em;color:var(--cyan-800);text-align:left;
  /* it is an li, so it inherits the row's justify-content:center —
     which centred it in its own box the moment it wrapped onto a
     line of its own on a phone, and it read as indented under the
     third logo rather than aligned with the first. */
  justify-content:flex-start}

@media(max-width:820px){
  .ints__row{justify-content:flex-start}
  .ints__marks{gap:clamp(20px,5vw,34px)}
}
@media(max-width:520px){
  .ints__marks li{width:56px;height:38px}
  .ints__marks .ints__more{flex-basis:100%}
}

/* ---------- 9 · what it covers ----------
   Their three care settings down a left rail that lights as you
   scroll; ours are the four modules, which is the same device
   carrying real content.

   The segments now fade and lift as they pass the middle of the
   screen instead of just being there. Deliberately NOT motion.js
   reveals: a reveal fires once and holds, and these have to come
   back when you scroll up. */
.journey{background:radial-gradient(90% 60% at 50% 0%,var(--deep-hi) 0%,var(--deep) 52%,var(--deep-2) 100%);
  color:rgba(255,255,255,.72);
  /* the extra bottom padding is the radius the sheet above now
     overlaps by; without it the last module is clipped */
  padding:clamp(72px,9vw,120px) 0 calc(clamp(30px,4vw,50px) + clamp(26px,3.4vw,46px));
  /* clip, NOT hidden. overflow:hidden makes this element a scroll
     container, and a scroll container is the scrollport its own
     descendants stick to — so position:sticky on .jnav was being
     resolved against a box that never scrolls, which meant the rail
     did not stick at all. It scrolled away with the first segment
     and nobody ever saw the highlight move. overflow:clip does the
     same clipping without creating the scroll container. */
  position:relative;overflow:clip}
.journey h2{color:#fff;text-align:center}
.journey__lede{text-align:center;max-width:30ch;margin:clamp(24px,3vw,36px) auto 0;
  font-size:clamp(19px,1.9vw,24px);line-height:1.35;font-weight:500;color:rgba(255,255,255,.82)}
.journey__lede b{font-weight:600}
.journey__sub{text-align:center;max-width:52ch;margin:clamp(14px,1.8vw,20px) auto 0;
  font-size:15.5px;line-height:1.6;color:rgba(255,255,255,.62)}
.journey__grid{display:grid;grid-template-columns:236px 1fr;gap:44px;margin-top:clamp(40px,5vw,64px)}
@media(max-width:940px){.journey__grid{grid-template-columns:1fr}.jnav{display:none}}
.jnav{position:sticky;top:130px;align-self:start;border-left:1px solid rgba(255,255,255,.16)}
.jnav a{display:flex;align-items:center;gap:12px;padding:11px 0 11px 18px;font-size:16px;
  color:rgba(255,255,255,.4);position:relative;transition:color .3s ease}
.jnav a::before{content:'';position:absolute;left:-1px;top:0;bottom:0;width:2px;background:transparent;
  transition:background .3s ease}
.jnav a.on{color:#fff}
.jnav a.on::before{background:var(--m,var(--brand))}
.jseg{min-height:78vh;display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;gap:20px;padding:40px 0;
  opacity:.28;transform:translateY(18px) scale(.982);
  transition:opacity .5s var(--ease-out),transform .5s var(--ease-out)}
.jseg.on{opacity:1;transform:none}
.jseg > h3{font-family:var(--serif);font-size:clamp(24px,2.6vw,34px);font-weight:400;color:#fff;margin:0;
  letter-spacing:-.02em}
.jseg > p{margin:0;max-width:52ch;color:rgba(255,255,255,.7);font-size:15.5px}
.jshot{width:min(560px,100%)}
.jshot .dpanel{box-shadow:0 40px 80px -40px rgba(0,0,0,.85)}
@media(prefers-reduced-motion:reduce){.jseg{opacity:1;transform:none}}

/* ---------- 10 + 11 · the tail ----------
   Ours, and it is a recipe rather than a gradient. Black-into-
   white through grey is mud however it is eased, so the white
   ground is an object: a full-bleed sheet with a large radius on
   its top corners that slides up over the blue and stays there.
   What sells the lift is a shadow cast UPWARD onto the colour.

   The footer then continues the same sheet — same ground, square
   corners, no seam — with the footer itself as a card floating on
   it. Copied from .dark .d-lightband / .dark .d-foot in
   website/_src/dark.css and light-themed for this page. */
/* The sheet rides UP over the blue by exactly its own radius. It
   used to start where the blue stopped, so the two corners it cuts
   out showed the page ground behind them — a pale grey notch on
   either side of the handover, which is the one place the seam is
   supposed to be invisible. The journey section gets the same
   figure back as padding so nothing underneath is covered.

   The shadow is cast upward onto the colour and it was doing far
   too much: at .75 black it read as a smear rather than as a lift.
   It is now a third of that and pulled in tighter. */
.d-lightband{position:relative;z-index:2;text-align:center;
  --lb-r:clamp(26px,3.4vw,46px);
  margin-top:calc(-1 * var(--lb-r));
  padding:clamp(76px,9vw,132px) 0 clamp(72px,9vw,128px);
  border-radius:var(--lb-r) var(--lb-r) 0 0;
  background:radial-gradient(1100px 560px at 50% 30%,rgba(7,132,161,.08),transparent 70%),var(--sheet);
  box-shadow:0 -22px 44px -22px rgba(4,26,33,.42)}
.d-lightband h2{margin:0 auto;max-width:15ch}
.d-lightband p{margin:24px auto 0;max-width:50ch;font-size:clamp(16px,1.35vw,19px);
  line-height:1.62;color:var(--text)}
.d-lightband .d-acts{display:flex;gap:12px;justify-content:center;flex-wrap:wrap;margin-top:38px}

.d-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:46px;
  padding:0 24px;border-radius:var(--r-pill);border:1px solid transparent;font-size:15px;
  font-weight:600;letter-spacing:-.01em;white-space:nowrap;transform:translateZ(0);
  transition:transform .16s var(--ease-out),background .2s ease,border-color .2s ease,box-shadow .2s ease}
/* THE PRIMARY PILL IS CYAN, on the white sheet and everywhere else.
   Owen 2026-08-20: "the black demo with the rainbows is not good...
   it should be the blue one." It was ink with the label painted in a
   four-stop cyan-to-violet ramp through background-clip:text, which
   is the one place on the site a colour appeared that is not ours.

   These two rules are .btn--cta's, to the pixel. The site now has
   exactly one look for "book a demo" — the nav pill, the hero and
   all six closing bands — and .d-grad is gone rather than left
   sitting unused for somebody to reach for again. */
.d-btn--primary{background:var(--brand);color:#04222A;
  box-shadow:0 8px 22px -12px rgba(12,199,237,.9)}
.d-btn--ghost{background:var(--white);border-color:var(--border);color:var(--text-strong)}

/* ============================================================
   BUTTON HOVER, PRESS AND THE POINTER LIGHT
   Both families in one place, because the rules are the same
   rules and splitting them is how they drift apart.
   ============================================================ */

/* HOVER IS GATED. A phone has no pointer, so :hover latches on tap
   and stays lit until something else is touched — which reads as a
   button that did not un-press. Everything that only makes sense
   under a cursor lives in here. */
@media(hover:hover) and (pointer:fine){
  .btn--cta:hover,.d-btn--primary:hover{transform:translate3d(0,-1px,0);
    box-shadow:0 12px 28px -12px rgba(12,199,237,1)}
  .btn--ghost:hover{transform:translate3d(0,-1px,0);background:rgba(11,18,32,.09)}
  .btn--onink:hover{transform:translate3d(0,-1px,0);background:rgba(255,255,255,.18)}
  .d-btn--ghost:hover{transform:translate3d(0,-1px,0);border-color:var(--n-300)}
  .btn--cta:hover::before,.d-btn--primary:hover::before{opacity:1}
  /* The hero CTA sits over the circuit. A 1px lift recasts that
     layer; the pointer light and the denser shadow are the hover. */
  .hero .btn--cta:hover{transform:translateZ(0)}
}

/* THE PRESS, and it is last on purpose. Pressing means hovering
   too, so both rules match at once and the later one has to be
   this one — move it above the block up there and the lift wins
   and nothing happens under the finger. .97 rather than .95: the
   pill is 46px tall and any more reads as a wobble. */
.btn:active,.btn--cta:active,.btn--ghost:active,.btn--onink:active,
.d-btn:active,.d-btn--primary:active,.d-btn--ghost:active{transform:scale(.97)}

/* THE POINTER LIGHT, primary only, both families.
   This is the site's own [data-pointer-glow] — the light on the
   hero — at pill size, and reusing it is the point: a second use
   of a device we already have reads as ours, where a new effect
   reads as an effect. site.js writes --mx/--my; with no script and
   under reduced motion the highlight simply sits in the middle,
   which is the gentler version rather than none.

   isolation:isolate is load-bearing. It gives the button its own
   stacking context so z-index:-1 lands the layer above the pill's
   own background and below its label. Without it the layer goes
   behind the button entirely and nothing shows. */
.btn--cta,.d-btn--primary{position:relative;isolation:isolate;transform:translateZ(0)}
.btn--cta::before,.d-btn--primary::before{content:'';position:absolute;inset:0;z-index:-1;
  border-radius:inherit;opacity:0;pointer-events:none;transition:opacity .22s var(--ease-out);
  background:radial-gradient(120px 60px at var(--mx,50%) var(--my,50%),
    rgba(255,255,255,.55),rgba(255,255,255,0) 70%)}

/* Reduced motion keeps the colour and the light and drops the
   travel — fewer and gentler, not nothing. */
@media(prefers-reduced-motion:reduce){
  .btn,.d-btn{transition:box-shadow .2s ease,background .2s ease,border-color .2s ease}
  .btn:hover,.btn:active,.d-btn:hover,.d-btn:active,
  .btn--cta:hover,.btn--ghost:hover,.btn--onink:hover,
  .d-btn--primary:hover,.d-btn--ghost:hover{transform:none}
}

.d-foot{position:relative;z-index:2;background:var(--sheet);
  padding:0 0 clamp(24px,4vw,48px);font-size:14px;color:var(--text)}
.d-foot__card{background:var(--white);border:1px solid var(--border);border-radius:26px;
  padding:clamp(34px,4vw,54px) clamp(24px,3.4vw,52px) clamp(22px,2.4vw,30px);
  box-shadow:0 1px 2px rgba(11,18,32,.04)}
.d-foot__top{display:grid;grid-template-columns:minmax(0,1.6fr) repeat(2,minmax(0,1fr));gap:48px}
@media(max-width:760px){.d-foot__top{grid-template-columns:minmax(0,1fr);gap:34px}}
.d-foot img{height:24px;width:auto;margin-bottom:20px}
.d-foot h4{font-size:11.5px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:var(--text-muted);margin:0 0 18px}
.d-foot a,.d-foot__line{display:block;padding:6px 0;font-size:15px;color:var(--text)}
.d-foot a:hover{color:var(--text-strong)}
.d-foot__blurb{max-width:32ch;margin:0;font-size:14.5px;line-height:1.6;color:var(--text-2)}
.d-foot__marks{display:flex;flex-direction:column;align-items:flex-start;gap:16px;margin-top:24px}
/* PointClickCare keeps its own colours — a partner mark is not
   ours to restyle — and this is the white sheet it was drawn for. */
.d-foot a.d-foot__badge{display:inline-block;margin:0;padding:0;opacity:.9;transition:opacity .2s ease}
.d-foot a.d-foot__badge:hover{opacity:1}
.d-foot a.d-foot__badge img{height:auto;width:168px;margin:0;display:block}
/* HIPAA / PHIPA / PIPEDA are acts, not brands. There is no badge
   to reproduce and an invented seal would imply a certifying body
   that does not exist, so they are set as a footnote. */
.d-foot a.d-foot__comply{display:block;margin:0;padding:15px 0 0;border-top:1px solid var(--border);
  max-width:250px}
.d-foot a.d-foot__comply h5{margin:0 0 9px;font-size:10.5px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--text-muted)}
.d-foot a.d-foot__comply p{display:flex;align-items:center;gap:9px;margin:0;padding:0;
  font-size:13.5px;font-weight:500;color:var(--text)}
.d-foot a.d-foot__comply svg{width:14px;height:14px;color:var(--cyan-700);flex:0 0 auto}
.d-social{display:flex;gap:10px;margin-top:22px}
.d-social a{width:38px;height:38px;padding:0;border-radius:50%;border:1px solid var(--border);
  background:var(--n-100);display:grid;place-items:center;color:var(--text)}
.d-social a:hover{background:var(--border);color:var(--text-strong)}
.d-social svg{width:16px;height:16px}
.d-foot__bottom{margin-top:clamp(38px,5vw,64px);padding-top:26px;border-top:1px solid var(--border);
  display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;font-size:13.5px;
  color:var(--text-muted)}

@media(prefers-reduced-motion:reduce){.logos__row{animation:none}}


/* ############################################################
   ############################################################

   PART 2 · THE INTERIOR PAGES

   Written 2026-08-19, when Product, Case Studies, Security,
   About, FAQ and Book a Demo came off the near-black shell and
   onto this one. Owen's brief was that they should not only
   match the white ground but match the GRAPHICS, "very
   one-to-one" with the homepage.

   So almost nothing new is invented below. The rule is that a
   job the homepage already has a device for uses that device:

     a row of figures            .band          (case study)
     a figure with a sentence    .cols/.col     (the worth row)
     two things in contrast      .pair/.pcard
     a walk through four steps   .split/.step/.stick/.shot
     a walk through the modules  .journey/.jnav/.jseg
     a customer speaking         .story
     the assistant               .gcard/.gchat
     a board, anywhere           dashboard.css, untouched

   WHAT IS NOT HERE, AND ON PURPOSE: a grid of rounded white
   boxes each holding an icon, a heading and a paragraph. Owen
   killed that shape on 2026-08-18 — "this looks a little Claude
   to me" — and he was right about why: the container does no
   work. A box around a figure adds an edge and takes away air.
   The interior pages ran on exactly that shape (.d-card, three
   and four across, six times a page) and every one of those
   grids is now .cols: no container, and the only ink spent on
   structure is a short rule in the block's own colour. That is
   the device already running down the four outputs on the flow
   diagram, which is what makes the pages read as one system.

   Colour still means something and is still fixed: falls
   orange, behaviours green, hydration blue, skin violet.
   Anything that is not a module uses cyan.
   ############################################################
   ############################################################ */

/* ---------- the skip link ----------
   base.css used to carry this and is not loaded here. It has to
   be invisible until focused and legible the moment it is; a
   skip link that is merely off-screen forever is not one. */
.skip-link{position:absolute;left:-9999px;top:0;z-index:200;
  padding:12px 18px;border-radius:0 0 12px 0;background:var(--text-strong);color:#fff;
  font-size:14px;font-weight:600}
.skip-link:focus{left:0}

/* ---------- section rhythm ----------
   One measure, so a page reads at the homepage's pace. .sec is
   the homepage's own section padding (.split and .cases both sit
   at this figure); --tight is for a block that belongs to the one
   above it and should not read as a new subject. */
.sec{padding:clamp(56px,7vw,100px) 0;position:relative}
.sec--tight{padding-block:clamp(34px,4.4vw,62px)}
.sec--first{padding-top:0}

/* The one dark surface, and it is .journey's ground rather than a
   second recipe: the same radial off cyan-900. Used where an
   interior page needs the page to change colour under it. */
.sec--ink{background:radial-gradient(90% 60% at 50% 0%,var(--deep-hi) 0%,var(--deep) 52%,var(--deep-2) 100%);
  color:rgba(255,255,255,.72);
  /* the extra bottom padding is the radius the white sheet above
     overlaps by. Without it the last line in the section is under
     the sheet, which is the bug .journey already had. */
  padding-bottom:calc(clamp(56px,7vw,100px) + clamp(26px,3.4vw,46px));
  /* clip, NOT hidden — hidden makes this a scroll container and
     kills position:sticky in every descendant, silently. */
  overflow:clip}
.sec--ink h2,.sec--ink h3{color:#fff}
.sec--ink .sub,.sec--ink p{color:rgba(255,255,255,.7)}
.sec--ink .tlink{color:rgba(255,255,255,.82)}
.sec--ink .tlink:hover{color:#fff}
/* A board must not inherit a dark section's ink. dashboard.css
   leaves `color` to inherit on .dcard__value and .dchart__avg, so
   on the blue they come out white on a white panel and vanish. */
.sec--ink .dpanel{color:var(--text);box-shadow:0 40px 80px -40px rgba(0,0,0,.85)}

/* ---------- the interior hero ----------
   Same proportions as .hero, minus the 208px — nothing sits under
   an interior headline the way the flow diagram sits under the
   homepage's, so the extra headroom would just be a hole. The
   accent is the homepage's: one italic word, not a colour. */
.phero{text-align:center;padding:clamp(132px,13.5vw,186px) 0 clamp(34px,4.4vw,58px)}
.phero h1{margin:0 auto;max-width:16ch}
.phero .sub{margin:24px auto 0;text-align:center;max-width:58ch}
/* Miss page: one composed block, not a stub hero over an empty sheet. */
.phero--miss{padding-bottom:clamp(96px,14vw,168px)}
.phero--miss .d-acts{display:flex;gap:12px;justify-content:center;flex-wrap:wrap;margin-top:36px}
/* The kicker over an interior H1. One use so far — the case study
   page, which needs to say what kind of page it is before it says
   whose story it is, now that the H1 is only the operator's name.
   Mono and small, the same register the section labels use. */
.pkick{margin:0 auto 14px;font-family:var(--mono);font-size:11.5px;font-weight:500;
  letter-spacing:.15em;text-transform:uppercase;color:var(--cyan-700)}
.phero--left{text-align:left}
/* .phero .sub sets text-align:center and outranks .phero--left on
   its own, so the override has to carry the same weight. */
.phero--left h1,.phero--left .sub{margin-inline:0}
.phero--left .sub{text-align:left}

/* Conference booth landing. The generic interior hero is a heading
   with 34–58px under it; this page IS the form, so it has to fill
   the first screen. Four fields is still the point — the height
   comes from padding and field size, not from asking more. */
.phero--meet{min-height:100svh;display:flex;flex-direction:column;
  justify-content:center;align-items:center;
  padding:clamp(148px,15vw,196px) 0 clamp(96px,11vw,148px)}
.phero--meet .shotpair{margin-top:0;align-items:center;width:100%;
  gap:clamp(36px,5vw,72px)}
.phero--meet h1{font-size:clamp(40px,5vw,66px);max-width:13ch;line-height:1.06}
.phero--meet .sub{margin-top:clamp(22px,2.4vw,32px);max-width:42ch;
  font-size:clamp(16.5px,1.4vw,19px);line-height:1.68}
.phero--meet .points{margin-top:clamp(28px,3.2vw,40px);gap:16px;max-width:42ch}
.phero--meet .points li{font-size:15.5px;padding-left:22px;line-height:1.55}
.phero--meet .points li::before{width:7px;height:7px;top:.55em}
.phero--meet .formcard{padding:clamp(32px,3.8vw,48px);
  box-shadow:0 1px 2px rgba(11,18,32,.04),0 28px 56px -36px rgba(11,18,32,.22)}
.phero--meet .form{gap:20px}
.phero--meet .form__row{gap:18px}
.phero--meet .field{gap:8px}
.phero--meet .field input{padding:15px 16px;min-height:52px}
.phero--meet .form .btn{margin-top:6px;padding:17px 26px}
@media(max-width:900px){
  .phero--meet{min-height:0;padding-bottom:clamp(64px,9vw,96px)}
  .phero--meet .shotpair{align-items:stretch}
}
@media(max-height:740px){.phero--meet{min-height:0}}

/* NOT .acts. That name is already taken by the action cell in the
   incident tracking table, and a button row that declares
   display:flex on it blockifies the three glyphs inside and wraps
   them onto two lines — with `white-space:nowrap` still set, which
   is what makes it look impossible. Renamed 2026-08-19 on finding
   exactly that. */
.btnrow{display:flex;gap:12px;flex-wrap:wrap;justify-content:center;margin-top:clamp(28px,3.4vw,40px)}
.btnrow--left{justify-content:flex-start}

/* ---------- the trust row ----------
   Three facts under a hero, set as text with a tick rather than
   as chips. A chip is a container, and see the note at the top. */
.trust{display:flex;flex-wrap:wrap;justify-content:center;gap:12px 30px;
  margin-top:clamp(26px,3vw,38px);font-size:14.5px;font-weight:500;color:var(--text-2)}
.trust span{display:inline-flex;align-items:center;gap:9px}
.trust svg{width:15px;height:15px;flex:0 0 auto;color:var(--cyan-700)}

/* ---------- the column device ----------
   The worth row, generalised. Same rule — 46 by 5, radius 3, the
   block's own colour — and the same lack of a container. --n is
   how many across; it collapses to two and then one.

   .col__r is deliberately the same declaration as .wfig__r rather
   than a shared class: the worth row is a row of FIGURES and this
   is a row of SUBJECTS, they are different sizes, and folding them
   together means the next change to one silently moves the other. */
.cols{display:grid;grid-template-columns:repeat(var(--n,3),minmax(0,1fr));
  gap:clamp(26px,3.2vw,52px);margin-top:clamp(38px,4.8vw,64px)}
@media(max-width:900px){.cols{grid-template-columns:repeat(2,minmax(0,1fr));row-gap:42px}}
@media(max-width:600px){.cols{grid-template-columns:minmax(0,1fr)}}
.col__r{display:block;width:46px;height:5px;border-radius:3px;margin:0 0 18px;
  background:var(--c,var(--brand))}
.col h3{margin:0;font-size:19px;font-weight:600;letter-spacing:-.015em;color:var(--text-strong)}
.col > p{margin:10px 0 0;font-size:15px;line-height:1.62;color:var(--text-2)}
.col .points{margin-top:16px}

/* ---------- the dotted list ----------
   Off the flow diagram's input card, at reading size. The dot is
   the same 6px on a 3px cyan halo. */
.points{margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:11px}
.points li{position:relative;padding-left:20px;font-size:14.5px;line-height:1.58;color:var(--text-2)}
.points li::before{content:'';position:absolute;left:0;top:.52em;width:6px;height:6px;
  border-radius:50%;background:var(--brand);box-shadow:0 0 0 3px rgba(12,199,237,.14)}
.points b{font-weight:600;color:var(--text-strong)}

/* A lede under a section heading, centred. Same size as .split__lede. */
.lede{max-width:64ch;margin:clamp(20px,2.4vw,28px) auto 0;text-align:center;
  font-size:clamp(16px,1.35vw,18.5px);line-height:1.6;color:var(--text-2)}
.lede--left{margin-inline:0;text-align:left}

/* The attribution line under a set of figures. Same treatment as
   .cases__attrib, because it is doing the same job. */
.pnote{margin:clamp(24px,3vw,34px) auto 0;max-width:76ch;text-align:center;
  font-size:12.5px;line-height:1.55;color:var(--text-muted)}
.pnote--left{margin-inline:0;text-align:left}

/* ---------- questions ----------
   Hairline rows, not cards. Twelve bordered boxes down a page is
   twelve containers doing no work; a rule between two questions is
   one pixel doing the same job. The row opens in place. */
.qa{margin-top:clamp(34px,4.4vw,56px);border-top:1px solid var(--border)}
.qa details{border-bottom:1px solid var(--border)}
.qa summary{list-style:none;cursor:pointer;display:flex;align-items:flex-start;gap:18px;
  padding:22px 2px;font-size:clamp(16.5px,1.5vw,19px);font-weight:500;line-height:1.42;
  letter-spacing:-.012em;color:var(--text-strong);transition:color .2s ease}
.qa summary::-webkit-details-marker{display:none}
.qa summary:hover{color:var(--cyan-700)}
/* The marker is drawn rather than typed so it can rotate. A plus
   that becomes a minus says "this opens" without a word. */
.qa summary::after{content:'';flex:0 0 auto;width:13px;height:13px;margin:.34em 0 0 auto;
  background:
    linear-gradient(currentColor,currentColor) center/13px 1.6px no-repeat,
    linear-gradient(currentColor,currentColor) center/1.6px 13px no-repeat;
  color:var(--n-300);transition:transform .3s var(--ease-out),color .2s ease}
.qa details[open] summary::after{transform:rotate(45deg);color:var(--cyan-700)}
.qa__a{padding:0 46px 26px 0}
.qa__a p{margin:0;font-size:15.5px;line-height:1.68;color:var(--text-2);max-width:74ch}
.qa__a p + p{margin-top:14px}
.qa__more{margin:clamp(28px,3.4vw,40px) 0 0;text-align:center}
@media(prefers-reduced-motion:reduce){.qa summary::after{transition:none}}

/* ---------- the home list ----------
   Twelve names is a list, not twelve cards. The town sits under
   the name in the muted grey the footer uses for its column heads. */
/* Four columns, not auto-fill. Twelve divides by four, three, two
   and one, and auto-fill left two empty cells at the end of the last
   row — which, with the grid lines drawn as a 1px gap over a
   coloured container, showed as a grey block rather than as nothing. */
.homes{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  gap:1px;background:var(--border);border:1px solid var(--border);border-radius:20px;
  overflow:hidden}
.homes span{display:block;padding:17px 20px;background:var(--white);
  font-size:15px;font-weight:500;letter-spacing:-.01em;color:var(--text-strong)}
.homes i{display:block;margin-top:4px;font-style:normal;font-size:13px;font-weight:400;
  color:var(--text-muted)}
@media(max-width:1000px){.homes{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media(max-width:760px){.homes{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:480px){.homes{grid-template-columns:minmax(0,1fr)}}

/* ---------- the quote, standing alone ----------
   The case-studies page runs the full quote rather than the middle
   clause the homepage's .story card carries, so it gets the size
   .say gives a statement. No card: a bordered box around a
   testimonial reads as a widget, and the words on the page in
   display type read as somebody talking. */
.said{max-width:900px;margin:clamp(36px,4.6vw,64px) auto 0;text-align:center}
.said blockquote{margin:0;font-family:var(--serif);font-weight:400;
  font-size:clamp(23px,2.7vw,38px);line-height:1.2;letter-spacing:-.024em;color:var(--text-strong)}
.said blockquote em{font-style:italic;color:var(--cyan-700)}
.said figcaption{display:inline-flex;align-items:center;gap:14px;margin-top:clamp(28px,3.4vw,42px);
  text-align:left}
.said__face{width:54px;height:54px;flex:0 0 auto;border-radius:50%;object-fit:cover;
  box-shadow:0 0 0 1px var(--border),0 0 0 5px rgba(12,199,237,.12)}
.said__who b{display:block;font-size:16px;font-weight:600;color:var(--text-strong)}
.said__who i{display:block;font-style:normal;font-size:14px;color:var(--text-2);margin-top:3px}

/* ---------- a photograph beside copy ----------
   The .story card's photo half, used on its own. Same radius, same
   ground, same object-fit; a portrait is cropped by the frame, not
   by squashing it. */
.shotpair{display:grid;grid-template-columns:minmax(0,.86fr) minmax(0,1.14fr);
  gap:clamp(28px,4vw,60px);align-items:center;margin-top:clamp(38px,4.8vw,64px)}
@media(max-width:900px){.shotpair{grid-template-columns:minmax(0,1fr)}}
.shotpair--flip > figure{order:2}
@media(max-width:900px){.shotpair--flip > figure{order:0}}
.ph{margin:0;border-radius:24px;overflow:hidden;background:var(--n-100);
  border:1px solid var(--border)}
.ph img{width:100%;height:100%;object-fit:cover;display:block}
/* Without a ratio the frame stretches to whatever height the column
   beside it happens to be, and a portrait next to six paragraphs
   becomes a tower. 4:3 is the shape both photographs were shot in. */
.shotpair .ph{align-self:start}
.shotpair .ph img{aspect-ratio:4/3}
.ph figcaption{padding:13px 18px;font-size:13px;color:var(--text-muted);background:var(--white);
  border-top:1px solid var(--border)}

/* ---------- the form ----------
   components.css carried this for the near-black site and is not
   loaded here. One card, the fields on the page ground inside it,
   the submit at full width. The focus ring is the brand at 14% —
   a colour change alone is not enough to see on a white field. */
.formcard{background:var(--white);border:1px solid var(--border);border-radius:24px;
  padding:clamp(24px,2.8vw,36px);box-shadow:0 1px 2px rgba(11,18,32,.04)}
.form{display:flex;flex-direction:column;gap:16px}
.form__row{display:grid;grid-template-columns:1fr 1fr;gap:16px}
@media(max-width:560px){.form__row{grid-template-columns:1fr}}
.field{display:flex;flex-direction:column;gap:7px;min-width:0}
.field label{font-size:13.5px;font-weight:600;letter-spacing:-.005em;color:var(--text-strong)}
.field .opt{font-weight:400;color:var(--text-muted)}
.field input,.field select,.field textarea{
  width:100%;padding:12px 14px;border:1px solid var(--border);border-radius:12px;
  background:var(--subtle);font-family:var(--sans);font-size:15px;color:var(--text-strong);
  transition:border-color .18s ease,box-shadow .18s ease,background .18s ease}
.field textarea{min-height:104px;resize:vertical;line-height:1.55}
.field input::placeholder,.field textarea::placeholder{color:var(--text-muted)}
.field input:focus,.field select:focus,.field textarea:focus{
  outline:0;background:var(--white);border-color:var(--cyan-400);
  box-shadow:0 0 0 4px rgba(12,199,237,.14)}
/* The native arrow is drawn by the OS and does not match anything
   on the page, so it is replaced with the same chevron the nav
   dropdown uses, as a background image. */
.field select{appearance:none;-webkit-appearance:none;padding-right:38px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2.4'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 13px center;background-size:14px}
.form__note{margin:0;font-size:12.5px;line-height:1.55;color:var(--text-muted)}
.form .btn{width:100%}
.form__hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.form__status{margin:0;font-size:14.5px;line-height:1.5;font-weight:600;color:var(--text-strong)}
.form[data-state='err'] .form__status{color:var(--danger)}
.form[data-state='ok'] .field,
.form[data-state='ok'] .form__row,
.form[data-state='ok'] button[type='submit'],
.form[data-state='ok'] .form__note{display:none}
.form__done[hidden]{display:none}
.form[data-state='ok'] .form__done{display:flex;flex-direction:column;gap:16px}
.form__done p{margin:0;font-size:15.5px;line-height:1.55;color:var(--text-strong)}
.form[data-state='busy'] button[type='submit']{opacity:.7;pointer-events:none}

/* ---------- a table on the page ----------
   .dtable sets min-width:620px because it is built for a board, so
   on a narrow column it has to be allowed to scroll rather than
   forced to squash. .app is dashboard.css's frame and is already
   light; it only needs the page's own shadow under it. */
.frame{margin-top:clamp(34px,4.4vw,56px);box-shadow:0 24px 60px -40px rgba(11,18,32,.4)}
/* .app is a two-column grid — a 46px icon rail and the main pane —
   because that is what a dashboard shot needs. A table in the frame
   has no rail, and without this the table lands in the 46px column
   and renders as a stripe. dark.css carried this modifier and it had
   to come across with the frame. */
.app--flat{grid-template-columns:minmax(0,1fr)}

/* ############################################################
   THE BOARDS, AND GLENN, IN THE LIGHT

   dashboard.css is already a light stylesheet — the ring, the
   bars, the incident table, the note, the heatmap and the rank
   list all draw themselves on white and needed nothing. What did
   NOT come across is the chrome around them, because all of it
   was written under a `.dark` selector: the board pager, the Ask
   Glenn bar, and the overlay panel the bar opens.

   That chrome is re-drawn here, and the target is not "the dark
   one, lighter". It is the Glenn card on the homepage — the same
   bubble shape, the same cyan spark, the same composer — because
   a prospect who sees Glenn twice on one visit should see the
   same product both times. Owen, 2026-08-19: "spruce up the
   Glenn to look more like the current Glenn we have on the
   [homepage] one, moving the vibe from that black into the
   light."
   ############################################################ */

/* ---------- the board pager ---------- */
.d-boardnav{display:flex;align-items:center;justify-content:center;gap:18px;
  margin-bottom:clamp(24px,2.8vw,36px)}
.d-boardnav__arrow{width:40px;height:40px;display:grid;place-items:center;cursor:pointer;
  border:1px solid var(--border);border-radius:50%;background:var(--white);color:var(--text);
  transition:background .2s ease,border-color .2s ease,color .2s ease}
.d-boardnav__arrow:hover{background:var(--n-100);border-color:var(--n-300);color:var(--text-strong)}
.d-boardnav__arrow svg{width:16px;height:16px}
.d-boardnav__label{min-width:15ch;text-align:center;font-size:15px;font-weight:600;
  letter-spacing:-.01em;color:var(--text-strong)}
.d-boardnav__count{display:block;margin-top:2px;font-size:12px;font-weight:500;
  color:var(--text-muted)}
@media(max-width:720px){.d-boardnav{display:none}}

/* One board is in the flow at a time. They are different heights,
   so animating between them would jump the page. */
.d-board[hidden]{display:none}
.d-appwrap{position:relative;max-width:1020px;margin-inline:auto}

/* ---------- the Ask Glenn bar ----------
   A composer under the thing it talks about. It reads as a field
   you type into because the panel it opens is a chat and this is
   that chat's front door. */
.d-ask{display:flex;align-items:center;gap:13px;width:100%;max-width:1020px;cursor:pointer;
  margin:clamp(22px,2.6vw,36px) auto 0;padding:15px 16px 15px 15px;text-align:left;
  border:1px solid rgba(12,199,237,.3);border-radius:16px;
  background:linear-gradient(180deg,rgba(12,199,237,.10),rgba(12,199,237,.03)),var(--white);
  transition:border-color .25s ease,box-shadow .25s ease}
.d-ask:hover{border-color:rgba(12,199,237,.7);
  box-shadow:0 0 0 4px rgba(12,199,237,.09),0 16px 38px -26px rgba(11,18,32,.5)}
.d-ask[aria-expanded='true']{border-color:var(--brand)}
.d-ask__spark{width:34px;height:34px;flex:0 0 auto;display:grid;place-items:center;
  border-radius:10px;background:var(--brand);color:#04222A;box-shadow:var(--sh-glow)}
.d-ask__spark svg{width:17px;height:17px}
.d-ask__t{flex:1;min-width:0;font-size:15px;color:var(--text-2);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.d-ask__caret{display:inline-block;width:1.5px;height:1.05em;margin-left:3px;
  background:var(--cyan-700);vertical-align:text-bottom;
  animation:gcaret 1.1s steps(1) infinite}
.d-ask__go{width:32px;height:32px;flex:0 0 auto;display:grid;place-items:center;border-radius:50%;
  background:var(--brand);color:#04222A;transition:transform .2s var(--ease-out)}
.d-ask:hover .d-ask__go{transform:translateX(3px)}
.d-ask__go svg{width:15px;height:15px}
@media(max-width:720px){.d-ask{padding:13px}.d-ask__t{font-size:13.5px}}
@media(prefers-reduced-motion:reduce){.d-ask__caret{animation:none}}

/* ---------- the overlay ----------
   It sits in front of the board rather than inside it. The scrim
   is the page ground at 72% rather than black at 78%: on a light
   page a black scrim reads as the lights going out, and the point
   is that Glenn is a layer over the dashboard, not a modal that
   replaces it. */
.glenn-sheet{position:absolute;inset:0;z-index:9;display:grid;place-items:center;padding:22px;
  background:rgba(233,239,245,.72);
  backdrop-filter:blur(9px);-webkit-backdrop-filter:blur(9px)}
.glenn-sheet[hidden]{display:none}
.glenn-sheet__card{width:min(560px,100%);max-height:100%;display:flex;flex-direction:column;
  border-radius:18px;border:1px solid var(--border);background:var(--white);
  box-shadow:0 40px 80px -30px rgba(11,18,32,.42),0 0 0 1px rgba(255,255,255,.6) inset;
  overflow:hidden}
.glenn-sheet__bar{display:flex;align-items:center;gap:11px;padding:13px 15px;
  border-bottom:1px solid var(--border);
  background:linear-gradient(180deg,rgba(12,199,237,.11),transparent)}
.glenn-sheet__x{width:28px;height:28px;flex:0 0 auto;display:grid;place-items:center;cursor:pointer;
  border:1px solid var(--border);border-radius:50%;background:var(--white);color:var(--text-2);
  transition:background .2s ease,color .2s ease}
.glenn-sheet__x:hover{background:var(--n-100);color:var(--text-strong)}
.glenn-sheet__x svg{width:13px;height:13px}
/* Both states share the stage, which carries the min-height, so
   the card does not resize under the reader on the swap. */
.glenn-sheet__stage{min-height:292px;display:grid}
.glenn-sheet__body{min-height:0;padding:15px;display:grid;gap:11px;overflow-y:auto}
.glenn-sheet__body[hidden]{display:none}
.glenn-sheet .glenn__composer{background:var(--n-100)}

/* ---------- the thread ----------
   The composer is present the whole time. A panel with a permanent
   input reads as an assistant; a panel without one reads as a
   report somebody screenshotted.

   Fixed height rather than min-height, and anchored to the end, so
   a short thread sits just above the composer and grows upward the
   way a chat app does. */
.glenn-chat{display:grid;gap:14px;padding:16px;height:330px;overflow-y:auto;align-content:end}
.glenn-msg{display:flex;gap:10px;align-items:flex-start}
/* The question, right-aligned, in the homepage's bubble exactly:
   brand at 14% inside a cyan-600 hairline at 22%, one square
   corner at the bottom right. */
.glenn-msg--me{justify-content:flex-end}
.glenn-msg--me .glenn-msg__body{max-width:86%;padding:10px 14px;border-radius:14px 14px 4px 14px;
  background:rgba(12,199,237,.14);border:1px solid rgba(12,199,237,.22);
  font-size:13px;line-height:1.5;font-weight:500;color:var(--text-strong)}
.glenn-msg--ai .glenn-msg__body{flex:1;min-width:0;display:grid;gap:11px;font-size:12.5px}
.glenn-msg .report__item{font-size:12.5px;line-height:1.6;color:var(--text-2)}
.glenn-msg .report__item b{color:var(--text-strong)}
/* The avatar is the homepage's .gspark: the brand square, not a
   gradient chip. Same mark, same corner radius, same size class. */
.glenn-msg__av{width:24px;height:24px;flex:0 0 auto;margin-top:1px;border-radius:8px;
  background:var(--brand);box-shadow:var(--sh-glow)}
.glenn-msg__body.is-writing .report__item:last-child::after{content:'';display:inline-block;
  width:2px;height:1em;margin-left:2px;background:var(--cyan-700);vertical-align:text-bottom;
  animation:gcaret .9s steps(1) infinite}

/* Thinking, in the thread rather than in place of it: a spinner
   while a step runs, a tick once it is done. */
.glenn-msg__body--think{gap:9px}
.glenn-msg__body--think .glenn-think__steps{display:grid;gap:9px;margin:0;padding:0;list-style:none}
.glenn-msg__body--think li{position:relative;padding-left:22px;font-size:12px;line-height:1.5;
  color:var(--text-muted);opacity:0;transform:translateY(3px);
  transition:opacity .28s ease,transform .28s ease,color .28s ease}
.glenn-msg__body--think li.is-on{opacity:1;transform:none}
.glenn-msg__body--think li.is-done{color:var(--text-2)}
.glenn-msg__body--think li::before{content:'';position:absolute;left:0;top:2px;
  width:12px;height:12px;border-radius:50%;
  border:1.5px solid rgba(12,199,237,.3);border-top-color:var(--brand);
  animation:gspin .7s linear infinite}
.glenn-msg__body--think li.is-done::before{border-color:rgba(23,178,106,.55);
  border-top-color:rgba(23,178,106,.55);animation:none}
.glenn-msg__body--think li.is-done::after{content:'';position:absolute;left:3.5px;top:5px;
  width:5px;height:2.5px;border-left:1.5px solid #17B26A;border-bottom:1.5px solid #17B26A;
  transform:rotate(-45deg)}
@keyframes gspin{to{transform:rotate(360deg)}}

/* Follow-up chips arrive with the answer, not before it. */
.glenn-sheet [data-glenn-chips]{opacity:0;min-height:0;transition:opacity .35s ease}
.glenn-sheet [data-glenn-chips].is-on{opacity:1}
.glenn-sheet [data-glenn-chips]:empty{display:none}
.glenn-src{display:none}

@media(prefers-reduced-motion:reduce){
  .glenn-msg__body--think li::before{animation:none}
  .glenn-sheet [data-glenn-chips]{opacity:1}
}

/* On a phone the sheet stops being an overlay on the board and
   becomes an overlay on the screen. Absolute works on the desktop
   because the board fits in the viewport, so "in front of the
   board" and "in front of you" are the same place; on a phone the
   board is three screens tall and an absolutely positioned panel
   opens a thousand pixels above the reader. */
@media(max-width:760px){
  .glenn-sheet{position:fixed;inset:0;z-index:120;padding:16px 12px;align-items:center}
  .glenn-sheet__card{width:100%;max-height:100%}
  .glenn-chat{height:300px;padding:13px}
}

/* ---------- three dashboard.css tweaks that were dark-scoped ---------- */
/* Twelve hours of bars need thinner columns than a six-category
   breakdown, and the labels have to stay on one line. */
.dchart--wide .dbar{min-width:0}
.dchart--wide .dchart__labels span{font-size:10px}
/* A zero-height bar still has to read as a column rather than
   vanish, so it keeps a hairline footprint. */
.dchart__plot .dbar__fill[data-h='0']{height:2px !important;opacity:.3}
/* "9/13" — the denominator on a ratio stat sits down a size. */
.dcard__of{font-size:.55em;font-weight:600;color:var(--text-muted);margin-left:2px}
/* The ring arc reads green when the home is inside its cap. */
.dring__arc--good{stroke:var(--success,#17B26A)}

/* ---------- the closing band, on a light page ----------
   The homepage's tail is an object: the white sheet rides up over
   the blue by its own radius and casts a shadow upward onto it.
   That only works where there IS blue underneath. On a page whose
   last section is on the page ground, the ride-up hangs the sheet
   over nothing and the upward shadow reads as a smudge across the
   page rather than as a lift.

   So --flat is the same band with the three things that describe
   the handover taken off. It is not a second design; the type, the
   buttons and the padding are identical, and #FAFAFA on #F8FAFC is
   close enough that the seam is the point at which the page simply
   gets a shade warmer under the call to action. */
.d-lightband--flat{margin-top:0;border-radius:0;box-shadow:none}

/* ---------- questions on the ink ----------
   The FAQ pages close on a dark section so the sheet has something
   to ride up over. Same rows, same drawn marker, inverted. */
.sec--ink .qa{border-top-color:rgba(255,255,255,.16)}
.sec--ink .qa details{border-bottom-color:rgba(255,255,255,.16)}
.sec--ink .qa summary{color:#fff}
.sec--ink .qa summary:hover{color:var(--cyan-200)}
.sec--ink .qa summary::after{color:rgba(255,255,255,.4)}
.sec--ink .qa details[open] summary::after{color:var(--cyan-300)}
.sec--ink .qa__a p{color:rgba(255,255,255,.68)}
.sec--ink .points li{color:rgba(255,255,255,.7)}
.sec--ink .points b{color:#fff}
.sec--ink .col h3{color:#fff}
.sec--ink .col > p{color:rgba(255,255,255,.68)}
.sec--ink .pnote{color:rgba(255,255,255,.5)}
.sec--ink .trust{color:rgba(255,255,255,.72)}
.sec--ink .trust svg{color:var(--cyan-300)}
.sec--ink .homes{background:rgba(255,255,255,.16);border-color:rgba(255,255,255,.16)}
.sec--ink .homes span{background:rgba(255,255,255,.05);color:#fff}
.sec--ink .homes i{color:rgba(255,255,255,.55)}

/* A section heading that is not centred. .journey centres its own
   and the homepage never needed the other case; the interior pages
   do, for a heading that sits over a two-column block. */
.h--left{text-align:left}

/* A module segment on the product page carries the detail the
   homepage's one-line version does not. .jseg centres its
   children, so the list is centred as a block and set left as
   text — a centred bullet list is unreadable. */
.jseg .points{text-align:left;max-width:56ch;margin-top:2px}
.jseg .points li{color:rgba(255,255,255,.72)}
.jseg .points li::before{box-shadow:0 0 0 3px rgba(12,199,237,.18)}
.jseg .points b{color:#fff}

/* ############################################################
   THE OTHER TWO BOARDS

   The three boards on the product page are partials, and two of
   them — the incident tracking table and the falls-by-hour
   histogram — carried their own components rather than only
   dashboard.css's. Every one of those was written under a
   `.dark` selector, so they came across the same way the Glenn
   chrome did: re-drawn here, on the light ground, with the same
   geometry and the same intent.

   The filter bar, the action glyphs and the 24-hour switch are
   deliberately inert. This is a picture of the product, and a
   control that looks live but does nothing is worse than one
   that plainly does not.

   THE FLAG IS THE EXCEPTION. Clicking "Insufficient post-incident
   notes" opens a note and posts it to the EHR, which is the
   close-the-record loop the board is there to sell.
   ============================================================ */

.app__body--table{padding-bottom:0}
.dtable__top{display:flex;align-items:center;justify-content:space-between;gap:16px;
  flex-wrap:wrap;margin-bottom:16px}
.dtable__actions{display:flex;gap:9px}
.dbtn{display:inline-flex;align-items:center;gap:7px;padding:8px 14px;
  border:1px solid var(--border);border-radius:10px;background:var(--white);
  font-size:12.5px;font-weight:600;font-family:inherit;color:var(--text);
  white-space:nowrap;cursor:pointer}
.dbtn svg{width:14px;height:14px}
.dbtn--primary{background:var(--brand);border-color:var(--brand);color:#04222A}

/* The filter bar wraps to two rows at the board's width, which is
   what the product does too. */
.dfilterbar{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:9px;padding:11px;
  border:1px solid var(--border);border-radius:14px;background:var(--subtle);margin-bottom:16px}
@media(max-width:720px){.dfilterbar{grid-template-columns:minmax(0,1fr)}}
.dfilter{display:flex;align-items:center;justify-content:center;gap:8px;padding:9px 14px;
  border:1px solid var(--border);border-radius:999px;background:var(--white);
  font-size:12.5px;font-weight:500;color:var(--text);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dfilter svg{width:14px;height:14px;flex:0 0 auto;color:var(--text-muted)}
.dfilter b{color:var(--text-strong);font-weight:600}
.dfilter--on{border-color:rgba(240,68,56,.34);background:var(--danger-bg);color:#B42318}
.dfilter--on svg,.dfilter--on b{color:#B42318}

/* The 24-hour switch. Off, because the table shows 12-hour times. */
.dtoggle{width:28px;height:16px;border-radius:999px;background:var(--n-300);
  position:relative;flex:0 0 auto}
.dtoggle::after{content:'';position:absolute;top:2px;left:2px;width:12px;height:12px;
  border-radius:50%;background:var(--white);box-shadow:0 1px 2px rgba(11,18,32,.2)}

.dtable--track{min-width:860px;font-size:12.5px}
.dtable--track th{padding:11px 14px}
.dtable--track td{padding:13px 14px;vertical-align:middle}
.dtable--track .who{white-space:nowrap;display:flex;align-items:center;
  justify-content:space-between;gap:14px}
.dtable--track .who b{display:block;font-size:13px;font-weight:600;color:var(--text-strong)}
.dtable--track .who i{display:block;font-style:normal;font-size:11.5px;
  color:var(--text-muted);margin-top:3px}
.dtable--track .muted{color:var(--text-muted)}

/* A cause Glenn drafted out of the source note. */
.dcell--ai{display:inline-block;padding:5px 10px;border-radius:8px;
  background:var(--success-bg);color:#067647}

/* Three inert action glyphs. At this size real icons read as noise,
   and they are not clickable anyway. */
.dtable--track .acts{white-space:nowrap;text-align:right}
.dtable--track .acts svg{display:inline-block;width:15px;height:15px;margin-left:11px;
  color:var(--text-muted);vertical-align:middle}

/* Why a row is flagged. The reason travels with the flag rather than
   living behind a click, which is the whole argument of the board.
   Up and to the RIGHT: directly above, it lands on the resident names
   in the rows overhead and the table reads as broken. */
.dwhy{position:relative;display:inline-block;flex:0 0 auto}
.dwhy__mark{display:inline-flex;align-items:center;justify-content:center;
  width:22px;height:22px;border-radius:50%;background:var(--danger-bg);color:#B42318}
.dwhy__mark svg{width:12px;height:12px}
.dwhy__pop{position:absolute;bottom:calc(100% + 4px);left:calc(100% + 10px);z-index:4;
  width:250px;padding:13px 14px;border:1px solid var(--border);border-radius:12px;
  background:var(--white);box-shadow:0 18px 44px -18px rgba(11,18,32,.42);
  font-size:12px;line-height:1.5;font-weight:400;color:var(--text);white-space:normal}
.dtable--track .dwhy__pop b{display:inline;font-size:inherit;font-weight:700;color:var(--text-strong)}
.dwhy__tag{display:inline-flex;align-items:center;gap:6px;margin-top:9px;padding:5px 11px;
  border:1px solid rgba(23,178,106,.35);border-radius:999px;background:var(--success-bg);
  color:#067647;font-size:11.5px;font-weight:600;font-family:inherit;line-height:1.3;
  cursor:pointer;text-align:left}
.dwhy__tag:hover,.dwhy__tag:focus-visible{border-color:#067647;outline:none}

/* The close-the-record strip. Opens under the filters when the
   green pill is clicked; goes away once the note is posted. */
.dclose{margin:0 0 14px;padding:14px 16px;border:1px solid rgba(12,199,237,.28);
  border-radius:14px;background:rgba(12,199,237,.06)}
.dclose__k{margin:0;font-size:11.5px;font-weight:600;letter-spacing:.04em;
  text-transform:uppercase;color:var(--text-muted)}
.dclose__note{margin:8px 0 12px;font-size:13.5px;line-height:1.5;color:var(--text-strong)}
.dclose .dbtn{cursor:pointer}
.dclose__done{margin:0;font-size:13.5px;font-weight:600;color:#067647}
.dwhy__mark--ok{background:var(--success-bg);color:#067647}

/* ---------- falls by hour ----------
   Twenty-four columns, the share above each and the count inside it,
   and the day split into three bands so the night shift reads as one
   block. Flex rather than a grid so a zero-count hour still holds
   its column. */
.dhours{display:flex;gap:10px}
.dhours__ticks{display:flex;flex-direction:column;justify-content:space-between;
  padding-bottom:44px;font-size:10.5px;color:var(--text-muted);flex:0 0 auto}
.dhours__plot{flex:1;display:flex;align-items:flex-end;gap:4px;height:210px;
  border-bottom:1px solid var(--border);margin-bottom:34px;position:relative}
.dhours__plot::before{content:'';position:absolute;inset:0;pointer-events:none;
  background-image:repeating-linear-gradient(to top,transparent 0,transparent calc(33.333% - 1px),
    var(--border) calc(33.333% - 1px),var(--border) 33.333%)}
.dbarh{flex:1;min-width:0;position:relative;display:flex;flex-direction:column;
  justify-content:flex-end;align-items:center;height:100%}
.dbarh i{font-style:normal;font-size:9.5px;color:var(--text-2);margin-bottom:4px;white-space:nowrap}
.dbarh b{display:block;width:100%;border-radius:4px 4px 0 0;position:relative;
  transition:height .7s var(--ease-out)}
/* The count sits inside the bar where it fits and above it where it
   does not — a "0" inside a zero-height bar is invisible. */
.dbarh em{position:absolute;left:0;right:0;top:4px;font-style:normal;font-size:10px;
  font-weight:600;color:#08231A;text-align:center}
.dbarh b[data-h='0']{min-height:2px;opacity:.35}
.dbarh b[data-h='0'] em,.dbarh b[data-h='17'] em{top:-15px;color:var(--text-muted)}
.dbarh[data-small] i{margin-bottom:20px}
.dbarh u{position:absolute;top:calc(100% + 9px);text-decoration:none;font-size:10px;
  color:var(--text-muted)}
/* The three bands are the site's own violet, green and hydration
   blue rather than the near-black site's mixes. */
.dbarh[data-band='night'] b{background:var(--skin)}
.dbarh[data-band='day']   b{background:var(--behav)}
.dbarh[data-band='eve']   b{background:var(--hydr)}
.dhours__key{display:flex;flex-wrap:wrap;gap:8px 20px;margin-top:18px}
.dhours__key span{display:inline-flex;align-items:center;gap:8px;font-size:11.5px;color:var(--text-2)}
.dhours__key span::before{content:'';width:9px;height:9px;border-radius:3px}
.dhours__key span[data-band='night']::before{background:var(--skin)}
.dhours__key span[data-band='day']::before{background:var(--behav)}
.dhours__key span[data-band='eve']::before{background:var(--hydr)}
@media(max-width:900px){
  .dhours__plot{gap:2px}
  .dbarh i{display:none}
  .dbarh u{font-size:8.5px}
}

/* The one base.css utility the boards use. base.css is not loaded
   here and pulling the whole file in for a single margin would give
   every rule in site.css a second definition to argue with. */
.mt-4{margin-top:var(--space-4)}

/* ---------- the integration tile ----------
   Owen, 2026-08-19: "a rounded cube for each, with a white
   background and then the logo in the middle, the same kind of
   border size as the header menu."

   THE HAIRLINE IS THE HEADER PILL'S, and it is the same value
   rather than a similar one: rgba(16,32,48,.13). --border is tuned
   for a card on the page ground and disappears the moment the fill
   is white on near-white paper, which is exactly why the pill
   needed a denser line and exactly why this does.

   The radius is the app-icon proportion, about a quarter of the
   tile, which is what makes it read as an icon rather than as a
   small card.

   IT USED TO BE A ROW OF THREE BIG ONES under the product hero and
   again over the security columns. Both are gone at Owen's
   direction the same day — "it should not be a main thing" on
   product, and "way too big" on security. The tile survives at
   bullet size inside .intcard, which is the only place it runs now.
   The width below is the base; .intcard overrides it. */
.int{width:clamp(84px,8.6vw,104px);aspect-ratio:1;display:grid;place-items:center;
  border-radius:clamp(20px,2.2vw,26px);
  background:var(--white);border:1px solid rgba(16,32,48,.13);
  box-shadow:0 1px 2px rgba(11,18,32,.04),0 12px 28px -20px rgba(11,18,32,.5)}
/* Optical sizing, not mechanical. The marks are different shapes —
   a circle, two wide short wordmarks and a drawn glyph — so one
   width sizes them wrong: at the same measure the circle towers
   over the wordmarks and the wordmarks touch the tile edge. --cap
   is set per mark on the element, and the tile's padding lives in
   that number rather than on the box, so a mark can be tuned
   without moving the tile it sits in. */
.int__mark{display:block;width:var(--cap,72%);max-width:100%;height:auto;
  margin-inline:auto;object-fit:contain}

/* ---------- integrations, named ----------
   Owen, 2026-08-19: "shrink those, they're way too big. Remove the
   blue dots and blue lines. It should be the PointClickCare icon,
   then PointClickCare the text, then Epic, then MC."

   That quote is kept as it was said. The row is not: Epic came off
   on 2026-08-20 — "here are the EHRs we use. Remove Epic" — and
   Yardi is in that slot now.

   So the tile stops being the whole statement and becomes the
   bullet: a small mark, the name beside it, and one line under
   both. The coloured rule that led every other .col on the site is
   deliberately gone from these — a mark and a rule are two
   different ways of saying "this item starts here", and running
   both makes the row read as two lists on top of each other.

   The fourth item is "any other EHR or EMR" and it gets a mark too,
   at his direction. It is drawn by us rather than borrowed: a plug,
   in the brand cyan, so a generic entry does not sit in a row of
   real logos looking like a vendor nobody recognises. */
.intcards{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(20px,2.4vw,34px);margin-top:clamp(34px,4.4vw,54px)}
@media(max-width:900px){.intcards{grid-template-columns:repeat(2,minmax(0,1fr));row-gap:36px}}
@media(max-width:520px){.intcards{grid-template-columns:minmax(0,1fr)}}
.intcard__top{display:flex;align-items:center;gap:12px}
/* The same tile as the big row, at bullet size. Same hairline, same
   proportional radius, so it is recognisably the same object. */
.intcard .int{width:46px;flex:0 0 auto;border-radius:13px;
  box-shadow:0 1px 2px rgba(11,18,32,.04),0 6px 16px -12px rgba(11,18,32,.5)}
.intcard h3{margin:0;font-size:17px;font-weight:600;letter-spacing:-.015em;
  color:var(--text-strong)}
.intcard p{margin:14px 0 0;font-size:14.5px;line-height:1.6;color:var(--text-2)}
.intcard p b{font-weight:600;color:var(--text-strong)}


/* ---------- the case-study index ----------
   Two cards, 2026-08-20. The whole card is the link on both — see
   the note in the markup — so everything inside is a <span>, and
   the hover state lives on .cscard rather than on a button that
   is not there.

   The two are deliberately NOT the same object. The story card
   leads with a photograph and carries three figures; the ask card
   has no photograph at all, for the same reason its twin in the
   homepage rail does not: an invitation sitting in a row of
   results should not look like a third result.

   The figures repeat what the story page says in full. That is the
   one place on the site where a number is allowed to appear twice,
   because a card that promised a case study without saying what is
   in it is a link, not a card. */
.csgrid{display:grid;grid-template-columns:minmax(0,1.35fr) minmax(0,1fr);
  gap:clamp(20px,2.4vw,32px);margin-top:clamp(28px,3.4vw,44px);align-items:stretch}
@media(max-width:860px){.csgrid{grid-template-columns:minmax(0,1fr)}}

.cscard{display:flex;flex-direction:column;overflow:hidden;text-decoration:none;
  border-radius:var(--r-xl);background:var(--white);border:1px solid var(--border);
  box-shadow:var(--sh-xs);transform:translateZ(0);
  transition:transform .2s var(--ease-out),box-shadow .2s var(--ease-out),
             border-color .2s var(--ease-out)}
@media(hover:hover) and (pointer:fine){
  .cscard:hover{transform:translate3d(0,-2px,0);box-shadow:var(--sh-md);border-color:var(--n-300)}
  .cscard:hover .cscard__go svg{transform:translateX(3px)}
}
.cscard:active{transform:scale(.995)}

.cscard__ph{display:block;position:relative;aspect-ratio:16/7;background:var(--n-100);
  border-bottom:1px solid var(--border)}
/* Absolute, not height:100%. The parent carries the aspect-ratio
   and has no resolved height of its own, so a percentage height on
   the child falls back to the image's intrinsic ratio and the box
   grows past the ratio it was given. */
.cscard__ph img{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:50% 38%;display:block}
.cscard__b{display:flex;flex-direction:column;flex:1;
  padding:clamp(24px,2.8vw,34px)}
.cscard__kick{display:block;font-family:var(--mono);font-size:11px;font-weight:500;
  letter-spacing:.13em;text-transform:uppercase;color:var(--cyan-700);margin-bottom:12px}
.cscard__ttl{display:block;font-family:var(--serif);font-weight:400;letter-spacing:-.02em;
  font-size:clamp(24px,2.4vw,32px);line-height:1.1;color:var(--text-strong)}
.cscard__say{display:block;margin-top:12px;font-size:15px;line-height:1.6;color:var(--text-2);
  max-width:42ch}
/* The go line is pinned to the bottom so the two cards agree on
   where it sits, whatever is above it. */
.cscard__go{display:inline-flex;align-items:center;gap:7px;margin-top:auto;
  padding-top:clamp(22px,2.6vw,30px);
  font-size:15px;font-weight:600;letter-spacing:-.01em;color:var(--cyan-700)}
.cscard__go svg{width:17px;height:17px;transition:transform .2s var(--ease-out)}

.csfig{display:flex;flex-wrap:wrap;gap:clamp(18px,2.4vw,34px);margin-top:clamp(20px,2.4vw,28px)}
.csfig span{display:block;max-width:16ch;font-size:12.5px;line-height:1.45;color:var(--text-2)}
.csfig b{display:block;font-family:var(--serif);font-weight:400;letter-spacing:-.04em;
  font-size:clamp(26px,2.6vw,34px);line-height:1;color:var(--text-strong);margin-bottom:7px}

/* Same ground as the homepage rail's ask card, so the two read as
   one object in two places. */
.cscard--ask{background:
  radial-gradient(120% 100% at 12% 0%,rgba(12,199,237,.16) 0%,rgba(12,199,237,0) 58%),
  linear-gradient(158deg,var(--cyan-800) 0%,var(--deep-2) 62%);
  border-color:transparent}
.cscard--ask .cscard__b{justify-content:center}
.cscard--ask .cscard__ttl{color:#fff;max-width:12ch}
.cscard--ask .cscard__say{color:rgba(255,255,255,.76)}
.cscard--ask .cscard__go{color:var(--cyan-300);margin-top:0;padding-top:clamp(22px,2.6vw,30px)}

/* ---------- the tinted card ----------
   Owen, 2026-08-19, pointing at the Dreelio template: this is the
   card he wants on the pages that are not the homepage. Its anatomy
   is three parts, in this order, and the order is the whole point:

     heading  →  a white panel with real UI in it  →  a sentence
                 that opens on a bold phrase and then explains

   The reader gets told what it is, shown the actual screen, and
   then given the reason — rather than being given a paragraph and
   asked to imagine the screen. A card with nothing to show simply
   leaves the panel out; the security page's access and setup pair
   runs that way.

   It is a MODIFIER on .pcard, not a fourth card. The homepage's
   pair is already a dark card and a plain white one; this is the
   same object on the neutral step between them, which is what lets
   the pages read as one system. The tint is --n-100 rather than a
   new value, and the panel inside is the same white the boards
   already sit on, so a board dropped in needs nothing.

   The panel is deliberately NOT full-bleed to the card's edge. The
   band of tint around it is what makes it read as a screen sitting
   on a surface rather than as a card with a picture for a lid. */
.pcard--tint{background:var(--n-100);border:1px solid var(--border);
  padding:clamp(24px,2.6vw,34px)}
.pcard--tint .pcard__say{max-width:20ch}
/* Both panels in a pair stretch to the taller card so the two read
   as one object, with the content centred inside so a short board
   sits in the middle of its panel rather than at the top. */
.pcard__stage{flex:1;display:grid;align-items:stretch;
  margin:clamp(22px,2.6vw,32px) 0 0}
.pcard__panel{width:100%;display:grid;align-content:center;
  background:var(--white);border:1px solid var(--border);
  border-radius:18px;padding:clamp(12px,1.4vw,16px);
  box-shadow:0 18px 40px -30px rgba(11,18,32,.55)}
/* .dpanel brings its own white ground and border, so a board
   dropped straight in would double the edge. */
.pcard__panel > .dpanel{border:0;box-shadow:none;padding:0;background:transparent}
/* The sentence under the panel. Bold phrase, then the explanation —
   the reference's device, and it happens to be the site's already:
   the sticky split's steps run the same shape one size up. */
.pcard__body{margin:clamp(22px,2.6vw,32px) 0 0;font-size:15.5px;line-height:1.62;
  color:var(--text-2)}
.pcard__body b{font-weight:600;color:var(--text-strong)}

/* ---------- three across, and a card with a figure in it ----------
   The case study's results. Owen, 2026-08-19: the four-across white
   banner "looks like shit" on that page — it is a homepage device,
   and on a page whose whole job is one operator's story a banner
   strips every figure of the sentence that makes it mean something.

   So the figures moved into cards, one per seat, at a smaller size:
   who it mattered to, the number, and what it bought. --stat drops
   the 430px floor .pcard carries for a card that has a board in it. */
.pair--3{grid-template-columns:repeat(3,minmax(0,1fr))}
@media(max-width:900px){.pair--3{grid-template-columns:minmax(0,1fr)}}
.pcard--stat{min-height:0}
.pcard__n{display:block;margin:clamp(18px,2vw,26px) 0 0;font-family:var(--serif);
  font-weight:400;white-space:nowrap;font-size:clamp(34px,3.4vw,46px);line-height:.96;
  letter-spacing:-.04em;color:var(--cyan-700)}
.pcard--stat .pcard__say{font-size:20px;margin-top:12px;max-width:22ch}
.pcard--stat .pcard__body{margin-top:14px;font-size:14.5px}

/* The twelve homes, inside the white panel of a card. .homes draws
   its own grid lines over a coloured container; in a panel that is
   a box inside a box, so this is the bare version — columns, a
   name, the town under it, nothing else. */
.homes--bare{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(14px,1.6vw,20px) clamp(16px,2vw,26px);
  background:none;border:0;border-radius:0;overflow:visible}
.homes--bare span{padding:0;background:none;font-size:14px}
.homes--bare i{font-size:12.5px}
@media(max-width:900px){.homes--bare{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:520px){.homes--bare{grid-template-columns:minmax(0,1fr)}}

/* ============================================================
   THE POP-OUT RIG — product page section 2, added 2026-08-19.

   Prototyped in _proposals/2026-08-19-pop-out-boards-and-
   compliance.html and lifted from it unchanged. The behaviour it
   is written against is initPop() in motion.js.
   ============================================================ */

/* Tight under the product hero. The old clamp(96px,12vw,180px)
   plus a 100vh centred pin left a hole between Book a Demo and
   the dashboard; both of those are gone. */
.sec--rig{padding-top:clamp(20px,2.4vw,36px)}

/* ============================================================
   THE POP-OUT RIG.  Second pass, 2026-08-19, off Owen's four
   notes on the first one: the left rail ran into the board, the
   right rail sat too far out, the cards carried too many words,
   and they arrived in FRONT of the dashboard.

   So: four cards instead of six, each about four tenths of the
   stage, sitting BEHIND the board and sliding out from under it.
   The sentence is off the face of the card and behind an eye,
   which is what lets the card read as a number.

   Geometry is measured off the board's own rendered box rather
   than off the stage. That is what stops one rail touching it
   while the other floats.

   Two modes. data-mode="flat" is what the markup ships as, so a
   reader with no JavaScript, a narrow window or reduced motion
   gets the finished arrangement rather than a blank frame. The
   script upgrades to data-mode="pin" only above 1100px with
   motion allowed.
   ============================================================ */

.pop{--p:1;--ph:1;position:relative}
.pop__stage{position:relative;margin-inline:auto;display:flex;flex-direction:column}
.pop__head{text-align:center;flex:0 0 auto}
.pop__head h2{margin:0 auto;max-width:16ch;font-size:clamp(30px,3.4vw,46px)}
.pop__head p{margin:14px auto 0;max-width:56ch;font-size:clamp(15px,1.25vw,17px);
  line-height:1.55;color:var(--text-2)}
.pop__body{position:relative;flex:1 1 auto}
.pop__frame{width:980px;transform-origin:50% 50%}

/* ---- the card ---- */
.popc{position:relative;display:flex;flex-direction:column;overflow:hidden;
  background:#fff;border:1px solid var(--border);border-radius:16px;
  padding:19px 21px 21px;
  box-shadow:0 30px 64px -34px rgba(11,18,32,.55),0 2px 6px -2px rgba(11,18,32,.06)}
.popc__l{font-size:13px;font-weight:600;color:var(--text-2);padding-right:38px}
/* The number and what it counts sit on one line, baseline aligned,
   which is what takes roughly a third off the height of the card.
   Owen, 2026-08-19: "hydration, same residents, three, and then
   days under goal beside that." */
.popc__v{display:flex;align-items:baseline;gap:11px;margin-top:9px;
  font-family:var(--sans);font-weight:700;letter-spacing:-.03em;line-height:1;
  font-size:40px;color:var(--text-strong)}
.popc__v--good{color:var(--success)}
.popc__v--bad{color:var(--danger)}
.popc__v small{font-size:13px;font-weight:600;letter-spacing:0;line-height:1.35;
  color:var(--text-muted)}
.popc__art{margin-top:15px}

/* a proportion bar */
.popbar{height:7px;border-radius:4px;background:var(--n-100);overflow:hidden}
.popbar i{display:block;height:100%;border-radius:4px;background:var(--c,var(--brand))}
.popc__foot{margin:9px 0 0;font-size:11.5px;color:var(--text-muted)}

/* five little columns, the location breakdown */
.popbars{display:flex;align-items:flex-end;gap:9px;height:46px}
.popbars span{flex:1;border-radius:4px 4px 0 0;background:var(--c,var(--brand));opacity:.32}
.popbars span.on{opacity:1}

/* six days, three of them under goal */
.popdots{display:flex;gap:8px}
.popdots i{flex:1;height:24px;border-radius:5px;background:var(--hydr);opacity:.28}
.popdots i.miss{background:var(--danger);opacity:.85}

.popkv{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  padding-top:11px;border-top:1px solid var(--border);font-size:12.5px;color:var(--text-2)}
.popkv b{font-size:14px;font-weight:700;color:var(--text-strong)}
.poptag{display:inline-flex;align-items:center;gap:6px;padding:5px 11px;border-radius:999px;
  font-size:11.5px;font-weight:600;background:var(--danger-bg);color:#B42318}
.poptag svg{width:11px;height:11px}

/* ---- the eye, and what it opens ---- */
.popc__eye{position:absolute;top:16px;right:16px;z-index:3;width:32px;height:32px;
  display:grid;place-items:center;border-radius:50%;cursor:pointer;
  border:1px solid var(--border);background:var(--n-50,#fff);color:var(--text-2);
  transition:background .18s ease,color .18s ease,border-color .18s ease}
.popc__eye svg{width:16px;height:16px}
.popc__eye:hover,.popc__eye:focus-visible,.popc[data-open='true'] .popc__eye{
  background:rgba(255,255,255,.16);border-color:rgba(255,255,255,.34);color:#fff;outline:none}
/* The note is the card, not a panel inside it: the blue fills the
   whole box from under the eye and takes it over, and lets go on
   mouse-out. clip-path does the wipe; opacity carries it on
   anything that will not animate a circle. */
.popc__note{position:absolute;z-index:2;inset:0;margin:0;
  display:flex;align-items:center;   /* the sentence is one <span>, or
     every inline child would become its own flex item */
  padding:20px 22px;background:var(--deep);color:#fff;
  font-size:15px;line-height:1.4;
  opacity:0;visibility:hidden;
  clip-path:circle(0% at calc(100% - 33px) 33px);
  transition:opacity .16s ease,clip-path .34s var(--ease-out),visibility .34s}
.popc__note b{font-weight:700}
.popc__eye:hover ~ .popc__note,
.popc__eye:focus-visible ~ .popc__note,
.popc[data-open='true'] .popc__note{opacity:1;visibility:visible;
  clip-path:circle(150% at calc(100% - 33px) 33px)}
@media(prefers-reduced-motion:reduce){.popc__note{transition:none}}

/* the one line that says the eye is there */
.pophint{margin:18px 0 0;text-align:center;font-size:13px;color:var(--text-muted)}
.pophint svg{width:14px;height:14px;vertical-align:-2px;margin-right:5px}

/* ---- flat: the finished arrangement, stacked ---- */
.pop[data-mode='flat'] .pop__stage{display:grid;gap:clamp(22px,3vw,34px);justify-items:center;
  width:min(1320px,calc(100% - 48px))}
.pop[data-mode='flat'] .pop__head{padding-bottom:6px}
.pop[data-mode='flat'] .pop__head h2{font-size:clamp(32px,4.2vw,58px)}
.pop[data-mode='flat'] .pop__body{width:100%;display:grid;gap:clamp(22px,3vw,34px);justify-items:center}
.pop[data-mode='flat'] .pop__frame{width:100%;max-width:1020px;transform:none}
.pop[data-mode='flat'] .pop__cards{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(16px,2vw,24px);width:100%}
/* relative, not static: the eye is absolutely positioned inside the
   card and would otherwise anchor to the stage. */
.pop[data-mode='flat'] .pop__card{width:auto;transform:none;position:relative}
@media(max-width:1000px){.pop[data-mode='flat'] .pop__cards{grid-template-columns:repeat(2,minmax(0,1fr))}}
/* Under 560 the cards STAY two across and shrink, at Owen's
   direction (2026-08-20) — a single column of four was a screen and
   a half of cards under the board. Two rows of two reads as the
   board's own stat strip. The eye's circle origin moves with the
   smaller eye so the wipe still starts under the finger. */
@media(max-width:560px){
  .pop[data-mode='flat'] .pop__cards{grid-template-columns:repeat(2,minmax(0,1fr));gap:11px}
  .popc{padding:13px 14px 14px;border-radius:14px;
    box-shadow:0 16px 34px -22px rgba(11,18,32,.4),0 2px 6px -2px rgba(11,18,32,.06)}
  .popc__l{font-size:11.5px;padding-right:30px}
  .popc__v{font-size:29px;gap:7px;margin-top:8px}
  .popc__v small{font-size:11px}
  .popc__art{margin-top:11px}
  .popc__eye{top:10px;right:10px;width:28px;height:28px}
  .popc__eye svg{width:14px;height:14px}
  .popc__note{font-size:12.5px;line-height:1.4;padding:12px 14px;
    clip-path:circle(0% at calc(100% - 24px) 24px)}
  .popc__eye:hover ~ .popc__note,
  .popc__eye:focus-visible ~ .popc__note,
  .popc[data-open='true'] .popc__note{clip-path:circle(150% at calc(100% - 24px) 24px)}
  .popbars{height:36px;gap:7px}
  .popdots i{height:20px}
}

/* ---- pin: the scroll rig ---- */
.pop[data-mode='pin']{height:380vh}
/* Stick below the fixed header (~82px). Height is the stage, not
   100vh: a viewport-tall pin centred the board and left a white
   hole under the hero while the pin was still in flow. */
.pop[data-mode='pin'] .pop__pin{position:sticky;top:86px;height:auto;display:grid;
  place-items:start center;overflow:hidden}
.pop[data-mode='pin'] .pop__stage{width:min(1320px,calc(100% - 40px));
  /* 680, not 740. The board is anchored in the middle of the body,
     so every extra pixel of stage is half a pixel of air between
     the heading and the board and half a pixel under it. Owen,
     2026-08-20: the heading and the sub should sit closer to the
     chart. */
  height:min(680px,calc(90vh - 86px))}
/* The heading is inside the artwork and arrives second, after the
   board has settled and before the cards leave it. It is hidden at
   the top of the pin, which is Owen's order: dashboard, then the
   name over it, then the four. */
.pop[data-mode='pin'] .pop__head{padding-bottom:clamp(10px,1.4vw,18px);
  opacity:var(--ph);
  /* 34px of travel, up from 22. At 22 over a short window the
     heading read as switched on rather than as arriving; the
     longer run in motion.js and the longer road here are one
     change. It rises FROM the board, which is Owen's "glide out". */
  transform:translate3d(0,calc((1 - var(--ph)) * 34px),0)}
/* z-index 1 against the board's 2. This is the whole "out of the
   back" note: the cards are always behind the dashboard, so at
   rest they are not hidden by opacity, they are hidden by it. */
.pop[data-mode='pin'] .pop__cards{position:absolute;inset:0;z-index:1;pointer-events:none}
.pop[data-mode='pin'] .pop__frame{position:absolute;z-index:2;left:50%;top:47%;
  translate:-50% -50%;
  transform:scale(calc(var(--s,.6) * (.94 + .06 * var(--p))))}
.pop[data-mode='pin'] .pop__card{position:absolute;left:50%;top:47%;translate:-50% -50%;
  /* 47%, and the same 47% on the frame above: the cards are placed
     off the board's centre, so the two anchors move as one or the
     rails land skewed. */
  width:var(--cw,290px);pointer-events:auto;
  transform:translate(calc(var(--dx,0px) * var(--e,0)),calc(var(--dy,0px) * var(--e,0)))
            scale(calc(.93 + .07 * var(--e,0)))}

/* =========================================================
   THE LAYER TABS - product page section 3 - 2026-08-20
   One heading, four panes: Risk Radar, Compliance, Reporting,
   Trends. Owen: the old sections 3 and 4b "should be in one
   section... one set of headings, and then you could switch
   between them." The pill row echoes the header pill: white
   fill, the denser hairline (--border disappears against white
   on this paper), ink pill when on.

   hidden and .on are kept in sync by site.js. The explicit
   [hidden] rule below is load-bearing: .on's display:block is
   an author rule and beats the UA style behind [hidden].
   ========================================================= */
.ltabs{display:flex;justify-content:center;margin-top:clamp(26px,3.2vw,40px)}
.ltabs__row{display:inline-flex;flex-wrap:wrap;justify-content:center;gap:4px;padding:5px;
  background:var(--white);border:1px solid rgba(16,32,48,.13);border-radius:999px}
.ltab{appearance:none;border:0;background:transparent;font:inherit;font-size:15px;font-weight:600;
  color:var(--text);padding:9px 18px;border-radius:999px;cursor:pointer;
  transition:color .18s,background-color .18s}
.ltab:hover{color:var(--text-strong)}
.ltab.on{background:var(--text-strong);color:#fff}
.lpane{display:none}
.lpane.on{display:block}
.lpane[hidden]{display:none}
.lpane .pair{padding-bottom:0;margin-top:clamp(28px,3.4vw,44px)}
.lpane .pcard--wide{margin-top:clamp(28px,3.4vw,44px);min-height:0}
/* board-noncomp and board-hours arrive in the .app frame, which
   brings its own edge the same way .dpanel does. */
.pcard__panel > .app{border:0;box-shadow:none;background:transparent}
/* 24 per-bar percentage labels do not fit a half-width panel. The
   counts inside the bars stay. */
.lpane .dbarh i{display:none}

/* The management board's own two pieces: the metric chip row, and
   the dashed organisation-average line over the plot. */
.dmgmt__chips{display:flex;flex-wrap:wrap;gap:6px;margin:14px 0 18px}
.dmgmt .dchart__plot{position:relative}
.davg{position:absolute;left:0;right:0;bottom:var(--avg,50%);z-index:1;pointer-events:none;
  border-top:2px dashed rgba(16,32,48,.30)}
.davg i{position:absolute;right:0;top:6px;font-style:normal;font-size:11px;font-weight:600;
  color:var(--text);background:var(--white);border:1px solid var(--border);
  border-radius:999px;padding:2px 8px}
/* At phone width the histogram's 24 hour labels merge into one
   string; the band key and the caption already carry the when. */
@media(max-width:560px){.lpane .dbarh u{display:none}}
/* A wide card whose board does not want the whole width: the panel
   centres at a working width instead of stretching. The Risk Radar
   tab uses it - five rank rows across 1150px read as a banner, not
   a screen. */
.pcard__panel--fit{max-width:680px;justify-self:center}
