/* ============================================================================
 * sections.css — page section layouts for the marketing narrative:
 * hero (parallax), logo strip, featured four, capabilities, live widgets,
 * feature illustrations, productivity loop, dashboards, Lumina climax,
 * trust, plays heroes, and CTA bands. Depends on tokens/base/components.
 * ==========================================================================*/

/* ---------------------------------------------------------------------------
 * Section tones
 * ------------------------------------------------------------------------- */
/* Grid/flex items default to min-width:auto, which lets an intrinsically wide
   child (e.g. an SVG with a 1200px viewBox) blow past the viewport. Reset it. */
.hero-grid > *, .split > *, .lumina-climax-grid > *, .loop > *,
.featured-grid > *, .trust-grid > *, .illus-grid > *, .capgrid > *,
.mascot-states > *, .module-row > *, .btn-row > *,
/* the same guard was missing from the grids declared in layout/pages/replica */
.plan-grid > *, .policy-layout > *, .footer-grid > *, .menu-grid > *,
.menu-cols > *, .rep-tilegrid > *, .rep-flow > *, .rep-roadmap > *,
/* .doc-layout copied .policy-layout's grid shape from pages.css but not its
   guard from here. It was not overflowing only by luck: .storyframe__frame is
   position:absolute, so the frame contributes zero min-content width. */
.doc-layout > *, .doc-nav > *,
/* Newsletters. .cf__track's children are position:absolute in 3D mode and so
   contribute no min-content width — but the SAME markup becomes a real flex row
   in flat mode, where a 200px cover in a 320px viewport is exactly the overflow
   this guards. .pdfframe__bar copies .storyframe__bar, whose items are .btn
   (white-space:nowrap, components.css:22) and it carries three of them. */
.cf__track > *, .news-detail > *, .pdfframe__bar > *,
.news-card__acts > * {
  min-width: 0;
}
.hero-visual,
.split-media,
.split-copy,
.dash-wrap,
.browser {
  min-width: 0;
  max-width: 100%;
}

.section.alt {
  background: var(--surface-2);
}
.section.ink {
  background: var(--grad-deep);
  color: rgba(255, 255, 255, 0.82);
}
.section.ink h1,
.section.ink h2,
.section.ink h3 {
  color: #fff;
}
.section.ink .lead {
  color: rgba(255, 255, 255, 0.78);
}

/* faint top spectrum hairline for a section (edge use of band-of-light) */
.band-top {
  position: relative;
}
.band-top::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: var(--band);
  opacity: 0.9;
}

/* ---------------------------------------------------------------------------
 * HERO
 * ------------------------------------------------------------------------- */
.hero {
  position: relative;
  overflow: hidden;
  padding-top: clamp(48px, 7vw, 96px);
  padding-bottom: clamp(56px, 8vw, 120px);
  background:
    radial-gradient(
      1200px 620px at 8% -20%,
      rgba(24, 104, 219, 0.1),
      transparent 60%
    ),
    radial-gradient(
      900px 560px at 108% 4%,
      rgba(73, 178, 182, 0.09),
      transparent 60%
    ),
    var(--surface);
}
.hero .constellation {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
  opacity: 0.7;
}
.hero-grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(40px, 5vw, 72px);
  align-items: center;
}
.hero-copy {
  max-width: 620px;
}
.hero-copy .eyebrow-pill {
  margin-bottom: var(--s5);
}
.hero-copy .honeycomb {
  margin-bottom: var(--s4);
}
.hero h1 {
  font-size: var(--fs-display);
  line-height: 1;
  letter-spacing: -0.03em;
  margin-bottom: var(--s5);
}
.hero h1 .hl {
  color: var(--blue);
}
.hero .lead {
  font-size: var(--fs-lead);
  color: var(--ink-soft);
  max-width: 46ch;
  margin-bottom: var(--s6);
}
.hero .btn-row {
  margin-bottom: var(--s3);
}
.hero .trial {
  font-size: var(--fs-xs);
  color: var(--ink-mute);
  font-weight: 600;
}

/* Differentiator sub-line (the "why us", grounded in positioning). */
.hero-diff {
  margin-top: calc(-1 * var(--s2));
  margin-bottom: var(--s6);
  font-size: var(--fs-sm);
  color: var(--ink-mute);
  font-weight: 600;
  max-width: 48ch;
  line-height: 1.5;
}
/* Non-technical outcome trio (reuses .checks; tighter in the hero). */
.hero-outcomes {
  margin-top: var(--s5);
  gap: 10px;
}
.hero-outcomes li {
  font-size: var(--fs-sm);
  font-weight: 600;
}
/* Audience signpost, now interactive pills that swap the hero preview
   (role=tablist wired by widgets.js; [data-autocycle-lock] stops on a pick). */
