/* ═══════════════════════════════════════════════════════════════════════════
   MODULE-2027 · "M27" — the product-surface layer for the /module/* pages
   ---------------------------------------------------------------------------
   platinum-theme.css gives every page the homepage's editorial vocabulary:
   acts, grounds, textures, act headers, cards, the number wall, the journey
   line, tabs, the split, the accordion, photo plates and the close band. What
   it deliberately does NOT carry is the homepage's other signature — the
   PRODUCT STAGE: the dark application window in the hero, and the light data
   panel that follows it. Those lived in home-2027.css as .h27-hs*, welded to
   the homepage's own hero markup.

   This file is that idea generalised. Six module pages each need to show their
   own software, and each was carrying a slightly different hand-rolled mock in
   its {% block extra_css %}. Instead every page now composes the same
   primitives and supplies only content:

     .m27-hero     the hero bed — copy left, product right
     .m27-stage    the glow bed a window sits in
     .m27-app      the dark application window (chrome + body)
     .m27-pan      the light data panel
     .m27-list     the checklist used in splits and tab panels
     .m27-badge    the floating proof badge pinned to a window corner

   ── Scoping ────────────────────────────────────────────────────────────────
   Every selector is `.h27 .m27-*` (two classes), the same footing
   platinum-theme.css stands on, so this layer never fights the theme and never
   matches on a page that has not opted in with the .h27 wrapper. Colour comes
   only from the theme's locked tokens, so brand-2026.css's enforcement layer
   stays authoritative.

   ── Motion ─────────────────────────────────────────────────────────────────
   The windows carry ambient loops (a shimmer over the skeleton lines, a
   waveform, a pulsing live dot, bars that grow in). All of them are decorative
   and all of them are switched off under prefers-reduced-motion at the foot of
   this file. Every window is aria-hidden in the markup — it is a picture of
   software, not software, and a screen reader gains nothing from its parts.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ══ §1 · HERO BED ═══════════════════════════════════════════════════════ */

.h27 .m27-hero {
  display: grid;
  grid-template-columns: minmax(0, 1.02fr) minmax(0, .98fr);
  gap: clamp(30px, 4.6vw, 74px);
  align-items: center;
}
.h27 .m27-hero h1 {
  font-size: var(--h27-d0);
  line-height: 1.04; letter-spacing: -.022em;
  color: #fff; margin: 0; text-wrap: balance;
}

/* chips read as glass on a dark act rather than as light pills */
.h27 .h27-act--ink .h27-chip {
  background: rgba(255,255,255,.06); color: #fff;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.18);
}


/* ══ §1b · DARK-BAND HEADINGS — the on-ink safety net ════════════════════
   platinum-theme.css enforces the display FACE on h1/h2 but never the COLOUR,
   so a heading only turns white because some hero wrapper (.m27-hero, .mx-hero,
   .pv-hero …) says so. A page whose hero is a bare <h1> straight inside
   .h27-act--ink therefore inherits the legacy dark heading colour from
   styles.css and renders navy-on-navy — invisible except for whatever sits in
   an .h27-hl span. That was live on twelve pages (pricing, platform, security,
   about, why-platinum, resources, early-access, boarding-app,
   community-partners, sitemap, privacy, terms).

   Scoping it to the dark grounds rather than to a wrapper means the guarantee
   holds however a page chooses to build its hero, and it cannot leak onto the
   paper/ice bands where headings must stay navy. (0,3,1) clears the legacy
   (0,0,1) without !important, so brand-2026.css keeps the last word on type. */

.h27 .h27-act--ink h1,  .h27 .h27-act--ink h2,
.h27 .h27-act--void h1, .h27 .h27-act--void h2,
.h27 .h27-close h1 { color: #fff; }

/* the lede and body copy that travel with such a heading */
.h27 .h27-act--ink > .h27-edge > .h27-lede,
.h27 .h27-act--void > .h27-edge > .h27-lede { color: var(--h27-onink); }

/* ══ §2 · CHECKLIST ══════════════════════════════════════════════════════ */

.h27 .m27-list { list-style: none; margin: 24px 0 0; padding: 0; display: grid; gap: 11px; }
.h27 .m27-list li {
  display: flex; gap: 11px; align-items: flex-start;
  font-size: clamp(14px, 1.05vw, 15.5px); line-height: 1.62; color: var(--h27-body);
}
.h27 .m27-list .ico { flex: none; width: 17px; height: 17px; margin-top: 4px; color: var(--h27-coral); }
/* on the dark act and on the "after" side of a split, the list inverts */
.h27 .h27-act--ink .m27-list li,
.h27 .h27-split__side--new .m27-list li { color: var(--h27-onink); }
.h27 .h27-act--ink .m27-list .ico,
.h27 .h27-split__side--new .m27-list .ico { color: var(--h27-coral-lt); }

/* the "what it means" footer a feature card closes on */
.h27 .h27-card .h27-card__foot {
  margin: auto 0 0; padding-top: 14px;
  border-top: 1px solid var(--h27-hair);
  font-size: 13px; line-height: 1.55; color: var(--h27-mute);
}
.h27 .h27-card--ink .h27-card__foot,
.h27 .h27-card--glass .h27-card__foot { border-top-color: rgba(255,255,255,.16); color: var(--h27-onink); }

/* a number-wall cell may carry a line of prose under its label */
.h27 .h27-wall__cell p { font-size: 13px; line-height: 1.6; color: var(--h27-mute); margin: 10px 0 0; max-width: 30ch; }

.h27 .m27-cap { margin-top: 12px; font-size: 11.5px; color: var(--h27-mute); }


/* ══ §3 · THE STAGE — the bed a product window sits in ═══════════════════ */

.h27 .m27-stage { position: relative; }
.h27 .m27-stage__aura {
  position: absolute; inset: -16% -12% -20% -10%;
  z-index: 0; pointer-events: none;
  background:
    none;
  filter: blur(18px);
  animation: m27-aura 15s ease-in-out infinite alternate;
}
@keyframes m27-aura {
  from { transform: translate3d(0,0,0) scale(1);        opacity: .8; }
  to   { transform: translate3d(-2%,2%,0) scale(1.07);  opacity: 1;  }
}


/* ══ §4 · THE DARK APPLICATION WINDOW ════════════════════════════════════ */

.h27 .m27-app {
  position: relative; z-index: 1;
  border-radius: 14px; overflow: hidden;
  background: #0B1630;
  border: 1px solid rgba(255,255,255,.13);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.07),
    0 34px 72px -24px rgba(0,0,0,.7),
    0 8px 22px -10px rgba(0,0,0,.5);
}
/* on a LIGHT act the same window needs a rim rather than a void-drop shadow,
   or it reads as a hole cut in the page */
.h27 .h27-act--paper .m27-app,
.h27 .h27-act--ice .m27-app {
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.07),
    0 2px 4px rgba(13,27,62,.06),
    0 30px 66px -22px rgba(13,27,62,.42);
}

