/* ============================================================================
   Page compositions. site.css holds the primitives, mk.css holds the product
   artifacts, and this file arranges them into the sections each page needs.
   Nothing here introduces a colour, a radius or a curve of its own.
   ============================================================================ */

/* The hero's action row keeps the product artifact inside the fold. */
@media (max-width: 720px) { .herorow { flex-direction: column; align-items: flex-start } }
.proofline {
  display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp2) var(--sp3);
  margin: var(--sp6) 0 0; font-size: var(--t-small); color: var(--ink-faint);
}
.proofline i { font-style: normal; opacity: .5 }

/* ------------------------------- run flow ----------------------------------
   Describe, then run. Two artifacts with one arrow between them; the arrow
   turns to point down when the pair stacks. */
/* The arrow lines up with the first artifact row, not with the midpoint of two
   columns of different heights. */
@media (max-width: 1080px) {
  .runflow { grid-template-columns: minmax(0, 1fr); gap: var(--sp5) }
  .runflow-arrow { width: auto; padding: 0; transform: rotate(90deg) }
}
/* A composer and a step list are not cropped views, they are ordinary UI, so
   they reflow instead of running off the edge. The 1:1 crop rule is for the
   dense artifacts (the shell, the ledger, the sequence) where shrinking the
   pixels would make them read as a picture of software. */

/* ------------------------------ start grid --------------------------------- */
.startgrid {
  display: grid; grid-template-columns: minmax(280px, 420px) minmax(0, 760px);
  justify-content: center; align-items: center; gap: clamp(var(--sp5), 4vw, var(--sp8));
}
@media (max-width: 1000px) { .startgrid { grid-template-columns: minmax(0, 1fr); gap: var(--sp7) } }
.connect-copy, .connect-list { width: 100% }
.connect-list .hairitem { grid-template-columns: minmax(0, 1fr); padding-block: var(--sp4) }
.connect-list .hairitem:first-child { border-top: 0 }
.hairlist.connect-list > .hairitem:last-child { border-bottom: 0 }
.connect-list .hairitem h3 { font-size: var(--t-title) }
.connect-list .hairitem p { margin-top: var(--sp1); max-width: 48ch }
.connect-copy .h2 { white-space: nowrap }
@media (min-width: 721px) {
  #start > .wrap > .section-head .h2 { max-width: none; white-space: nowrap }
}
@media (max-width: 1000px) { .connect-copy .h2 { white-space: normal } }

/* --------------------------- template library -----------------------------
   This is the launch-site host for the web app's production template banner.
   The design-system stylesheet owns the banner itself; this layer only owns
   the card, its catalog metadata, and the responsive three-card grid. */
.template-library-head {
  align-items: center; max-width: 52rem; margin-inline: auto; text-align: center;
}
.template-library-head .h2, .template-library-head .sub { margin-inline: auto }
.workflow-template-library {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: stretch; gap: var(--sp4); width: 100%;
}
.workflow-template-card {
  position: relative; display: flex; min-width: 0; height: 100%;
  flex-direction: column; overflow: hidden; padding: 0;
  border: 1px solid var(--ui-line); border-radius: var(--r-xl);
  background: var(--s1); container-name: workflow-template-card;
  container-type: inline-size;
  transition: border-color var(--fast) var(--ease);
}
.workflow-template-card:hover,
.workflow-template-card:has(.workflow-template-card-link:focus-visible) {
  border-color: var(--ui-line-strong);
}
.workflow-template-card-link {
  position: absolute; z-index: 3; inset: 0; border-radius: inherit;
}
.workflow-template-card-link:focus-visible {
  border-radius: inherit; outline: 2px solid color-mix(in srgb, var(--ink) 52%, transparent);
  outline-offset: -2px;
}
.workflow-template-banner-frame {
  --sapiom-template-banner-radius: 0;
  display: block; margin: 0; border: 0; background: transparent;
}
/* External SVG images do not inherit currentColor. The production React
   component inlines this mark, so the static host mirrors that result across
   the two themes with the same inverse construction as the banner. */