.hero-pills-label {
  margin-top: var(--s5);
  margin-bottom: var(--s3);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.hero-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: var(--s5);
}
.hero-pill {
  font-family: inherit;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--ink-soft);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  padding: 8px 14px;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition:
    border-color 0.18s var(--ease),
    color 0.18s var(--ease),
    background 0.18s var(--ease),
    box-shadow 0.18s var(--ease);
}
.hero-pill:hover {
  border-color: var(--blue);
  color: var(--ink);
}
.hero-pill[aria-selected="true"] {
  background: var(--blue);
  border-color: var(--blue);
  color: #fff;
  box-shadow: 0 4px 14px rgba(24, 104, 219, 0.28);
}
.hero-pill:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}
@media (pointer: coarse) {
  .hero-pill {
    min-height: 44px;
  } /* was 42px */
  .widget .wtab {
    min-height: 44px;
  } /* was 37px */
}

/* hero product visual + floating chips (parallax layers) */
.hero-visual {
  position: relative;
}
.hero-visual .browser {
  position: relative;
  z-index: 2;
}
.float-chip {
  position: absolute;
  z-index: 3;
  /* Decorative overlay (an orb plus two lines of text, no controls) sitting at
     z-index 3 over the hero replica. It covered the replica's "For product
     teams" link at 1024px and up, so clicks on that CTA hit the chip instead.
     Let them through — there is nothing here to click. */
  pointer-events: none;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--shadow-bento);
  padding: 12px 14px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.float-chip .fc-ic {
  width: 34px;
  height: 34px;
  border-radius: 10px;
  display: grid;
  place-items: center;
  flex: none;
}
.float-chip .fc-ic svg {
  width: 18px;
  height: 18px;
  stroke: #fff;
  fill: none;
}
.float-chip b {
  font-family: var(--font-display);
  font-size: 1.0625rem;
  font-weight: 700;
  display: block;
  line-height: 1;
}
.float-chip small {
  font-size: 12px;
  color: var(--ink-mute);
  font-weight: 600;
}
.float-chip.chip-a {
  top: -18px;
  right: 8px;
}
.float-chip.chip-b {
  bottom: -18px;
  left: 8px;
}
.float-chip .lumina-orb {
  width: 30px;
  height: 30px;
}
@media (min-width: 640px) {
  .float-chip.chip-a {
    right: -12px;
  }
  .float-chip.chip-b {
    left: -16px;
  }
}
@media (max-width: 440px) {
  .float-chip {
    padding: 9px 11px;
  }
  .float-chip small {
    display: none;
  }
}

.hero-logos {
  position: relative;
  z-index: 1;
  margin-top: clamp(40px, 5vw, 64px);
}
.hero-logos .trusted-label {
  margin-bottom: var(--s4);
}

@media (min-width: 1024px) {
  .hero-grid {
    grid-template-columns: 1.02fr 1.1fr;
  }
}

/* ---------------------------------------------------------------------------
 * FEATURED FOUR
 * ------------------------------------------------------------------------- */
.featured-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: var(--s5);
}

/* ---------------------------------------------------------------------------
 * LIVE WIDGET (tabbed, skeleton -> content)
 * ------------------------------------------------------------------------- */
.widget {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-bento);
  overflow: hidden;
}
.widget .wtabs {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
}
.widget .wtab {
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--ink-mute);
  padding: 8px 14px;
  border-radius: 8px;
  cursor: pointer;
  border: none;
  background: none;
}
.widget .wtab[aria-selected="true"] {
  background: #fff;
  color: var(--blue-deep);
  box-shadow: var(--shadow-sm);
}
.widget .wbody {
  position: relative;
  padding: 18px;
  min-height: 280px;
}
/* Stack panes in one grid cell so the widget height stays at the tallest pane
   — switching (or auto-cycling) tabs no longer resizes the section. */
/* minmax(0,1fr) + min-width:0 so the single track cannot be forced wider than
   the widget by a pane's intrinsic content. Without them the widest pane (the
   6-column product table) sized the track to 996px at EVERY viewport and
   .widget's overflow:hidden silently cut up to 730px of it. */
