/*
 * Shared layer for the sub-page templates (p-*.html).
 *
 * The site chrome this file used to carry a second copy of — announcement bar,
 * sticky header, section heads, steps, panel/ledger, pricing cards, FAQ,
 * closing CTA — now lives once in shared.css, which every page loads. What is
 * left here is the components only the sub-pages need: breadcrumbs, the compact
 * hero, the capability table, the internal-link grid and the prose column.
 *
 * The responsive breakpoints for the promoted components stay below rather than
 * moving to shared.css with them. Two media rules of equal specificity break
 * their tie on source order, so hoisting one into an earlier stylesheet hands
 * the match to whichever rule stayed behind.
 *
 * Load order is shared.css -> fx.css -> p-shared.css -> p-<page>.css.
 *
 * Same constraint as everywhere else: no literal colour, radius or font size.
 * Every value below resolves to a token in shared.css.
 */

.topbar.is-stuck {
  border-bottom-color: var(--line);
  box-shadow: var(--shadow-sm);
}

/* ---------- breadcrumbs ----------
   Every sub-page is at least one level down, and the live site already emits
   BreadcrumbList markup on all of them. Rendering the trail as well as marking
   it up is what earns the breadcrumb line in the result snippet. */

.crumb {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2);
  font-size: var(--t-sm); color: var(--muted);
  padding: var(--s-5) 0 0;
}
.crumb ol { display: contents; list-style: none; margin: 0; padding: 0; }
.crumb li { display: inline-flex; align-items: center; gap: var(--s-2); }
.crumb li + li::before { content: '/'; color: var(--line-strong); }
.crumb a:hover { color: var(--accent); text-decoration: underline; }
.crumb [aria-current] { color: var(--ink); font-weight: 600; }

/* ---------- compact hero ----------
   The homepage hero earns its height by carrying the live demo. A pair page
   answers "does this work with my two shops", so the answer needs to be above
   the fold and the hero has to get out of the way. */

.subhero { position: relative; padding: var(--s-7) 0 var(--s-8); overflow: clip; }
.subhero__glow {
  position: absolute; z-index: -1; pointer-events: none;
  width: 780px; height: 460px; left: 50%; top: -240px; margin-left: -390px;
  border-radius: var(--r-full); filter: blur(90px); opacity: .5;
  background: radial-gradient(closest-side, var(--accent-tint), transparent 72%);
}
.subhero__grid { display: grid; grid-template-columns: 7fr 5fr; gap: var(--s-8); align-items: center; }
.subhero__grid > * { min-width: 0; }
@media (max-width: 900px) {
.subhero__grid { grid-template-columns: 1fr; gap: var(--s-6); }
}
.subhero h1 { max-width: 15em; }
/* No flex-wrap, and baseline rather than center. The label is a bare text run,
   so the whole sentence is one anonymous flex item sized to its longest possible
   line. Under wrap that item cannot share a line with the dot whenever the
   sentence is wider than the column, and the dot is left stranded 22px above the
   text it labels: measured on 52 of the 53 pages carrying this, at 390 and 375,
   at 1024 on every /integrations/ page, and at 1440 on the two with an
   11-character channel name. Not at 834 or 768, where .subhero__grid has already
   collapsed to one column and the note has more room than it does at 1024.
   Wrap buys nothing back: a label only overflows on a single unbreakable token
   past ~24 characters, and it then overflows by the same number of pixels with
   wrap and without. Dropping wrap lets the label wrap in place instead, which is
   what rules center out, since center would measure the dot against the whole
   block. Fourth member of this family, after .chan-card__lat (fx.css),
   .solo-mark__facts li (p-platform.css) and .hero__note (home.css). */
.subhero__note { display: flex; align-items: baseline; gap: var(--s-2); font-size: var(--t-sm); color: var(--muted); }

/* Two channel marks either side of the QuickSync mark. This is the whole
   proposition of a pair page in one object, so it sits where the homepage
   puts its demo panel. */
.pair-mark {
  display: flex; align-items: center; justify-content: center; gap: var(--s-4);
  padding: var(--s-6) var(--s-5);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--white); box-shadow: var(--shadow-md);
}
.pair-mark__side { display: flex; flex-direction: column; align-items: center; gap: var(--s-2); flex: 1; min-width: 0; }
.pair-mark__side img { width: 44px; height: 44px; object-fit: contain; }
.pair-mark__name { font-size: var(--t-sm); font-weight: 700; color: var(--ink); text-align: center; }
.pair-mark__link { display: flex; flex-direction: column; align-items: center; gap: var(--s-1); flex: none; }
.pair-mark__hub { width: 34px; height: 34px; border-radius: var(--r-sm); background: var(--accent); }
.pair-mark__arrows { font-size: var(--t-xs); color: var(--muted); letter-spacing: .1em; }

