/* Case pages on phones (<= 767px, loaded with that media query): every block in one
   column. Sizes in --um (1px of a 390px-wide phone mock, mobile.css) where the desktop
   floors would be too large on a narrow screen. The rhythm is the landing's phones':
   blocks a section's air apart (--section-y), a title 24px over its content (the stack's
   headline over its chips, mobile-what.css), the pieces inside a block 16px apart. */

.case {
  --cb-x: var(--page-x); /* the narrow gutter on phones, as the landing's phones keep */
  --cb-xh: 0; /* the split stacks here: nothing to level */
  --cb-gap: var(--section-y);
  --cb-tight: var(--m-2);
  --cb-col: var(--m-2);
  --cb-head: var(--m-3);
  --cb-body: var(--fs-body); /* 18px here, as the landing's body */
  --cb-lead-fs: 21px; /* the lead, and the logo plate standing in it (case.css .cb-inline-mark--float) */
  --cb-air: var(--m-4); /* the larger air: the stats' under their title or their text */
}

/* No curtain on phones (the landing's phones have none either): the hero scrolls away */
.cb-hero {
  position: relative;
  clip-path: none;
  min-height: var(--case-hero-h);
}
/* ...and the plate over it (case.js, case.css .cb-hero-plate) the same air: its copy of the
   text has to land on the text. With the desktop's foot (48px, against 40 here) it stood
   higher, and the eyebrow and the title dropped as the plate lifted off with the mark. */
.cb-hero,
.cb-hero-plate {
  padding-top: var(--m-below-head);
  padding-bottom: var(--m-4);
}
.cb-hero-title { font-size: calc(38 * var(--um)); line-height: 1.08; }
/* A service's mark (case.css .cb-hero-media--mark): above the title, in the screen's middle */
.cb-hero:has(.cb-hero-media--mark) > .cb-hero-title { max-width: none; }
.cb-hero-media--mark canvas {
  top: calc(var(--m-below-head) + var(--m-3));
  right: auto;
  left: 50%;
  width: min(64vw, 30svh);
  height: min(64vw, 30svh);
  /* (a nudge up and right: the funnel's mass sits low and left of its box, so centred on the
     line it read off-centre -- by eye) */
  translate: calc(-50% + 8px) -12px;
}
.cb-title      { font-size: var(--fs-m-list-lg); }
.cb-label      { font-size: 22px; }
/* The float plate (case.css .cb-inline-mark--float) stands in the lead as on the desktop,
   square here: --float-lines of the lead tall and as wide, so the lines beside it still
   hold a few words each */
.cb-inline-mark--float {
  --float-lines: 4;
  width: calc((var(--float-lines) - 1) * 1lh + 0.686em);
}

/* Split: the title above its content, like a stacked block */
.cb-split { display: block; }
.cb-split > :first-child { padding-right: 0; }
.cb-split > :is(.cb-title, .cb-label, .eyebrow) + * { margin-top: var(--cb-head); }
/* (a list's first row starts with its own padding: the gap to its text is the same) */
.cb-split > .cb-title + .cb-list { margin-top: calc(var(--cb-head) - var(--cb-list-pad)); }
.cb-split > :is(.cb-title, .cb-text) + .cb-stats { margin-top: var(--cb-air); }
/* A service's close (case-next.js): the board with what's next on it is pinned to the
   screen here too -- the whole screen, in lvh, as the landing's close (mobile.css
   .contact-sticky): in svh it fell short of the screen once Safari's toolbar had gone,
   and the page showed under it. Held for the same run as the desktop's (105svh: the turn
   at 0.6 of a screen, then the call's 0.45). On it, in the call's own places: the eyebrow
   on the first line under the header, the title and the text pressed to the foot; the
   mark on the centre line between (the call's, as the AI's first). The feet ride with the
   toolbar: the call's copy sticks to the window's foot (the landing's .contact-copy), and
   what's next stands on the visible screen (dvh) -- the toolbar covers neither. */
.cb-cta.cb-cta--next { height: calc(100lvh + 105svh); overflow: clip; }
.cb-cta--next .cb-cta-panel {
  position: sticky;
  top: 0;
  height: 100lvh;
  min-height: 0;
  padding-top: calc(var(--header-h) + var(--m-foot)); /* its top behind the header: the overline under it (below) */
}
.cb-cta.cb-cta--next .contact-copy { position: sticky; bottom: var(--m-foot); } /* (past .cb-cta .contact-copy, below) */
.cb-cta-panel > .cb-next {
  bottom: auto;
  height: 100dvh;
  padding: var(--m-foot) var(--cb-x);
}
/* Its eyebrow as the call's overline on a case's board: in the flow, 56px under the board's
   top and going with it -- and never under the header: held at its foot + the air, for the
   board pinned with its top behind it. (Set a header + 56px down the board, it stood 128px
   under the board's top while the board came up to the header.) The text stays at the foot. */