.widget .wpanes {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}
.widget .wpane {
  grid-area: 1 / 1;
  visibility: hidden;
  min-width: 0;
}
.widget .wpane.is-active {
  visibility: visible;
}
.widget .wskel {
  position: absolute;
  inset: 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.widget.is-loaded .wskel {
  display: none;
}
/* Only hide the real content behind the skeleton when JS is there to swap it in
   (html.js is set before first paint in the page <head>). With JS off the
   skeleton would otherwise shimmer forever over hidden content. */
html.js .widget:not(.is-loaded) .wpanes {
  visibility: hidden;
}
html:not(.js) .widget .wskel {
  display: none;
}

/* ---------------------------------------------------------------------------
 * PRODUCTIVITY LOOP
 * ------------------------------------------------------------------------- */
.loop {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s5);
}
.loop-node {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 26px;
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 10px;
  position: relative;
}
.loop-node .ln-ic {
  width: 48px;
  height: 48px;
  border-radius: 14px;
  display: grid;
  place-items: center;
}
.loop-node .ln-ic svg {
  width: 24px;
  height: 24px;
  stroke: #fff;
  fill: none;
}
.loop-node h3 {
  font-size: 1.25rem;
}
.loop-node p {
  font-size: var(--fs-sm);
  color: var(--ink-mute);
  line-height: 1.55;
}
.loop-node.n1 .ln-ic {
  background: var(--grad-blue);
}
.loop-node.n2 .ln-ic {
  background: linear-gradient(150deg, #922791, #6f1c6e);
}
.loop-node.n3 .ln-ic {
  background: linear-gradient(150deg, #8ac036, #5f8d1d);
}
.loop-outcome {
  margin-top: var(--s6);
}
@media (min-width: 860px) {
  .loop {
    grid-template-columns: repeat(3, 1fr);
  }
}
/* Card the flow token is currently on lights up in sync (flow.js). */
.loop-node {
  transition:
    border-color 0.3s var(--ease),
    box-shadow 0.3s var(--ease);
}
.loop-node.is-active {
  border-color: var(--blue);
  box-shadow: 0 10px 26px rgba(24, 104, 219, 0.14);
}
.loop-node.n2.is-active {
  border-color: #922791;
  box-shadow: 0 10px 26px rgba(146, 39, 145, 0.16);
}

/* ---------------------------------------------------------------------------
 * INTERACTIVE FLOW — a work-item token travels the four steps (flow.js).
 * Decorative/animated (aria-hidden); the .loop cards below carry the detail.
 * ------------------------------------------------------------------------- */
.flow {
  position: relative;
  margin-top: var(--s7);
}
/* Persona toggle above the flow (reuses .hero-pill; wired by flow.js). */
.flow-personas {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  margin-bottom: var(--s6);
}
.flow-cta {
  text-align: center;
  margin-top: var(--s5);
  font-size: var(--fs-sm);
  font-weight: 700;
}
.flow-cta a {
  color: var(--blue-deep);
  text-decoration: none;
}
.flow-cta a:hover {
  text-decoration: underline;
}
.flow-cta a[hidden] {
  display: none;
}
.flow-track {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: stretch;
  gap: 0;
}
.flow-node {
  flex: 1 1 0;
  min-width: 0;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 16px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: #fff;
  box-shadow: var(--shadow-sm);
  transition:
    border-color 0.3s var(--ease),
    box-shadow 0.3s var(--ease),
    transform 0.3s var(--ease);
}
.flow-node__ic {
  width: 40px;
  height: 40px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  background: var(--grad-blue);
}
.flow-node__ic svg {
  width: 20px;
  height: 20px;
  stroke: #fff;
  fill: none;
}
.flow-node--ai .flow-node__ic {
  background: linear-gradient(150deg, #922791, #6f1c6e);
}
.flow-node__label {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-sm);
  color: var(--ink);
  line-height: 1.15;
}
.flow-node__sub {
  font-size: var(--fs-xs);
  color: var(--ink-mute);
  font-weight: 600;
  line-height: 1.4;
}
.flow-node.is-active {
  border-color: var(--blue);
  box-shadow: 0 8px 22px rgba(24, 104, 219, 0.18);
  transform: translateY(-3px);
}
.flow-node--ai.is-active {
  border-color: #922791;
  box-shadow: 0 8px 22px rgba(146, 39, 145, 0.2);
}
.flow-conn {
  flex: 0 0 26px;
  align-self: center;
  height: 2px;
  background: var(--line);
  position: relative;
}
.flow-conn::after {
  content: "";
  position: absolute;
  right: -1px;
  top: -3px;
  border: 4px solid transparent;
  border-left-color: var(--line);
}
.flow-token {
  position: absolute;
  top: 0;
  left: 0;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: radial-gradient(
    circle at 32% 30%,
    #fff,
    var(--blue) 55%,
    #922791
  );
  box-shadow:
    0 0 0 4px rgba(24, 104, 219, 0.14),
    0 2px 10px rgba(24, 104, 219, 0.5);
  transform: translate(-100px, -100px);
  transition: transform 0.7s var(--ease);
  pointer-events: none;
  opacity: 0;
  z-index: 2;
}
.flow.is-playing .flow-token {
  opacity: 1;
}
@media (max-width: 620px) {
  .flow-track {
    flex-direction: column;
    align-items: stretch;
  }
  .flow-node {
    align-items: flex-start;
    text-align: left;
  }
  .flow-conn {
    flex: 0 0 18px;
    width: 2px;
    height: 18px;
    align-self: center;
  }
  .flow-conn::after {
    right: -3px;
    top: auto;
    bottom: -1px;
    border: 4px solid transparent;
    border-top-color: var(--line);
  }
}
@media (prefers-reduced-motion: reduce) {
  .flow-token {
    display: none;
  }
  .flow-node.is-active {
    transform: none;
  }
}

/* ---------------------------------------------------------------------------
 * DASHBOARD wrapper (holds the inline SVG bento replica)
 * ------------------------------------------------------------------------- */
.dash-wrap {
  position: relative;
}
.dash-wrap .browser__body {
  padding: 0;
}
.sample-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 700;
  color: var(--ink-mute);
  letter-spacing: 0.03em;
}
.sample-tag::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ink-faint);
}