.sapiom-template-banner__logotype[src] { filter: invert(1) }
[data-theme="dark"] .sapiom-template-banner__logotype[src] { filter: none }
.workflow-template-card-body {
  display: flex; min-width: 0; flex: 1; flex-direction: column;
  gap: var(--sp3); padding: var(--card-pad); container-type: inline-size;
}
.workflow-template-description,
.workflow-template-meta { margin: 0; color: var(--ink-muted) }
.workflow-template-description {
  display: -webkit-box; min-width: 0; min-height: 3em; overflow: hidden;
  font-size: var(--t-body); line-height: 1.5;
  -webkit-box-orient: vertical; -webkit-line-clamp: 2;
}
.workflow-template-tags {
  position: relative; z-index: 2; display: flex; min-width: 0;
  min-height: 1.5rem; align-items: center; gap: var(--sp1);
  margin-top: auto; overflow: hidden; pointer-events: none;
}
.workflow-template-tag {
  display: inline-flex; min-width: 0; min-height: 1.5rem;
  flex: 0 1 auto; align-items: center; overflow: hidden;
  border-radius: 9999px; padding-inline: var(--sp2);
  background: var(--active-shade); color: var(--ink-muted);
  font-family: var(--mono); font-size: var(--t-meta); line-height: 1;
  text-overflow: ellipsis; white-space: nowrap;
}
.workflow-template-tag:not(.workflow-template-tag-count) { max-width: 7rem }
.workflow-template-tag-count { flex: 0 0 auto }
.workflow-template-meta {
  min-height: 2.6em; font-size: var(--t-small); line-height: 1.3;
}
.template-library-cta {
  display: flex; justify-content: center; margin-top: var(--sp5);
}
@media (max-width: 1040px) {
  .workflow-template-library { grid-template-columns: repeat(2, minmax(0, 1fr)) }
}
@media (max-width: 680px) {
  .workflow-template-library { grid-template-columns: minmax(0, 1fr) }
}
@container workflow-template-card (max-width: 15rem) {
  .workflow-template-tag-secondary { display: none }
}

/* The home tour is one three-product sequence. Each product keeps the shared
   artifact track while the stack owns the rhythm between the three chapters. */
#how .blockstack { display: flex; flex-direction: column; gap: var(--band) }
#how .blockstack > .wrap { width: 100% }
/* The flex gap owns the product-tour rhythm. The generic blockstack margin in
   crops.css is neutralised here so each chapter gets one band, not two. */
#how .blockstack > * + * { margin-top: 0 }

/* -------------------------------- quotes -----------------------------------
   Sourced quotes only. A quote card with a placeholder name is the single
   loudest tell on a marketing page, so the wall is two real voices, not four
   invented ones. */
/* Three peers, so three columns, then two, then one. A row of three quote cards
   is a set; a row of two with a gap where the third should be is a set that is
   missing one, and the reader reads the gap. */
.quotegrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp4) }
/* Three peers at the two-up step leave the third beside a hole, so it takes the
   row. Same rule the card grid runs, for the same reason. */
@media (max-width: 1000px) {
  .quotegrid { grid-template-columns: repeat(2, minmax(0, 1fr)) }
  .quotegrid > :last-child:nth-child(odd) { grid-column: 1 / -1 }
}
@media (max-width: 700px) { .quotegrid { grid-template-columns: minmax(0, 1fr) } }
.quote {
  display: flex; flex-direction: column; gap: var(--sp4); margin: 0;
  padding: clamp(28px, 3.5vw, 40px);
  background: var(--s1); border: 1px solid var(--line); border-radius: var(--r-xl);
}
/* Every quote card leads with the mark of what it is and sits on the same
   guilloche wash the feature cards carry, so a testimonial is part of the same
   card system rather than a plainer cousin. The loop motif: a voice that comes
   back around. */