.cb-cta-panel > .cb-next > .eyebrow {
  position: sticky;
  top: calc(var(--header-h) + var(--m-foot));
  left: auto;
  margin-bottom: auto;
  font-size: var(--fs-m-min);
}
.cb-cta-panel > .cb-next > .cb-title { max-width: none; }
.cb-cta-panel > .cb-next > .cb-text { display: block; max-width: none; }
.cb-cta-panel > .cb-next > .cb-text > p + p { margin-top: var(--m-2); }

/* The facts as a table, one to a row: the key at the left edge, the value at the right,
   hairlines between the rows and the block's own closing the last. (Two abreast, a long
   value ran to three lines and threw the row out; stacked, the keys read as a list.) */
.cb:has(> .cb-meta) { padding-bottom: 0; }
.cb-meta { display: block; }
.cb-meta > div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 24px;
  padding: 14px 0;
  border-top: 1px solid var(--hairline);
}
.cb-meta dt { flex: none; }
.cb-meta dd { margin: 0; white-space: normal; text-align: right; }

/* Stats: two to a line, whatever the desktop rows held, each label on one line: the caps at
   the tighter tracking (0.2 -> 0.12em; half of a 390px screen is 163px, "/ Loyalty members"
   takes 158px so, 173 at 0.2em). A label too long even so takes its short form here
   (.ov-short, as the landing's contact overline); on a narrower screen a long one wraps */
.cb-stats { gap: 24px; }
.cb-stats-row { flex-wrap: wrap; gap: 24px 16px; }
.cb-stat { flex: 1 1 calc(50% - 8px); }
.cb-stat-value { font-size: 25px; } /* = the landing's stats (sections.css .stat .h4) */
.cb-stat .eyebrow { letter-spacing: var(--track-caps-tight); }
.cb-stat .ov-long { display: none; }
.cb-stat .ov-short { display: inline; }

.cb-cards { grid-auto-flow: row; }
.cb-card { padding: 24px; }
.cb-list--numbered > li { padding-left: 48px; }

.cb-points { max-width: none; gap: 28px; }
/* A list of points after a block's text (a service's integrations) is a block of its own
   here, and so is the line after it: the full gap, not the desktop's tight one (16px read
   as part of the list above) */
.case > .cb + .cb-points.cb--tight,
.case > .cb-points + .cb.cb--tight { margin-top: var(--cb-gap); }

/* Pictures run edge to edge of the content (in the gutters, as the landing's works tiles),
   one after another. The desktop's wide strips
   (1352 / 534) are a sliver this narrow: 16:9 here (a plate with a ratio of its own keeps it) */
.cb-plate { --ratio: 16 / 9; }
.cb-media--offset .cb-plate { width: 100%; margin-left: 0; }
.cb-pair { grid-template-columns: 1fr; gap: var(--m-2); }
.cb-pair > :first-child { margin-right: 0; }
.cb-pair > .cb-plate--tall { --ratio: 4 / 5; }

/* Full bleed, its text on the page's gutters */
.cb-callout {
  margin-inline: calc(-1 * var(--cb-x));
  padding: 28px var(--cb-x) 32px;
}
.cb-callout-eq { height: 36%; }
.cb-callout-text { font-size: var(--fs-m-list); } /* the 28 step (mobile.css) */

/* The call on phones: a plain block, a screen high, on the scene's ground -- no board, no
   pin, nothing held to the window: it comes up and goes on with the page as one piece. The
   landing's phone composition (css/mobile.css .contact-*): the overline at its head, the
   mark on the centre line behind, the title and the button at its foot (in the block, not
   on the window's foot: held there, they slid over the mark as the block moved). svh, not
   the landing's lvh: with Safari's toolbar up the foot, and the button, is still on screen.
   In turn (js/case.js): the overline with the mark setting off, then the call once the
   mark has formed; once the block has covered the screen, all of it stays. */
html.case-js .cb-cta { --cta-open: 1; }
.cb-cta { --scene-glow-at: 50% 30%; height: auto; overflow: visible; }
/* The overline at the head, the call at the foot, the same air above the one as below the
   other (--m-foot, 56px) as the reader sees it -- under the header, which the board passes
   under. The overline stands in the flow at the board's head and goes with the board: the
   case's plain board, resting just under the header, has it there by itself; a service's
   board, pinned with its top behind the header, starts its flow the header lower (above).
   (Held at the header's foot instead -- sticky -- it stood still while the plain board went
   on up, and came down onto the title. A fixed offset from the board's top counted the
   header once too often on the plain board: 96px over the overline against 56 under the
   button.) */
.cb-cta-panel {
  position: relative;
  height: auto;
  min-height: 100svh;
  clip-path: none;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-start;
  padding-top: var(--m-foot);
}
.cb-cta .contact-overline {
  position: relative;
  top: auto;
  left: auto;
}
/* (Its row, .cta-overline-row in the markup, is the room over the call; on the desktop an
   empty flex item, the overline placed from the board) */
.cb-cta .cta-overline-row { display: block; flex: 1; align-self: stretch; }
.cb-cta-panel > :not(.cb-cta-mark, .cta-overline-row),
.cb-cta-panel > .cta-overline-row > * { translate: none; }
.cb-cta .contact-copy { position: relative; bottom: auto; }
/* Its overline in a line mask (js/case.js): the slash beside the line, not over it, and
   coming in with it (it stood alone before the words had risen) */