/* ---------------------------------------------------------------------------
 * LUMINA climax (dark)
 * ------------------------------------------------------------------------- */
.lumina-section {
  position: relative;
  overflow: hidden;
}
.lumina-section .constellation {
  opacity: 0.5;
}
.lumina-climax-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(32px, 5vw, 64px);
  align-items: center;
  position: relative;
  z-index: 1;
}
.lumina-climax-grid .checks li {
  color: rgba(255, 255, 255, 0.9);
}
@media (min-width: 1024px) {
  .lumina-climax-grid {
    grid-template-columns: 1fr 1fr;
  }
}

/* checklist */
.checks {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
/* Text flows as normal inline content (not a flex row), so inline spans such
   as the branded .lumina-word stay in the sentence; the tick is absolute. */
.checks li {
  position: relative;
  padding-left: 36px;
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--ink-soft);
  line-height: 1.45;
}
.checks li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 1px;
  width: 24px;
  height: 24px;
  border-radius: 7px;
  background: var(--green-tint)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%235f8d1d' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E")
    center / 14px no-repeat;
}
.section.ink .checks li::before {
  background-color: rgba(138, 192, 54, 0.22);
}

/* mascot states row */
.mascot-states {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 180px), 1fr));
  gap: var(--s4);
}
.mstate {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 22px 18px;
  box-shadow: var(--shadow-sm);
  text-align: center;
}
.mstate b {
  font-size: 0.9375rem;
}
.mstate small {
  font-size: var(--fs-xs);
  color: var(--ink-mute);
  font-weight: 500;
  line-height: 1.4;
}

/* ---------------------------------------------------------------------------
 * TRUST
 * ------------------------------------------------------------------------- */
.trust-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: var(--s4);
}

/* ---------------------------------------------------------------------------
 * FEATURE ILLUSTRATIONS
 * ------------------------------------------------------------------------- */
.illus-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: var(--s6);
}
.illus-card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
}
.illus-card .illus-art {
  aspect-ratio: 4 / 3;
  background: var(--surface-2);
  display: grid;
  place-items: center;
  overflow: hidden;
}
.illus-card .illus-art svg,
.illus-card .illus-art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.illus-card .illus-body {
  padding: 22px 24px 26px;
}
.illus-card h3 {
  font-size: 1.25rem;
  margin-bottom: 8px;
}
.illus-card p {
  font-size: var(--fs-sm);
  color: var(--ink-mute);
  line-height: 1.55;
}

/* ---------------------------------------------------------------------------
 * PLAYS hero (For QA / product teams / Jira)
 * ------------------------------------------------------------------------- */
.play-hero {
  position: relative;
  overflow: hidden;
  padding-top: clamp(40px, 6vw, 80px);
  padding-bottom: clamp(48px, 6vw, 88px);
}
.play-hero .eyebrow {
  margin-bottom: var(--s4);
}
.play-hero h1 {
  font-size: var(--fs-h1);
  margin-bottom: var(--s5);
  max-width: 18ch;
}
.play-hero .lead {
  margin-bottom: var(--s6);
}

