/* The palette, light and dark. Every colour on the site is a variable from
   this file; the pages carry no hex of their own beyond white image
   backgrounds and black mask stops.

   Lives at the site root, not in /assets/, because netlify.toml caches
   /assets/* for a year. Cloudflare Pages ignores that file, but a Netlify
   deploy would pin an old palette in returning visitors' browsers.

   Light is the white stock palette: the style tile's primaries on near white,
   with neutral greys replacing the warm ones. Dark swaps ink and paper and
   brightens every accent used as text, because the light values fail on
   #141414. Fills keep their hue; red, blue and olive are lifted so a shape
   still separates from the page.

   The -text accents are the README's "darker than the tile" values in light
   and brighter than the tile in dark. Contrast for every pairing is listed in
   the README; re-measure after any change here. */

:root {
  color-scheme: light;
  --paper: #FAFAF8;
  --paper-glass: rgba(250,250,248,.70);
  --card: #FFFFFF;
  --well: #EEEEEB;
  --ink: #141414;
  --ink-2: #2A2A2C;
  --muted: #55565A;
  --muted-2: #6A6B6F;
  --rule: #D0D0CC;
  --rule-strong: #B4B4B0;
  --track: #C6C6C3;
  --scrim: rgba(10,10,10,.78);

  --red: #D2301C;
  --red-text: #B93312;
  --red-kicker: #C22C1A;
  --red-deep: #AD2F10;
  --blue: #1E52C4;
  --blue-text: #1A46A8;
  --yellow: #EFA71C;
  --on-yellow: #141414;
  --ochre-text: #8A5E10;
  --ochre-deep: #82580F;
  --olive: #6E7024;
  --olive-text: #656721;
  --pink: #DA92A6;
  --purple: #33268C;

  /* Active section tab in each case study's nav, accent at 14% over white. */
  --tint-red: #F9E2DF;
  --tint-blue: #DFE7F7;
  --tint-gold: #FDF3DF;
  --tint-olive: #EBEBE0;

  --orange: #E8641B;
  --orange-text: #CC5214;

  /* A case study cover's colour field, its text, and the number block. Set
     once and not redefined for dark: the field is a printed colour, not a
     surface, so it stays the tile colour on either page. Text on the field:
     #FAFAF8 on red 4.8074, on blue 6.5685, on olive 5.0159; yellow takes ink,
     8.9607 (near white on it would be 1.9673). */
  --field-red: #D2301C;
  --field-blue: #1E52C4;
  --field-yellow: #EFA71C;
  --field-olive: #6E7024;
  --on-field: #FAFAF8;
  --on-field-yellow: #141414;
  --field-block: #141414;
  /* The numeral in the block is the case colour at its dark page value, the
     one the site already uses on near black: the tile blue is 2.6837 on
     #141414 and fails even at display size. Red 4.6262, blue 5.6111, yellow
     8.9607, olive 5.2022. */
  --num-red: #E8432E;
  --num-blue: #5B8BF0;
  --num-yellow: #EFA71C;
  --num-olive: #8A8D2E;

  /* The homepage "Get in touch" band: an ink panel in light, a raised dark
     panel in dark. It has its own set because the page values are tuned for
     the page, and --ink/--paper would invert it into a light block. */
  --band-bg: #141414;
  --band-fg: #FAFAF8;
  --band-rule: #55565A;
  --band-accent: #EFA71C;
  --band-edge: transparent;
}

/* Headings balance their lines and paragraphs avoid ending on one word. Count
   ups use tabular figures, so a number doesn't change width while it climbs. */
h1, h2, h3, h4 { text-wrap: balance; }
/* Set on main as well, because it inherits: figure labels, stat labels and
   card titles are divs, and they were ending on one word. */
main, p, li, blockquote, figcaption { text-wrap: pretty; }
/* Short labels that wrap to two lines balance instead: pretty can't stop a
   three word title ending on one word. */
.doc-cover-title, .doc-cover-kicker, .next-card-kicker, .study p:first-child,
.evidence-grid button > div > div:nth-child(2) { text-wrap: balance; }
[data-count] { font-variant-numeric: tabular-nums; }
/* Callout text is Jost 500 or 600, so the 600 its bold phrases carry from the
   body text barely registers. */