/* ---------- capability table ----------
   The single most load-bearing component on the pair and platform templates.
   It states, per channel, what actually syncs — so it has to be legible at a
   glance, honest about the "no" rows, and readable on a phone. Marks carry the
   meaning rather than a background wash, so it survives colour blindness. */

.cap { width: 100%; border-collapse: separate; border-spacing: 0; border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; }
.cap caption { caption-side: bottom; padding-top: var(--s-3); font-size: var(--t-sm); color: var(--muted); text-align: left; }
.cap th, .cap td { padding: var(--s-3) var(--s-4); font-size: var(--t-sm); text-align: left; vertical-align: middle; }
.cap thead th { background: var(--surface); color: var(--ink); font-weight: 700; border-bottom: 1px solid var(--line); }
.cap tbody th { font-weight: 600; color: var(--ink); }
.cap tbody tr + tr th, .cap tbody tr + tr td { border-top: 1px solid var(--line); }
.cap__chan { display: inline-flex; align-items: center; gap: var(--s-2); }
.cap__chan img { width: 18px; height: 18px; object-fit: contain; flex: none; }

/* The mark is a pseudo-element so the cell text stays the accessible name and
   a screen reader is never read a bare tick. Cells that mean "no" still say
   why in text — a cross with no explanation is the thing that generates the
   support ticket this table exists to prevent. */
.cap__mark { display: inline-flex; align-items: center; gap: var(--s-2); }
.cap__mark::before {
  content: ''; flex: none;
  width: 18px; height: 18px; border-radius: var(--r-full);
}
.cap__mark--yes::before { background: var(--ok-tint) var(--icon-tick) center/11px no-repeat; }
.cap__mark--no::before { background: var(--bad-tint) var(--icon-cross) center/11px no-repeat; }
.cap__mark--part::before { background: var(--warn-tint); border: 3px solid var(--warn); }
.cap__mark--no { color: var(--muted); }

@media (max-width: 720px) {
/* A four-column matrix does not fit a phone, so each row becomes a card and
     the column header is repeated per cell from data-label.
     The table has to become a flex column rather than a plain block: dropping
     table layout also drops `caption-side: bottom`, which leaves the caption
     shrink-wrapped to one word per line at the top of the table. `order` puts
     it back underneath. */
.cap { display: flex; flex-direction: column; }
.cap caption { display: block; order: 2; }
.cap tbody { display: block; order: 1; }
.cap tr, .cap td, .cap th { display: block; }
.cap thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.cap tbody tr { border-top: 1px solid var(--line); padding: var(--s-3) 0; }
.cap tbody tr:first-child { border-top: 0; }
.cap tbody th { padding-bottom: var(--s-1); }
.cap tbody tr + tr th, .cap tbody tr + tr td { border-top: 0; }
.cap td { display: flex; justify-content: space-between; gap: var(--s-3); padding: var(--s-1) var(--s-4); }
.cap td::before { content: attr(data-label); color: var(--muted); font-size: var(--t-xs); }
}

/* ---------- honest caveat ----------
   Distinct from .todo, which flags unfinished lab work. This one ships: it is
   how the page says "this channel cannot do that" without burying it. */

.note {
  display: flex; gap: var(--s-3); align-items: flex-start;
  padding: var(--s-4);
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: var(--r-sm);
  background: var(--surface);
  font-size: var(--t-sm);
}
.note--warn { border-left-color: var(--warn); background: var(--warn-tint); color: var(--warn); }
.note--warn b { color: var(--warn); }
.note b { color: var(--ink); }

/* ---------- internal link grid ----------
   The long tail is 36 pair pages plus 11 platform pages, and they only rank as
   a set if they link to each other. Anchor text is the channel names, never
   "learn more" — the anchor is doing the ranking work here. */

.link-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-3); }
@media (max-width: 900px) {
.link-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
.link-grid { grid-template-columns: 1fr; }
}
.link-grid__item {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--white);
  font-size: var(--t-sm); color: var(--body);
  transition: border-color .2s var(--fx-ease), color .2s var(--fx-ease), transform .2s var(--fx-ease-out);
}
.link-grid__item:hover { border-color: var(--accent); color: var(--accent); }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
.link-grid__item:hover { transform: translateY(-2px); }
}
.link-grid__marks { display: inline-flex; align-items: center; gap: var(--s-1); flex: none; }
.link-grid__marks img { width: 18px; height: 18px; object-fit: contain; }

/* ---------- setup steps ---------- */

.steps--4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 900px) {
.steps, .steps--4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
.steps, .steps--4 { grid-template-columns: 1fr; }
}

.step::before {
  content: counter(step, decimal-leading-zero);
  position: absolute; top: var(--s-3); left: 0;
  font-family: var(--mono); font-size: var(--t-xs); font-weight: 700; color: var(--accent);
}