/* Split hero: copy left, art right. Works on .hero and .play-hero alike.
   Most generated hero art is composed with its left half deliberately clear,
   so .hero-art crops to the right of the source by default; --op nudges the
   window where a subject does not sit hard against the right edge, and pages
   whose art spans the full frame set --ar: 16 / 9 to keep it uncropped. */
.hero-split .container {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(28px, 4vw, 56px);
  align-items: center;
}
.hero-split .section-head {
  margin-bottom: 0;
}
/* .hero sets a display-size h1 for the full-width home hero; in a split
   column that runs to six lines, so step it back to the standard page h1. */
.hero.hero-split h1 {
  font-size: var(--fs-h1);
  line-height: 1.08;
}
.hero-split .hero-art {
  width: 100%;
  max-width: min(var(--art-max, 520px), 480px);
  justify-self: center;
}
.hero-split .hero-art img {
  object-position: var(--op, 100% 50%);
}
@media (min-width: 960px) {
  .hero-split .container {
    grid-template-columns: 1.05fr 0.95fr;
  }
  .hero-split .hero-art {
    justify-self: end;
    max-width: var(--art-max, 520px);
  }
}

/* ---------------------------------------------------------------------------
 * CTA band (a CTA in every section; big closing band)
 * ------------------------------------------------------------------------- */
.cta-band {
  position: relative;
  overflow: hidden;
  text-align: center;
}
.cta-band .container {
  position: relative;
  z-index: 1;
}
.cta-band h2 {
  font-size: var(--fs-h1);
  margin-bottom: var(--s5);
  max-width: 20ch;
  margin-inline: auto;
}
.cta-band .lead {
  margin-inline: auto;
  margin-bottom: var(--s7);
}
.cta-band .btn-row {
  justify-content: center;
}

.finale {
  background: var(--grad-deep);
  color: #fff;
}
.finale h2 {
  color: #fff;
}
.finale .band-art {
  height: 34px;
  max-width: 156px;
  margin: 0 auto var(--s8);
  background: var(--honeycomb) center / contain no-repeat;
}
.finale h2 .hl {
  background: linear-gradient(90deg, #6db0ff, #4fd0d4);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* inline CTA row that closes a mid-page section */
.section-cta {
  margin-top: var(--s8);
}
.section-cta.center {
  display: flex;
  justify-content: center;
}

/* ---------------------------------------------------------------------------
 * Generic two-column split (copy + media)
 * ------------------------------------------------------------------------- */
.split {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(32px, 5vw, 64px);
  align-items: center;
}
.split .split-media {
  position: relative;
}
@media (min-width: 960px) {
  .split {
    grid-template-columns: 1fr 1fr;
  }
  .split.media-left .split-copy {
    order: 2;
  }
  .split.wide-media {
    grid-template-columns: 0.9fr 1.1fr;
  }
}

/* ---------------------------------------------------------------------------
 * ARTICLE (resources long-form / guides)
 * ------------------------------------------------------------------------- */
.article {
  max-width: 720px;
  margin-inline: auto;
}
.article .article-meta {
  font-size: var(--fs-xs);
  color: var(--ink-mute);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-bottom: var(--s4);
}
.article .lead {
  font-size: var(--fs-lead);
  color: var(--ink-soft);
  margin-bottom: var(--s7);
}
.article h2 {
  font-size: var(--fs-h3);
  margin-top: var(--s9);
  margin-bottom: var(--s4);
}
.article p {
  margin-bottom: var(--s5);
  line-height: var(--lh-body);
  color: var(--ink-soft);
}
.article ul {
  margin: 0 0 var(--s5) var(--s5);
  display: flex;
  flex-direction: column;
  gap: 8px;
  color: var(--ink-soft);
}
.article li {
  line-height: var(--lh-body);
}
/* :not(.btn) — this rule is (0,1,1) and so out-specifies .btn-primary (0,1,0),
   which stripped the white text off the CTAs at the end of both article pages
   and left them blue on a blue gradient at 1.46:1. */
.article a:not(.btn) {
  color: var(--blue-deep);
}
.article .article-cta {
  margin-top: var(--s9);
  padding-top: var(--s7);
  border-top: 1px solid var(--line);
}

/* ---------------------------------------------------------------------------
 * INTEGRATIONS — "works with your tools" pill row (+ gated official-logo slot)
 * ------------------------------------------------------------------------- */
.int-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
  margin-top: var(--s7);
}
.int-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: #fff;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--ink-soft);
  box-shadow: var(--shadow-sm);
}
.int-pill.is-live {
  border-color: var(--green);
  color: var(--ink);
}
.int-live {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--green-deep);
  background: var(--green-tint);
  padding: 2px 7px;
  border-radius: var(--r-pill);
}
.int-note {
  text-align: center;
  margin-top: var(--s4);
  font-size: var(--fs-xs);
  color: var(--ink-mute);
  font-weight: 600;
}
/* Gated slot for the official marks (hidden in public until `integrations` clears). */
.int-logos {
  margin-top: var(--s6);
  border: 2px dashed var(--line);
  border-radius: var(--r);
  padding: var(--s7);
  text-align: center;
  color: var(--ink-mute);
}
.int-logos b {
  display: block;
  font-size: var(--fs-sm);
  color: var(--ink-soft);
}
.int-logos small {
  font-size: var(--fs-xs);
}