.cb-cta .contact-overline.rv:not(.rv-block) { display: inline-flex; align-items: baseline; }
.cb-cta .contact-overline.rv:not(.rv-block)::before { transition: opacity var(--dur-slow) ease; }
.cb-cta .contact-overline.rv:not(.rv-block):not(.is-in)::before { opacity: 0; }

/* Pinned points: the landing's phone services (mobile-what.css) -- no pinned screen, an
   accordion. The titles stand in a column in grey, 16px apart; the open one is in ink with
   its tagline and copy under it, the grey plate with the mark beside the copy, run out to
   the screen's edge, and --open-air above and below it. A tap opens another (case-points.js:
   the plate goes with it and the mark re-forms, wiping in). */
.cb-points--pinned {
  --open-air: var(--m-4);
  --plate-w: var(--m-plate-w);
  --plate-h: var(--m-plate-h);
  height: auto;
}
.cb-points-panel { position: static; display: block; height: auto; padding-top: 0; }
.cb-points-list { gap: var(--m-2); padding-right: 0; }
.cb-points--pinned .cb-point {
  transition: grid-template-rows var(--dur-accordion) var(--ease-out), margin-top var(--dur-accordion) var(--ease-out);
}
.cb-points--pinned .cb-point.is-active:not(:first-child) { margin-top: calc(var(--open-air) - var(--m-2)); }
/* The titles at the integrations' step (mobile-what.css .list): the longest holds two lines */
.cb-points--pinned .cb-point > .cb-sub {
  font-size: var(--fs-m-list);
  color: var(--muted);
  cursor: pointer;
}
.cb-points--pinned .cb-point.is-active > .cb-sub { color: var(--ink); }
/* The body: the tagline across, then the copy in the left column and the plate in the
   right one, standing at the copy's foot (the copy's rows grow to the plate's height
   when it is the taller). Every body keeps the plate's column, so a copy's lines are the
   same with the plate or without it. Out to the screen's edge, where the plate stands. */
.cb-points--pinned .cb-point-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) calc(var(--plate-w) + var(--cb-x));
  grid-template-rows: auto auto 1fr;
  column-gap: var(--m-2);
  align-content: start;
  max-width: none;
  margin-right: calc(-1 * var(--cb-x));
}
.cb-points--pinned .cb-point-body > * { grid-column: 1; }
.cb-points--pinned .cb-point-body > :first-child { padding-top: var(--m-2); }
.cb-points--pinned .cb-point-body > * + * { margin-top: var(--m-2); }
.cb-points--pinned .cb-point-body > .cb-point-tag { grid-column: 1 / -1; max-width: 30ch; }
.cb-points--pinned .cb-point-body > p:not(.cb-point-tag),
.cb-points--pinned .cb-point-body li { color: var(--ink); }
/* The air under the open entry (the list's gap makes up the rest), clipped with it shut */
.cb-points--pinned .cb-point-body::after {
  content: "";
  grid-column: 1 / -1;
  height: calc(var(--open-air) - var(--m-2));
}
.cb-points--pinned .cb-point-body > .cb-points-plate {
  grid-column: 2;
  grid-row: 2 / 4;
  align-self: end;
  justify-self: stretch;
  width: auto;
  height: var(--plate-h);
  aspect-ratio: auto;
  margin: 0;
}

/* Points that are names only (a service's integrations, case-points.js): no accordion --
   the names in rows under the eyebrow, the picked one in ink, and one plate standing over
   it, the list's own 16px above and below it, as between the names (an open entry's 40px
   round it read as a hole, 19 Oct). A tap on another name glides the plate over it
   (case-points.js), the mark turning on the way */
.cb-points--names .cb-points-list > .cb-points-plate {
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  margin: 0;
}
.cb-points--names .cb-point-body { display: none; }
/* (the move is the glide's: the new places are set at once, measured, and glided to) */
.cb-points--names .cb-point { transition: none; }
.cb-points--names .cb-point.is-active:not(:first-child) { margin-top: 0; }

/* Back to top (js/ui/back-to-top.js): a white disc in the bottom right corner, lit as the
   pills are; it rises in once the hero has gone by (block-rise) */
.to-top {
  position: fixed;
  right: 16px;
  bottom: calc(16px + env(safe-area-inset-bottom));
  z-index: calc(var(--z-menu) - 1); /* under the drawer and the grey */
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 0;
  border-radius: var(--r-round);
  background: var(--white);
  color: var(--ink);
  box-shadow: var(--lift-rest);
  opacity: 0;
  translate: 0 var(--rise-block);
  pointer-events: none;
  transition: opacity var(--dur-slow) ease, translate var(--dur-slow) ease;
}
.to-top.is-on { opacity: 1; translate: 0 0; pointer-events: auto; }
.to-top svg {
  width: 24px; /* = its viewBox: the 2px stroke falls on whole pixels */
  height: 24px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2; /* = the service disc's plus */
  stroke-linecap: butt; /* square-ended, as every line on the site */
  stroke-linejoin: miter;
}
@media (prefers-reduced-motion: reduce) {
  .to-top { transition: none; }
}