.quote.tex-quote { position: relative; isolation: isolate; overflow: hidden }
.quote.tex-quote::before {
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  right: var(--tex-bleed-x); bottom: var(--tex-bleed-y);
  width: var(--tex-wash); height: var(--tex-wash);
  background: url("../art/guilloche-loop.svg") no-repeat center / 100% 100%;
  opacity: var(--tex-ink); filter: invert(var(--tex-invert));
}
.quote .qmark { display: flex; color: var(--ink-faint) }
.quote .qmark svg { width: 26px; height: 26px }
.quote.solo .qmark { justify-content: center }
.quote blockquote {
  margin: 0; font-size: var(--t-title); font-weight: 500;
  letter-spacing: -.018em; line-height: 1.35; text-wrap: balance;
}
.quote figcaption { display: flex; flex-direction: column; gap: 2px; margin-top: auto }
.quote figcaption b { font-size: var(--t-small); font-weight: 500 }
/* An attribution is chrome, so it runs at the chrome step. 13px beside a 22px
   blockquote reads as a footnote, and the person's name is not a footnote. */
.quote figcaption span { font-size: var(--t-small); color: var(--ink-faint) }
/* A lone quote is a pull quote, not a card in a grid of one: it reads at the
   prose measure and larger, centred in the rail. */
.quote.solo { max-width: 46rem; margin-inline: auto; align-items: center; text-align: center }
.quote.solo blockquote { font-size: clamp(1.3rem, 2.6vw, 1.75rem) }
.quote.solo figcaption { align-items: center }
/* Standalone artifacts inside a section need their own air, since the section
   only pads its outer edges. */
.section > .wrap > .quote { margin-top: var(--sp6) }

.backers-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(var(--sp5), 5vw, var(--sp8)); align-items: stretch;
}
.backers-copy { grid-column: 2; grid-row: 1; display: flex; flex-direction: column; justify-content: center }
.backers-copy .sub { margin-top: var(--sp4) }
.backers-grid > .quote { grid-column: 1; grid-row: 1; margin: 0 }
.backers-logos {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: center; justify-items: center; gap: var(--sp6) var(--sp5);
  margin-top: var(--sp7); padding-top: var(--sp5); border-top: 1px solid var(--line-2);
}
.backers-logos img { width: auto; height: 24px; max-width: min(108px, 100%); filter: grayscale(1); opacity: .54 }
[data-theme="dark"] .backers-logos img { filter: grayscale(1) invert(1); opacity: .48 }
@media (max-width: 700px) {
  .backers-grid { grid-template-columns: minmax(0, 1fr) }
  .backers-copy, .backers-grid > .quote { grid-column: 1; grid-row: auto }
  .backers-grid > .quote { margin-top: var(--sp2) }
}

/* ------------------------------- blog cards -------------------------------- */
.blogcard { transition: border-color var(--fast) var(--ease), transform .35s var(--ease) }
.blogcard:hover { border-color: var(--line-2); transform: translateY(-2px) }
.blogcard .link-arrow { margin-top: auto }
/* A card's body is a sentence a reader reads, so it is the base step, the same
   as every other .card on the site. */
.blogcard p { margin: 0; font-size: var(--t-body); color: var(--ink-muted); line-height: 1.6 }

/* -------------------------------- page hero --------------------------------
   Inner pages open on words, not on an artifact. The artifact lands in the
   first section so the reader has a reason to keep going. */
.page-hero { padding-block: clamp(56px, 8vw, 96px) 0 }
.page-hero .display { max-width: 20ch }
.page-hero .lead { max-width: 54ch }
.page-hero.center { text-align: center }
.page-hero.center .display, .page-hero.center .lead { margin-inline: auto }
.page-hero.center .cta-row { justify-content: center }
/* Split hero: copy left, one artifact right. Used where the page's first
   artifact is small enough to sit beside the words rather than under them. */
.page-hero.split .wrap { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(32px, 5vw, 72px); align-items: center }
.page-hero.split .display { max-width: 17ch }
.page-hero.split .lead { max-width: 42ch }
@media (max-width: 1000px) { .page-hero.split .wrap { grid-template-columns: minmax(0, 1fr); gap: var(--sp7) } }
/* Two-tone headline: the claim in ink, the consequence in muted ink. */
.twotone { display: block; color: var(--ink-muted) }

/* --------------------------------- tiers ----------------------------------- */
.tier-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp4) }
@media (max-width: 940px) { .tier-grid { grid-template-columns: minmax(0, 1fr) } }