/* Integration pill with a hotlinked brand mark (<img>). Square glyphs render at
   18x18; a wordmark (e.g. Mendix) keeps its aspect via .int-logo--wide. If a
   remote mark fails, the inline onerror removes the <img> and the text stands. */
.int-pill--logo {
  padding-left: 10px;
}
.int-pill img.int-logo {
  height: 18px;
  width: auto;
  max-width: 22px;
  flex: none;
  object-fit: contain;
  display: block;
}
.int-pill img.int-logo--wide {
  max-width: 78px;
}

/* ---------------------------------------------------------------------------
 * FAQ (native <details>/<summary> — accessible, no JS)
 * ------------------------------------------------------------------------- */
.faq {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  margin-top: var(--s8);
}
.faq-item {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  box-shadow: var(--shadow-sm);
}
/* Block, not flex: luminaword.js splits the "Lumina" mention into its own
   <span>, and under `display:flex; justify-content:space-between` each fragment
   became a separate flex item, tearing the question into pieces spread across
   the row. Block flow keeps the text as text; the chevron is positioned instead. */
.faq-item summary {
  cursor: pointer;
  list-style: none;
  padding: var(--s5) var(--s6);
  padding-right: calc(var(--s6) + 22px);
  position: relative;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-body);
  color: var(--ink);
}
.faq-item summary::-webkit-details-marker {
  display: none;
}
.faq-item summary:hover {
  color: var(--blue-deep);
}
.faq-item summary::after {
  content: "";
  width: 9px;
  height: 9px;
  position: absolute;
  right: var(--s6);
  top: 50%;
  border-right: 2px solid var(--ink-mute);
  border-bottom: 2px solid var(--ink-mute);
  transform: translateY(-70%) rotate(45deg);
  transition: transform var(--dur) var(--ease);
}
.faq-item[open] summary::after {
  transform: translateY(-30%) rotate(-135deg);
}
.faq-a {
  padding: 0 var(--s6) var(--s5);
}
.faq-a p {
  max-width: 72ch;
  color: var(--ink-soft);
  line-height: var(--lh-body);
}
.faq-a a:not(.btn) {
  color: var(--blue-deep);
}
@media (prefers-reduced-motion: reduce) {
  .faq-item summary::after {
    transition: none;
  }
}

/* ---------------------------------------------------------------------------
 * COVERFLOW — the newsletter rail (assets/js/newsletters.js)
 *
 * ONE MARKUP, TWO PRESENTATIONS. A 3D flow where there is room and no
 * reduced-motion preference; a plain scroll-snap rail otherwise. --cf-flat is
 * the single declaration of which, and newsletters.js reads it back with
 * getComputedStyle rather than restating the breakpoints — the rule
 * storyframe.js:113-118 sets: two sources of truth for one question drift the
 * moment either is edited.
 *
 * Geometry lives here as local custom properties on .cf, not in tokens.css:
 * that file is the brand contract and says "do not redefine ad hoc". A
 * component's own measurements belong on the component, which is where
 * .storyframe keeps --frame-room (components.css:1409).
 *
 * Covers are A4 PORTRAIT (210/297), not 3:4. The cover image is a facsimile of
 * page one of the issue, so any other ratio crops or letterboxes it.
 * ------------------------------------------------------------------------- */