/* one app bar: brand · where you are · session state · who you are */
.h27 .m27-app__chrome {
  display: flex; align-items: center; gap: 9px;
  height: 38px; padding: 0 12px;
  background: rgba(255,255,255,.03);
  border-bottom: 1px solid rgba(255,255,255,.07);
}
.h27 .m27-app__brand {
  flex: none; width: 21px; height: 21px; border-radius: 6px;
  display: grid; place-items: center;
  background: var(--h27-navy-up);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.18);
  font-family: 'Inter', sans-serif; font-size: 10px; font-weight: 800;
  color: var(--h27-coral-lt);
}
.h27 .m27-app__crumb {
  flex: 1 1 auto; min-width: 0;
  font-family: 'Inter', sans-serif; font-size: 9.5px; font-weight: 600;
  color: rgba(255,255,255,.42);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.h27 .m27-app__crumb i { font-style: normal; opacity: .5; margin: 0 3px; }
.h27 .m27-app__crumb b { color: rgba(255,255,255,.88); font-weight: 700; }
.h27 .m27-app__live {
  flex: none; display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 8px; border-radius: 999px;
  background: rgba(232,89,58,.14);
  box-shadow: inset 0 0 0 1px rgba(232,89,58,.30);
  font-family: 'Inter', sans-serif;
  font-size: 8px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--h27-coral-lt);
}
.h27 .m27-app__live i {
  width: 5px; height: 5px; border-radius: 50%; background: var(--h27-coral);
  animation: m27-ping 2.6s var(--h27-ease) infinite;
}
@keyframes m27-ping { 0%,100% { opacity: 1; transform: scale(1); } 50% { opacity: .35; transform: scale(.7); } }
.h27 .m27-app__me {
  flex: none; width: 21px; height: 21px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(122,158,142,.30);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.16);
  font-family: 'Inter', sans-serif; font-size: 8px; font-weight: 800; color: #DCEAE2;
}
.h27 .m27-app__body { padding: 15px 16px 16px; }


/* ══ §5 · WHAT GOES INSIDE A WINDOW ══════════════════════════════════════
   Deliberately generic. A record header, a segmented control, skeleton copy,
   a chip set, a status bar, a stat tile, a sparkline and a row list cover all
   six modules between them — the page supplies the words. */

/* ── record header: avatar · identity · state ─────────────────────────── */
.h27 .m27-rec {
  display: flex; align-items: center; gap: 11px;
  padding-bottom: 13px; border-bottom: 1px solid rgba(255,255,255,.07);
}
.h27 .m27-rec__ava {
  flex: none; width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(59,134,188,.26);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.16);
  font-family: 'Inter', sans-serif; font-size: 11px; font-weight: 800; color: #CFE3F2;
}
.h27 .m27-rec__id { flex: 1 1 auto; min-width: 0; }
.h27 .m27-rec__n {
  display: block; font-family: 'Inter', sans-serif;
  font-size: 13px; font-weight: 700; letter-spacing: -.01em; color: #fff;
}
.h27 .m27-rec__m {
  display: block; margin-top: 2px;
  font-family: 'Inter', sans-serif; font-size: 10.5px; color: rgba(255,255,255,.44);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.h27 .m27-state {
  flex: none; padding: 4px 9px; border-radius: 999px;
  font-family: 'Inter', sans-serif;
  font-size: 9px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  background: rgba(122,158,142,.18);
  box-shadow: inset 0 0 0 1px rgba(122,158,142,.36);
  color: var(--h27-sage-lt);
}
.h27 .m27-state--sky   { background: rgba(59,134,188,.18); box-shadow: inset 0 0 0 1px rgba(59,134,188,.36); color: var(--h27-sky-lt); }
.h27 .m27-state--coral { background: rgba(232,89,58,.16);  box-shadow: inset 0 0 0 1px rgba(232,89,58,.34);  color: var(--h27-coral-lt); }

/* ── segmented control (SOAP tabs, day/week/month, funnel stages) ─────── */
.h27 .m27-seg { display: flex; gap: 6px; margin: 14px 0 13px; flex-wrap: wrap; }
.h27 .m27-seg span {
  min-width: 34px; height: 29px; padding: 0 10px; border-radius: 7px;
  display: grid; place-items: center;
  font-family: 'Inter', sans-serif; font-size: 11px; font-weight: 800;
  color: rgba(255,255,255,.42);
  background: rgba(255,255,255,.05);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.07);
  white-space: nowrap;
}
.h27 .m27-seg span.on { background: var(--h27-coral); color: #fff; box-shadow: 0 6px 16px -6px rgba(232,89,58,.8); }

/* ── skeleton copy, shimmering as if it were being written ────────────── */
.h27 .m27-sk {
  position: relative; overflow: hidden;
  height: 8px; border-radius: 4px;
  background: rgba(255,255,255,.085);
  margin: 9px 0;
}
.h27 .m27-sk::after {
  content: ''; position: absolute; inset: 0; transform: translateX(-100%);
  background: none;
  animation: m27-shim 2.6s ease-in-out infinite;
  animation-delay: var(--d, 0s);
}
@keyframes m27-shim { 0% { transform: translateX(-100%); } 55%, 100% { transform: translateX(110%); } }

/* ── chip set (codes, tags, channels) ─────────────────────────────────── */
.h27 .m27-chipset { display: flex; gap: 7px; flex-wrap: wrap; margin: 14px 0 13px; }
.h27 .m27-tag {
  font-family: 'Inter', sans-serif; font-size: 10.5px; font-weight: 700;
  padding: 5px 9px; border-radius: 6px; white-space: nowrap;
  background: rgba(255,255,255,.06); color: rgba(255,255,255,.66);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.09);
}
.h27 .m27-tag--sky   { background: rgba(59,134,188,.16);  color: var(--h27-sky-lt);   box-shadow: inset 0 0 0 1px rgba(59,134,188,.32); }
.h27 .m27-tag--sage  { background: rgba(122,158,142,.16); color: var(--h27-sage-lt);  box-shadow: inset 0 0 0 1px rgba(122,158,142,.32); }
.h27 .m27-tag--coral { background: rgba(232,89,58,.14);   color: var(--h27-coral-lt); box-shadow: inset 0 0 0 1px rgba(232,89,58,.30); }

/* ── the status bar: what the system is doing right now ───────────────── */
.h27 .m27-bar {
  display: flex; align-items: center; gap: 9px;
  padding: 10px 12px; border-radius: 8px;
  background: rgba(232,89,58,.10);
  box-shadow: inset 0 0 0 1px rgba(232,89,58,.26);
  font-family: 'Inter', sans-serif; font-size: 11.5px; font-weight: 600;
  color: var(--h27-coral-lt);
}
.h27 .m27-bar .ico { flex: none; width: 14px; height: 14px; color: var(--h27-coral); }
.h27 .m27-bar--sky {
  background: rgba(59,134,188,.12); box-shadow: inset 0 0 0 1px rgba(59,134,188,.28); color: var(--h27-sky-lt);
}
.h27 .m27-bar--sky .ico { color: var(--h27-sky-lt); }

/* the live waveform that rides at the end of a status bar */
.h27 .m27-wave { display: flex; align-items: center; gap: 2px; height: 15px; margin-left: auto; }
.h27 .m27-wave i {
  width: 2px; height: 100%; border-radius: 1px;
  background: var(--h27-coral); opacity: .85;
  animation: m27-wave 1.15s ease-in-out infinite;
  animation-delay: var(--d, 0s);
}
@keyframes m27-wave { 0%,100% { transform: scaleY(.28); } 50% { transform: scaleY(1); } }

/* ── stat tiles and a sparkline, for dashboard-shaped windows ─────────── */
.h27 .m27-tiles { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 8px; margin: 13px 0; }
.h27 .m27-tile {
  padding: 11px 12px; border-radius: 8px;
  background: rgba(255,255,255,.05);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.08);
}
.h27 .m27-tile b {
  display: block; font-family: 'DM Serif Display', Georgia, serif;
  font-size: 20px; line-height: 1; color: #fff;
}
.h27 .m27-tile span {
  display: block; margin-top: 6px;
  font-family: 'Inter', sans-serif; font-size: 9px; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase; color: rgba(255,255,255,.44);
}
.h27 .m27-tile em { font-style: normal; color: var(--h27-sage-lt); }