.pricing-rates {
  display: grid;
  gap: var(--sp5);
  max-width: 920px;
}

.pricing-rates .btn {
  justify-self: start;
}
.tier {
  display: flex; flex-direction: column; gap: var(--sp3);
  padding: clamp(28px, 3.2vw, 38px) clamp(24px, 2.6vw, 32px);
  background: var(--s1); border: 1px solid var(--line); border-radius: var(--r-xl);
}
.tier.hot { border-color: var(--line-2); box-shadow: var(--shadow-soft) }
.tier-top { display: flex; align-items: center; justify-content: space-between; gap: var(--sp2); min-height: 24px }
.tier-top .who { margin: 0 }
.tier-badge {
  flex: 0 0 auto; padding: 5px 9px; border-radius: var(--r-sm);
  background: var(--ink); color: var(--bg); border: 1px solid var(--ink);
  font-family: var(--mono); font-size: var(--t-meta); font-weight: 600; line-height: 1;
  text-transform: lowercase; white-space: nowrap;
}
.tier-badge.outline { background: transparent; color: var(--ink-muted); border-color: var(--line-2) }
.tier .who {
  font-family: var(--mono); font-size: var(--t-meta); color: var(--ink-faint);
  text-transform: lowercase;
}
.tier h3 { margin: 0; font-size: var(--t-title); font-weight: 600; letter-spacing: -.018em }
.tier .price { display: flex; align-items: baseline; gap: 6px; font-size: clamp(1.9rem, 3vw, 2.35rem); font-weight: 600; letter-spacing: -.028em; line-height: 1.1 }
.tier .price small { font-size: .42em; font-weight: 400; color: var(--ink-muted); letter-spacing: 0 }
.tier > p { margin: 0; font-size: var(--t-small); color: var(--ink-muted); line-height: 1.55 }
.tier ul { list-style: none; margin: var(--sp3) 0 var(--sp5); padding: 0; display: flex; flex-direction: column; gap: 10px }
.tier li { display: flex; gap: 10px; font-size: var(--t-body); color: var(--ink-muted); line-height: 1.5 }
.tier li svg { flex: 0 0 auto; width: 15px; height: 15px; margin-top: 3px; color: var(--ink-faint) }
.tier .btn { margin-top: auto; width: 100% }
.tier-note { margin: var(--sp5) 0 0; font-size: var(--t-small); color: var(--ink-faint); max-width: 78ch; line-height: 1.6 }

/* ---------------------------- comparison table ------------------------------
   One grid owns the columns and every row takes subgrid from it, which is the
   only way the cells actually line up once a label wraps. Numeric tracks are
   max-content so a value can never clip. */
.cmp { --cmp-cols: minmax(14rem, 1.7fr) repeat(3, minmax(max-content, 1fr)) }
/* overflow-x: auto forces overflow-y to auto, which makes this element the
   sticky scrollport and gives the head zero sticky range. Above the width where
   the table fits, stop being a scroll container at all. */
.cmp-scroll { overflow-x: auto; scrollbar-width: thin }
@media (min-width: 830px) { .cmp-scroll { overflow: visible } }
/* 44rem of minimum keeps all four columns real on a phone; the scroller shows
   the Startup column peeking past the edge, which IS the affordance. */
.cmp-table { display: grid; grid-template-columns: var(--cmp-cols); min-width: 44rem }
.cmp-row .qty { margin-left: 7px }
.cmp-table > * { display: grid; grid-template-columns: subgrid; grid-column: 1 / -1; align-items: center }
.cmp-head { position: sticky; top: var(--nav-h); z-index: 2; background: var(--bg); border-bottom: 1px solid var(--line-2) }
/* Plan names sit on the same axis as their Yes and No cells, otherwise the eye
   has to re-find the column on every row. */