.callout b { font-weight: 800 !important; }

/* Dark is for screens, so every dark block in this file is screen only and
   paper always gets the light palette above. Printed in dark, a case study
   came out as eight solid black pages, background graphics on or off. */
@media screen {
  :root[data-theme="dark"] {
    color-scheme: dark;
    --paper: #141414;
    --paper-glass: rgba(20,20,20,.72);
    --card: #1E1E1E;
    --well: #262626;
    --ink: #ECECE8;
    --ink-2: #CFCFCB;
    --muted: #A3A3A0;
    --muted-2: #999996;
    --rule: #3A3A3A;
    --rule-strong: #5A5A5A;
    --track: #4A4A4A;
    --scrim: rgba(0,0,0,.82);

    --red: #E8432E;
    --red-text: #F06A55;
    --red-kicker: #F06A55;
    --red-deep: #F06A55;
    --blue: #5B8BF0;
    --blue-text: #7FA3F5;
    --yellow: #EFA71C;
    --on-yellow: #141414;
    --ochre-text: #EFA71C;
    --ochre-deep: #EFA71C;
    --olive: #8A8D2E;
    --olive-text: #A9B54A;
    --pink: #DA92A6;
    --purple: #6A5AE0;

    --tint-red: #361C18;
    --tint-blue: #1F2737;
    --tint-gold: #372C15;
    --tint-olive: #292A1A;

    --orange: #E8641B;
    --orange-text: #E8641B;

    --band-bg: #1E1E1E;
    --band-fg: #ECECE8;
    --band-rule: #5A5A5A;
    --band-accent: #EFA71C;
    --band-edge: #3A3A3A;
  }
}

/* No stored choice: follow the system. theme.js sets data-theme only when
   the visitor has used the toggle, so this block and the one above hold the
   same values and must be edited together. */
@media screen and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --paper: #141414;
    --paper-glass: rgba(20,20,20,.72);
    --card: #1E1E1E;
    --well: #262626;
    --ink: #ECECE8;
    --ink-2: #CFCFCB;
    --muted: #A3A3A0;
    --muted-2: #999996;
    --rule: #3A3A3A;
    --rule-strong: #5A5A5A;
    --track: #4A4A4A;
    --scrim: rgba(0,0,0,.82);

    --red: #E8432E;
    --red-text: #F06A55;
    --red-kicker: #F06A55;
    --red-deep: #F06A55;
    --blue: #5B8BF0;
    --blue-text: #7FA3F5;
    --yellow: #EFA71C;
    --on-yellow: #141414;
    --ochre-text: #EFA71C;
    --ochre-deep: #EFA71C;
    --olive: #8A8D2E;
    --olive-text: #A9B54A;
    --pink: #DA92A6;
    --purple: #6A5AE0;

    --tint-red: #361C18;
    --tint-blue: #1F2737;
    --tint-gold: #372C15;
    --tint-olive: #292A1A;

    --orange: #E8641B;
    --orange-text: #E8641B;

    --band-bg: #1E1E1E;
    --band-fg: #ECECE8;
    --band-rule: #5A5A5A;
    --band-accent: #EFA71C;
    --band-edge: #3A3A3A;
  }
}

/* In dark, the homepage poster's ink is cream instead of the page's
   neutral white, frame and grid lines included, so it reads as a printed
   object on black. Scoped by redefining --ink on .poster: every inline
   var(--ink) inside it follows.

   Headings take the same cream so the hero headline matches the poster
   beside it, and every page follows the same rule. Everything read or
   clicked (body text, nav, labels, rules) stays neutral, which keeps cream
   an accent. Dark only: in light the "Get in touch" heading inherits paper
   from its ink band, and a heading colour would override that. */