@media (prefers-reduced-motion: no-preference) {
.js-reveal .steps.fx-in .step { opacity: 0; transform: translateY(10px); }
.js-reveal .steps.fx-in.is-in .step { opacity: 1; transform: none; transition: opacity .5s var(--fx-ease-out), transform .5s var(--fx-ease-out); }
.js-reveal .steps.fx-in .step:nth-child(2) { transition-delay: .1s }
.js-reveal .steps.fx-in .step:nth-child(3) { transition-delay: .2s }
.js-reveal .steps.fx-in .step:nth-child(4) { transition-delay: .3s }
}

/* ---------- product mockup card ---------- */

.panel-card__time { font-family: var(--mono); font-size: var(--t-xs); color: var(--muted); }

.panel-card .fx-hair { background: var(--line); }

.ledger__t { font-family: var(--mono); font-size: var(--t-xs); color: var(--muted); min-width: 6ch; text-align: right; }

/* ---------- pricing cards ---------- */

@media (max-width: 1000px) {
.price-cards { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
.price-cards { grid-template-columns: 1fr; }
}

@media (hover: hover) and (prefers-reduced-motion: no-preference) {
.price-card:hover { border-color: var(--accent); transform: translateY(-3px); box-shadow: var(--shadow-md); }
}

/* ---------- plan strip ----------
   The three-plan reminder a sub-page drops in before its closing CTA. Not
   .grid-3: that goes three-two-one, and two columns leaves the third plan
   orphaned on its own row. Three plans want three or one. */

.plan-strip {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s-4);
  align-items: stretch;
}
.plan-strip > .card { display: flex; flex-direction: column; gap: var(--s-2); }
/* Beside a price these read as the section's own headings rather than plan
   names, so they step down one. */
.plan-strip h3 { font-size: var(--t-lg); }
@media (max-width: 900px) {
  .plan-strip { grid-template-columns: 1fr; }
}

/* ---------- FAQ ---------- */

@media (prefers-reduced-motion: no-preference) {
.faq summary::after { transition: transform .25s var(--fx-ease); }
.faq details[open] summary::after { transform: rotate(180deg); }
.faq details[open] .faq__a { animation: faq-in .32s var(--fx-ease-out) both; }
@keyframes faq-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
}

/* ---------- prose column ----------
   Legal pages and docs. One measured column, a sticky contents rail beside it
   on desktop. The live /security/ page has no h1 at all and /privacy-policy/
   is a wall of unstructured text; the structure here is the fix. */

.prose-layout { display: grid; grid-template-columns: 220px 1fr; gap: var(--s-8); align-items: start; }
@media (max-width: 900px) {
.prose-layout { grid-template-columns: 1fr; gap: var(--s-5); }
}

.toc { position: sticky; top: calc(var(--s-8) + var(--s-4)); font-size: var(--t-sm); }
@media (max-width: 900px) {
.toc { position: static; padding: var(--s-4); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); }
}
.toc__h { font-size: var(--t-xs); font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); margin-bottom: var(--s-3); }
.toc ol { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-2); }
.toc a { color: var(--body); border-left: 2px solid var(--line); padding-left: var(--s-3); display: block; }
.toc a:hover { color: var(--accent); border-left-color: var(--accent); }

.prose { max-width: 42em; }
.prose > * + * { margin-top: var(--s-4); }
.prose h2 { font-size: var(--t-2xl); margin-top: var(--s-7); scroll-margin-top: var(--s-8); }
.prose h3 { font-size: var(--t-lg); margin-top: var(--s-5); scroll-margin-top: var(--s-8); }
.prose h2:first-child { margin-top: 0; }
.prose ul, .prose ol { margin: 0; padding-left: var(--s-5); display: flex; flex-direction: column; gap: var(--s-2); }
.prose a { color: var(--accent); text-decoration: underline; }
.prose table { width: 100%; border-collapse: collapse; font-size: var(--t-sm); }
.prose th, .prose td { text-align: left; padding: var(--s-3); border-bottom: 1px solid var(--line); vertical-align: top; }
.prose th { color: var(--ink); font-weight: 600; }
.prose__meta { font-size: var(--t-sm); color: var(--muted); padding-bottom: var(--s-4); border-bottom: 1px solid var(--line); }

/* ---------- Shopify App Store rating cite ----------
   Same markup as the homepage Customers block. Lives here so pricing,
   integrations and pair pages can show the cite without loading home.css.
   Never pair with aggregateRating schema — see schema-home.php. */

.rating {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-3);
  font-size: var(--t-sm);
}
.rating__score { min-width: 0; color: var(--body); }
.rating__score b { color: var(--ink); font-size: var(--t-base); }
.rating__src { color: var(--accent); font-weight: 600; }
.rating__src:hover { text-decoration: underline; }
.section--tight .rating { margin: 0; }