.cmp-head > * { padding: var(--sp4) var(--sp3); font-size: var(--t-small); font-weight: 500; text-align: center }
.cmp-head > *:first-child { padding-left: 0; text-align: left }
.cmp-group { padding: var(--sp5) 0 var(--sp2); font-family: var(--mono); font-size: var(--t-meta); color: var(--ink-faint); letter-spacing: .04em }
.cmp-row { border-top: 1px solid var(--line) }
.cmp-row > * { padding: 13px var(--sp3); font-size: var(--t-body); color: var(--ink-muted); text-align: center }
.cmp-row > *:first-child { padding-left: 0; text-align: left; color: var(--ink) }
/* The tick and the cross. Same 18px box so the two columns of glyphs line up
   down the table, and the ink does the work the words used to: full ink for a
   yes, faint for a no. The word itself stays in the DOM inside .mk-sr, because
   a glyph is not a label and shape alone is not an accessible answer. */
.cmp-row .yes, .cmp-row .no { color: var(--ink) }
.cmp-row .no { color: var(--ink-faint) }
.cmp-row .tick { display: inline-block; width: 18px; height: 18px; vertical-align: -4px }
/* A tick followed by a quantity, for the one row that answers with a number. */
.cmp-row .tick + .mk-sr + * , .cmp-row .yes > .mk-sr + * { margin-left: 6px }
/* position: relative is load-bearing. .mk-sr is absolutely positioned, and an
   absolutely positioned box inside an overflow: auto scroller whose ancestors are
   all static escapes the scroller's containing block: it stops being clipped and
   starts contributing to the DOCUMENT's scroll width. Measured: the pricing page
   went 431px wider than a 320px viewport because of a 1px screen-reader span.
   Giving the cell a containing block puts it back inside the scroller. */
.cmp-row .yes, .cmp-row .no { position: relative }
.cmp-row .mono { font-size: var(--t-small) }

/* --------------------------------- FAQ tint -------------------------------- */
/* No margin-inline: auto. A heading on the text rail above a list starting a
   third of the way across reads as two unrelated blocks. */

/* -------------------------------- careers ---------------------------------- */
@media (max-width: 760px) { .hw-grid { grid-template-columns: minmax(0, 1fr) } }
.bene-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp7) var(--sp6) }
@media (max-width: 1020px) { .bene-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) } }
@media (max-width: 560px) { .bene-grid { grid-template-columns: minmax(0, 1fr) } }
.bene-group { border-top: 1px solid var(--line-2); padding-top: var(--sp5) }
.bene-group h3 { display: flex; align-items: center; gap: 10px; margin: 0 0 var(--sp4); font-size: var(--t-title); font-weight: 600 }
.bene-group .bene-ic { display: inline-flex; color: var(--ink-muted) }
.bene-group .bene-ic svg { width: 20px; height: 20px }
.bene-group ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp4) }
/* Each line leads with a check: the list is a list of things you get, and the
   check is the sentence's verb. It hangs in its own 24px column so wrapped
   descriptions stay aligned under their own first line. */
.bene-group li { display: flex; align-items: flex-start; gap: 10px }
.bene-group .bene-check { display: inline-flex; flex: 0 0 auto; margin-top: 3px; color: var(--ink-faint) }
.bene-group .bene-check svg { width: 14px; height: 14px }
.bene-group .bene-body { min-width: 0 }
.bene-group b { display: block; font-size: var(--t-body); font-weight: 500 }
.bene-group span { display: block; margin-top: 2px; font-size: var(--t-body); color: var(--ink-muted); line-height: 1.5 }
/* An explicit background, and it is load-bearing: .reveal leaves a transform on
   this panel, which isolates it as a stacking context, and a mix-blend-mode
   inside an isolated group composites against the GROUP's backdrop, not the
   page. With a transparent panel that backdrop is transparent black, so the
   inverted Equinox raster screened against nothing and shipped as a dark plate.
   Painting the page colour inside the group gives screen and multiply the
   backdrop they were written for. */
.perk-panel { margin-top: var(--sp7); border-top: 1px solid var(--line-2); padding-top: var(--sp6); background: var(--bg) }
.perk-panel .eyebrow { text-align: center }
.perk-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: center; justify-items: center; gap: clamp(24px, 3.5vw, 44px) }
.perk-grid img { height: 26px; max-width: min(112px, 100%); width: auto; object-fit: contain; filter: grayscale(1); opacity: .55 }
/* Two of these marks are rasters with a baked opaque background, which reads as
   a plate in a row of transparent SVGs. Blending drops the flat field: multiply
   loses white on a light panel, screen loses black on a dark one. */