@media screen {
  :root[data-theme="dark"] .poster { --ink: #EDE6D3; }
  :root[data-theme="dark"] :is(h1, h2, h3, h4, h5, h6) { color: #EDE6D3; }
}
@media screen and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .poster { --ink: #EDE6D3; }
  :root:not([data-theme="light"]) :is(h1, h2, h3, h4, h5, h6) { color: #EDE6D3; }
}

/* The robot and person icons are black line art on transparent PNGs. */
@media screen {
  :root[data-theme="dark"] img[src$="robot.png"],
  :root[data-theme="dark"] img[src$="person.png"] { filter: invert(.93); }
}
@media screen and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) img[src$="robot.png"],
  :root:not([data-theme="light"]) img[src$="person.png"] { filter: invert(.93); }
}

/* Theme toggle. A circle half filled with ink: the filled half swaps sides
   with the theme. 44px tap target around a 16px mark, pulled back into the
   bar with negative margins so it doesn't change the topbar's height. */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  flex: none; width: 44px; height: 44px; margin: -13px -12px -13px -6px;
  padding: 0; border: 0; background: transparent; color: var(--ink);
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.theme-toggle:hover { color: var(--red-text); }
.theme-toggle-mark {
  display: block; width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid currentColor;
  background: linear-gradient(90deg, currentColor 50%, transparent 50%);
  transition: transform .3s ease;
}
:root[data-theme="dark"] .theme-toggle-mark { transform: rotate(180deg); }
@media screen and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle-mark { transform: rotate(180deg); }
}
@media (prefers-reduced-motion: reduce) {
  .theme-toggle-mark { transition: none; }
}

/* Theme wipe. theme.js grows the new theme out of the mark as a circle on
   ::view-transition-new(root); these rules apply to that transition only,
   via its "theme" type. The default cross fade is off, and so is the UA's
   plus-lighter blend, which would add the two themes together inside the
   circle. Named elements are folded back into the root snapshot so nothing
   fades on its own across the edge. */
:root:active-view-transition-type(theme)::view-transition-old(root),
:root:active-view-transition-type(theme)::view-transition-new(root) {
  animation: none; mix-blend-mode: normal;
}
:root:active-view-transition-type(theme) * { view-transition-name: none !important; }
/* Hit testing stops for the length of a transition, so :hover drops and
   the mark went from red to ink and back under a still pointer. Held red
   when a pointer pressed it. */
:root:active-view-transition-type(theme-hover) .theme-toggle { color: var(--red-text); }

/* In dark the band is a raised panel only 1.1:1 off the page, so it gets an
   edge. Inset, so the box doesn't grow; transparent in light. */
.contact-bar { box-shadow: inset 0 0 0 2px var(--band-edge); }

/* Keyboard focus. One ring for every control on every page, replacing
   Chrome's blue default. Ink, because it clears every surface a control sits
   on in both themes, including the translucent header and jump bar whatever
   is scrolled under them; red fails there. :focus-visible only, so a mouse
   click doesn't draw it. The 2px offset leaves a strip of background between
   ring and control, so the ring never touches a control's own ink border or
   red fill and only has to contrast with what's behind it. */
:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
/* The band is ink in light, so its links take the band's own foreground. */
.contact-bar :focus-visible { outline-color: var(--band-fg); }
/* Inset where an outset ring would be cut off. The section nav scrolls
   sideways, so it clips anything outside its own box. The toggle's 44px
   target is mostly empty, so its ring hugs the mark. */
.cs-secnav a:focus-visible { outline-offset: -2px; }
/* The active section's tint is only 1.05 to 1.35:1 against the header, so
   a 2px bar in the link's own colour marks it too. It steps aside while
   the tint glides, like the link's background, and lands with the colour. */
.cs-secnav a[aria-current] { box-shadow: inset 0 -2px 0 currentColor; }
.cs-secnav[data-gliding] a { box-shadow: none; }
.theme-toggle:focus-visible { outline-offset: -6px; }
/* The homepage's header links are 45px tap targets around 18px of text,
   pulled into the bar with negative margins, so an outset ring ran off the
   top of the window and onto the header's bottom rule. Inset vertically,
   on ::after because an outline takes one offset for all four sides. */
.topbar-nav a { position: relative; }
.topbar-nav a:focus-visible { outline: none; }
.topbar-nav a:focus-visible::after { content: ''; position: absolute; inset: 6px -6px;
  border: 2px solid var(--ink); pointer-events: none; }
/* Above 900px the case cards are bands stacked rule to rule, so an outset
   ring's bottom edge landed on the next card's rule and vanished into it.
   Pulled up clear of that rule. Below 900px they are boxed with a gap
   between, and the plain outline works. */