.h27 .m27-spark { display: flex; align-items: flex-end; gap: 3px; height: 54px; margin: 13px 0 0; }
.h27 .m27-spark i {
  flex: 1 1 0; height: var(--h, 40%); border-radius: 2px 2px 0 0;
  background: rgba(59,134,188,.9);
}
.h27 .m27-spark i.on { background: var(--h27-coral); }

/* ── row list (a queue, a schedule, a claim run) ──────────────────────── */
.h27 .m27-rows { display: grid; gap: 6px; margin: 13px 0 0; }
.h27 .m27-rows > div {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 11px; border-radius: 7px;
  background: rgba(255,255,255,.04);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.06);
  font-family: 'Inter', sans-serif; font-size: 11px; color: rgba(255,255,255,.62);
}
.h27 .m27-rows b { font-weight: 700; color: #fff; }
.h27 .m27-rows .m27-tag { margin-left: auto; }
.h27 .m27-rows .ico { flex: none; width: 14px; height: 14px; color: var(--h27-sky-lt); }


/* ══ §6 · FLOATING PROOF BADGE ═══════════════════════════════════════════ */

.h27 .m27-badge {
  position: absolute; z-index: 3;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 13px; border-radius: 6px;
  background: rgba(255,255,255,.94);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  box-shadow: 0 14px 34px -12px rgba(0,0,0,.6), inset 0 0 0 1px rgba(13,27,62,.08);
  font-family: 'Inter', sans-serif; font-size: 11.5px; font-weight: 700;
  color: var(--h27-navy); white-space: nowrap;
}
.h27 .m27-badge .ico { width: 14px; height: 14px; color: var(--h27-coral); }
.h27 .m27-badge--a { top: -14px;    right: -12px; }
.h27 .m27-badge--b { bottom: -16px; left: -14px; }


/* ══ §7 · THE LIGHT DATA PANEL ═══════════════════════════════════════════
   The counterpart to the window: where the window shows the software being
   used, the panel shows what the software produced. Light, so it belongs to
   the paper/ice acts the way the window belongs to the dark ones. */

.h27 .m27-pan {
  position: relative; border-radius: 6px; overflow: hidden;
  background: var(--h27-paper);
  box-shadow:
    inset 0 0 0 1px var(--h27-hair),
    0 2px 4px rgba(13,27,62,.05),
    0 26px 64px rgba(13,27,62,.11);
}
.h27 .m27-pan__top {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--h27-hair);
  background: var(--h27-ice);
}
.h27 .m27-pan__t { font-family: 'Inter', sans-serif; font-size: 13px; font-weight: 700; color: var(--h27-navy); }
.h27 .m27-pan__s {
  margin-left: auto; font-family: 'Inter', sans-serif;
  font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--h27-mute);
}
.h27 .m27-pan__body { padding: 18px; }