.cf {
  --cf-w: clamp(160px, 22vw, 290px); /* cover width                */
  --cf-h: calc(var(--cf-w) * 297 / 210); /* A4 portrait                */
  /* Room under the cover for the caption: chip, then a two-line title, then the
     date. It is a variable rather than a literal because .cf__viewport's height
     and .cf__cell's centring offset BOTH derive from it, and they were silently
     inconsistent once the topic chip was added — the viewport reserved 64px,
     the caption grew to ~86px, and overflow:clip cut the title and date off
     entirely. One number, two consumers. */
  --cf-cap: 88px;
  --cf-fan: 1; /* fan multiplier, narrowed below */
  --cf-drag: 0px; /* live drag nudge, written by JS */
  --cf-flat: 0; /* the mode flag JS reads back */
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: center;
}
.cf__viewport {
  position: relative;
  /* Room for the scaled centre card (1.06) plus its shadow and the caption. */
  height: calc(var(--cf-h) * 1.06 + var(--cf-cap));
  perspective: 1400px;
  perspective-origin: 50% 44%;
  /* pan-y: a vertical scroll is never captured by the drag engine, and a
     horizontal one is always ours. The one line that makes the gesture safe. */
  touch-action: pan-y;
  /* clip, not hidden: hidden would make this a scroll container and flatten the
     3D depth into a scrollport — the distinction base.css:27-29 records. */
  overflow: clip;
}
.cf__track {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  transform-style: preserve-3d;
  transform: translate3d(var(--cf-drag), 0, 0);
}
/* The cell positions; the card transforms. Splitting them means JS writes a
   pure numeric transform and never has to compose a -50% centring offset. */
.cf__cell {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--cf-w);
  margin-left: calc(var(--cf-w) / -2);
  /* Centres the whole card — cover plus caption — rather than just the cover,
     so growing the caption does not drift the cover off centre. */
  margin-top: calc(var(--cf-h) / -2 - var(--cf-cap) / 2);
}
.cf__card {
  display: block;
  width: 100%;
  transform-origin: 50% 50%;
  transform-style: preserve-3d;
  backface-visibility: hidden;
  transition:
    transform var(--dur-slow) var(--ease),
    opacity var(--dur) var(--ease);
  /* No will-change. base.css:155-156 records why: it was never cleared, so
     every revealed element kept a compositor layer for the life of the page.
     With a long archive that is one layer per cover. The drag sets it on
     .cf__track — ONE element — and clears it on pointerup. */
}
.cf__art {
  display: block;
  height: var(--cf-h);
  border-radius: var(--r);
  overflow: hidden;
  background: var(--surface-3);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-bento);
}
.cf__art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.cf__cap {
  display: block;
  margin-top: var(--s3);
  text-align: center;
  /* Only the centre caption is legible at this size; the neighbours are already
     at 0.74 opacity and rotated 38deg, so hide theirs rather than ship a row of
     unreadable smudges. opacity, NOT visibility or display: the caption must
     stay in the accessibility tree so every cover keeps an accessible name. */
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.cf__card.on .cf__cap {
  opacity: 1;
}
.cf__cap-title {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-sm);
  color: var(--ink);
  line-height: var(--lh-snug);
}
.cf__cap-date {
  display: block;
  font-size: var(--fs-xs);
  color: var(--ink-mute);
  margin-top: 2px;
}

/* Selected reads as selected without relying on scale alone. */
.cf__card.on .cf__art {
  border-color: var(--blue);
  box-shadow: var(--shadow-lg);
}
/* base.css:70-74 is the site's contract — the ring is never removed, only made
   legible against a rotated neighbour. */
.cf__card:focus-visible .cf__art {
  box-shadow: var(--shadow-lg);
}

/* Outside the window. This is the whole performance story: no transform is
   written, nothing is painted or hit-tested, and Tab cannot reach it (the
   roving tabindex has already set -1). contain-intrinsic-size keeps the skipped
   box the right size so nothing shifts when it comes back. */
.cf__card--far {
  visibility: hidden;
  content-visibility: auto;
  contain-intrinsic-size: var(--cf-w) calc(var(--cf-h) + var(--cf-cap));
}
/* .cf__card--far is applied by newsletters.js and by nothing else, which is
   what keeps JS-off correct: with no script there is no --far, so every cover
   is visible, and html:not(.js) in pages.css has already put the rail into
   flat mode where that is exactly right. Deliberately NOT pre-hidden under
   html.js: nothing carries --far until the first paint, so a pre-hide rule
   would have to be undone by a second rule that un-hides everything. In 3D
   mode every cell is absolutely positioned at the same point, so an unpainted
   rail reads as one centred cover — near enough to the settled state that
   there is nothing worth flashing. */