@media (width > 900px) {
  .case-card { position: relative; }
  .case-card:focus-visible { outline: none; }
  .case-card:focus-visible::after { content: ''; position: absolute; inset: -8px -12px 6px;
    border: 2px solid var(--ink); pointer-events: none; }
}
/* The jump bar's links fill it top to bottom, between an ink rule and the
   bottom of the window, so the ring has to sit inside them vertically. Not
   sideways: their arrows sit right on their outer edges. An outline can't
   take a different offset per side, so the ring is drawn on ::after. The
   forward link's left edge is the back link's text, so it insets there. */
.jumpbar a { position: relative; }
.jumpbar a:focus-visible { outline: none; }
.jumpbar a:focus-visible::after { content: ''; position: absolute; inset: 4px -6px;
  border: 2px solid var(--ink); pointer-events: none; }
.jumpbar a.jump-next:focus-visible::after { left: 4px; }
/* Tabbing scrolls the next control only just into view, which on these
   pages puts it under the sticky header going up, and under a case study's
   jump bar going down. The margins clear both, ring included. */
main :is(a[href], button, input) { scroll-margin: 88px 0 64px; }
/* The jump bar slides off screen when it isn't wanted, but its links stayed
   in the tab order, so tabbing past the pager put focus where nobody could
   see it. Hidden once the slide out has finished. */
.jumpbar:not([data-show]) { visibility: hidden; transition: transform .22s ease, visibility 0s linear .22s; }
/* The skip link's target. It takes focus so the next Tab starts there, not
   to be operated, and a ring round the whole page says nothing. */
main[tabindex="-1"]:focus-visible { outline: none; }

/* Scroll reveal. Only figures, metric rows and the homepage's case card
   graphics carry data-rv. Headings and paragraphs are never held back: text
   that fades in is text the reader waits for. The fade follows the scroll
   position, not a timer, so nothing is left hidden: jump past a figure, stop
   anywhere or print, and it is there. Visible is the default. The fade needs
   a screen, scroll driven animations and no reduced motion setting, and it
   is over 140px after the figure's top edge clears the bottom of the window.
   translate, not transform, so it stacks with the cards' own hover nudge.
   data-motion="off" is set by the component's motion prop. */
@keyframes rv-in { from { opacity: 0; translate: 0 14px; } }
@supports (animation-timeline: view()) {
  @media screen and (prefers-reduced-motion: no-preference) {
    :root:not([data-motion="off"]) [data-rv] {
      animation: rv-in ease-out both;
      animation-timeline: view();
      animation-range: entry 0% entry 140px;
    }
  }
}
/* Bars, count ups and the gauge wait at their start until their figure is
   in view: each page's script sets data-pend, then plays them once. Screen
   only, so a printout never shows an empty chart, and the script settles
   anything still moving on beforeprint. */
@media screen {
  [data-grow-x][data-pend] { transform: scaleX(0); }
  [data-grow][data-pend] { transform: scaleY(0); }
  [data-grow-head][data-pend] { transform: translateX(var(--grow-from, 0px)); }
  [data-dot][data-pend] { transform: scale(0); }
  [data-count][data-pend] { opacity: 0; }
  [data-gauge][data-pend] { background: conic-gradient(from 270deg, var(--track) 0deg 180deg, rgba(0,0,0,0) 180deg 360deg) !important; }
}
/* Case study reading progress. A scroll timeline on the root scroller runs
   it on the compositor, and scaleX keeps it off layout, where the old width
   write on every scroll event put it. The page script's scroll listener is
   only the fallback for browsers without scroll timelines. */
@keyframes progress-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@supports (animation-timeline: scroll()) {
  [data-progress] { animation: progress-grow linear both; animation-timeline: scroll(root); }
}

/* Page transitions. transitions.js opts each page in, decides what pairs
   up, and gives every page transition the "page" type; this is how it
   moves. The wildcard and root rules are scoped to that type so none of
   them reach the theme wipe. */