.h27 .m27-kpis { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 10px; }
.h27 .m27-kpi {
  padding: 13px 14px; border-radius: 5px;
  background: var(--h27-ice);
  box-shadow: inset 0 0 0 1px var(--h27-hair);
}
.h27 .m27-kpi b {
  display: block; font-family: 'DM Serif Display', Georgia, serif;
  font-size: clamp(21px, 2vw, 27px); line-height: 1; color: var(--h27-navy);
}
.h27 .m27-kpi span {
  display: block; margin-top: 7px;
  font-family: 'Inter', sans-serif; font-size: 10.5px; font-weight: 600;
  letter-spacing: .05em; text-transform: uppercase; color: var(--h27-mute);
}
.h27 .m27-kpi em { font-style: normal; font-weight: 700; color: #4E7A67; }

/* the plot — bars grow in, the final bar in persimmon so the eye lands on
   "now" rather than on the tallest column */
.h27 .m27-plot {
  display: flex; align-items: flex-end; gap: clamp(4px, .7vw, 8px);
  height: clamp(84px, 9vw, 116px);
  margin-top: 20px; padding-bottom: 9px;
  border-bottom: 1px solid var(--h27-hair);
}
.h27 .m27-plot i {
  flex: 1 1 0; height: var(--h, 40%);
  border-radius: 3px 3px 0 0; transform-origin: 50% 100%;
  background: rgba(59,134,188,.85);
  animation: m27-grow 900ms var(--h27-ease) both;
  animation-delay: calc(var(--i, 0) * 55ms);
}
.h27 .m27-plot i:last-child { background: var(--h27-coral); }
@keyframes m27-grow { from { transform: scaleY(.04); opacity: 0; } to { transform: scaleY(1); opacity: 1; } }

.h27 .m27-axis {
  display: flex; justify-content: space-between; margin-top: 9px;
  font-family: 'Inter', sans-serif; font-size: 10px; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase; color: var(--h27-mute);
}

.h27 .m27-att { display: flex; gap: 7px; flex-wrap: wrap; margin-top: 17px; padding-top: 15px; border-top: 1px solid var(--h27-hair); }
.h27 .m27-att span {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 11px; border-radius: 4px;
  background: var(--h27-ice);
  box-shadow: inset 0 0 0 1px var(--h27-hair);
  font-family: 'Inter', sans-serif; font-size: 11.5px; font-weight: 600; color: var(--h27-navy);
}
.h27 .m27-att .ico { width: 13px; height: 13px; color: var(--h27-sky); }


/* ══ §8 · JOURNEY COLUMN COUNTS ══════════════════════════════════════════
   platinum-theme.css draws the station line at five stops. A module page's
   "how it works" is usually three or four, and below 1024px the theme turns
   the line vertical and these overrides stop applying — which is correct. */

@media (min-width: 1025px) {
  .h27 .m27-jrn3 .h27-jrn__list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .h27 .m27-jrn4 .h27-jrn__list { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}


/* ══ §9 · THE HERO CANVAS — COMPACT ══════════════════════════════════════
   Every page opens on the same move the homepage opens on: the argument left,
   a picture of the software right. But the homepage's own canvas (.h27-hs,
   home-2027.css §4b) renders 469 × 346, while the same content built out of
   §3–§6 above was landing at 553 × 380–450 — one and a half rows taller and
   84px wider. Side by side the sub-pages read looser and heavier than the
   front door they are meant to echo, and on a 900px-tall laptop the extra
   height was pushing the CTA row toward the fold.

   This section brings the hero canvas back to the homepage's proportions. It
   changes no colour, no component and no markup — only the metrics: the
   chrome bar, the body padding, and the vertical rhythm of every primitive a
   hero window is built from. Everything is dialled from ONE place, so a page
   inherits the right size just by putting a .m27-stage in its .m27-hero.

   Scoped to `.m27-hero` on purpose. The same primitives are reused further
   down several pages at full size — inside a split, a tab panel, an "in
   action" act — and that use is correct as it stands. Only the first section
   shrinks.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── the frame: homepage width, hung off the right of its column ───────── */
/* `width:100%` is not redundant — `margin-left:auto` switches a grid item off
   `justify-self: stretch`, and without an explicit width it would then size to
   fit-content, i.e. the window would be as wide as its longest row of copy.
   That is how 24 pages ended up with 24 different canvas widths. */
.h27 .m27-hero .m27-stage {
  width: 100%;
  max-width: 486px;
  margin-left: auto;
}

/* THE CLIP FIX — load-bearing, not cosmetic.
   theme-motion-2027.css reveals anything carrying [data-t27] with
   `clip-path: inset(0 0 0 0)`, which clips the element to its own border box.
   The stage is exactly the element that needs to paint OUTSIDE that box: the
   aura sits at inset -16% -12% -20% -10%, and both proof badges hang off the
   corners on negative offsets. So on every page the glow was being cut to a
   hard rectangle and both badges were being sliced clean in half — the top
   one losing its upper 14px, the bottom one its lower 16px. Since .m27-stage
   reveals with "rise" (opacity + transform), it never needed a clip-path at
   all; dropping it costs the reveal nothing and restores both.

   The revealed rule over there is `html.t27-ready .h27 [data-t27].x27-in`,
   which is (0,4,1) — so the gate prefix has to be repeated here or a plain
   (0,3,0) selector loses however late this file loads. The pair below is
   (0,5,1) and (0,3,0): the first beats the motion layer once the reveal has
   fired, the second covers the pre-gate and reduced-motion paths.  */
html.t27-ready .h27 .m27-hero .m27-stage.x27-in,
.h27 .m27-hero .m27-stage { clip-path: none; }

/* with the clip gone the badges can finally be placed on their merits. At the
   §6 offsets a badge sat 15px INTO the window, i.e. squarely on top of a 32px
   chrome bar, hiding the live pill and the avatar behind it. */
.h27 .m27-hero .m27-badge {
  padding: 8px 12px;
  font-size: 11px;
  border-radius: 5px;
}
.h27 .m27-hero .m27-badge .ico { width: 13px; height: 13px; }
/* anchored to the window's OUTER edge (bottom:100% / top:100%) rather than to
   a fixed negative offset, so a badge can never grow back over the chrome bar
   whatever its own height turns out to be. The -6px lets it rest ON the glass
   by a hair — the homepage's proof cards do the same — while leaving the live
   pill, the avatar and the status bar underneath fully readable. */
.h27 .m27-hero .m27-badge--a {
  top: auto; bottom: 100%; margin-bottom: -6px;
  right: 16px; left: auto;
}
.h27 .m27-hero .m27-badge--b {
  bottom: auto; top: 100%; margin-top: -6px;
  left: 16px; right: auto;
}

/* ── the window chrome ────────────────────────────────────────────────── */
.h27 .m27-hero .m27-app { border-radius: 12px; }
.h27 .m27-hero .m27-app__chrome { height: 32px; padding: 0 11px; gap: 8px; }
.h27 .m27-hero .m27-app__brand,
.h27 .m27-hero .m27-app__me { width: 19px; height: 19px; }
.h27 .m27-hero .m27-app__crumb { font-size: 9px; }
.h27 .m27-hero .m27-app__live { padding: 2px 7px; font-size: 7.5px; }
.h27 .m27-hero .m27-app__body { padding: 12px 13px 13px; }

/* ── record header ────────────────────────────────────────────────────── */
.h27 .m27-hero .m27-rec { gap: 9px; padding-bottom: 10px; }
.h27 .m27-hero .m27-rec__ava { width: 28px; height: 28px; font-size: 10px; }
.h27 .m27-hero .m27-rec__n { font-size: 12px; }
.h27 .m27-hero .m27-rec__m { font-size: 9.5px; margin-top: 1px; }
.h27 .m27-hero .m27-state { padding: 3px 8px; font-size: 8.5px; }

/* ── segmented control ────────────────────────────────────────────────── */
.h27 .m27-hero .m27-seg { gap: 5px; margin: 10px 0 9px; }
.h27 .m27-hero .m27-seg span {
  min-width: 30px; height: 24px; padding: 0 9px;
  border-radius: 6px; font-size: 10px;
}

/* ── skeleton copy ────────────────────────────────────────────────────── */
.h27 .m27-hero .m27-sk { height: 7px; margin: 7px 0; }

/* ── chip set ─────────────────────────────────────────────────────────── */
.h27 .m27-hero .m27-chipset { gap: 6px; margin: 10px 0 9px; }
.h27 .m27-hero .m27-tag { padding: 4px 8px; font-size: 9.5px; }

/* ── row list — the single biggest saving. Four rows at the §5 metrics run
     ~164px; here they run ~112px, and a row is pinned to one line so a page
     whose wording is long loses the tail rather than growing the window. ── */
.h27 .m27-hero .m27-rows { gap: 5px; margin-top: 10px; }
.h27 .m27-hero .m27-rows > div {
  gap: 7px; padding: 6px 9px; border-radius: 6px;
  font-size: 10px; line-height: 1.35;
  white-space: nowrap; overflow: hidden;
}
.h27 .m27-hero .m27-rows .ico { width: 13px; height: 13px; }

/* ── status bar ───────────────────────────────────────────────────────── */
.h27 .m27-hero .m27-bar {
  gap: 8px; padding: 8px 10px; border-radius: 7px;
  font-size: 10.5px; line-height: 1.35;
}
.h27 .m27-hero .m27-bar .ico { width: 13px; height: 13px; }
.h27 .m27-hero .m27-wave { height: 13px; }
/* several pages set `style="margin-top:13px"` on the closing bar; an inline
   declaration out-ranks any selector, so the compact spacing is expressed as
   a negative top margin on the element BEFORE it instead of fighting it. */
.h27 .m27-hero .m27-rows + .m27-bar { margin-top: 10px !important; }

/* ── stat tiles + sparkline (analytics, support) ──────────────────────── */
.h27 .m27-hero .m27-tiles { gap: 7px; margin: 10px 0; }
.h27 .m27-hero .m27-tile { padding: 9px 10px; border-radius: 7px; }
.h27 .m27-hero .m27-tile b { font-size: 18px; }
.h27 .m27-hero .m27-tile span { margin-top: 4px; font-size: 8.5px; }
/* the spark keeps most of its height on purpose: the frame lost 67px of width
   as well, and cutting the bars to match the rest of the compact scale would
   leave twelve near-square blocks rather than a chart. */
.h27 .m27-hero .m27-spark { height: 48px; margin-top: 10px; }

/* ── photo heroes (about · community partners · resources · early access)
     carry a plate instead of a window. Same job in the layout, so the same
     height: at the column's 553px, 1.58 lands the plate on 350 — level with
     the tallest product window — where the pages' own 1.42 gave 390. One
     rule at (0,3,0) beats four (0,2,0) page rules without touching four
     templates — but it has to be gated to the two-column width, or it would
     also out-rank those pages' ≤1024px rule and hold a phone-width plate at
     1.58 when it is supposed to letterbox out to 2.1. ─────────────────── */
@media (min-width: 1025px) {
  .h27 .m27-hero > .h27-ph { --h27-ph-ar: 1.58; }
}


/* ══ §10 · THE SHOT WALL — real captures of the running product ══════════
   §3–§7 draw PICTURES of software: hand-built windows made of divs, sized and
   worded by the page. They are the right thing in a hero, where the job is to
   say "this is software" in 486px without asking anyone to read.

   This section is the opposite instrument. When a page has actual screenshots
   of the shipping product, the reader wants to READ them — and a 3420 × 1244
   clinical workspace shown small is a grey smear. So the shot wall does four
   things a plain <img> cannot:

     1 · HOLDS THE RAIL.  The wall spans the .h27-edge exactly, so the act
         header above it, the capture, the notes and the closing capabilities
         panel all share one left and one right edge — the block reads as one
         built thing. Reading the small print is the lightbox's job (4), not
         the frame's.
     2 · FRAMES IT.  Each capture sits inside the same dark .m27-app window
         the hero uses, so five screenshots exported on five slightly
         different backgrounds read as one product rather than five files.
     3 · ANNOTATES IT.  Numbered pins sit on the capture at authored
         percentages and name the region under them on hover/focus. The same
         numbers repeat as prose in the panel's note list, so the explanation
         survives on a phone where the pins are hidden.
     4 · OPENS IT.  The chrome bar carries a link to the full-resolution
         rendition. Without JS that is a plain link to the file; with JS,
         m27-shots.js upgrades it into a pannable lightbox.
     5 · SPLITS + REACTS.  Every active panel is a split: the capture on the
         left, a reading rail (kicker, claim, numbered notes) beside it.
         The rail is live — hovering note n lights pin n, and a spotlight
         vignette (.m27-shot__spot, injected by JS) dims everything on the
         capture except the region that note describes; hovering a pin
         lights its note back. On fine pointers a loupe (.m27-loupe, also
         injected) magnifies the capture at native pixels under the cursor,
         and the window itself answers the pointer with a ≤1.2° tilt.
         All of it degrades to the static wall: no JS, coarse pointers and
         prefers-reduced-motion each simply lose the layer.

   ── Sizing contract ──────────────────────────────────────────────────────
   Each panel declares its capture's real aspect on --shot-ar. The picture is
   then width:100% but capped at `--shot-cap × --shot-ar`, which expresses a
   MAX HEIGHT as a max width — the one form that neither distorts the image
   nor letterboxes it. Ultra-wide captures therefore fill the frame; the
   portrait outcome report and the near-square dashboard centre inside it at a
   readable height instead of running 1500px down the page. aspect-ratio on
   the wrapper means the frame is the right size before the file has loaded,
   so nothing shifts and the pins never land in the wrong place.

   ── Markup contract ──────────────────────────────────────────────────────
     <div class="m27-shots">
       <div class="m27-shots__tabs h27-tabs" role="tablist">     ← theme JS
         <button role="tab" aria-controls="shot-x" aria-selected="true">…
       </div>
       <section class="m27-shot is-active" id="shot-x" role="tabpanel"
                style="--shot-ar:2.749">
         <div class="m27-app">
           <div class="m27-app__chrome">… <a class="m27-shot__zoom">…</a></div>
           <div class="m27-shot__stage">
             <div class="m27-shot__pic">
               <picture><img …></picture>
               <button class="m27-pin" style="--x:40%;--y:26%">…</button>
             </div>
           </div>
         </div>
         <div class="m27-shot__meta">…</div>
       </section>
   The tablist carries .h27-tabs purely so theme-2027.js §4 owns selection,
   arrow keys and aria state; every visual the theme attaches to that class is
   overridden below.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── the frame ────────────────────────────────────────────────────────────
   Full width of the .h27-edge rail and nothing more. An earlier cut broke the
   wall out to 1560px for legibility, but a block wider than the act header
   above it and the checklist below it reads as three different pages sharing
   a scroll — alignment IS the design. If a capture's small print matters,
   that is what the full-size lightbox is for. */
.h27 .m27-shots {
  position: relative;
  width: 100%;
  margin-top: clamp(28px, 3.2vw, 50px);
}

/* ── the switcher rail ────────────────────────────────────────────────── */
.h27 .m27-shots__tabs {
  display: flex;
  gap: 8px;
  border-bottom: 0;                 /* the theme's tab underline is not wanted */
  margin: 0 0 clamp(13px, 1.5vw, 20px);
  padding: 0 0 2px;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}
.h27 .m27-shots__tabs::-webkit-scrollbar { display: none; }

.h27 .m27-shots__tabs button {
  flex: 1 1 0;
  min-width: 186px;
  scroll-snap-align: start;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: 11px;
  align-items: center;
  margin: 0;
  padding: 11px 13px;
  border-radius: 9px;
  text-align: left;
  background: var(--h27-paper);
  box-shadow: inset 0 0 0 1px var(--h27-hair);
  transition:
    background 320ms var(--h27-ease),
    box-shadow 320ms var(--h27-ease),
    transform  320ms var(--h27-ease);
}
.h27 .m27-shots__tabs button::after { display: none; }   /* kill the underline */
.h27 .m27-shots__tabs button:hover { transform: translateY(-1px); box-shadow: inset 0 0 0 1px #C9D8E9; }
.h27 .m27-shots__tabs button[aria-selected="true"] {
  background: var(--h27-navy);
  box-shadow: inset 0 0 0 1px var(--h27-navy), 0 12px 26px -14px rgba(13,27,62,.55);
}

.h27 .m27-shots__no {
  grid-row: span 2;
  width: 27px; height: 27px; border-radius: 7px;
  display: grid; place-items: center;
  background: var(--h27-ice-2);
  font-family: 'Inter', sans-serif; font-size: 11px; font-weight: 800;
  color: var(--h27-mute);
  transition: background 320ms var(--h27-ease), color 320ms var(--h27-ease);
}
.h27 .m27-shots__lbl {
  font-family: 'Inter', sans-serif;
  font-size: 13.5px; font-weight: 700; letter-spacing: -.01em; line-height: 1.25;
  color: var(--h27-navy);
}
.h27 .m27-shots__sub {
  margin-top: 2px;
  font-family: 'Inter', sans-serif;
  font-size: 11px; font-weight: 600; line-height: 1.3;
  color: var(--h27-mute);
}
.h27 .m27-shots__tabs button[aria-selected="true"] .m27-shots__no  { background: var(--h27-coral); color: #fff; }
.h27 .m27-shots__tabs button[aria-selected="true"] .m27-shots__lbl { color: #fff; }
.h27 .m27-shots__tabs button[aria-selected="true"] .m27-shots__sub { color: rgba(255,255,255,.6); }

/* ── the panel ────────────────────────────────────────────────────────── */
.h27 .m27-shot {
  display: none;
  --shot-cap: min(72vh, 620px);
}
/* every panel is a split: the capture keeps the lion's share of the wall and
   its explanation stands beside it as a reading rail. The rail is capped at
   384px — a measure, not a column — so even the ultra-wide captures still get
   ~1100px of the wall, which is what keeps dense UI legible. */
.h27 .m27-shot.is-active {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 384px);
  gap: clamp(18px, 2.4vw, 40px);
  align-items: center;
  animation: h27-panel 560ms var(--h27-ease) both;   /* theme §15 keyframes */
}
/* a portrait or near-square capture flips the balance — the frame is only
   ~640px wide, so the text takes the width left over instead of a fixed rail */
.h27 .m27-shot--tall { --shot-cap: min(78vh, 720px); }
.h27 .m27-shot--tall.is-active {
  grid-template-columns: minmax(320px, 680px) minmax(0, 1fr);
  align-items: start;
}

/* ── the window ───────────────────────────────────────────────────────── */
.h27 .m27-shots .m27-app { border-radius: 13px; }
.h27 .m27-shots .m27-app__chrome { height: 40px; padding: 0 13px; }
.h27 .m27-shots .m27-app__crumb { font-size: 10.5px; }

.h27 .m27-shot__zoom {
  flex: none;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 11px; border-radius: 999px;
  background: rgba(255,255,255,.07);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.16);
  font-family: 'Inter', sans-serif; font-size: 10.5px; font-weight: 700;
  color: rgba(255,255,255,.86); text-decoration: none; white-space: nowrap;
  cursor: pointer;
  transition: background 280ms var(--h27-ease), box-shadow 280ms var(--h27-ease);
}
.h27 .m27-shot__zoom:hover {
  background: rgba(232,89,58,.20);
  box-shadow: inset 0 0 0 1px rgba(232,89,58,.46);
  color: #fff;
}
.h27 .m27-shot__zoom .ico { width: 13px; height: 13px; color: var(--h27-coral-lt); }

/* the bezel — dark on purpose, so five captures exported on five different
   whites stop announcing the seams between them */
.h27 .m27-shot__stage {
  display: grid; place-items: center;
  padding: clamp(9px, .9vw, 16px);
  background: #0B1630;
}
.h27 .m27-shot__pic {
  position: relative;
  width: 100%;
  max-width: calc(var(--shot-cap) * var(--shot-ar, 2));
  aspect-ratio: var(--shot-ar, 2);
  margin-inline: auto;
  border-radius: 5px;
  box-shadow: 0 0 0 1px rgba(255,255,255,.11), 0 20px 44px -22px rgba(0,0,0,.85);
}
.h27 .m27-shot__pic img {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 0;
  border-radius: 5px;
}

/* ── the pins ─────────────────────────────────────────────────────────── */
.h27 .m27-pin {
  position: absolute;
  left: var(--x); top: var(--y);
  transform: translate(-50%, -50%);
  z-index: 3;
  width: 25px; height: 25px; padding: 0; border: 0; border-radius: 50%;
  display: grid; place-items: center;
  cursor: pointer;
  background: var(--h27-coral); color: #fff;
  font-family: 'Inter', sans-serif; font-size: 11px; font-weight: 800;
  box-shadow: 0 0 0 3px rgba(232,89,58,.26), 0 8px 18px -8px rgba(0,0,0,.7);
  transition: box-shadow 300ms var(--h27-ease);
}
.h27 .m27-pin:hover,
.h27 .m27-pin:focus-visible,
.h27 .m27-pin.is-hot,
.h27 .m27-pin[aria-expanded="true"] { box-shadow: 0 0 0 5px rgba(232,89,58,.34), 0 8px 18px -8px rgba(0,0,0,.7); }
/* the halo that makes a pin findable on a busy capture */
.h27 .m27-pin::before {
  content: ''; position: absolute; inset: -4px; border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(232,89,58,.6);
  animation: m27-pinping 3s var(--h27-ease) infinite;
  animation-delay: var(--d, 0s);
  pointer-events: none;
}
@keyframes m27-pinping {
  0%       { transform: scale(.85); opacity: .9; }
  60%,100% { transform: scale(1.9); opacity: 0;  }
}

.h27 .m27-pin__t {
  position: absolute;
  left: 50%; bottom: calc(100% + 13px);
  transform: translate(-50%, 7px);
  width: max-content; max-width: 244px;
  padding: 9px 12px; border-radius: 8px;
  background: var(--h27-navy);
  box-shadow: 0 20px 40px -16px rgba(0,0,0,.7), inset 0 0 0 1px rgba(255,255,255,.14);
  font-family: 'Inter', sans-serif;
  font-size: 11.5px; font-weight: 600; line-height: 1.45; letter-spacing: 0;
  color: #fff; text-align: left; white-space: normal;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity 280ms var(--h27-ease), transform 280ms var(--h27-ease), visibility 280ms;
}
.h27 .m27-pin__t::after {
  content: ''; position: absolute; top: 100%; left: 50%;
  margin-left: -5px; border: 5px solid transparent;
  border-top-color: var(--h27-navy);
}
.h27 .m27-pin:hover .m27-pin__t,
.h27 .m27-pin:focus-visible .m27-pin__t,
.h27 .m27-pin.is-hot .m27-pin__t,
.h27 .m27-pin[aria-expanded="true"] .m27-pin__t { opacity: 1; visibility: visible; transform: translate(-50%, 0); }

/* a pin near an edge flips its tip inward rather than off the frame */
.h27 .m27-pin--l .m27-pin__t { left: auto; right: -4px; transform: translate(0, 7px); }
.h27 .m27-pin--l:hover .m27-pin__t,
.h27 .m27-pin--l:focus-visible .m27-pin__t,
.h27 .m27-pin--l.is-hot .m27-pin__t,
.h27 .m27-pin--l[aria-expanded="true"] .m27-pin__t { transform: translate(0, 0); }
.h27 .m27-pin--l .m27-pin__t::after { left: auto; right: 8px; margin-left: 0; }

.h27 .m27-pin--r .m27-pin__t { left: -4px; transform: translate(0, 7px); }
.h27 .m27-pin--r:hover .m27-pin__t,
.h27 .m27-pin--r:focus-visible .m27-pin__t,
.h27 .m27-pin--r.is-hot .m27-pin__t,
.h27 .m27-pin--r[aria-expanded="true"] .m27-pin__t { transform: translate(0, 0); }
.h27 .m27-pin--r .m27-pin__t::after { left: 13px; margin-left: 0; }

.h27 .m27-pin--d .m27-pin__t { bottom: auto; top: calc(100% + 13px); transform: translate(-50%, -7px); }
.h27 .m27-pin--d:hover .m27-pin__t,
.h27 .m27-pin--d:focus-visible .m27-pin__t,
.h27 .m27-pin--d.is-hot .m27-pin__t,
.h27 .m27-pin--d[aria-expanded="true"] .m27-pin__t { transform: translate(-50%, 0); }
.h27 .m27-pin--d .m27-pin__t::after { top: auto; bottom: 100%; border-top-color: transparent; border-bottom-color: var(--h27-navy); }
.h27 .m27-pin--d.m27-pin--l .m27-pin__t { transform: translate(0, -7px); }
.h27 .m27-pin--d.m27-pin--l:hover .m27-pin__t,
.h27 .m27-pin--d.m27-pin--l:focus-visible .m27-pin__t,
.h27 .m27-pin--d.m27-pin--l.is-hot .m27-pin__t,
.h27 .m27-pin--d.m27-pin--l[aria-expanded="true"] .m27-pin__t { transform: translate(0, 0); }

/* pins arrive one after another when a panel opens — display:none → grid
   restarts the animation on every tab switch, so each capture introduces its
   own annotations. The stagger reuses the ping delay (--d) at a third of its
   value, so the order matches the numbering without a second set of knobs. */
.h27 .m27-shot.is-active .m27-pin {
  animation: m27-pinin 460ms var(--h27-ease) both;
  animation-delay: calc(200ms + var(--d, 0s) / 3);
}
@keyframes m27-pinin {
  from { opacity: 0; transform: translate(-50%, -50%) scale(.3); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

/* ── the spotlight ────────────────────────────────────────────────────────
   Injected into .m27-shot__pic by m27-shots.js. While a note in the rail is
   hovered, everything on the capture except the region its pin marks dims
   behind this vignette; --sx/--sy are the pin's own authored coordinates.
   Registering the two lets the hole GLIDE from note to note instead of
   jumping — browsers without @property just jump, which is fine. */
@property --sx { syntax: '<percentage>'; inherits: false; initial-value: 50%; }
@property --sy { syntax: '<percentage>'; inherits: false; initial-value: 50%; }
.h27 .m27-shot__spot {
  position: absolute; inset: 0; z-index: 2;      /* under the pins (z 3) */
  border-radius: 5px;
  pointer-events: none;
  background: radial-gradient(circle clamp(130px, 15vw, 220px) at var(--sx, 50%) var(--sy, 50%),
              rgba(6,12,30,0) 55%, rgba(6,12,30,.52) 100%);
  opacity: 0;
  transition:
    opacity 340ms var(--h27-ease),
    --sx    420ms var(--h27-ease),
    --sy    420ms var(--h27-ease);
}
.h27 .m27-shot__spot.is-on { opacity: 1; }

/* ── the loupe + the tilt — fine pointers only ────────────────────────────
   The loupe is a circular window onto the full-resolution rendition (the same
   file the lightbox opens), moved under the cursor by m27-shots.js — the one
   way to read 2600px of clinical UI without leaving the page. The tilt is the
   window answering the pointer: ≤1.2° of perspective, driven through --rx/--ry
   so CSS keeps the easing. Neither exists for touch, and §12 stills the tilt
   for prefers-reduced-motion. */
@media (hover: hover) and (pointer: fine) {
  .h27 .m27-loupe {
    position: absolute; z-index: 5;
    width: 210px; height: 210px; border-radius: 50%;
    pointer-events: none;
    background-color: #0B1630;
    background-repeat: no-repeat;
    box-shadow:
      0 0 0 2.5px rgba(255,255,255,.94),
      0 0 0 4px rgba(13,27,62,.28),
      0 34px 64px -20px rgba(0,0,0,.8);
    opacity: 0;
    transform: translate(-50%, -50%) scale(.72);
    transition: opacity 240ms var(--h27-ease), transform 240ms var(--h27-ease);
  }
  .h27 .m27-loupe.is-on { opacity: 1; transform: translate(-50%, -50%) scale(1); }

  .h27 .m27-shots .m27-app {
    transform: perspective(1300px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
    transition: transform 520ms var(--h27-ease);
  }
  /* while the pointer is on the window the transition shortens, so the tilt
     tracks instead of trailing */
  .h27 .m27-shots .m27-app.is-tilting { transition-duration: 90ms; }
}

/* ── what the capture is, in words — the reading rail ─────────────────── */
.h27 .m27-shot__meta {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(14px, 1.7vw, 22px);
  align-content: center;
}

.h27 .m27-shot__kicker {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px; font-weight: 800; letter-spacing: .16em; text-transform: uppercase;
  color: var(--h27-coral);
}
.h27 .m27-shot__intro h3 {
  margin: 9px 0 0;
  font-family: 'Inter', sans-serif;
  font-size: clamp(19px, 1.7vw, 24px); font-weight: 700;
  line-height: 1.24; letter-spacing: -.018em;
  color: var(--h27-navy);
}
.h27 .m27-shot__intro p {
  margin: 11px 0 0; max-width: 56ch;
  font-size: clamp(14.5px, 1.1vw, 16px); line-height: 1.66;
  color: var(--h27-body);
}

/* the numbered notes — the pins' labels, spelled out. On a phone the pins are
   hidden and this list is the whole annotation, so it must stand alone. */
.h27 .m27-shot__notes {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 9px;
}
.h27 .m27-shot__notes li {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 11px;
  align-items: start;
  padding: 11px 13px; border-radius: 8px;
  background: var(--h27-paper);
  box-shadow: inset 0 0 0 1px var(--h27-hair);
  font-size: 13.5px; line-height: 1.55; color: var(--h27-body);
  transition:
    transform  300ms var(--h27-ease),
    background 300ms var(--h27-ease),
    box-shadow 300ms var(--h27-ease);
}
.h27 .m27-shot__notes li b {
  width: 21px; height: 21px; border-radius: 6px;
  display: grid; place-items: center;
  background: rgba(232,89,58,.12);
  box-shadow: inset 0 0 0 1px rgba(232,89,58,.3);
  font-family: 'Inter', sans-serif; font-size: 10.5px; font-weight: 800;
  color: var(--h27-coral-dk);
  transition: background 300ms var(--h27-ease), color 300ms var(--h27-ease);
}
/* the rail reacts: hovering a note (or its pin — m27-shots.js mirrors the two
   with .is-hot) lifts the row and fills its number, so word and pin read as
   one thing */
.h27 .m27-shot__notes li:hover,
.h27 .m27-shot__notes li.is-hot {
  transform: translateX(5px);
  background: #fff;
  box-shadow: inset 0 0 0 1px rgba(232,89,58,.42), 0 14px 30px -18px rgba(13,27,62,.45);
}
.h27 .m27-shot__notes li:hover b,
.h27 .m27-shot__notes li.is-hot b { background: var(--h27-coral); color: #fff; box-shadow: none; }

.h27 .m27-shots__foot {
  margin-top: clamp(16px, 1.8vw, 24px);
  padding-top: 15px;
  border-top: 1px solid var(--h27-hair);
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 18px;
  font-size: 12px; color: var(--h27-mute);
}
.h27 .m27-shots__foot .ico { width: 14px; height: 14px; color: var(--h27-sky); vertical-align: -2px; margin-right: 6px; }

/* ── the capabilities panel — how the act ends ────────────────────────────
   The wall's closing statement: the six feature lines that used to trail the
   act as a bare two-column list, floating in open space at neither the wall's
   width nor its voice. Boxed like the switcher cards and holding the same
   left/right edges as everything above it, it reads as the wall's own footer
   — "and all of this is in every chart" — instead of leftover copy. */
.h27 .m27-caps {
  margin-top: clamp(14px, 1.6vw, 20px);
  padding: clamp(18px, 2vw, 26px) clamp(18px, 2.2vw, 30px) clamp(20px, 2.2vw, 28px);
  border-radius: 12px;
  background: var(--h27-paper);
  box-shadow: inset 0 0 0 1px var(--h27-hair), 0 2px 4px rgba(13,27,62,.04);
}
.h27 .m27-caps__grid {
  list-style: none; margin: 15px 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 13px clamp(22px, 2.8vw, 44px);
}
.h27 .m27-caps__grid li {
  display: flex; gap: 10px; align-items: flex-start;
  font-size: clamp(13.5px, 1vw, 15px); line-height: 1.55; color: var(--h27-body);
}
.h27 .m27-caps__grid .ico { flex: none; width: 16px; height: 16px; margin-top: 3px; color: var(--h27-coral); }


/* ── the lightbox ─────────────────────────────────────────────────────────
   Built and appended to <body> by m27-shots.js, never authored in a template
   — it has to sit outside .m27-shots, whose translateX would otherwise become
   the containing block for its position:fixed. */
.m27-lb {
  position: fixed; inset: 0; z-index: 4000;
  display: flex; flex-direction: column;
  background: rgba(6,12,30,.94);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity 320ms cubic-bezier(.16, 1, .3, 1);
}
.m27-lb[hidden] { display: none; }
.m27-lb.is-open { opacity: 1; }

.m27-lb__bar {
  flex: none;
  display: flex; align-items: center; gap: 14px;
  padding: 14px clamp(14px, 2vw, 26px);
  border-bottom: 1px solid rgba(255,255,255,.12);
  font-family: 'Inter', sans-serif; color: #fff;
}
.m27-lb__t { font-size: 14px; font-weight: 700; letter-spacing: -.01em; }
.m27-lb__hint {
  font-size: 11.5px; font-weight: 600; color: rgba(255,255,255,.55);
  padding-left: 14px; border-left: 1px solid rgba(255,255,255,.16);
}
.m27-lb__x {
  margin-left: auto; flex: none;
  width: 34px; height: 34px; border: 0; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  background: rgba(255,255,255,.09);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.18);
  color: #fff; font-size: 17px; line-height: 1;
  transition: background 260ms cubic-bezier(.16, 1, .3, 1);
}
.m27-lb__x:hover { background: rgba(232,89,58,.5); }

.m27-lb__scroll {
  flex: 1 1 auto; min-height: 0;
  overflow: auto;
  padding: clamp(12px, 2vw, 28px);
  cursor: grab;
  scrollbar-color: rgba(255,255,255,.3) transparent;
  display: flex;                   /* + auto margins on the img = safe centring */
}
.m27-lb__scroll.is-dragging { cursor: grabbing; }
.m27-lb__scroll img {
  display: block;
  flex: none;                      /* never shrink — full pixels are the point */
  max-width: none;
  width: auto; height: auto;
  /* auto margins centre a small capture but resolve to 0 once it overflows,
     so the top-left corner always stays scrollable — the `safe center`
     behaviour, in the form every browser has always supported */
  margin: auto;
  border-radius: 5px;
  box-shadow: 0 30px 80px -30px rgba(0,0,0,.9);
  -webkit-user-select: none; user-select: none; -webkit-user-drag: none;
}


/* ══ §10b · THE STILL — one framed capture, no wall ══════════════════════
   The wall (§10) is the full instrument: tabs, pins, notes, loupe. Pages that
   only want to show ONE real region of the product — the schedule grid on
   /module/pms, the Services strip on /billing — need the frame and the
   honesty, not the machinery. A still is the §10 capture parts (.m27-app
   chrome, .m27-shot__stage bezel, .m27-shot__pic sizing) inside a <figure>,
   plus a caption. The zoom link in the chrome works exactly as on the wall —
   m27-shots.js binds every [data-m27-zoom] on the page — so a page that uses
   it must include that script; without it the link degrades to the file.

     <figure class="m27-still" style="--shot-ar:2.463" data-t27="rise">
       <div class="m27-app">
         <div class="m27-app__chrome">… <a class="m27-shot__zoom" …></div>
         <div class="m27-shot__stage"><div class="m27-shot__pic">
           <picture>…</picture>
         </div></div>
       </div>
       <figcaption class="m27-still__cap">Real screen — …</figcaption>
     </figure>

   --shot-cap must be declared here because .m27-shot__pic caps its width at
   `--shot-cap × --shot-ar` and only .m27-shot (absent on a still) provides
   the variable — without it the portrait captures run the full column. */
.h27 .m27-still {
  margin: 0;
  --shot-cap: min(62vh, 560px);
}
/* a still standing alone under an act head (not in a side column) holds the
   rail like the wall does */
.h27 .m27-still--wide { margin-top: clamp(22px, 2.6vw, 38px); }
/* portrait captures in a side column: don't tower over the prose beside them */
.h27 .m27-still--tall { --shot-cap: min(70vh, 640px); }
.h27 .m27-still--tall .m27-shot__pic { max-width: calc(var(--shot-cap) * var(--shot-ar)); }
.h27 .m27-still__cap {
  margin-top: 12px;
  font-size: 11.5px; line-height: 1.5;
  color: var(--h27-mute);
}
/* on a dark act the caption keeps its contrast */
.h27 .h27-act--ink .m27-still__cap { color: rgba(255,255,255,.55); }
/* two stills stacked in one column read as one exhibit, not two windows */
.h27 .m27-still + .m27-still { margin-top: 18px; }


/* ══ §11 · RESPONSIVE ════════════════════════════════════════════════════ */

/* the shot wall's own breakpoints, kept beside the block they belong to */
@media (max-width: 1080px) {
  /* the split folds: the capture takes the full wall again and the rail drops
     below it, spreading back into two columns (intro | notes) */
  .h27 .m27-shot.is-active,
  .h27 .m27-shot--tall.is-active { grid-template-columns: minmax(0, 1fr); }
  .h27 .m27-shot__meta { grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: clamp(18px, 2.6vw, 44px); }
}
@media (max-width: 900px) {
  /* a 25px pin on a 340px-wide capture covers the thing it points at, and a
     tooltip would be wider than the frame. The note list carries the same
     information in full, so the pins simply leave — and so does the footer
     line that tells the reader to hover them. */
  .h27 .m27-pin,
  .h27 .m27-shots__foot--pins { display: none; }
  .h27 .m27-shot__meta { grid-template-columns: minmax(0, 1fr); }
  .h27 .m27-shots__tabs button { flex: 0 0 auto; min-width: 168px; }
  .h27 .m27-caps__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .h27 .m27-shots__tabs button { min-width: 0; grid-template-columns: auto; padding: 9px 11px; }
  .h27 .m27-shots__lbl, .h27 .m27-shots__sub { display: none; }
  .h27 .m27-shots .m27-app__crumb { display: none; }
  .h27 .m27-shot__stage { padding: 6px; }
}

@media (max-width: 900px) {
  .h27 .m27-hero { grid-template-columns: minmax(0, 1fr); }
  /* the badges lose their negative offsets — there is no gutter left to hang
     in, and a badge half off a phone screen is just a clipped word */
  .h27 .m27-badge--a { top: -12px;    right: 0; }
  .h27 .m27-badge--b { bottom: -14px; left: 0; }
  /* single column: the stage stops hugging the right and takes the full width
     back, and the compact badge offsets from §9 go with it */
  .h27 .m27-hero .m27-stage { max-width: none; margin-left: 0; }
  /* §9 pins a hero row to one line so a long label cannot grow the window.
     That trade only makes sense against a FIXED 486px frame — here the stage
     is fluid and the rows have no ceiling to protect, so wrapping beats
     clipping and the copy comes back in full. */
  .h27 .m27-hero .m27-rows > div { white-space: normal; overflow: visible; flex-wrap: wrap; }
  .h27 .m27-hero .m27-badge--a { margin-bottom: -8px; right: 0; }
  .h27 .m27-hero .m27-badge--b { margin-top: -8px;    left: 0; }
}
@media (max-width: 560px) {
  .h27 .m27-kpis  { grid-template-columns: minmax(0, 1fr); }
  .h27 .m27-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .h27 .m27-badge { font-size: 11px; padding: 8px 11px; }
}


/* ══ §12 · REDUCED MOTION ════════════════════════════════════════════════
   Every loop in this file is ambient decoration on a picture of software.
   Asked for less motion, all of it stops — and the bars, whose entrance is an
   animation rather than a transition, are pinned to their finished state so
   the plot does not simply vanish. */

@media (prefers-reduced-motion: reduce) {
  .h27 .m27-stage__aura,
  .h27 .m27-sk::after,
  .h27 .m27-wave i,
  .h27 .m27-app__live i,
  .h27 .m27-pin::before,
  .h27 .m27-plot i { animation: none !important; }
  .h27 .m27-plot i { opacity: 1; transform: none; }
  /* the halo stops pinging but must still mark the pin */
  .h27 .m27-pin::before { opacity: 1; transform: none; }
  /* the panel swap is a state change, not an entrance — it may not fade in */
  .h27 .m27-shot.is-active { animation: none !important; }
  /* the pins may not parade in — they are simply there, fully visible */
  .h27 .m27-shot.is-active .m27-pin { animation: none !important; }
  /* the window holds still (m27-shots.js also never binds the tilt) and the
     spotlight's hole stops gliding — it just appears where it is needed */
  .h27 .m27-shots .m27-app { transform: none !important; transition: none !important; }
  .h27 .m27-shot__spot { transition: none !important; }
  .h27 .m27-loupe { transition: none !important; }
  .m27-lb { transition: none !important; }
}