.cf__arrow {
  position: absolute;
  top: calc(var(--cf-h) * 0.53);
  z-index: 200; /* above every card (max 100) */
  width: 44px;
  height: 44px; /* already at the touch floor */
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: #fff;
  color: var(--ink);
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
  cursor: pointer;
}
.cf__arrow:hover {
  background: var(--surface-2);
}
.cf__arrow svg {
  stroke: currentColor;
  fill: none;
}
.cf__arrow--prev {
  left: 0;
}
.cf__arrow--next {
  right: 0;
}

/* Narrow the fan before abandoning it: between 640 and 900px there is room for
   one neighbour a side but not three. Content-driven, and 900 is a value
   tokens.css:15 already lists. */
@media (max-width: 899.98px) {
  .cf {
    --cf-fan: 0.72;
  }
}

/* ---------------------------------------------------------------------------
 * FLAT MODE — the same markup as a plain scroll-snap rail.
 *
 * Two triggers, an OR:
 *   reduced motion — a 3D stack that rotates and slides on every arrow press is
 *     exactly what the preference asks not to happen, and there is no "less" of
 *     it that is still a cover flow. So it is absent, not slower.
 *   639.98px — the value layout.css and .storyframe__veil already use for this
 *     edge. At 390px a 150px cover leaves 120px each side, which is one
 *     neighbour clipped in half: that reads as broken, not as depth.
 * Deliberately NOT (pointer: coarse): the drag engine works under a finger, and
 * an iPad at 1024px has room for the full fan.
 * ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce), (max-width: 639.98px) {
  .cf {
    --cf-flat: 1;
  }
  .cf__viewport {
    height: auto;
    perspective: none;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: 50%; /* centres the snapped cover        */
    overscroll-behavior-x: contain; /* no swipe-past-the-end navigation */
    -webkit-overflow-scrolling: touch;
    padding-block: var(--s3);
  }
  .cf__track {
    position: static;
    inset: auto;
    display: flex;
    gap: var(--s5);
    transform: none; /* the drag var is inert here */
    transform-style: flat;
    padding-inline: 50%; /* first and last can reach centre */
  }
  .cf__cell {
    position: static;
    left: auto;
    top: auto;
    margin: 0;
    flex: 0 0 var(--cf-w);
    scroll-snap-align: center;
  }
  /* Every card is present and readable: there is no window in flat mode,
     because the browser's own scroller already skips what is offscreen. */
  .cf__card,
  .cf__card--far {
    visibility: visible;
    content-visibility: auto;
    contain-intrinsic-size: var(--cf-w) calc(var(--cf-h) + var(--cf-cap));
    transform: none;
    opacity: 1;
    transition: none;
  }
  .cf__cap {
    opacity: 1;
  }
  /* The scroller is the affordance; the arrows would scroll it invisibly. */
  .cf__arrow {
    display: none;
  }
}
@media (max-width: 639.98px) {
  .cf {
    --cf-w: clamp(150px, 46vw, 210px);
  }
}

/* ---------------------------------------------------------------------------
 * NEWSLETTER ARCHIVE — reuses .featured-grid (auto-fit, so two issues and two
 * hundred both work with no breakpoint) and .tile.tile--art with a portrait
 * --art-ar. .featured-grid > * is already in the min-width:0 guard above.
 *
 * It is also the crawlable surface, the no-JS content, and the copy source
 * newsletters.js clones the detail head from — so it is never dropped.
 * ------------------------------------------------------------------------- */
.news-year {
  font-size: var(--fs-h3);
  margin: var(--s9) 0 var(--s5);
  padding-bottom: var(--s3);
  border-bottom: 1px solid var(--line);
  scroll-margin-top: calc(var(--header-h) + 24px);
}
.news-year:first-of-type {
  margin-top: 0;
}
.news-card {
  scroll-margin-top: calc(var(--header-h) + 24px);
}
.news-card h4 {
  font-size: 1.0625rem;
}
.news-date {
  font-size: var(--fs-xs);
  color: var(--ink-mute);
  font-weight: 600;
  margin: 2px 0 8px;
}
.news-card__acts {
  margin-top: var(--s4);
  gap: var(--s2);
}

/* The topic chip. Reuses .badge wholesale, so this is spacing only.
   Both parents put a block element straight after it (.cf__cap-title and the
   card's h4), so the inline-flex badge already sits on its own line and needs
   no display change. */
.cf__cap-topic {
  margin-bottom: 6px;
}
.news-card .news-topic {
  margin-bottom: var(--s2);
}
/* The chip needs no opacity rule of its own: it is inside .cf__cap, which is
   already opacity 0 until its card is selected, so it fades with the caption
   rather than floating over a rotated neighbour on its own. */