.perk-grid img[src$=".png"] { mix-blend-mode: multiply }
[data-theme="dark"] .perk-grid img[src$=".png"] { mix-blend-mode: screen }
/* A mark authored white disappears on a light page, so it inverts, and then
   inverts back in dark. Without this it renders as an empty cell. */
.perk-grid img.inv { filter: grayscale(1) invert(1) }
[data-theme="dark"] .perk-grid img { filter: grayscale(1) invert(1); opacity: .5 }
[data-theme="dark"] .perk-grid img.inv { filter: grayscale(1) }
/* A named partner set as text sits on the same optical row as the drawn marks,
   so it runs at wordmark weight, not at label weight. */
.perk-grid .wordmark { font-size: 1.125rem; font-weight: 560; letter-spacing: .01em; color: var(--ink-muted); opacity: .8 }
/* The Apple mark is a compact glyph in a row of wide wordmarks; equal cap
   heights make it read smaller than its neighbours, so it gets optical size. */
.perk-grid img[src*="apple"] { height: 30px }
/* A roles row's tail is a count plus its action, one cluster. */
.role-acts { display: flex; align-items: center; gap: var(--sp4); flex: 0 0 auto }
@media (max-width: 640px) { .perk-grid { grid-template-columns: repeat(2, 1fr) } .perk-grid img { height: 22px; max-width: min(92px, 100%) } }

/* -------------------------------- contact ---------------------------------- */
@media (max-width: 900px) { .contact-grid { grid-template-columns: minmax(0, 1fr) } }

/* --------------------------------- article ---------------------------------
   Resources hosts the two posts inline rather than shipping a blog engine for
   two articles. */
/* .section anchors already carry a band of top padding; an <article> does not,
   so it needs its own clearance under the sticky header. */
/* Centred in the rail: a 62ch article flush left in a 1152 rail leaves a 590px
   empty column beside it, which reads as a page missing its second half. The
   reading measure is unchanged; only its position moves. */
.article { max-width: var(--m-prose); margin-inline: auto; scroll-margin-top: calc(var(--nav-h) + var(--sp5)) }
.article + .article { margin-top: var(--sp7); border-top: 1px solid var(--line-2); padding-top: var(--sp7) }
.article h3 { margin: var(--sp6) 0 var(--sp3); font-size: clamp(1.2rem, 2.2vw, 1.5rem); font-weight: 600; letter-spacing: -.018em }
.article p { margin: 0 0 var(--sp4); font-size: var(--t-body); line-height: 1.75 }
.article .byline { display: flex; align-items: center; gap: var(--sp3); margin-bottom: var(--sp5) }
.article .byline .mk-avatar { width: 34px; height: 34px }
.article .byline b { display: block; font-size: var(--t-body); font-weight: 500 }
.article .byline span { font-size: var(--t-small); color: var(--ink-faint) }

/* The FAQ command line: the answer's action, ready to paste. One row, mono,
   the kit's copy button, and the same quiet inset every code surface uses. */
.faq-cmd {
  display: flex; align-items: center; gap: var(--sp2); justify-content: space-between;
  margin-top: var(--sp3); margin-bottom: var(--sp4);
  min-height: var(--control-h); padding: var(--sp1) var(--sp1) var(--sp1) var(--sp3);
  background: var(--s1); border-radius: var(--ctl-r);
  box-shadow: inset 0 0 0 1px var(--line);
}
.faq-cmd + .faq-cmd { margin-top: 8px }
.faq-cmd code {
  font-family: var(--mono); font-size: 13px; color: var(--ink);
  min-width: 0; overflow-x: auto; white-space: nowrap; scrollbar-width: none;
}
.faq-cmd code::-webkit-scrollbar { display: none }
.faq-cmd .mk-copy { position: static; flex: 0 0 auto }