:root:active-view-transition-type(page)::view-transition-group(*) {
  animation-duration: .44s; animation-timing-function: cubic-bezier(.2,.8,.2,1);
}
:root:active-view-transition-type(page)::view-transition-old(root),
:root:active-view-transition-type(page)::view-transition-new(root) { animation-duration: .3s; }
/* The badge grows into the cover's number block, which has the badge's
   shape: both images stretch to fill the box as it grows, and the pair is
   clipped to that shape the whole way (--vt-badge and --vt-bar are the
   same; the names are from when the cover end was a flat bar). The block is
   black and large, so its colour changes quickly in both directions: on a
   slow close it sat black over the card's kicker, and on the dark page it
   vanished into the page. The 01 badge is square and needs no clip. The
   clip is on the image pair, not on an image: on an image, Chrome left the
   top and left edges of the box unclipped, a 1px line for most of the
   morph. Each pair of fades shares one timing, so the two add up to the
   full colour. */
::view-transition-old(case-mark), ::view-transition-new(case-mark) { height: 100%;
  mix-blend-mode: plus-lighter; }
:root:active-view-transition-type(measuring-success) { --vt-badge: inset(0 round 50%); --vt-bar: inset(0 round 50%); }
:root:active-view-transition-type(ai-research-ops) { --vt-badge: polygon(50% 0, 50% 0, 100% 100%, 0 100%); --vt-bar: polygon(50% 0, 50% 0, 100% 100%, 0 100%); }
:root:active-view-transition-type(research-enablement) { --vt-badge: inset(0 round 50% 50% 50% 0); --vt-bar: inset(0 round 50% 50% 50% 0); }
:root:active-view-transition-type(case-open)::view-transition-image-pair(case-mark) { animation: .44s cubic-bezier(.2,.8,.2,1) both vt-unclip; }
:root:active-view-transition-type(case-open)::view-transition-old(case-mark) { animation: .08s both vt-fade-out; }
:root:active-view-transition-type(case-open)::view-transition-new(case-mark) { animation: .08s both vt-fade-in; }
:root:active-view-transition-type(case-close)::view-transition-image-pair(case-mark) { animation: .44s cubic-bezier(.2,.8,.2,1) both vt-clip; }
:root:active-view-transition-type(case-close)::view-transition-old(case-mark) { animation: .1s .04s both vt-fade-out; }
:root:active-view-transition-type(case-close)::view-transition-new(case-mark) { animation: .1s .04s both vt-fade-in; }
/* A half with no partner (the card is off screen when the other page
   reveals) fades on its own, quickly, instead of lingering for the group's
   .44s where it was left. */
:root:active-view-transition-type(page)::view-transition-old(case-mark):only-child { animation: .15s both vt-fade-out; }
:root:active-view-transition-type(page)::view-transition-new(case-mark):only-child { animation: .15s both vt-fade-in; }
@keyframes vt-unclip { from { clip-path: var(--vt-badge, none); } to { clip-path: var(--vt-bar, none); } }
@keyframes vt-clip { from { clip-path: var(--vt-bar, none); } to { clip-path: var(--vt-badge, none); } }
/* The title wraps differently at each size, so the old and new lines can't
   line up while both show. The new one starts as the old one finishes. */
::view-transition-old(case-title) { animation: .07s ease-in both vt-fade-out; }
::view-transition-new(case-title) { animation: .2s ease-out .07s both vt-fade-in; }
/* Between case studies the page slides and the header holds still. The
   outgoing page leaves faster than the incoming one arrives, so the two are
   never both half there. */
:root:active-view-transition-type(slide-forward)::view-transition-old(root) {
  animation: .16s cubic-bezier(.4,0,1,1) both vt-fade-out, .36s cubic-bezier(.4,0,.2,1) both vt-to-left; }
:root:active-view-transition-type(slide-forward)::view-transition-new(root) {
  animation: .28s cubic-bezier(0,0,.2,1) .08s both vt-fade-in, .36s cubic-bezier(.2,.8,.2,1) both vt-from-right; }
:root:active-view-transition-type(slide-back)::view-transition-old(root) {
  animation: .16s cubic-bezier(.4,0,1,1) both vt-fade-out, .36s cubic-bezier(.4,0,.2,1) both vt-to-right; }
:root:active-view-transition-type(slide-back)::view-transition-new(root) {
  animation: .28s cubic-bezier(0,0,.2,1) .08s both vt-fade-in, .36s cubic-bezier(.2,.8,.2,1) both vt-from-left; }
@keyframes vt-fade-out { to { opacity: 0; } }
@keyframes vt-fade-in { from { opacity: 0; } }
@keyframes vt-to-left { to { transform: translateX(-80px); } }
@keyframes vt-to-right { to { transform: translateX(80px); } }
@keyframes vt-from-right { from { transform: translateX(80px); } }
@keyframes vt-from-left { from { transform: translateX(-80px); } }

/* Until the runtime boots, a case study is its raw template, and the
   viewer's fixed layer, invisible but still taking clicks, covers all of
   it. <x-dc> is gone once the page boots, so this only ever matches a
   page whose script failed to load. */
x-dc .viewer, x-dc .viewer-scrim { display: none !important; }

/* Print, and Save as PDF. The screen furniture goes: header nav and theme
   toggle, progress bar, jump bar, artifact viewer. The header itself stays,
   unstuck, as a masthead, so every printout carries the name. support.js's
   print baseline already prints background colours (the figures are drawn
   with them) and runs transitions to their end. The colour and animation
   lines here repeat that for content, so a printout showing every figure
   doesn't rest on a vendored runtime. */
@media print {
  header { position: static !important; background: none !important;
    -webkit-backdrop-filter: none !important; backdrop-filter: none !important; }
  .topbar-nav, .cs-secnav, .theme-toggle, [data-progress], .jumpbar, .skip-link,
  .skip-to-work, [role="dialog"], header svg { display: none !important; }
  /* The pager and next case card are links, which do nothing on paper. After
     the 7 October reflection paragraphs the card broke across a page on Trust
     and Measuring Success and cost each a ninth page. */
  .pager, .next-card { display: none !important; }
  /* The artifact viewer locks scrolling on body while open. */
  body { overflow: visible !important; }
  main { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  [data-rv], [data-grow], [data-grow-x], [data-grow-head], [data-dot] { animation: none !important; transition: none !important; }
  /* Figures, metric rows, artifact cards and the homepage's case cards stay
     whole. */
  .fig, [role="img"], .metric-3, .finding-grid > *, button[data-artifact],
  .case-card, .snap-stats, .callout,
  [data-screen-label="Contact"] { break-inside: avoid; }
  /* A study's title and its meta line go with the first lines of its text. */
  .study p:first-child, .study p:nth-child(2) { break-after: avoid; }
  /* A section label sits inside its h2 (on the Trust page, in the rail just
     before it), so the h2 has to stay whole, and the rail stay with it, or the
     label is stranded at the foot of a page. */
  h2, h3 { break-after: avoid; break-inside: avoid; }
  /* The Snapshot lead and the callouts are set large for a screen. On paper
     that cost the Trust case study a ninth page holding only its footer. */
  .snap-lead { font-size: 18px !important; }
  /* The footer line's screen padding did it again after the October
     headline pass, so it closes up on paper too. */
  main footer p { padding: 16px 0 0 !important; }
  /* A cover's colour field prints as an ordinary cover: ink on paper, no
     block. Printed solid it was most of a page of red, and with background
     graphics off its white title would vanish. */
  /* main raises these over the page's own !important rules at 980px, which a
     sheet's width also matches and which come later in the cascade. */
  main .cs-field { background: none !important; color: var(--ink) !important;
    margin: 0 !important; padding: 8px 0 0 !important; min-height: 0 !important; }
  main .cs-field h1, main .cs-field p { color: var(--ink) !important; }
  /* On paper the headline keeps its old 1.06. The screen's 1.1 grew AI
     Research Ops' cover 6px and pushed its Problem section to page 2,
     costing a seventh page. */
  main .cs-field h1 { line-height: 1.06 !important; }
  /* The kicker bar prints in the case colour, which each field names. */
  main .cs-field p > span { background: var(--cs-kick, var(--red)) !important; }
  main .cs-num { display: none !important; }
  .cs-rail { position: static !important; break-after: avoid; }
  .callout > p:last-child { font-size: 19px !important; }
  /* A sheet is 760 to 780px wide, so the homepage's phone layer applies and
     each case card stacks its graphic under its text: whole, only one fitted
     on a page. Side by side, as on a desktop, two do. main raises the
     specificity over the page's own !important phone rules. */
  main .case-card { grid-template-columns: 1fr 300px !important; gap: 28px !important; }
  main .case-aside { border-top: 0 !important; padding-top: 0 !important;
    border-left: 2px solid var(--ink) !important; padding-left: 24px !important; }
}
