/* =============================================================================
   pages-2026.css -- the ONE shared stylesheet for the 2026 marketing pages.
   =============================================================================

   WHY THIS FILE EXISTS
   --------------------
   homepage.css (248 KB / 1354 classes), glp-1.2019.css (252 KB / 1321) and
   iPhone.2019.css (239 KB) are one design copied three times; 1268 class names
   are shared between the first two. Every new page used to add a fourth copy.
   This file is the single destination instead.

   IT MUST COVER THE WHOLE PAGE, NOT JUST THE BODY BLOCKS
   ------------------------------------------------------
   A page that swaps homepage.css for this file loses EVERYTHING homepage.css was
   supplying -- not only the sections you wrote, but the header, the navbar, the
   footer, the sticky banner, and the bootstrap utility classes. The first version
   of this file covered body blocks only, and the page rendered with its
   navigation as an unstyled bulleted list. 68 rendered classes had no rule, and
   the class-coverage check passed anyway, because it compared the TEMPLATE
   against the CSS and the template never mentions what `$sticky_header()$` or
   `$footer_2019()$` emit.

   So the block list is GENERATED FROM THE RENDERED PAGE, not from source:

     curl -k -s https://localminder/iPhone.html \
       | grep -oE 'class="[^"]*"' | sed 's/class="//;s/"//' | tr ' ' '\n' | sort -u

   then keep what homepage.css defines, minus what a component's own stylesheet
   already covers. `footer_updates.st` loads `footer-2026.css` itself, so those 9
   classes are deliberately NOT duplicated here.

   Where that link actually sits, because it is not where you would guess:
   `</head>` closes at rendered line 275, and the `footer-2026.css` link is at
   rendered line **1301** -- injected mid-body by the component, not in the head.
   (An earlier version of this comment claimed it was in the `<head>`; wM:p4
   caught that.) index does the same thing, so it is pre-existing and shared, not
   something this page introduced. It works, but it is a render-blocking
   stylesheet discovered late in the document, which is a real if minor
   performance smell. Not ours to fix here -- it belongs to the footer component.

   The list lives in tickets/SRV-4560/blocks.txt. Regenerate it; do not hand-edit.

   THIS FILE IS NOW THE SOURCE OF TRUTH. DO NOT REGENERATE IT.
   -----------------------------------------------------------
   It was produced twice by an ad-hoc generator: once to bootstrap it, and once to
   rebuild it after the header/navbar/footer were found unstyled. **Both
   generations are done.** From here the file is edited in place, by appending.

   This is not a stylistic preference, it is the append gate in rule 2 applied to
   the file itself, and it is enforced by having been violated twice in one day:

     - The second generation silently reverted a hand-written defect fix in the
       ADDITIONS section, because the generator read its own copy of that section
       from elsewhere. Caught only by grepping for the fix afterwards.
     - The generator's header text also lived only inside the generator, so a
       correction made here -- to a claim about where the footer stylesheet link
       sits -- would have been regenerated away next run.

   Anything that regenerates this file wholesale will lose every hand edit in it,
   and this header and the ADDITIONS section are nothing but hand edits. If a
   future page needs blocks that are not here, APPEND them (rule 2). If you truly
   must regenerate, diff the result against this file first and expect to lose
   work.

   HOW TO CHANGE IT -- READ BEFORE EDITING
   ---------------------------------------
   1. There is exactly ONE of these files, repo-wide. Do not fork it per page.
   2. A new page APPENDS only what is not already present, under its own dated
      section comment. It never re-extracts the whole thing.
   3. A block that needs CHANGING rather than adding is not an append. Stop and
      take it to the design owner -- a change here affects every shipped page.
   4. No selector may appear twice in the same @media context, and no selector may
      OVERRIDE another with a different value undeclared. Run:
         scripts/assert-no-duplicate-selectors.py \
             --exceptions tickets/SRV-4560/exceptions.txt \
             src/minderweb/css/pages-2026.css
      Known intentional exceptions are declared there, including `a` / `a:hover`,
      which are duplicated in homepage.css itself (lines 112/116 from the
      normalize reset, then 5212/5216 from the 2026 base) with identical bodies.
      Both are kept: dropping either changes source order, and source order is
      what resolves equal-specificity rules.
   5. Verify coverage against the RENDERED page, never the template:
         scripts/assert-class-coverage.py --rendered <url-or-file> ...
   6. The old sheets are FROZEN. Do not edit them to make this file work.
   7. This file is NOT self-sufficient. The FAQ accordion is JS-driven, so a page
      using it must include $cmp_script(src="mnt-faq.2019")$. A page adding the
      feature-slider block must also add $cmp_script(src="mnt-carousel")$.

   =============================================================================
   APPEND LOG
   =============================================================================
   2026-08-27  SRV-4560  /iPhone.html  created the file. Body blocks only.
   2026-08-27  SRV-4560  /iPhone.html  REBUILT from the rendered class list after
                                       the header/footer/navbar were found
                                       unstyled: 281 -> 483 rules.
   2026-08-27  SRV-4560  /iPhone.html  APPEND +7: runtime-injected state classes
                                       (.slideout-open et al). Mobile nav opened
                                       nothing. First real use of the append gate.
   2026-08-27  SRV-4560  /iPhone.html  APPEND: review-card, after the pending-art
                                       stubs reinstated the four review cards.
                                       Caught by rendered coverage, pre-review.
   2026-08-27  SRV-4560  /iPhone.html  APPEND +4: .container (REGRESSION -- the
                                       rebuild's subtraction wrongly treated a
                                       descendant selector as a definition) and a
                                       hero text-contrast fix.
   ============================================================================= */


/* =============================================================================
   SRV-4560 -- EXTRACTED FROM homepage.css                      483 rules
   -----------------------------------------------------------------------------
   ONE extraction pass, blocks and elements together, source order preserved.
   Not two passes concatenated: CSS resolves equal-specificity rules by source
   order, so splitting the extraction and gluing the halves reorders rules against
   the source and silently changes what renders.

   THE BASE LAYER IS NOT OPTIONAL. Element and pseudo-class rules cannot be
   reached by any block name, yet every block depends on them. The one that
   matters most is `html { font-size: 10px }` (homepage.css:5015): this design is
   authored in rem against a 10px root, so `font-size: 2rem` means 20px, not 32px.
   Omit it and the page renders ~1.6x too large with every breakpoint firing at
   the wrong content width.

   @keyframes are scoped to those actually referenced by a kept rule.
   `logo-marquee-scroll` is dropped for that reason: it belongs to `.logo-marquee`
   (homepage.css:11528), which index nests inside its device-sync section
   (static_index.st:1385), and its `var(--marquee-distance)` is set at runtime by
   the inline script at static_index.st:1817-1833. Carrying it would leave an
   orphaned animation that silently does nothing.

   Elements requested (30):
      html body h1 h2 h3 h4 h5 h6 p a ul ol li img figure figcaption dl dt dd table
      caption th td details summary button svg * :root [hidden]

   Blocks requested (109) -- generated, see tickets/SRV-4560/blocks.txt:
      __item _buttons _get-link _heading _logo _section _stats _stats--trustpilot _stores
      ai-card ai-card__list ai-card__title ai-features ai-features__header
      ai-features__intro ai-features__title ai-features__wrapper align-items-center
      app-stats app-stats__rating app-stats__title banner-sticky banner-sticky__direct
      banner-sticky__dismiss banner-sticky__icon btn btn-primary btn-secondary
      btn-tertiary collapse collapsed comparison-cta comparison-cta__store-link
      comparison-cta__stores comparison-section comparison-section__note
      comparison-section__title comparison-table comparison-table-wrap
      comparison-table__caption comparison-table__col comparison-table__col--feature
      comparison-table__head comparison-table__mark comparison-table__mark--no
      comparison-table__mark--yes comparison-table__note comparison-table__row-title
      copyright copyright__links copyright__text d-block d-flex d-md-flex
      d-md-inline-block d-md-none d-none d-sm-none device-sync device-sync__title
      dropdown dropdown-menu fade faq-item faq-item__content faq-item__content-inner
      faq-item__icon faq-item__question faq-item__summary faq-section faq-section__list
      faq-section__title flex-row footer-site footer-site__scores h6 has-sticky-header
      hero hero__content hero__media hero__subtitle hero__title img-fluid list-share
      ml-auto mr-2 mr-auto nav-item nav-link navbar navbar-brand navbar-collapse
      navbar-expand-md navbar-nav navbar-nav-site navbar-site navbar-subnav
      navbar-subnav_no-bullets navbar-toggler navbar-toggler-icon page-section
      section-insights section-insights__wrapper section-start slideout-menu
      stretched-link text-truncate trustpilot-widget w-100

   Provenance: src/minderweb/css/homepage.css, md5 3a40e61733fc2296a2d97d9342a48ff6
               scripts/extract-css-blocks.py --blocks-file tickets/SRV-4560/blocks.txt \
                   --elements-file tickets/SRV-4560/elements.txt --keyframes
   ============================================================================= */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  font-family: sans-serif;
  line-height: 1.15;
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

article,
aside,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section {
  display: block;
}

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.5;
  color: #212529;
  text-align: left;
  background-color: #fff;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  margin-top: 0;
  margin-bottom: 0.5rem;
}

p {
  margin-top: 0;
  margin-bottom: 1rem;
}

ol,
ul,
dl {
  margin-top: 0;
  margin-bottom: 1rem;
}

ol ol,
ul ul,
ol ul,
ul ol {
  margin-bottom: 0;
}

dt {
  font-weight: 700;
}

dd {
  margin-bottom: 0.5rem;
  margin-left: 0;
}

a {
  text-decoration: none;
  background-color: transparent;
}

a:hover {
  text-decoration: underline;
}

a:not([href]):not([tabindex]) {
  color: inherit;
  text-decoration: none;
}

a:not([href]):not([tabindex]):hover,
a:not([href]):not([tabindex]):focus {
  color: inherit;
  text-decoration: none;
}

a:not([href]):not([tabindex]):focus {
  outline: 0;
}

figure {
  margin: 0 0 1rem;
}

img {
  vertical-align: middle;
  border-style: none;
}

svg {
  overflow: hidden;
  vertical-align: middle;
}

table {
  border-collapse: collapse;
}

caption {
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
  color: #6c757d;
  text-align: left;
  caption-side: bottom;
}

th {
  text-align: inherit;
}

button {
  border-radius: 0;
}

button:focus {
  outline: 1px dotted;
  outline: 5px auto -webkit-focus-ring-color;
}

input,
button,
select,
optgroup,
textarea {
  margin: 0;
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
}

button,
input {
  overflow: visible;
}

button,
select {
  text-transform: none;
}

button,
[type="button"],
[type="reset"],
[type="submit"] {
  -webkit-appearance: button;
}

button:not(:disabled),
[type="button"]:not(:disabled),
[type="reset"]:not(:disabled),
[type="submit"]:not(:disabled) {
  cursor: pointer;
}

button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
  padding: 0;
  border-style: none;
}

summary {
  display: list-item;
  cursor: pointer;
}

[hidden] {
  display: none !important;
}

@font-face {
  font-family: "Inter";
  src: url("../fonts/InterVariable.woff2") format("woff2");
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
}

:root {
  --font-desktop: "Inter",
        -apple-system,
        BlinkMacSystemFont,
        "Segoe UI",
        Roboto,
        "Helvetica Neue",
        Arial,
        sans-serif;
  --font-ios: -apple-system,
        BlinkMacSystemFont,
        "Helvetica Neue",
        Arial,
        sans-serif;
  --font-android: Roboto,
        "Noto Sans",
        "Helvetica Neue",
        Arial,
        sans-serif;
  --font-default: "Segoe UI",
        Roboto,
        "Helvetica Neue",
        Arial,
        sans-serif;
  --app-font: var(--font-default);
}

html.platform-ios {
  --app-font: var(--font-ios);
}

html.platform-android {
  --app-font: var(--font-android);
}

html.platform-desktop {
  --app-font: var(--font-desktop);
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--app-font);
  text-rendering: optimizeLegibility;
}

html {
  box-sizing: border-box;
  -ms-overflow-style: scrollbar;
}

*,
*::before,
*::after {
  box-sizing: inherit;
}

.nav-link {
  display: block;
  padding: 0.5rem 1rem;
}

.nav-link:hover,
.nav-link:focus {
  text-decoration: none;
}

.nav-link.disabled {
  color: #6c757d;
  pointer-events: none;
  cursor: default;
}

.navbar {
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  -ms-flex-wrap: wrap;
  -webkit-flex-wrap: wrap;
  flex-wrap: wrap;
  -ms-flex-align: center;
  -webkit-align-items: center;
  align-items: center;
  -ms-flex-pack: justify;
  -webkit-justify-content: space-between;
  justify-content: space-between;
  position: relative;
  padding: 0.5rem 1rem;
}

.navbar > .container,
.navbar > .container-fluid {
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  -ms-flex-wrap: wrap;
  -webkit-flex-wrap: wrap;
  flex-wrap: wrap;
  -ms-flex-align: center;
  -webkit-align-items: center;
  align-items: center;
  -ms-flex-pack: justify;
  -webkit-justify-content: space-between;
  justify-content: space-between;
}

.navbar-brand {
  display: inline-block;
  padding-top: 0.3125rem;
  padding-bottom: 0.3125rem;
  margin-right: 1rem;
  font-size: 1.25rem;
  line-height: inherit;
  white-space: nowrap;
}

.navbar-brand:hover,
.navbar-brand:focus {
  text-decoration: none;
}

.navbar-nav {
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  -ms-flex-direction: column;
  -webkit-flex-direction: column;
  flex-direction: column;
  padding-left: 0;
  margin-bottom: 0;
  list-style: none;
}

.navbar-nav .nav-link {
  padding-right: 0;
  padding-left: 0;
}

.navbar-nav .dropdown-menu {
  position: static;
  float: none;
}

.navbar-collapse {
  -ms-flex-preferred-size: 100%;
  flex-basis: 100%;
  -ms-flex-positive: 1;
  flex-grow: 1;
  -ms-flex-align: center;
  -webkit-align-items: center;
  align-items: center;
}

.navbar-toggler {
  padding: 0.25rem 0.75rem;
  font-size: 1.25rem;
  line-height: 1;
  background-color: transparent;
  border: 1px solid transparent;
  border-radius: 0.25rem;
}

.navbar-toggler:hover,
.navbar-toggler:focus {
  text-decoration: none;
}

.navbar-toggler-icon {
  display: inline-block;
  width: 1.5em;
  height: 1.5em;
  vertical-align: middle;
  content: "";
  background: no-repeat center center;
  background-size: 100% 100%;
}

@media (max-width: 767.98px) {
  .navbar-expand-md > .container,
    .navbar-expand-md > .container-fluid {
      padding-right: 0;
      padding-left: 0;
    }
}

@media (min-width: 768px) {
  .navbar-expand-md {
      -ms-flex-flow: row nowrap;
      flex-flow: row nowrap;
      -ms-flex-pack: start;
      justify-content: flex-start;
    }
  .navbar-expand-md .navbar-nav {
      -ms-flex-direction: row;
      flex-direction: row;
    }
  .navbar-expand-md .navbar-nav .dropdown-menu {
      position: absolute;
    }
  .navbar-expand-md .navbar-nav .nav-link {
      padding-right: 0.5rem;
      padding-left: 0.5rem;
    }
  .navbar-expand-md > .container,
    .navbar-expand-md > .container-fluid {
      -ms-flex-wrap: nowrap;
      flex-wrap: nowrap;
    }
  .navbar-expand-md .navbar-collapse {
      display: -ms-flexbox !important;
      display: flex !important;
      -ms-flex-preferred-size: auto;
      flex-basis: auto;
    }
  .navbar-expand-md .navbar-toggler {
      display: none;
    }
}

.btn {
  display: inline-block;
  font-weight: 600;
  color: #056000;
  text-align: center;
  vertical-align: middle;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  background-color: transparent;
  border: 0.15rem solid transparent;
  padding: 0.85rem 3rem;
  font-size: 2rem;
  line-height: 1.5;
  border-radius: 3.5rem;
  text-transform: capitalize;
}

@media only screen and (max-width: 1366px) {
  .btn {
      font-size: 1.8rem;
    }
}

@media (prefers-reduced-motion: reduce) {
  .btn {
      transition: none;
    }
}

.btn:hover {
  color: #212529;
  text-decoration: none;
}

.btn:focus,
.btn.focus {
  outline: 0;
  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}

.btn.disabled,
.btn:disabled {
  opacity: 0.65;
}

a.btn.disabled,
fieldset:disabled a.btn {
  pointer-events: none;
}

.btn-primary {
  color: #fff;
  background: #FFA046;
  border-color: #FFA046;
  background-clip: padding-box;
}

.btn-primary:hover {
  color: #fff;
  background: #ffae45;
  border-color: #ffae45;
  background-clip: padding-box;
}

.btn-primary:focus,
.btn-primary.focus {
  color: #fff;
  background: #ff8420;
  border-color: #ff8420;
  background-clip: padding-box;
  box-shadow: none;
}

.btn-secondary {
  color: #fff;
  background: #0bab4b;
  background: linear-gradient(to bottom, #0dcb59 0%, #0bab4b 100%);
  border-color: rgba(7, 96, 0, 0.39);
  background-clip: padding-box;
}

.btn-secondary:hover {
  color: #fff;
  background: linear-gradient(to bottom, #0dd85f 0%, #0bba51 100%);
  background-clip: padding-box;
}

.btn-secondary:focus,
.btn-secondary.focus {
  color: #fff;
  background: linear-gradient(to bottom, #0cc054 0%, #0ab04c 100%);
  background-clip: padding-box;
  box-shadow: none;
}

.btn-tertiary {
  color: #0bb850;
  background-color: transparent;
  border-color: rgba(11, 184, 80, 0.4);
}

.btn-tertiary:hover {
  color: #0bb850;
  background-color: transparent;
  border-color: #0bb850;
}

.btn-tertiary:focus,
.btn-tertiary.focus {
  box-shadow: none;
  color: #fff;
  background-color: #0bb850;
  border-color: #0bb850;
}

.btn-tertiary.disabled,
.btn-tertiary:disabled {
  color: #fff;
  background-color: #6c757d;
  border-color: #6c757d;
}

.btn-tertiary:not(:disabled):not(.disabled):active,
.btn-tertiary:not(:disabled):not(.disabled).active,
.show > .btn-tertiary.dropdown-toggle {
  color: #fff;
  background-color: #0bb850;
  border-color: #0bb850;
}

.btn-shadow.btn-secondary::before {
  box-shadow: rgba(65, 28, 0, 0.52) 0 25px 30px -20px;
}

.btn-arrow.btn-primary ._overlay::before {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 4rem;
  height: 100%;
  border-radius: 0 2rem 2rem 0;
  background-color: rgba(0, 0, 0, 0.05);
  content: '';
  z-index: 1;
}

@media only screen and (max-width: 1366px) {
  .btn-arrow.btn-primary ._overlay::before {
      width: 3.8rem;
    }
}

@media only screen and (max-width: 991px) {
  .btn-arrow.btn-primary ._overlay::before {
      width: 3rem;
    }
}

@media only screen and (max-width: 767px) {
  .btn-arrow.btn-primary ._overlay::before {
      width: 2.2rem;
    }
}

.btn-arrow.btn-md.btn-tertiary:hover,
.btn-arrow.btn-md.btn-tertiary:focus,
.btn-arrow.btn-md.btn-tertiary.focus {
  color: #fff;
  background-color: #09B84F;
}

.btn-arrow.btn-md.btn-tertiary:hover::after,
.btn-arrow.btn-md.btn-tertiary:focus::after,
.btn-arrow.btn-md.btn-tertiary.focus::after {
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill-rule='evenodd' viewBox='0 0 14 22' fill='rgb(255, 255, 255)' %3e%3cpath d='M2.086,1.253 L13.499,9.988 C14.165,10.499 14.165,11.492 13.499,12.002 L2.086,20.738 C1.240,21.386 0.009,20.789 0.009,19.732 L2.000,11.000 L0.009,2.259 C0.009,1.201 1.240,0.604 2.086,1.253 Z'/%3e%3c/svg%3e");
}

.btn-arrow.btn-lg.btn-tertiary:focus::after,
.btn-arrow.btn-lg.btn-tertiary.focus::after {
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill-rule='evenodd' viewBox='0 0 14 22' fill='rgb(255, 255, 255)' %3e%3cpath d='M2.086,1.253 L13.499,9.988 C14.165,10.499 14.165,11.492 13.499,12.002 L2.086,20.738 C1.240,21.386 0.009,20.789 0.009,19.732 L2.000,11.000 L0.009,2.259 C0.009,1.201 1.240,0.604 2.086,1.253 Z'/%3e%3c/svg%3e");
}

.btn-arrow.btn-max.btn-primary ._overlay::before {
  width: 8rem;
  border-radius: 0 4rem 4rem 0;
}

@media only screen and (max-width: 1366px) {
  .btn-arrow.btn-max.btn-primary ._overlay::before {
      width: 7.8rem;
    }
}

@media only screen and (max-width: 991px) {
  .btn-arrow.btn-max.btn-primary ._overlay::before {
      width: 7rem;
    }
}

@media only screen and (max-width: 767px) {
  .btn-arrow.btn-max.btn-primary ._overlay::before {
      width: 6.2rem;
    }
}

.btn-rectangle,
button.btn-rectangle,
a.btn-rectangle {
  font-weight: 400;
  font-size: 14px;
  box-shadow: 0px 2.66667px 2.66667px rgba(0, 0, 0, 0.24);
  border-radius: 2.66667px;
  letter-spacing: 0.02em;
}

.img-fluid {
  max-width: 100%;
  height: auto;
}

.d-none {
  display: none !important;
}

.d-block {
  display: block !important;
}

.d-flex {
  display: -ms-flexbox !important;
  display: flex !important;
}

@media (min-width: 576px) {
  .d-sm-none {
      display: none !important;
    }
}

@media (min-width: 768px) {
  .d-md-none {
      display: none !important;
    }
  .d-md-inline-block {
      display: inline-block !important;
    }
  .d-md-flex {
      display: -ms-flexbox !important;
      display: flex !important;
    }
}

.w-100 {
  width: 100% !important;
}

.mr-2,
.mx-2 {
  margin-right: 0.5rem !important;
}

.mr-auto,
.mx-auto {
  margin-right: auto !important;
}

.ml-auto,
.mx-auto {
  margin-left: auto !important;
}

.flex-row {
  -ms-flex-direction: row !important;
  flex-direction: row !important;
}

.align-items-center {
  -ms-flex-align: center !important;
  align-items: center !important;
}

a.text-success:hover,
a.text-success:focus {
  color: #4ea403 !important;
}

a.text-info:hover,
a.text-info:focus {
  color: #006D84 !important;
}

a.text-warning:hover,
a.text-warning:focus {
  color: #EA6B3C !important;
}

a.text-danger:hover,
a.text-danger:focus {
  color: #dc3545 !important;
}

a.text-light:hover,
a.text-light:focus {
  color: #cbd3da !important;
}

a.text-dark:hover,
a.text-dark:focus {
  color: #243146 !important;
}

.text-truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fade {
  transition: opacity 0.15s linear;
}

@media (prefers-reduced-motion: reduce) {
  .fade {
      transition: none;
    }
}

.fade:not(.show) {
  opacity: 0;
}

.collapse:not(.show) {
  display: none;
}

.stretched-link::after {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1;
  pointer-events: auto;
  content: "";
  background-color: rgba(0, 0, 0, 0);
}

@media print {
  *,
    *::before,
    *::after {
      text-shadow: none !important;
      box-shadow: none !important;
    }
  a:not(.btn) {
      text-decoration: underline;
    }
  tr,
    img {
      page-break-inside: avoid;
    }
  p,
    h2,
    h3 {
      orphans: 3;
      widows: 3;
    }
  h2,
    h3 {
      page-break-after: avoid;
    }
  body {
      min-width: 992px !important;
    }
  .navbar.navbar-site {
      position: absolute !important;
    }
}

html {
  font-size: 10px;
}

body {
  font-size: 2rem;
  font-weight: 400;
  color: #2c3e50;
}

@media only screen and (max-width: 991px) {
  body {
      font-size: 1.6rem;
    }
}

@media only screen and (max-width: 767px) {
  body {
      font-size: 1.4rem;
    }
}

body.has-sticky-header {
  padding-top: 14rem;
}

@media only screen and (max-width: 1280px) {
  body.has-sticky-header {
      padding-top: 12rem;
    }
}

@media only screen and (max-width: 767px) {
  body.has-sticky-header {
      padding-top: 10rem;
    }
}

@media print {
  body {
      font-size: 18px;
      color: #000;
    }
}

h1,
h2,
h3,
h4,
h5,
h6,
.h1,
.h2,
.h3,
.h4,
.h5,
.h6 {
  margin-bottom: 0.5rem;
  font-weight: 600;
  line-height: 1.2;
  color: #268fd0;
  letter-spacing: -0.02em;
}

h1,
.h1 {
  font-size: 7.2rem;
  line-height: 1.1;
}

@media only screen and (max-width: 991px) {
  h1,
    .h1 {
      font-size: 5.2rem;
    }
}

@media only screen and (max-width: 575px) {
  h1,
    .h1 {
      font-size: 3.2rem;
    }
}

@media print {
  h1,
    .h1 {
      font-size: 6.4rem;
    }
}

h2,
.h2 {
  font-size: 5.6rem;
  line-height: 1.1;
}

@media only screen and (max-width: 991px) {
  h2,
    .h2 {
      font-size: 3.6rem;
    }
}

@media only screen and (max-width: 575px) {
  h2,
    .h2 {
      font-size: 2.8rem;
    }
}

@media print {
  h2,
    .h2 {
      font-size: 4.8rem;
    }
}

h3,
.h3 {
  font-size: 2.8rem;
  line-height: 1.15;
}

@media only screen and (max-width: 991px) {
  h3,
    .h3 {
      font-size: 2.4rem;
    }
}

@media only screen and (max-width: 575px) {
  h3,
    .h3 {
      font-size: 2.2rem;
    }
}

@media print {
  h3,
    .h3 {
      font-size: 2.4rem;
    }
}

h4,
.h4 {
  font-size: 2.4rem;
  line-height: 1.15;
}

@media only screen and (max-width: 991px) {
  h4,
    .h4 {
      font-size: 2.2rem;
    }
}

@media only screen and (max-width: 575px) {
  h4,
    .h4 {
      font-size: 2rem;
    }
}

@media print {
  h4,
    .h4 {
      font-size: 2.2rem;
    }
}

h5,
.h5 {
  font-size: 2rem;
}

@media only screen and (max-width: 991px) {
  h5,
    .h5 {
      font-size: 1.8rem;
    }
}

@media only screen and (max-width: 575px) {
  h5,
    .h5 {
      font-size: 1.6rem;
    }
}

@media print {
  h5,
    .h5 {
      font-size: 1.8rem;
    }
}

h6,
.h6 {
  font-size: 1.8rem;
}

@media only screen and (max-width: 991px) {
  h6,
    .h6 {
      font-size: 1.6rem;
    }
}

@media only screen and (max-width: 575px) {
  h6,
    .h6 {
      font-size: 1.4rem;
    }
}

@media print {
  h6,
    .h6 {
      font-size: 1.6rem;
    }
}

p {
  margin: 0 0 2rem;
}

a {
  color: #2c3e50;
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

a:focus,
a:active {
  outline: none;
  text-decoration: none;
}

/* In-prose text links need a non-colour cue: the base `a` rule at :1193 paints
   them #2c3e50, the exact body-text colour, so an untagged prose link is
   invisible (contrast 1.00 against its own paragraph, WCAG 1.4.1 fail). Scoped
   to an explicit class rather than `p a` so it cannot reach nav, footer, cards
   or CTA links. `a:hover` at :1198 already underlines, so this only changes the
   resting state. */
.prose-link {
  text-decoration: underline;
  text-underline-offset: 0.15em;
  text-decoration-thickness: from-font;
}

/* `a:focus, a:active` at :1202 is specificity 0,1,1 and strips text-decoration;
   `.prose-link` alone is 0,1,0 and loses. Measured: 11/11 underlined at rest,
   0/11 when focused, with no outline either -- the link vanishes exactly when a
   keyboard user selects it. This selector is 0,2,0 and wins. It restores the
   underline only; the missing focus RING is the site-wide `outline: none` defect
   at :1202, logged in TODO.md and deliberately not touched here. */
.prose-link:focus {
  text-decoration: underline;
}

button:focus {
  outline: none;
}

.navbar-site {
  position: absolute !important;
  top: 0;
  left: 0;
  right: 0;
  padding-top: 0;
  padding-bottom: 0;
  height: 14rem;
  z-index: 1;
}

@media only screen and (max-width: 1280px) {
  .navbar-site {
      height: 12rem;
    }
}

@media only screen and (max-width: 767px) {
  .navbar-site {
      height: 10rem;
    }
}

@media print {
  .navbar-site {
      padding-top: 0;
    }
}

.navbar-site .navbar-brand {
  display: block;
  margin-top: -1.8rem;
  margin-right: 0;
  width: 30rem;
  height: 7rem;
  background: url(https://s3.amazonaws.com/img.mynetdiary.com/images/logo-main.svg) 50% 50% no-repeat;
  background-size: contain;
}

@media only screen and (max-width: 1366px) {
  .navbar-site .navbar-brand {
      width: 28rem;
      height: 6.5rem;
    }
}

@media only screen and (max-width: 575px) {
  .navbar-site .navbar-brand {
      width: 24rem;
      height: 5.5rem;
    }
}

@media print {
  .navbar-site .navbar-brand {
      position: relative;
      background: none;
    }
  .navbar-site .navbar-brand::before {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      content: url(https://s3.amazonaws.com/img.mynetdiary.com/images/logo-dark.svg);
    }
  .navbar-site .navbar-brand::after {
      position: absolute;
      left: 105%;
      top: 28%;
      color: #818b9a;
      font-size: 34px;
    }
}

.navbar-site .navbar-toggler .navbar-toggler-icon {
  width: 3.2rem;
  height: 3.3rem;
}

.navbar-site .navbar-toggler.collapsed .navbar-toggler-icon {
  background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(255, 255, 255, 1)' stroke-width='3' stroke-linecap='square' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}

@media only screen and (min-width: 768px) and (max-width: 1280px) {
  .navbar-site .navbar-collapse {
      -ms-flex-pack: end;
      -webkit-justify-content: flex-end;
      justify-content: flex-end;
    }
}

@media print {
  .navbar-site .navbar-collapse {
      display: none !important;
    }
}

@media only screen and (min-width: 768px) and (max-width: 1280px) {
  .navbar-site .navbar-nav-site {
      -ms-flex-pack: center;
      -webkit-justify-content: center;
      justify-content: center;
      position: absolute;
      left: 0;
      right: 0;
      bottom: -2rem;
      width: 100%;
    }
}

@media only screen and (max-width: 767px) {
  .navbar-site .navbar-nav-site {
      margin-top: 3rem;
      border-bottom: 0.1rem dashed #2c3e50;
    }
}

@media only screen and (max-width: 767px) {
  .navbar-site .navbar-nav-site .nav-item {
      border-top: 0.1rem dashed #2c3e50;
    }
}

.navbar-site .navbar-nav-site .nav-item:hover .nav-link,
.navbar-site .navbar-nav-site .nav-item:focus .nav-link,
.navbar-site .navbar-nav-site .nav-item.active .nav-link {
  color: #fcf8b3;
  text-decoration: underline;
}

@media only screen and (max-width: 767px) {
  .navbar-site .navbar-nav-site .nav-item:hover .nav-link,
    .navbar-site .navbar-nav-site .nav-item:focus .nav-link,
    .navbar-site .navbar-nav-site .nav-item.active .nav-link {
      color: #0bb850;
      text-decoration: none;
    }
}

@media only screen and (max-width: 767px) {
  .navbar-site .navbar-nav-site .nav-item:hover .nav-link[data-toggle="collapse"]::after,
    .navbar-site .navbar-nav-site .nav-item:focus .nav-link[data-toggle="collapse"]::after,
    .navbar-site .navbar-nav-site .nav-item.active .nav-link[data-toggle="collapse"]::after {
      position: absolute;
      top: 1.8rem;
      right: 0;
      width: 1.6rem;
      height: 0.9rem;
      background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 9' xmlns='http://www.w3.org/2000/svg'%3e%3cpath fill-rule='evenodd' fill='%230bb850' d='M15.059,8.284 C14.786,8.556 14.344,8.556 14.071,8.284 L7.980,2.195 L1.877,8.295 C1.604,8.568 1.161,8.568 0.888,8.295 C0.615,8.021 0.615,7.579 0.888,7.306 L7.319,0.878 C7.498,0.698 7.749,0.649 7.978,0.705 C8.208,0.649 8.458,0.698 8.637,0.877 L15.059,7.296 C15.332,7.569 15.332,8.011 15.059,8.284 Z' /%3e%3c/svg%3e");
      content: '';
    }
}

.navbar-site .navbar-nav-site .nav-item:hover .nav-link[data-toggle="collapse"].collapsed::after,
.navbar-site .navbar-nav-site .nav-item:focus .nav-link[data-toggle="collapse"].collapsed::after,
.navbar-site .navbar-nav-site .nav-item.active .nav-link[data-toggle="collapse"].collapsed::after {
  background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 9' xmlns='http://www.w3.org/2000/svg'%3e%3cpath fill-rule='evenodd' fill='%230bb850' d='M15.016,1.654 L8.629,8.182 C8.451,8.364 8.202,8.414 7.974,8.357 C7.746,8.414 7.497,8.364 7.318,8.181 L0.922,1.644 C0.651,1.366 0.651,0.916 0.922,0.638 C1.194,0.360 1.635,0.360 1.906,0.638 L7.975,6.841 L14.033,0.649 C14.305,0.372 14.745,0.372 15.016,0.649 C15.287,0.927 15.287,1.376 15.016,1.654 Z' /%3e%3c/svg%3e");
}

.navbar-site .navbar-nav-site .nav-item.active {
  font-weight: 500;
}

.navbar-site .navbar-nav-site .nav-link {
  position: relative;
  padding-left: 2rem;
  padding-right: 2rem;
  color: #fff;
  font-size: 2rem;
  text-align: center;
  z-index: 1000;
}

@media only screen and (max-width: 767px) {
  .navbar-site .navbar-nav-site .nav-link[data-toggle="collapse"]::after {
      position: absolute;
      top: 1.8rem;
      right: 0;
      width: 1.6rem;
      height: 0.9rem;
      background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 9' xmlns='http://www.w3.org/2000/svg'%3e%3cpath fill-rule='evenodd' fill='%230bb850' d='M15.059,8.284 C14.786,8.556 14.344,8.556 14.071,8.284 L7.980,2.195 L1.877,8.295 C1.604,8.568 1.161,8.568 0.888,8.295 C0.615,8.021 0.615,7.579 0.888,7.306 L7.319,0.878 C7.498,0.698 7.749,0.649 7.978,0.705 C8.208,0.649 8.458,0.698 8.637,0.877 L15.059,7.296 C15.332,7.569 15.332,8.011 15.059,8.284 Z' /%3e%3c/svg%3e");
      content: '';
    }
}

.navbar-site .navbar-nav-site .nav-link[data-toggle="collapse"].collapsed::after {
  background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 9' xmlns='http://www.w3.org/2000/svg'%3e%3cpath fill-rule='evenodd' fill='%232c3e50' d='M15.016,1.654 L8.629,8.182 C8.451,8.364 8.202,8.414 7.974,8.357 C7.746,8.414 7.497,8.364 7.318,8.181 L0.922,1.644 C0.651,1.366 0.651,0.916 0.922,0.638 C1.194,0.360 1.635,0.360 1.906,0.638 L7.975,6.841 L14.033,0.649 C14.305,0.372 14.745,0.372 15.016,0.649 C15.287,0.927 15.287,1.376 15.016,1.654 Z' /%3e%3c/svg%3e");
}

@media only screen and (max-width: 1366px) {
  .navbar-site .navbar-nav-site .nav-link {
      padding-left: 1.8rem;
      padding-right: 1.8rem;
      font-size: 1.6rem;
    }
}

@media only screen and (max-width: 767px) {
  .navbar-site .navbar-nav-site .nav-link {
      padding-top: 1rem;
      padding-bottom: 1rem;
      padding-right: 2.5rem;
      font-size: 1.4rem;
      color: #2c3e50;
      text-align: left;
      text-transform: uppercase;
    }
}

@media only screen and (max-width: 767px) {
  .navbar-site .navbar-nav-site .nav-link:hover,
    .navbar-site .navbar-nav-site .nav-link:focus {
      color: #0bb850;
    }
}

.navbar-site .navbar-nav-site .dropdown {
  position: relative;
}

@media only screen and (min-width: 768px) {
  .navbar-site .navbar-nav-site .dropdown .nav-link::after {
      position: absolute;
      top: 1.4rem;
      right: 0.2rem;
      width: 1.2rem;
      height: 1.2rem;
      background: url("data:image/svg+xml,%3csvg viewBox='0 0 12 12' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M10.6553 3.40717C10.9482 3.70006 10.9482 4.17494 10.6553 4.46783L6.53033 8.59283C6.23744 8.88572 5.76256 8.88572 5.46967 8.59283L1.34467 4.46783C1.05178 4.17494 1.05178 3.70006 1.34467 3.40717C1.63756 3.11428 2.11244 3.11428 2.40533 3.40717L6 7.00184L9.59467 3.40717C9.88756 3.11428 10.3624 3.11428 10.6553 3.40717Z' fill='white' /%3e%3c/svg%3e") 50% 50% no-repeat;
      content: '';
    }
}

@media only screen and (min-width: 768px) {
  .navbar-site .navbar-nav-site .dropdown:focus .nav-link::before,
    .navbar-site .navbar-nav-site .dropdown:hover .nav-link::before {
      display: none;
    }
}

@media only screen and (min-width: 768px) {
  .navbar-site .navbar-nav-site .dropdown:focus .nav-link::after,
    .navbar-site .navbar-nav-site .dropdown:hover .nav-link::after {
      position: absolute;
      top: 1.4rem;
      right: 0.2rem;
      width: 1.2rem;
      height: 1.2rem;
      background: url("data:image/svg+xml,%3csvg viewBox='0 0 12 12' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M10.6553 8.59283C10.9482 8.29994 10.9482 7.82506 10.6553 7.53217L6.53033 3.40717C6.23744 3.11428 5.76256 3.11428 5.46967 3.40717L1.34467 7.53217C1.05178 7.82506 1.05178 8.29994 1.34467 8.59283C1.63756 8.88572 2.11244 8.88572 2.40533 8.59283L6 4.99816L9.59467 8.59283C9.88756 8.88572 10.3624 8.88572 10.6553 8.59283Z' fill='%23FCF8B3' /%3e%3c/svg%3e") 50% 50% no-repeat;
      content: '';
    }
}

@media only screen and (min-width: 768px) {
  .navbar-site .navbar-nav-site .dropdown:focus .dropdown-menu,
    .navbar-site .navbar-nav-site .dropdown:hover .dropdown-menu {
      display: block;
      opacity: 1;
      transform: translateX(-50%) translateY(0);
      pointer-events: auto;
    }
}

.navbar-site .navbar-subnav {
  padding-left: 0;
  list-style: none;
  padding-left: 2.5rem;
  font-size: 1.6rem;
}

.navbar-site .navbar-subnav > li {
  padding-bottom: 1rem;
}

.navbar-site .navbar-subnav_no-bullets > li > a {
  display: flex;
  align-items: center;
}

.navbar-site .navbar-subnav_no-bullets > li > a::before {
  display: none;
}

@media only screen and (min-width: 768px) {
  .navbar-site .dropdown-menu {
      position: absolute;
      top: 100%;
      left: 50%;
      display: block;
      margin-top: -2px;
      padding: 4rem;
      min-width: 34rem;
      background-color: #fff;
      box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.16);
      border-radius: 2.4rem;
      z-index: 1000;
      text-align: left;
      font-size: 2rem;
      opacity: 0;
      transform: translateX(-50%) translateY(1rem);
      pointer-events: none;
      transition: all 0.2s ease;
    }
}

@media only screen and (min-width: 768px) and (max-width: 1366px) {
  .navbar-site .dropdown-menu {
      font-size: 1.8rem;
    }
}

@media only screen and (min-width: 768px) {
  .navbar-site .dropdown-menu > li {
      padding: 0;
      margin: 0;
    }
}

@media only screen and (min-width: 768px) {
  .navbar-site .dropdown-menu > li > a {
      position: relative;
      display: block;
      transition: all 0.15s ease-in-out 0s;
    }
}

@media only screen and (min-width: 768px) {
  .navbar-site .dropdown-menu > li > a:hover,
    .navbar-site .dropdown-menu > li > a:focus {
      color: #268fd0;
      text-decoration: none;
    }
}

@media only screen and (min-width: 768px) {
  .navbar-site .dropdown-menu > li + li {
      margin-top: 2rem;
    }
}

.navbar-site ._buttons .nav-item:last-child {
  margin-left: 2rem;
}

@media only screen and (max-width: 767px) {
  .navbar-site ._buttons .nav-item:last-child {
      margin-left: 0;
    }
}

@media only screen and (max-width: 767px) {
  .navbar-site ._buttons {
      -ms-flex-direction: row;
      -webkit-flex-direction: row;
      flex-direction: row;
      -ms-flex-pack: justify;
      -webkit-justify-content: space-between;
      justify-content: space-between;
    }
}

@media only screen and (max-width: 767px) {
  .navbar-site ._buttons .btn {
      min-width: 10rem;
      padding: 0.5rem 1.8rem;
      font-size: 1.6rem;
    }
}

@media only screen and (max-width: 767px) {
  .navbar-site ._buttons .btn-tertiary {
      border-color: rgba(107, 199, 45, 0.5);
    }
  .navbar-site ._buttons .btn-tertiary:hover,
    .navbar-site ._buttons .btn-tertiary:focus,
    .navbar-site ._buttons .btn-tertiary.focus {
      border-color: #0bb850;
    }
}

@media only screen and (max-width: 767px) {
  .navbar-site .slideout-menu {
      position: fixed;
      top: 0;
      right: -26.5rem;
      bottom: 0;
      display: none;
      padding: 4rem 2rem 2rem;
      min-height: 100vh;
      height: auto;
      margin: 0;
      width: 26.5rem;
      box-shadow: inset 18px 0 20px -20px rgba(142, 112, 103, 0.67);
      overflow-y: scroll;
      background: #f0ece8 url(https://s3.amazonaws.com/img.mynetdiary.com/images/pattern-noisy.jpg) 0 0 repeat;
      -webkit-overflow-scrolling: auto;
      z-index: 0;
    }
}

.navbar-site .btn-tertiary:hover {
  color: #fff;
  background-color: transparent;
  border-color: #fcf8b3;
}

.navbar-site .btn-tertiary:focus,
.navbar-site .btn-tertiary.focus {
  box-shadow: none;
  color: #fff;
  background-color: #0bb850;
  border-color: #0bb850;
}

@media only screen and (min-width: 768px) {
  .navbar-site .btn-tertiary {
      color: #fff;
      border-color: #fff;
    }
  .navbar-site .btn-tertiary:hover,
    .navbar-site .btn-tertiary:focus,
    .navbar-site .btn-tertiary.focus {
      color: #fff;
      border-color: #fff;
    }
}

.navbar-site ._get-link {
  display: none;
  text-transform: uppercase;
  text-decoration: underline;
  font-weight: 700;
  font-size: 1.7rem;
  color: #0bb850;
}

.navbar-site ._get-link:hover {
  text-decoration: none;
}

.navbar-site ._get-link > svg {
  margin-right: 1rem;
}

.navbar-site ._get-link > svg > path {
  fill: #0bb850;
}

.footer-site {
  background: #fff url(https://s3.amazonaws.com/img.mynetdiary.com/images/pattern-grunge-400x400.jpg) 0 0 repeat;
}

@media print {
  .footer-site {
      background: none;
    }
}

.footer-site > .container {
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  -ms-flex-pack: justify;
  -webkit-justify-content: space-between;
  justify-content: space-between;
  position: relative;
  padding-top: 7rem;
  padding-bottom: 5.5rem;
}

@media only screen and (max-width: 1469px) {
  .footer-site > .container {
      -ms-flex-wrap: wrap;
      -webkit-flex-wrap: wrap;
      flex-wrap: wrap;
      padding-top: 13rem;
      padding-bottom: 1rem;
    }
}

@media only screen and (max-width: 575px) {
  .footer-site > .container {
      padding-top: 10rem;
    }
}

.footer-site > .container ._heading {
  margin: 3.2rem 0 3.6rem;
  color: #2c3e50;
  font-weight: 500;
}

@media only screen and (max-width: 1469px) {
  .footer-site > .container ._heading {
      margin-bottom: 1.6rem;
    }
}

@media print {
  .footer-site > .container {
      display: none !important;
    }
}

.footer-site ._logo {
  display: block;
  max-width: 29.4rem;
  margin-bottom: 2.4rem;
  width: 100%;
}

@media only screen and (max-width: 1469px) {
  .footer-site ._logo {
      position: absolute;
      top: 9rem;
      left: 1.5rem;
      max-width: 29.5rem;
    }
}

@media only screen and (max-width: 575px) {
  .footer-site ._logo {
      max-width: 24rem;
    }
}

.footer-site.__rounded {
  position: relative;
  overflow: hidden;
}

.footer-site.__rounded::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 0;
  width: 120%;
  height: 12rem;
  background: #ffffff;
  border-radius: 0 0 50% 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
  z-index: 1;
}

@media only screen and (max-width: 575px) {
  .footer-site.__rounded::before {
      height: 6rem;
    }
}

.footer-site.__rounded > .container {
  padding-top: 15rem;
}

@media only screen and (max-width: 1469px) {
  .footer-site.__rounded > .container {
      padding-top: 17rem;
    }
}

@media only screen and (max-width: 575px) {
  .footer-site.__rounded > .container {
      padding-top: 12rem;
    }
}

.footer-site.__rounded > .container ._logo {
  top: 9rem;
}

@media only screen and (max-width: 575px) {
  .footer-site.__rounded > .container ._logo {
      top: 6rem;
    }
}

.footer-site ._section {
  margin-right: 1.5rem;
}

@media only screen and (max-width: 1469px) {
  .footer-site ._section {
      -ms-flex: 0 50%;
      -webkit-flex: 0 50%;
      flex: 0 50%;
      margin-right: 0;
    }
}

@media only screen and (max-width: 1469px) {
  .footer-site ._section:first-child {
      display: flex;
      flex-direction: column;
      flex: 0 100%;
      order: 5;
      padding-top: 0.5rem;
      overflow: hidden;
    }
}

@media only screen and (max-width: 767px) {
  .footer-site ._section:nth-child(2) {
      order: 1;
    }
}

@media only screen and (max-width: 767px) {
  .footer-site ._section:nth-child(3) {
      order: 4;
    }
}

@media only screen and (max-width: 767px) {
  .footer-site ._section:nth-child(4) {
      order: 2;
    }
}

@media only screen and (max-width: 767px) {
  .footer-site ._section:last-child {
      order: 3;
    }
}

.footer-site .navbar-nav {
  padding-left: 0;
  list-style: none;
  margin: 0;
  font-size: 1.4rem;
  color: #beaeac;
}

@media only screen and (max-width: 575px) {
  .footer-site .navbar-nav {
      font-size: 1rem;
    }
}

.footer-site .navbar-nav > li {
  position: relative;
  margin: 0 0 2rem;
  padding-left: 2.4rem;
}

@media only screen and (max-width: 1280px) {
  .footer-site .navbar-nav > li {
      margin-bottom: 1.5rem;
    }
}

@media only screen and (max-width: 575px) {
  .footer-site .navbar-nav > li {
      margin-bottom: 1rem;
    }
}

.footer-site .navbar-nav > li::before {
  position: absolute;
  left: 0;
  top: 0;
  font-size: 2rem;
  line-height: 1.4;
  content: '•';
}

@media only screen and (max-width: 1280px) {
  .footer-site .navbar-nav > li::before {
      font-size: 1.8rem;
    }
}

@media only screen and (max-width: 575px) {
  .footer-site .navbar-nav > li::before {
      font-size: 1.4rem;
    }
}

.footer-site .navbar-nav > li > a {
  font-size: 2rem;
  vertical-align: sub;
}

@media only screen and (max-width: 1280px) {
  .footer-site .navbar-nav > li > a {
      font-size: 1.8rem;
    }
}

@media only screen and (max-width: 575px) {
  .footer-site .navbar-nav > li > a {
      font-size: 1.4rem;
    }
}

.footer-site__scores {
  display: flex;
  flex-direction: column;
  gap: 1.6rem;
  margin-top: 2.4rem;
}

@media only screen and (max-width: 991px) {
  .footer-site__scores {
      flex-direction: row;
    }
}

@media only screen and (max-width: 575px) {
  .footer-site__scores {
      flex-direction: column;
    }
}

@media only screen and (max-width: 575px) {
  .footer-site ._stores {
      margin-top: 1.6rem;
    }
}

.footer-site ._stores .__item {
  display: inline-block;
  max-width: 14.4rem;
}

@media only screen and (max-width: 1280px) {
  .footer-site ._stores .__item {
      max-width: 13rem;
    }
}

@media only screen and (max-width: 1024px) {
  .footer-site ._stores .__item {
      max-width: 12rem;
    }
}

@media only screen and (max-width: 991px) {
  .footer-site ._stores .__item {
      max-width: none;
      width: 15rem;
    }
}

@media only screen and (max-width: 575px) {
  .footer-site ._stores .__item {
      width: 13rem;
    }
}

.footer-site ._stores .__item + .__item {
  margin-left: 1rem;
}

.footer-site ._stats {
  display: flex;
  align-items: center;
  gap: 1.2rem;
  font-size: 2rem;
}

@media only screen and (max-width: 991px) {
  .footer-site ._stats {
      font-size: 1.8rem;
    }
}

@media only screen and (max-width: 575px) {
  .footer-site ._stats {
      font-size: 1.4rem;
    }
}

.footer-site ._stats--trustpilot {
  flex-shrink: 0;
  gap: 0;
  line-height: 0;
}

.footer-site ._stats--trustpilot .trustpilot-widget {
  min-width: 11rem;
  min-height: 15rem;
}

.footer-site .list-share {
  margin-top: 2.4rem;
}

@media only screen and (max-width: 575px) {
  .footer-site .list-share {
      margin-top: 2.5rem;
    }
}

.footer-site .copyright {
  padding-top: 4.5rem;
  padding-bottom: 4.5rem;
  border-top: 1px solid rgba(143, 112, 102, 0.08);
  background-color: rgba(143, 112, 102, 0.05);
  font-size: 1.8rem;
}

@media only screen and (max-width: 1024px) {
  .footer-site .copyright {
      font-size: 1.6rem;
    }
}

@media only screen and (max-width: 575px) {
  .footer-site .copyright {
      font-size: 1.4rem;
    }
}

@media print {
  .footer-site .copyright {
      display: none !important;
    }
}

.footer-site .copyright > .container {
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  -ms-flex-align: center;
  -webkit-align-items: center;
  align-items: center;
  -ms-flex-pack: justify;
  -webkit-justify-content: space-between;
  justify-content: space-between;
}

@media only screen and (max-width: 991px) {
  .footer-site .copyright > .container {
      -ms-flex-direction: column;
      -webkit-flex-direction: column;
      flex-direction: column;
      text-align: center;
    }
}

.footer-site .copyright__text {
  font-size: 1.8rem;
  font-weight: 400;
}

.footer-site .copyright__links a {
  color: #0bb850;
}

.list-share {
  padding-left: 0;
  list-style: none;
  display: flex;
  gap: 3.2rem;
}

.list-share a {
  text-decoration: none;
}

.list-share a:hover,
.list-share afocus {
  text-decoration: none;
  outline: none;
}

.banner-sticky {
  position: sticky;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1010;
  padding: 16px 24px;
  background: #5FBE70;
  background: linear-gradient(90deg, rgba(95, 190, 112, 0.2) 0%, rgba(27, 123, 64, 0.2) 100%), #5FBE70;
}

@media screen and (max-width: 479px) {
  .banner-sticky {
      padding-left: 16px;
      padding-right: 16px;
    }
}

.banner-sticky__dismiss {
  position: relative;
  z-index: 2;
  margin-left: -16px;
  margin-right: 4px;
  padding: 8px;
  line-height: 0;
  opacity: 0.5;
}

@media screen and (max-width: 479px) {
  .banner-sticky__dismiss {
      margin-right: 0;
    }
}

.banner-sticky__dismiss:hover {
  opacity: 1;
}

@media screen and (max-width: 479px) {
  .banner-sticky__direct {
      width: 24px;
    }
}

@media screen and (max-width: 399px) {
  .banner-sticky__icon {
      max-width: 54px;
    }
}

.app-stats {
  margin-left: 1.6rem;
  color: #fff;
  font-size: 1.4rem;
}

@media screen and (max-width: 399px) {
  .app-stats {
      max-width: calc(100vw - 146px);
      margin-right: 8px;
      margin-left: 12px;
      font-size: 12px;
    }
}

.app-stats__title {
  margin: 0;
  font-size: 20px;
}

@media screen and (max-width: 479px) {
  .app-stats__title {
      font-size: 16px;
    }
}

@media screen and (max-width: 399px) {
  .app-stats__title {
      font-size: 14px;
    }
}

.app-stats__rating > svg {
  margin-right: 4px;
  width: 16px;
  height: auto;
}

@media screen and (max-width: 479px) {
  .app-stats__rating > svg {
      margin-right: 2px;
      width: 12px;
    }
}

@media screen and (max-width: 399px) {
  .app-stats__rating > svg {
      margin-right: 1px;
      min-width: 10px;
      width: 10px;
    }
}

.app-stats__rating > svg:last-of-type {
  margin-right: 10px;
}

@media screen and (max-width: 399px) {
  .app-stats__rating > svg:last-of-type {
      margin-right: 8px;
    }
}

.ai-features {
  overflow: hidden;
}

.ai-features__header {
  margin: 0 auto 4rem;
  text-align: center;
}

@media only screen and (max-width: 991px) {
  .ai-features__header {
      text-align: left;
    }
}

/* 4rem, not 1.6rem: Figma's 40px h2 gap -- this was the furthest off of the six,
   by 24px. C-09. Also used by static_glp-1-app.st and static_index.st, neither of
   which loads pages-2026.css, so this edit reaches the four family pages only. */
.ai-features__title {
  margin-bottom: 4rem;
  color: #268fd0;
}

.ai-features__intro {
  max-width: 88rem;
  margin-left: auto;
  margin-right: auto;
  font-size: 2rem;
  line-height: 1.45;
  color: #2c3e50;
}

@media only screen and (max-width: 991px) {
  .ai-features__intro {
      font-size: 1.6rem;
    }
}

@media only screen and (max-width: 575px) {
  .ai-features__intro {
      font-size: 1.4rem;
    }
}

.ai-features__wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 3.2rem;
}

@media only screen and (max-width: 991px) {
  .ai-features__wrapper {
      display: block;
    }
}

@media only screen and (max-width: 991px) {
  .ai-card {
      display: grid;
      grid-template-columns: 40% 1fr;
      gap: 1.6rem;
      align-items: center;
    }
}

@media only screen and (max-width: 767px) {
  .ai-card {
      align-items: initial;
    }
}

@media only screen and (max-width: 575px) {
  .ai-card {
      display: flex;
      flex-direction: column;
    }
}

.ai-card__media {
  margin-bottom: 4rem;
  border-radius: 2.4rem;
  overflow: hidden;
}

@media only screen and (max-width: 991px) {
  .ai-card__media {
      margin-bottom: 0;
    }
}

.ai-card__media img {
  display: block;
  width: 100%;
  height: auto;
}

.ai-card__title {
  margin-bottom: 2.4rem;
  color: #268fd0;
}

.ai-card__list {
  padding-left: 2.4rem;
  list-style-type: disc;
}

.ai-card__list li {
  margin-bottom: 0.8rem;
  font-size: 2rem;
  line-height: 1.3;
  color: #2c3e50;
}

@media only screen and (max-width: 991px) {
  .ai-card__list li {
      font-size: 1.6rem;
    }
}

@media only screen and (max-width: 575px) {
  .ai-card__list li {
      font-size: 1.4rem;
    }
}

/* The 4-up "Deep iOS Integration" cards carry prose in an __body div instead of
   the __list <ul> every other .ai-card set on this page uses, so none of the
   .ai-card__list li typography ever reached them -- the paragraph fell all the
   way back to the base cascade. Measured with a DOM probe at 1440/991/575, not a
   screenshot: the __body paragraph came out at 30/24/21px leading against the
   list items' 26/20.8/18.2px, and carried p's own margin-bottom: 2rem (20px)
   against the list's 0.8rem (8px), so those four cards read looser than their
   siblings and left a 20px dead gap under the last line.
   font-size and color are deliberately NOT set here: body already ramps
   2rem/1.6rem/1.4rem on these same three breakpoints and sets #2c3e50, and the
   probe confirmed both already matched the list items exactly. Restating them
   would fork the ramp and have to be kept in sync by hand. Only the two
   properties that actually differed are set. */
.ai-card__body {
  line-height: 1.3;
}

/* The margin lands on the paragraph, not on __body: `p { margin: 0 0 2rem }` is
   an element rule, so a margin on the wrapper would not override it. */
.ai-card__body p {
  margin: 0 0 0.8rem;
}

@media only screen and (max-width: 991px) {
  .ai-card + .ai-card {
      margin-top: 2.4rem;
    }
}

.faq-section {
  padding: 6.4rem 0;
}

@media only screen and (max-width: 991px) {
  .faq-section {
      padding: 5.6rem 0;
    }
}

@media only screen and (max-width: 767px) {
  .faq-section {
      padding: 4.8rem 0;
    }
}

/* 5.2rem, NOT the 4rem the other section headings get. Figma names an explicit
   52px exception for FAQ and reviews carousels -- vfd 3925:51305, android
   3613:4773, iPhone 3520:48552 -- so this heading is deliberately not on the
   40px rhythm. C-09. */
.faq-section__title {
  margin: 0 0 5.2rem;
  color: #268fd0;
}

@media only screen and (max-width: 991px) {
  .faq-section__title {
      margin-bottom: 3.2rem;
      line-height: 1.1;
    }
}

@media only screen and (max-width: 767px) {
  .faq-section__title {
      margin-bottom: 2.4rem;
      line-height: 1.12;
    }
}

.faq-section__list {
  display: grid;
  gap: 1.6rem;
}

.faq-item {
  border: 0.1rem solid #d8d8d8;
  border-radius: 2.4rem;
  overflow: hidden;
  will-change: height;
}

.faq-item__summary {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 4rem;
  align-items: center;
  gap: 2.4rem;
  padding: 3rem 2.4rem;
  cursor: pointer;
  list-style: none;
}

@media only screen and (max-width: 991px) {
  .faq-item__summary {
      padding: 2rem 2.4rem;
    }
}

@media only screen and (max-width: 767px) {
  .faq-item__summary {
      grid-template-columns: minmax(0, 1fr) 3.2rem;
      gap: 1.6rem;
      padding: 1.8rem 2rem;
    }
}

.faq-item__summary::-webkit-details-marker {
  display: none;
}

.faq-item__summary::marker {
  display: none;
}

.faq-item__question {
  display: block;
  font-size: 3.2rem;
  line-height: 1.2;
  font-weight: 600;
  color: #268fd0;
}

@media only screen and (max-width: 991px) {
  .faq-item__question {
      font-size: 2.2rem;
    }
}

@media only screen and (max-width: 767px) {
  .faq-item__question {
      font-size: 2rem;
      line-height: 1.15;
    }
}

.faq-item__icon {
  position: relative;
  width: 4rem;
  height: 4rem;
  justify-self: end;
  transition: transform 0.25s ease;
}

@media only screen and (max-width: 767px) {
  .faq-item__icon {
      width: 3.2rem;
      height: 3.2rem;
    }
}

.faq-item__icon::before,
.faq-item__icon::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 2.4rem;
  height: 0.2rem;
  background: #268fd0;
  border-radius: 999rem;
  transform: translate(-50%, -50%);
}

@media only screen and (max-width: 767px) {
  .faq-item__icon::before,
    .faq-item__icon::after {
      width: 2rem;
    }
}

.faq-item__icon::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.faq-item[open] .faq-item__icon {
  transform: rotate(45deg);
}

.faq-item__content {
  overflow: hidden;
}

@media only screen and (max-width: 991px) {
  .faq-item__content {
      padding: 0 2.4rem;
    }
}

.faq-item__content-inner {
  padding: 0 2.4rem 2rem;
}

@media only screen and (max-width: 991px) {
  .faq-item__content-inner {
      padding: 0 4.8rem 2rem 0;
    }
}

@media only screen and (max-width: 767px) {
  .faq-item__content-inner {
      padding: 0 2rem 1.8rem;
    }
}

.faq-item__content p {
  margin: 0;
  font-size: 2rem;
  line-height: 1.4;
  color: #2c3e50;
}

@media only screen and (max-width: 767px) {
  .faq-item__content p {
      font-size: 1.4rem;
      line-height: 1.38;
    }
}

.page-section {
  padding: 6rem 0;
}

@media only screen and (max-width: 991px) {
  .page-section {
      padding: 4rem 0;
    }
}

@media only screen and (max-width: 575px) {
  .page-section {
      padding: 3rem 0;
    }
}

.section-start {
  position: relative;
  overflow: hidden;
  margin-top: -14rem;
  font-size: 2rem;
  z-index: 0;
}

@media only screen and (max-width: 1280px) {
  .section-start {
      margin-top: -12rem;
    }
}

@media only screen and (max-width: 767px) {
  .section-start {
      font-size: 1.6rem;
      margin-top: -10rem;
    }
}

@media only screen and (max-width: 575px) {
  .section-start {
      text-align: center;
    }
}

.section-start::before {
  position: absolute;
  left: -5rem;
  right: -5rem;
  height: 84%;
  background: #4ea403;
  background: #05963d url(https://s3.amazonaws.com/img.mynetdiary.com/images/texture-noise@1x.png) 0 0 repeat;
  background: url(https://s3.amazonaws.com/img.mynetdiary.com/images/texture-noise@1x.png), radial-gradient(ellipse at top, #05b24a 0%, #05963d 60%);
  overflow: hidden;
  border-bottom-right-radius: 100rem 5rem;
  border-bottom-left-radius: 100rem 5rem;
  box-shadow: inset rgba(9, 108, 46, 0.76) 0 -2.3rem 10.7rem;
  z-index: 1;
  content: '';
}

@media only screen and (max-width: 1469px) {
  .section-start::before {
      left: -3rem;
      right: -3rem;
      height: 100%;
    }
}

@media only screen and (max-width: 1366px) {
  .section-start::before {
      left: -2rem;
      right: -2rem;
    }
}

@media only screen and (max-width: 1280px) {
  .section-start::before {
      left: -1rem;
      right: -1rem;
      height: 82%;
    }
}

@media only screen and (max-width: 767px) {
  .section-start::before {
      height: 80%;
    }
}

@media only screen and (max-width: 575px) {
  .section-start::before {
      height: 75%;
      background: url(https://s3.amazonaws.com/img.mynetdiary.com/images/texture-noise@1x.png), radial-gradient(ellipse at top, #05b24a 0%, #1eb553 60%);
    }
}

.section-start ._stores {
  display: flex;
  gap: 1.2rem;
}

@media only screen and (max-width: 1280px) {
  .section-start ._stores {
      justify-content: center;
    }
}

@media only screen and (max-width: 575px) {
  .section-start ._stores {
      flex-direction: column;
      align-items: center;
      gap: 1.6rem;
    }
}

.section-start ._stores .__item img {
  width: auto;
  height: 100%;
  max-height: 4.2rem;
}

@media only screen and (max-width: 1280px) {
  .section-start ._stores .__item img {
      max-height: 4.6rem;
    }
}

@media only screen and (max-width: 575px) {
  .section-start ._stores .__item img {
      max-height: 5rem;
    }
}

.section-start .hero {
  position: relative;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-top: 18rem;
  z-index: 3;
}

@media only screen and (max-width: 1280px) {
  .section-start .hero {
      flex-direction: column;
      align-items: center;
      margin-top: 14rem;
    }
}

@media only screen and (max-width: 991px) {
  .section-start .hero {
      margin-top: 18rem;
    }
}

@media only screen and (max-width: 767px) {
  .section-start .hero {
      margin-top: 10rem;
    }
}

.section-start .hero__content {
  margin-bottom: 4.8rem;
  max-width: 70rem;
  text-align: left;
}

@media only screen and (max-width: 1280px) {
  .section-start .hero__content {
      margin-bottom: 2.4rem;
      text-align: center;
    }
}

.section-start .hero__title {
  margin-top: 6.4rem;
  margin-bottom: 2.4rem;
  color: #fff;
}

@media only screen and (max-width: 1469px) {
  .section-start .hero__title {
      margin-top: 0.8rem;
    }
}

@media only screen and (max-width: 1280px) {
  .section-start .hero__title {
      margin-top: 4rem;
    }
}

@media only screen and (max-width: 991px) {
  .section-start .hero__title {
      margin-top: 0;
      margin-bottom: 0.8rem;
    }
}

.section-start .hero__subtitle {
  color: #fcf8b3;
  font-size: 2.4rem;
  line-height: 1.3;
}

@media only screen and (max-width: 991px) {
  .section-start .hero__subtitle {
      font-size: 2rem;
      line-height: 1.15;
    }
}

.section-start .hero__media {
  max-width: 72rem;
  min-width: 58rem;
}

@media only screen and (max-width: 1469px) {
  .section-start .hero__media {
      min-width: 50rem;
    }
}

@media only screen and (max-width: 991px) {
  .section-start .hero__media {
      min-width: auto;
    }
}

.section-start .btn-primary {
  border-color: rgba(7, 96, 0, 0.39);
}

.section-start .btn-primary:hover,
.section-start .btn-primary:focus,
.section-start .btn-primary.focus {
  border-color: rgba(7, 96, 0, 0.39);
}

.section-start .btn-shadow::before {
  box-shadow: rgba(8, 86, 0, 0.52) 0 25px 30px -20px;
}

.section-start .btn-shadow:focus::before,
.section-start .btn-shadow.focus::before {
  box-shadow: rgba(8, 86, 0, 0.52) 0 5px 5px -5px;
}

.section-insights {
  position: relative;
  overflow: hidden;
  z-index: 1;
}

@media print {
  .section-insights {
      display: none !important;
    }
}

/* Reverted to the original top values (was briefly -54rem/-58rem, tried as a
   "shrink the swoosh's reveal window" fix). That distorted the decoration
   itself: the curve is a rounded-corner rectangle whose horizontal radius
   (100rem) is wider than the box, so both bottom corners' arcs merge into
   one continuous shallow curve -- shrinking the revealed dip cropped that
   curve mid-arc, rendering it either flat (the arc's near-flat centre) or
   with a visible step (the steeper part near a corner), instead of moving a
   simple shape. See .section-insights__wrapper below for the real fix: give
   the heading clearance instead of re-cropping the art. */
.section-insights::before {
  position: absolute;
  top: -48rem;
  left: -5rem;
  right: -5rem;
  display: block;
  width: auto;
  height: 60rem;
  background: #fff;
  content: '';
  border-bottom-right-radius: 100rem 5rem;
  border-bottom-left-radius: 100rem 5rem;
  z-index: 1000;
}

@media only screen and (max-width: 1280px) {
  .section-insights::before {
      top: -50rem;
    }
}

@media only screen and (max-width: 991px) {
  .section-insights::before {
      top: -52rem;
    }
}

@media only screen and (max-width: 767px) {
  .section-insights::before {
      top: -54rem;
    }
}

.section-insights__wrapper {
  padding: 16rem 5rem;
  margin-left: -5rem;
  margin-right: -5rem;
  background: #fff url(https://s3.amazonaws.com/img.mynetdiary.com/images/pattern-grunge-400x400.jpg) 0 0 repeat;
  overflow: hidden;
  border-bottom-right-radius: 100rem 5rem;
  border-bottom-left-radius: 100rem 5rem;
}

@media only screen and (max-width: 1469px) {
  .section-insights__wrapper {
      padding-top: 14rem;
      padding-bottom: 1.6rem;
    }
}

@media only screen and (max-width: 1280px) {
  .section-insights__wrapper {
      padding-top: 12rem;
      padding-bottom: 8rem;
    }
}

@media only screen and (max-width: 767px) {
  .section-insights__wrapper {
      padding-top: 10rem;
    }
}

/* The wrapper's padding-top DUPLICATES the section's own. `.section-insights`
   is always on the same element as `.page-section` -- iPhone:655, android:668,
   vfd:618, the only three sections that nest this wrapper -- so the section
   already contributes 8rem/8rem/4rem/4rem (1440/1280/991/767), and the
   wrapper added 14rem (1440), 12rem (1200/768) or 10rem (390) on top of it.
   Measured, `.comparison-section__title` sat 220px below its section top at
   1440, 200 at 1200, 160 at 768, 130 at 390, against 80/80/40/30 for every
   other section heading. C-09.
   Zeroing padding-top here (this rule's original fix) landed the heading on
   80/80/40/30, matching every other section heading -- but it also put the
   heading right where `.section-insights::before` (the decorative swoosh,
   z-index 1000) dips into the section, which C-09 did not measure because
   the swoosh does not move: overlap was a new problem, not a reintroduced
   one. Confirmed by screenshot on /android.html.
   This is not a full revert of C-09 -- it adds back only enough clearance
   for the swoosh's OWN (unchanged) dip -- 12rem/10rem/8rem/6rem at
   1440/1280/991/767 -- plus a 2rem margin, minus what `.page-section`
   already contributes. Heading lands at 140/120/100/80 instead of C-09's
   target of 80/80/40/40, but nowhere near the original 220/200/160/130 bug.
   Buffer trimmed twice, 2026-09-04, Mikita, both times because the entry-side
   gap (paragraph into this section) read too big on iPhone and vfd: 2rem
   safety margin above the swoosh's own dip -> 1rem (6/4/6/4rem ->
   5/3/5/3rem, clearing by 10px) -> 0 (5/3/5/3rem -> 4/2/4/2rem, clearing by
   exactly 0px). Even at 0px it still didn't read as fixed, because the
   swoosh-clearance padding was never the biggest piece of the gap -- see
   the `:has()` rule further below for the piece that actually was.
   REMOVED 2026-09-04, Mikita, tuned live in DevTools: this padding-top
   moved to `.section-insights .comparison-section__title`'s own
   margin-top instead (near `.comparison-section__title`'s base rule) --
   same clearance job, but as a property of the heading rather than an
   ad-hoc number on an ancestor chasing the swoosh's dip. padding-bottom
   below is unrelated (the EXIT-side fix) and stays. */
.page-section.section-insights .section-insights__wrapper {
  padding-top: 0;
  /* TRIAL 2026-09-04, Mikita: the boundary after this section measured
     176px (16 wrapper pad-bottom + 80 this section's own pad-bottom + 80
     next section's pad-top) against the family's normal 160px (80+80)
     inter-section rhythm. The next section's own pad-top is zeroed below,
     bringing the section-to-section rhythm to a single 80px gap.
     padding-bottom here first went to 0 to match, but that put the store
     badges flush against the wrapper's own rounded bottom edge -- cramped,
     found by screenshot. 4rem matches `.comparison-cta`'s own margin-top
     (3398), so the badges get the same breathing room below that they
     already have above, rather than a new invented number.
     Higher specificity than the unscoped `.section-insights__wrapper`
     breakpoint rules above (0,3,0 vs 0,1,0), so this wins at every width
     without a matching set of per-breakpoint overrides. */
  padding-bottom: 4rem;
}

/* TRIAL 2026-09-04, pairs with the wrapper's padding-bottom: 0 above --
   see that comment for the full 176px -> 80px breakdown. `.page-section`'s
   own padding-top (80px, `.page-section` base rule) still applies to every
   OTHER section boundary on the page, so this only fires immediately after
   a `.section-insights` section: iPhone, android and verified-food-database
   are the only three pages with one. */
.section-insights + .page-section {
  padding-top: 0;
}

/* Same double-padding problem as the rule above, different pair: `.press-strip.page-section`
   carries its own padding: var(--section-80) 0 (pages-2026.css:4955) so its bottom padding
   already provides the gap before whatever follows. On free-calorie-tracker the very next
   section is "At a Glance" (`.ai-features.page-section`), so the press-strip's 8rem bottom
   plus this section's own 6rem top stacked into a visibly doubled gap after the "32 million
   people trust MyNetDiary" line. Mikita, 2026-09-07. */
.press-strip + .page-section {
  padding-top: 0;
}

/* Mirrors the rule above, for the OTHER side. Every earlier trim on the
   entry gap (paragraph/feature-grid into this section) touched only the
   wrapper's swoosh-clearance padding-top -- at most 60px of a 218-243px
   total -- so it never read as a visible change, exactly as it looked:
   Mikita confirmed twice, 2026-09-04, on iPhone and vfd, after each trim.
   The bulk of that gap was the SAME double-stack the exit side had: the
   preceding section's own 80px padding-bottom, stacked with this section's
   own 80px padding-top, on top of the swoosh's own clearance requirement --
   three numbers doing the one job the exit side now does with one.
   `:has()` is already used elsewhere in this sheet (grep count: 9), so this
   is an accepted pattern here, not a new dependency. Zeroing the preceding
   section's own padding-bottom removes the redundant half of the double
   stack; `.section-insights`'s own 80px padding-top plus the heading's own
   margin-top are what's left, and neither is redundant.
   `display: flow-root` fixes a real but separate bug: padding-bottom:0
   with no border means this section no longer blocks margin collapse, so
   its last child's own trailing margin was leaking through the section's
   bottom edge and escaping as space OUTSIDE the box, between this section
   and `.section-insights`, rather than being contained inside it. flow-root
   establishes a new block formatting context, containing that margin
   without clipping anything. Does NOT change the total visible gap --
   confirmed by measurement before/after, byte-identical -- because the
   margin still exists either way, just correctly inside the box now
   instead of leaking past it. Fixed for correctness, not for the number.
   The real per-page difference (iPhone/android both measure 128px true
   entry gap once you measure from the TALLEST content in a multi-column
   section, not blindly the last DOM child; vfd measures 143px, 20px more,
   from its own last paragraph's ordinary margin-bottom) is ordinary
   content spacing, not a section-boundary bug, and is deliberately left
   alone -- same principle as the exit side's badges, which get no special
   treatment either. */
.page-section:has(+ .section-insights) {
  padding-bottom: 0;
  display: flow-root;
}

@media only screen and (max-width: 991px) {
  .comparison-section {
      padding: 4rem 0;
    }
}

@media only screen and (max-width: 575px) {
  .comparison-section {
      padding: 3rem 0;
    }
}

/* 4rem, not 3.2rem: Figma's h2-to-first-element gap is 40px, declared as an
   auto-layout gap on node 3721:36533 and corroborated on eight more sections.
   C-09. */
.comparison-section__title {
  margin: 0 0 4rem;
  color: #268fd0;
}

@media only screen and (max-width: 991px) {
  .comparison-section__title {
      margin-bottom: 2.8rem;
    }
}

@media only screen and (max-width: 767px) {
  .comparison-section__title {
      margin-bottom: 2.4rem;
      line-height: 1.12;
    }
}

/* Mikita, 2026-09-04, tuned live in DevTools: the entry-side swoosh
   clearance was carried entirely by `.section-insights__wrapper`'s own
   padding-top (an ad-hoc value chasing the swoosh's dip -- see that rule's
   history below). Replaced with the SAME mechanism `.comparison-section__title`
   already uses for its OWN bottom gap -- margin, not an ancestor's padding --
   so the entry gap reads as a property of the heading, symmetric with its
   `margin-bottom: 4rem` above.
   SCOPED to `.section-insights` on purpose: this class is also used by
   free-calorie-tracker's plain `.page-section` (no wrapper, no swoosh,
   the C-09 control that must not move) and by static_index.st's two
   `.section-insights` sections (the homepage, out of scope for this
   ticket but sharing this exact class -- already affected by every
   swoosh/spacing fix today, not a new exposure). An unscoped margin-top
   here would have added 40px to the control page's already-correct
   spacing.
   4rem cleared the swoosh by exactly 0px -- correct by the numbers, but
   Mikita found it read as touching once he saw it rendered. Bumped to
   6rem, tuned live in DevTools, 2026-09-04: +2rem over the previous
   value, now clearing by 20px at this tier instead of 0. The same +2rem
   was carried into both breakpoints below for the same reason -- this is
   an addition on top of an already-verified-safe floor, so it can only
   increase clearance, never reintroduce the overlap. */
.section-insights .comparison-section__title {
  margin-top: 6rem;
}

/* 6rem, not 2.8 (`.comparison-section__title`'s own margin-bottom value at
   this breakpoint): the swoosh's own dip jumps from 10rem to 8rem exactly
   at 991px too, and `.page-section`'s padding-top drops from 8rem to 4rem
   at the same breakpoint. 2.8rem measured -12px here -- COVERED -- on all
   three pages; 4rem cleared by 0px. Found by measuring all 24 breakpoint
   pair x page combinations, not by eye -- this one only showed up between
   768 and 991, a range no screenshot in this thread happened to land on.
   Carries the same +2rem bump as the base rule above, 2026-09-04. */
@media only screen and (max-width: 991px) {
  .section-insights .comparison-section__title {
      margin-top: 6rem;
    }
}

@media only screen and (max-width: 767px) {
  .section-insights .comparison-section__title {
      margin-top: 4.4rem;
    }
}

.comparison-section__note {
  margin: 2rem 0 0;
  text-align: center;
  font-size: 1.4rem;
  line-height: 1.5;
  color: #2c3e50;
}

@media only screen and (max-width: 767px) {
  .comparison-section__note {
      font-size: 1.3rem;
    }
}

.comparison-table-wrap {
  padding-bottom: var(--space-40);
}

@media only screen and (max-width: 991px) {
/* D20, from SRV-4562: overflow-x moved OUT of this media query -- see the
   SRV-4562 ADDITIONS block at the end of this file. The free-calorie-tracker
   page's comparison table is 7 columns and escaped the page between 992px and
   ~1470px without it (measured: document 1227px in a 1024 viewport). The iPhone
   page's table is 4 columns and does not overflow, so this is inert here. */
}

.comparison-table-wrap:focus-visible {
  outline: 0.2rem solid #268fd0;
  outline-offset: 0.2rem;
}

.comparison-table {
  width: 100%;
  min-width: 96rem;
  border-radius: 3.2rem;
  border-collapse: separate;
  background: #ffffff;
  border-spacing: 0;
}

@media only screen and (max-width: 991px) {
  .comparison-table {
      min-width: 84rem;
    }
}

@media only screen and (max-width: 767px) {
  .comparison-table {
      min-width: 72rem;
      border-radius: 2.4rem;
    }
}

/* 34 rows, three tier columns. At 575 the old 48rem floor split as roughly
   12rem of feature column and 36rem of tiers, and the feature column is where all
   the words are -- "Health tracking: body measurements, blood pressure,
   cholesterol, blood glucose, A1C, ketones" wrapped to eight lines and turned a
   34-row table into a 34-row wall. The tier columns hold a single glyph and can
   take 7.2rem; the reclaimed width goes to the row title (see
   `.comparison-table__row-title` below). 19 + 3 x 7.2 = 40.6, so 41rem. */
@media only screen and (max-width: 575px) {
  .comparison-table {
      min-width: 41rem;
    }
}

.comparison-table th:nth-child(2),
.comparison-table td:nth-child(2) {
  position: relative;
  z-index: 1;
  background: #eef7f1;
}

.comparison-table thead th:nth-child(2) {
  border-top-left-radius: 2.4rem;
  border-top-right-radius: 2.4rem;
}

.comparison-table tbody tr:last-child td:nth-child(2) {
  border-bottom-left-radius: 2.4rem;
  border-bottom-right-radius: 2.4rem;
}

.comparison-table th:nth-child(2)::before,
.comparison-table td:nth-child(2)::before {
  content: '';
  position: absolute;
  inset: 0;
  border-left: 0.2rem solid #16b453;
  border-right: 0.2rem solid #16b453;
  pointer-events: none;
}

.comparison-table thead th:nth-child(2)::before {
  top: -16px;
  border-top: 0.2rem solid #16b453;
  border-top-left-radius: 2.4rem;
  border-top-right-radius: 2.4rem;
  background: #eef7f1;
  z-index: -1;
}

@media only screen and (max-width: 767px) {
  .comparison-table thead th:nth-child(2)::before {
      top: -8px;
      border-top-left-radius: 2rem;
      border-top-right-radius: 2rem;
    }
}

@media only screen and (max-width: 575px) {
  .comparison-table thead th:nth-child(2)::before {
      top: -4px;
      border-top-left-radius: 1.6rem;
      border-top-right-radius: 1.6rem;
    }
}

.comparison-table tbody tr:last-child td:nth-child(2)::before {
  bottom: -16px;
  border-bottom: 0.2rem solid #16b453;
  border-bottom-left-radius: 2.4rem;
  border-bottom-right-radius: 2.4rem;
  background: #eef7f1;
  z-index: -1;
}

@media only screen and (max-width: 767px) {
  .comparison-table tbody tr:last-child td:nth-child(2)::before {
      bottom: -8px;
      border-bottom-left-radius: 2rem;
      border-bottom-right-radius: 2rem;
    }
}

@media only screen and (max-width: 575px) {
  .comparison-table tbody tr:last-child td:nth-child(2)::before {
      bottom: -4px;
      border-bottom-left-radius: 1.6rem;
      border-bottom-right-radius: 1.6rem;
    }
}

.comparison-table tbody tr:last-child th:first-child {
  border-bottom-left-radius: 3.2rem;
}

@media only screen and (max-width: 767px) {
  .comparison-table tbody tr:last-child th:first-child {
      border-bottom-left-radius: 2.4rem;
    }
}

.comparison-table tbody tr:last-child td:last-child {
  border-bottom-right-radius: 3.2rem;
}

@media only screen and (max-width: 767px) {
  .comparison-table tbody tr:last-child td:last-child {
      border-bottom-right-radius: 2.4rem;
    }
}

.comparison-table thead th:first-child {
  position: sticky;
  left: 0;
  z-index: 4;
  background: #ffffff;
  box-shadow: 1.2rem 0 1.6rem -1.6rem rgba(73, 100, 143, 0.2);
  border-top-left-radius: 3.2rem;
}

@media only screen and (max-width: 767px) {
  .comparison-table thead th:first-child {
      border-top-left-radius: 2.4rem;
    }
}

.comparison-table thead th:last-child {
  border-top-right-radius: 3.2rem;
}

@media only screen and (max-width: 767px) {
  .comparison-table thead th:last-child {
      border-top-right-radius: 2.4rem;
    }
}

.comparison-table tbody th[scope='row'] {
  position: sticky;
  left: 0;
  z-index: 3;
  background: #ffffff;
  box-shadow: 1.2rem 0 1.6rem -1.6rem rgba(73, 100, 143, 0.2);
}

@media only screen and (max-width: 767px) {
  .comparison-table tbody th[scope='row']::after,
    .comparison-table thead th:first-child::after {
      content: '';
      position: absolute;
      top: 0;
      right: -1.6rem;
      width: 1.6rem;
      height: 100%;
      background: linear-gradient(to right, rgba(73, 100, 143, 0.08), rgba(73, 100, 143, 0));
      pointer-events: none;
    }
}

.comparison-table__caption {
  caption-side: top;
  padding: 0 0 4rem;
  text-align: center;
  font-size: 1.8rem;
  line-height: 1.4;
  font-weight: 500;
  color: #2c3e50;
}

@media only screen and (max-width: 767px) {
  .comparison-table__caption {
      padding-bottom: 3.6rem;
      font-size: 1.5rem;
    }
}

.comparison-table__col {
  min-width: 16rem;
  text-align: center;
}

@media only screen and (max-width: 991px) {
  .comparison-table__col {
      min-width: 16rem;
    }
}

@media only screen and (max-width: 767px) {
  .comparison-table__col {
      min-width: 12rem;
    }
}

.comparison-table__col--feature {
  min-width: 24rem;
  text-align: left;
}

@media only screen and (max-width: 991px) {
  .comparison-table__col--feature {
      min-width: 18rem;
    }
}

@media only screen and (max-width: 767px) {
  .comparison-table__col--feature {
      min-width: 16rem;
    }
}

@media only screen and (max-width: 767px) {
  .comparison-table__col--feature {
      min-width: 0;
    }
}

.comparison-table__head {
  font-size: 2.4rem;
}

.comparison-table__subhead {
  margin-top: 0.2rem;
  font-size: 2.4rem;
}

.comparison-table__head,
.comparison-table__subhead {
  color: #268fd0;
  line-height: 1.2;
  font-weight: 600;
}

@media only screen and (max-width: 991px) {
  .comparison-table__head,
    .comparison-table__subhead {
      display: block;
      font-size: 1.8rem;
    }
}

@media only screen and (max-width: 767px) {
  .comparison-table__head,
    .comparison-table__subhead {
      font-size: 1.4rem;
    }
}

.comparison-table thead th {
  padding: 2.4rem 1.6rem 2rem;
  vertical-align: top;
  background: #ffffff;
}

@media only screen and (max-width: 767px) {
  .comparison-table thead th {
      padding: 2rem 1.2rem 1.6rem;
    }
}

@media only screen and (max-width: 575px) {
  .comparison-table thead th {
      padding: 1.6rem 0.8rem;
    }
}

.comparison-table tbody th,
.comparison-table tbody td {
  padding: 2rem 1.6rem;
  border-top: 0.1rem solid #d8e0ea;
  background: #ffffff;
  vertical-align: middle;
  text-align: center;
  font-size: 2rem;
  line-height: 1.35;
  color: #2c3e50;
}

@media only screen and (max-width: 767px) {
  .comparison-table tbody th,
    .comparison-table tbody td {
      padding: 1.6rem 1.2rem;
      font-size: 1.4rem;
    }
}

@media only screen and (max-width: 767px) {
  .comparison-table tbody th,
    .comparison-table tbody td {
      padding: 1.4rem 0.8rem;
    }
}

.comparison-table tbody tr:first-child th,
.comparison-table tbody tr:first-child td {
  border-top: none;
}

.comparison-table__row-title {
  min-width: 24rem;
  text-align: left !important;
  font-size: 2.4rem !important;
  line-height: 1.25 !important;
  font-weight: 500;
  color: #2c3e50;
}

@media only screen and (max-width: 991px) {
  .comparison-table__row-title {
      font-size: 1.7rem !important;
    }
}

@media only screen and (max-width: 767px) {
  .comparison-table__row-title {
      min-width: 18rem;
      font-size: 1.4rem !important;
      line-height: 1.2 !important;
    }
}

/* Was `min-width: 0`, which let the sticky first column collapse to whatever the
   tier columns left over. It is the sticky column -- it is on screen for the whole
   scroll, so it is the one column that must stay readable. */
@media only screen and (max-width: 575px) {
  .comparison-table__row-title {
      min-width: 19rem;
    }
}

.comparison-table__mark {
  display: inline-block;
  font-size: 3rem;
  line-height: 1;
  font-weight: 600;
  vertical-align: middle;
}

@media only screen and (max-width: 767px) {
  .comparison-table__mark {
      font-size: 2.6rem;
    }
}

.comparison-table__mark--yes {
  color: #0bb850;
}

.comparison-table__mark--no {
  color: #f04438;
}

.comparison-table__note {
  display: block;
  margin-top: 0.8rem;
  font-size: 2rem;
  line-height: 1.35;
  color: #2c3e50;
}

@media only screen and (max-width: 767px) {
  .comparison-table__note {
      margin-top: 0.6rem;
      font-size: 1.1rem;
      line-height: 1.3;
    }
}

.comparison-cta {
  margin-top: 4rem;
  text-align: center;
}

@media only screen and (max-width: 767px) {
  .comparison-cta {
      margin-top: 3.2rem;
    }
}

.comparison-cta__text {
  margin: 0 0 2rem;
  font-size: 1.8rem;
  line-height: 1.4;
  font-weight: 400;
  color: #2c3e50;
}

@media only screen and (max-width: 767px) {
  .comparison-cta__text {
      margin-bottom: 2rem;
      font-size: 1.6rem;
    }
}

@media only screen and (max-width: 575px) {
  .comparison-cta__text {
      max-width: 24rem;
      margin-left: auto;
      margin-right: auto;
    }
}

.comparison-cta__stores {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.6rem;
  flex-wrap: wrap;
}

@media only screen and (max-width: 767px) {
  .comparison-cta__stores {
      gap: 1.2rem;
    }
}

@media only screen and (max-width: 575px) {
  .comparison-cta__stores {
      flex-direction: column;
    }
}

.comparison-cta__store-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
}

.comparison-cta__store-link img {
  display: block;
  width: auto;
  height: 4.2rem;
}

@media only screen and (max-width: 767px) {
  .comparison-cta__store-link img {
      height: 4.8rem;
    }
}

.device-sync {
  padding: 6.4rem 0;
  overflow: hidden;
}

@media only screen and (max-width: 991px) {
  .device-sync {
      padding: 5.6rem 0;
    }
}

@media only screen and (max-width: 767px) {
  .device-sync {
      padding: 4.8rem 0;
    }
}

.device-sync__title {
  margin: 0 0 4rem;
  text-align: center;
  color: #268fd0;
}

@media only screen and (max-width: 991px) {
  .device-sync__title {
      margin-bottom: 3.2rem;
      line-height: 1.1;
    }
}

@media only screen and (max-width: 767px) {
  .device-sync__title {
      margin-bottom: 2.8rem;
      text-align: left;
      line-height: 1.12;
    }
}


/* =============================================================================
   SRV-4560 -- ADDITIONS
   -----------------------------------------------------------------------------
   Hand-written. Everything above is extracted; everything here is not, so this
   section is the one a reviewer must actually read.
   ============================================================================= */

/* -----------------------------------------------------------------------------
   THE SPACING SCALE. Three families, and the reason there are three rather than
   one is that they are different registers, not different magnitudes: nothing in
   48-180 is ever a heading margin, and nothing in 4-40 is ever a section gap.
   One ladder would imply they trade off against each other, and they do not.

   Declared HERE, inside ADDITIONS, deliberately -- not in the `:root` at :362,
   which is in the machine-extracted half of this file. Everything above the
   ADDITIONS banner is generated by extract-css-blocks.py and is not ours to edit.

   Negatives use `calc(var(--x) * -1)` at the call site rather than a mirrored
   negative token set: seven call sites do not justify doubling the scale.

   NOT tokenised, on purpose, and each for its own reason:
     58/72/88/96rem  layout constraints -- a hero box, a prose measure cap, a
                     table scroll floor. Folding a measure cap into a spacing
                     scale invites someone to "unify" it with a section step.
     15px            the `.container` gutter. A layout constant.
     5rem / -5rem    `.section-insights__wrapper`'s full-bleed trick, where the
                     padding and the negative margin are one mechanism.
     1px / 2px / 0.2rem   hairlines and borders, not spacing.
     -0.1rem         an optical correction.
     0.3125rem       a legacy 5px-at-a-different-root conversion artefact.
   ----------------------------------------------------------------------------- */
:root {
  --space-4: 0.4rem;
  --space-8: 0.8rem;
  --space-12: 1.2rem;
  --space-16: 1.6rem;
  --space-20: 2rem;
  --space-24: 2.4rem;
  --space-28: 2.8rem;
  --space-32: 3.2rem;
  --space-40: 4rem;

  --section-48: 4.8rem;
  --section-52: 5.2rem;
  --section-56: 5.6rem;
  --section-64: 6.4rem;
  --section-80: 8rem;
  --section-120: 12rem;

  --space-decimal-10: 1rem;

  /* THE LINK COLOUR. Mikita ruled 2026-09-04: every link on these pages shares one
     CSS. #0cb04e was already the house link green -- it was just written as a literal
     in three separate scoped rules while `.prose-link`, the class carrying 31 of the
     family's in-prose links, had no colour at all and fell back to `a { color:
     #2c3e50 }`, the body-text colour. Same value, one home, and `.prose-link` joins it.
     Contrast is 2.86:1 on white, below WCAG AA for text -- which is why the underline
     `.prose-link` already sets stays: colour is not the only cue. */
  --link: #0cb04e;

  /* THE HAIRLINE. Figma draws the comparison tables' edge as 1px rgba(0,0,0,0.1)
     (nodes 3921:51042 and 3923:51136) and their row divider on the same value, so
     it is one token doing two jobs in the design. Declared once here.

     `.speed-chart` uses a DIFFERENT hairline, #e3eaf0, and a 12px radius against
     the table's 32px. Deliberately NOT folded in: Figma has not been read for that
     card, and unifying two values because they look similar is how a design gets
     answered by edit. Asked, not assumed -- see
     tickets/SRV-4560/reports/p7-speed-chart-2026-09-04.md when it lands. */
  --hairline: rgba(0, 0, 0, 0.1);
}

/* SEVEN TOKENS WERE DROPPED BEFORE THIS SHIPPED, because they had zero users in
   this section and a token with no users is dead weight from day one:
     --space-36, --space-decimal-5, --space-decimal-30, --section-100,
     --section-140, --section-180
   Their VALUES do occur in this file -- 3.6rem, 0.5rem, 3rem, 10rem, 14rem,
   18rem -- but only above the ADDITIONS banner, in the machine-extracted half,
   which is out of scope. Add a token back when a rule in THIS section needs it.

   --section-160 IS THE INTERESTING ONE, and it is worth knowing why it is not
   here. 160px is Figma's section rhythm -- the single most load-bearing spacing
   number in this design, measured 13 of 13 on the reference page. It appears
   NOWHERE as a literal, because it is not one: adjacent sections abut, so the
   gap is one section's padding-bottom plus the next one's padding-top, and
   `.page-section` supplies 8rem on each side. The 160 is an EMERGENT SUM of two
   80s, and `.page-section` itself lives in the extracted half.
   So the most important number in the system is the one that cannot be
   tokenised here. Anyone hunting for "the 160" will not find it -- they should
   look for `.page-section`'s 8rem instead. */

/* Modifiers on existing blocks. NOT new blocks -- each one only cancels or
   re-parameterises a declaration in the extracted rules above, because the
   mockup uses an existing block in a shape index does not happen to use.
   Anything larger than this belongs to the design owner, not to us. */

/* index only ever renders .ai-card WITH an .ai-card__media child, so below
   991px the block becomes a 40%/1fr two-column grid to sit the image beside the
   text. The mockup's "Why People Switch", "What You Get for Free" and "Deep iOS
   Integration" cards are text-only, and a text-only card in that grid would be
   squeezed into the 40% column. This restores normal flow for those. */
@media only screen and (max-width: 991px) {
  .ai-card.ai-card--text-only {
    /* Both classes on purpose. An .ai-card--text-only alone has the same
       specificity as the .ai-card rules it must beat, so it would be winning on
       source order only -- and it would silently stop winning the moment a
       later append adds another .ai-card rule below it, with no error. Doubling
       the class makes the override structural instead of positional. */
    display: block;
  }
}

/* .ai-features__wrapper is a 3-up grid on index. Two mockup sections are 4-up.
   Below 991px the base rule switches the wrapper to display:block and this
   becomes inert, which is the mobile-first behaviour we want. */
@media only screen and (min-width: 992px) {
  .ai-features__wrapper--4up {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* THE ONE NEW BLOCK IN THIS FILE. Flagged for sign-off.
   The mockup's "Recognized by" row is a static, centred list of press citations
   (Forbes Health, NYT, Am. Journal of Preventive Medicine). No existing block
   fits, for CONTENT reasons: index's .ratings-strip is an app-store ratings
   widget -- a star-rating card plus a Trustpilot embed, static_index.st:86-130 --
   so forcing press mentions into it would misrepresent them.

   An earlier draft of this comment claimed .ratings-strip "is a marquee". That
   was wrong and is recorded here on purpose. The marquee is .logo-marquee
   (homepage.css:11528), a different block that index nests inside device-sync.
   .ratings-strip has zero animation rules.

   Four rules, in the same token language as everything above. */
.press-strip {
  padding: 2.6rem 0;
  border-top: 0.1rem solid #e3eaf0;
  border-bottom: 0.1rem solid #e3eaf0;
}

.press-strip__eyebrow {
  margin-bottom: var(--space-16);
  font-size: 1.2rem;
  letter-spacing: 0.2rem;
  text-transform: uppercase;
  text-align: center;
  color: #6b7a88;
}

.press-strip__list {
  display: flex;
  flex-wrap: wrap;
  gap: 1.4rem var(--space-40);
  justify-content: center;
  align-items: center;
  padding-left: 0;
  list-style: none;
}

.press-strip__list li {
  max-width: 23rem;
  font-size: 1.4rem;
  text-align: center;
  color: #6b7a88;
}

/* -----------------------------------------------------------------------------
   DEFECT FIX: the comparison table highlighted the WRONG column.

   Found by wM:p6 in a screenshot, confirmed in the CSS by wM:p4 and again by me
   against the served page. It was a shipped defect, not a missing enhancement.

   The extracted highlight above (mint #eef7f1 + green #16b453 border + rounded
   caps, pages-2026.css ~1460-1535) is driven entirely by UNCONDITIONAL
   positional selectors -- `.comparison-table th:nth-child(2)` and
   `td:nth-child(2)`. There is no class and no scoping. It fires on column two of
   any .comparison-table, whatever that column happens to contain.

   On static_index.st that is harmless by coincidence: its highlighted column,
   "MyNetDiary (Free)", IS column two. On this page the columns are
   Feature | Free | Premium | Premium Plus, so the base rule painted **Free**,
   and `is-highlight` on Premium Plus painted nothing -- the page was telling
   readers the free tier was the recommended plan.

   Two of my earlier conclusions were wrong and are corrected here, on purpose:

     1. I recorded `is-highlight` as "no rule anywhere, therefore inert". The
        CLASS has no rule, but the highlight MECHANISM is very much alive; it is
        positional instead of declarative. "Unstyled class" and "no highlight"
        are not the same statement, and I conflated them.
     2. I recorded that homepage.css "has no brand tint to reuse", and refused to
        pick a colour on those grounds. The tint was there all along, in this very
        block: #eef7f1 with a #16b453 border. My earlier grep for light tints even
        surfaced #eef7f1 and I dismissed it. So this fix invents nothing -- it
        reuses the exact tokens the design already uses for exactly this job.

   The fix keeps the base rule intact for index's own use and only changes
   behaviour for a table that declares its highlight explicitly:
     - cancel the positional highlight WHEN the table contains .is-highlight
     - re-apply the identical tokens on .is-highlight instead
   Cancelling is scoped with :has(), giving it higher specificity than the base
   rule, so it wins structurally rather than by source order.
   ----------------------------------------------------------------------------- */

/* 1. Cancel the positional highlight wherever the column does not declare one.

   Two earlier drafts of this were worse, and both mistakes are worth keeping:

   Draft 1 scoped the cancel with `:has(.is-highlight)`, to stay byte-faithful to
   index's behaviour. But index does not load this file at all -- static_index.st:22
   loads homepage.css, and pages-2026.css is referenced by exactly one template.
   homepage.css is untouched. So the scoping protected nothing, while leaving a real
   trap in place: any future page loading this sheet WITHOUT declaring
   `.is-highlight` would still have had column two painted, whatever that column
   meant there. That is the identical defect, armed for SRV-4561 and SRV-4562.

   Draft 2 made the cancel unconditional but gave it the SAME selector as the
   extracted base rule, so it won only by sitting later in the file -- the exact
   positional fragility flagged earlier in this very file on
   `.ai-card--text-only`, reintroduced two hours later by the same author.

   `:not(.is-highlight)` fixes both at once:

     specificity   base (0,2,1) < cancel (0,3,1), so the cancel wins STRUCTURALLY,
                   not by source order.
     disjointness  the cancel and the re-apply below can never match the same
                   element, at any specificity, in any order. Bumping specificity
                   alone would have been worse than useless -- a stronger cancel
                   would kill the highlight on a page whose declared column IS
                   column two, which is precisely index's shape.

   Reads as a sentence: "column two is not special unless it says so." */
.comparison-table th:nth-child(2):not(.is-highlight),
.comparison-table td:nth-child(2):not(.is-highlight) {
  background: transparent;
}

.comparison-table thead th:nth-child(2):not(.is-highlight),
.comparison-table tbody tr:last-child td:nth-child(2):not(.is-highlight) {
  border-radius: 0;
}

.comparison-table th:nth-child(2):not(.is-highlight)::before,
.comparison-table td:nth-child(2):not(.is-highlight)::before {
  content: none;
}

/* 2. Re-apply the same treatment on the column that actually declares it. */
.comparison-table th.is-highlight,
.comparison-table td.is-highlight {
  position: relative;
  z-index: 1;
  background: #eef7f1;
}

.comparison-table thead th.is-highlight {
  border-top-left-radius: 2.4rem;
  border-top-right-radius: 2.4rem;
}

.comparison-table tbody tr:last-child td.is-highlight {
  border-bottom-left-radius: 2.4rem;
  border-bottom-right-radius: 2.4rem;
}

.comparison-table th.is-highlight::before,
.comparison-table td.is-highlight::before {
  content: '';
  position: absolute;
  inset: 0;
  border-left: 0.2rem solid #16b453;
  border-right: 0.2rem solid #16b453;
  pointer-events: none;
}

.comparison-table thead th.is-highlight::before {
  top: -16px;
  border-top: 0.2rem solid #16b453;
  border-top-left-radius: 2.4rem;
  border-top-right-radius: 2.4rem;
  background: #eef7f1;
  z-index: -1;
}

@media only screen and (max-width: 767px) {
  .comparison-table thead th.is-highlight::before {
    top: -8px;
    border-top-left-radius: 2rem;
    border-top-right-radius: 2rem;
  }
}

@media only screen and (max-width: 575px) {
  .comparison-table thead th.is-highlight::before {
    top: -4px;
    border-top-left-radius: 1.6rem;
    border-top-right-radius: 1.6rem;
  }
}

.comparison-table tbody tr:last-child td.is-highlight::before {
  bottom: -16px;
  border-bottom: 0.2rem solid #16b453;
  border-bottom-left-radius: 2.4rem;
  border-bottom-right-radius: 2.4rem;
  background: #eef7f1;
  z-index: -1;
}

@media only screen and (max-width: 767px) {
  .comparison-table tbody tr:last-child td.is-highlight::before {
    bottom: -8px;
    border-bottom-left-radius: 2rem;
    border-bottom-right-radius: 2rem;
  }
}

@media only screen and (max-width: 575px) {
  .comparison-table tbody tr:last-child td.is-highlight::before {
    bottom: -4px;
    border-bottom-left-radius: 1.6rem;
    border-bottom-right-radius: 1.6rem;
  }
}

/* -----------------------------------------------------------------------------
   PENDING-ART STUBS — temporary, and built to be deleted.

   The ticket lists "small illustrations from the design team" as an open
   dependency. My first pass omitted the mockup's dashed placeholders entirely,
   reasoning that shipping placeholder boxes would ship the blocker. That was the
   wrong trade: it left the hero lopsided and the reviews section reading as
   broken rather than pending, and it gave Vlad nothing to judge the composition
   against.

   These stubs reserve the EXACT dimensions the mockup specifies, so the layout a
   reviewer sees now is the layout the real art will drop into — no reflow, and no
   cumulative-layout-shift surprise when the images land.

   Sizes are taken verbatim from the mockup's own CSS, converted px -> rem against
   this sheet's 10px root (see the base-layer note above):

     .qr           76 x 76      -> 7.6rem
     .watch-chip  120 x 140     -> 12rem x 14rem
     .watchface   190 x 224     -> 19rem x 22.4rem, screen inset 16px -> 1.6rem
     .carousel    100% x 300    -> 100% x 30rem
     .rev .avatar  44 x 44      -> 4.4rem
     .rev card    min-height 170 -> 17rem

   The dashed treatment is the mockup's own `.ph`, kept deliberately ugly so it
   cannot be mistaken for finished work.

   TO REMOVE: every stub carries `data-pending-art`, so
       grep -rn 'data-pending-art' src/minderweb/templates/
   finds all of them, and this whole block plus those elements come out together.
   ----------------------------------------------------------------------------- */

.art-stub {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--space-12);
  border: 0.2rem dashed #b9c6d2;
  border-radius: 1.2rem;
  background: repeating-linear-gradient(45deg, #f8fafc, #f8fafc 1.2rem, #f2f6f9 1.2rem, #f2f6f9 2.4rem);
  color: #8494a3;
  font-size: 1.3rem;
  font-style: italic;
  line-height: 1.3;
}

.art-stub--qr {
  flex: none;
  width: 7.6rem;
  height: 7.6rem;
  padding: 0.6rem;
  font-size: 1.05rem;
  background-color: #fff;
}

/* Sits over the hero phone render, bottom-left, as in the mockup. */
.hero__media {
  position: relative;
}

.art-stub--watch-chip {
  position: absolute;
  bottom: -0.6rem;
  left: 2%;
  width: 12rem;
  height: 14rem;
  border-radius: 2.6rem;
}

/* Watch: navy body with an inset screen, both sized from the mockup. */
.art-watchface {
  position: relative;
  width: 19rem;
  height: 22.4rem;
  margin: 0 auto;
  border-radius: 4.4rem;
  background: #2c3e50;
}

.art-stub--watch-screen {
  position: absolute;
  inset: 1.6rem;
  border-radius: 3.2rem;
}

.art-stub--carousel {
  width: 100%;
  height: 30rem;
  margin-top: 2.6rem;
}

.art-stub--avatar {
  flex: none;
  width: 4.4rem;
  height: 4.4rem;
  padding: 0;
  border-radius: 50%;
  font-size: 1rem;
}

/* Review cards: avatar + quote, card height reserved so four sit level. */
.review-card--pending {
  display: flex;
  flex-direction: column;
  gap: var(--space-decimal-10);
  min-height: 17rem;
}

.art-stub--quote {
  flex: 1;
}

/* The store-badge row needs to sit the QR beside the badge. */
.cta-with-qr {
  display: flex;
  align-items: center;
  gap: var(--space-16);
  flex-wrap: wrap;
}

/* =============================================================================
   SRV-4560 -- APPEND: RUNTIME-INJECTED STATE CLASSES              7 rules
   -----------------------------------------------------------------------------
   SHIP BLOCKER, found by wM:p6 by actually clicking the hamburger through CDP.
   The mobile navigation opened nothing.

   `.slideout-menu` was in the block list, so its base hidden-state rule was
   extracted. The rule that REVEALS the panel is

       .slideout-open .navbar-site .slideout-menu { display: block; }   (homepage.css:5641)

   and its leftmost compound is `.slideout-open`, which was never requested. So it
   was excluded -- correctly, by the same leftmost-compound scoping we introduced
   to stop the `.footer-site ._stores` leak and then all independently verified as
   right. The scoping fix and this miss are one mechanism, not two bugs. Narrowing
   what counts as "belonging to a block" necessarily drops rules whose ancestor is
   a state class.

   WHY NO COVERAGE CHECK COULD HAVE CAUGHT THIS. `.slideout-open` exists in no
   DOM, static or rendered -- `slideout.min.2019.js` adds it to the document on
   click. Source-mode coverage cannot see it; rendered-mode coverage cannot see it
   either, because the class only exists after interaction. This is a third
   category beyond "read the source" and "read the output": **read the scripts.**

   The generalised rule, now the method for finding these:

       for each $cmp_script(src=...)$ the page includes, grep the JS for
       classList.add/remove/toggle and className assignments; treat every class
       name it manipulates as a REQUIRED block, and confirm its FULL rule set was
       extracted -- not merely its base or hidden state.

   That grep over all four included scripts found exactly one cluster, all from
   the slideout pair: slideout-open, slideout-panel, slideout-panel-right,
   slideout-menu-right, slideout-backdrop. `mnt-faq.2019.js` and
   `lazysizes.min.2019.js` manipulate no classes needing CSS. The blocks live in
   tickets/SRV-4560/blocks.txt under a RUNTIME section.

   Two details wM:p4 confirmed from the library source, both worth keeping:

   `slideout-open` is added to **`document.documentElement`**, not to `<body>`.
   That is why homepage.css carries `.slideout-open body` as its own selector
   rather than letting `.slideout-open` cascade -- the state class and the body are
   different elements. Anyone reading these rules will otherwise assume a typo.

   `slideout-menu-right` and `slideout-panel-right` are listed in the block file
   but match **zero** rules: the library builds those names as `'slideout-menu-' +
   side`, and homepage.css defines no CSS for either. They are kept in the list on
   purpose, as a guard for the next page, so the extractor's zero-match warning
   naming them is EXPECTED and not a defect. The single-hyphen naming trap is real
   in general -- our matcher only accepts `__` and `--` after a block name, so
   `.slideout-menu-right` would never match block `slideout-menu` -- it simply
   costs nothing here.

   Appended, not regenerated -- see the source-of-truth rule at the top.
   Provenance: src/minderweb/css/homepage.css, md5 3a40e61733fc2296a2d97d9342a48ff6
   ============================================================================= */

.slideout-open body {
  height: 100%;
}

.slideout-open {
  position: fixed;
  overflow: hidden;
  width: 100%;
  height: 100%;
}

.slideout-panel {
  position: relative;
  z-index: 1;
}

.slideout-backdrop {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}

.slideout-open .slideout-backdrop {
  z-index: 1;
  visibility: visible;
  pointer-events: auto;
}

.slideout-open .navbar-site .navbar-toggler {
  position: relative;
}

.slideout-open .navbar-site .slideout-menu {
  display: block;
}

/* =============================================================================
   SRV-4560 -- APPEND: review-card                                 26 rules
   -----------------------------------------------------------------------------
   `review-card` was deliberately DROPPED from the block list earlier in this
   ticket, with the reason recorded in blocks.txt: the mockup's four review quotes
   were all dashed placeholders, so the section shipped as a heading, an intro and
   a link, and no card styling was needed.

   Mikita then asked for a stub per image at the correct size, so the four cards
   came back as `review-card review-card--pending`. The `--pending` modifier was in
   the ADDITIONS section, but the base block was not in the file at all -- the
   cards would have rendered with no border, padding or shadow.

   Caught by the rendered-mode coverage check, on its first run after the change,
   as its single unexplained class. That is exactly the job it was added for one
   hour earlier, and it is the first time one of these checks caught a regression
   BEFORE a human saw the page rather than after.

   Appended, not regenerated. Provenance: homepage.css, md5 3a40e61733fc2296a2d97d9342a48ff6
   ============================================================================= */

.review-card {
  min-height: 25.2rem;
  padding: var(--space-16);
  height: 100%;
  border: 0.1rem solid #d8d8d8;
  border-radius: 2.4rem;
  box-sizing: border-box;
}

@media only screen and (max-width: 991px) {
  .review-card {
      min-height: 22.8rem;
    }
}

@media only screen and (max-width: 767px) {
  .review-card {
      min-height: 22rem;
      padding: var(--space-12);
      border-radius: 2rem;
    }
}

.review-card__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-16);
  margin-bottom: var(--space-16);
}

@media only screen and (max-width: 767px) {
  .review-card__top {
      gap: var(--space-12);
      margin-bottom: 1.4rem;
    }
}

.review-card__person {
  display: flex;
  align-items: center;
  gap: var(--space-12);
  min-width: 0;
}

@media only screen and (max-width: 991px) {
  .review-card__person {
      flex-direction: column;
    }
}

@media only screen and (max-width: 767px) {
  .review-card__person {
      gap: var(--space-decimal-10);
    }
}

.review-card__avatar {
  flex: 0 0 6.4rem;
  width: 6.4rem;
  height: 6.4rem;
  border-radius: 50%;
  overflow: hidden;
}

.review-card__name {
  margin: 0;
  font-size: 2rem;
  line-height: 1.15;
  font-weight: 600;
  color: #2c3e50;
}

@media only screen and (max-width: 991px) {
  .review-card__name {
      font-size: 1.6rem;
    }
}

@media only screen and (max-width: 575px) {
  .review-card__name {
      font-size: 1.4rem;
    }
}

.review-card__rating {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  padding-top: var(--space-16);
  color: #EA6B3C;
  font-size: 2rem;
  line-height: 1;
}

.review-card__text {
  margin: 0;
  font-size: 2rem;
  line-height: 1.45;
  color: #2c3e50;
}

@media only screen and (max-width: 991px) {
  .review-card__text {
      font-size: 1.6rem;
      line-height: 1.45;
    }
}

@media only screen and (max-width: 575px) {
  .review-card__text {
      font-size: 1.2rem;
    }
}

/* =============================================================================
   SRV-4560 -- APPEND: .container, and a hero contrast fix           3 + 1 rules
   -----------------------------------------------------------------------------
   REGRESSION, mine, spotted by Mikita comparing the page against the Figma frame.
   Every section was rendering full-bleed: the logo and the h1 sat hard against
   the viewport edge instead of inside a centred 1470px column.

   `.container` -- the rule that gives the whole page its width, gutters and
   centring -- was in the FIRST build (3 rules, confirmed in that run's report)
   and vanished in the rebuild.

   Cause, and it is the same bug we already fixed once. When I rebuilt the block
   list from the rendered page, I subtracted "classes a component's own stylesheet
   already covers", because footer_updates.st loads footer-2026.css itself. That
   subtraction asked "does footer-2026.css mention this class?" using a naive
   `\.([\w-]+)` regex. footer-2026.css line 116 is:

       .footer-updates__panel .container Ellipsis

   `.container` appears there as a DESCENDANT -- scoped inside the footer panel,
   saying nothing about the global container. The regex counted it as "defined",
   so `container` was dropped from the block list and its 3 rules were never
   extracted.

   "Mentioned anywhere in a selector" is not "defined by this sheet." That is
   precisely the distinction `extract-css-blocks.py` enforces with
   leftmost-compound scoping -- the fix that stopped `.footer-site ._stores`
   leaking in. I fixed it inside the tool and then reintroduced it in a throwaway
   subtraction script written for one rebuild. **A rule enforced by a tool is not
   enforced by the person who bypasses the tool.**

   The second rule below is a contrast fix, also mine. The hero's supporting lines
   (the rating line, "Free, with no ads...", "Updated August 2026") are bare <p>,
   so they inherit `body { color: #2c3e50 }` -- navy text on the green hero
   gradient, close to unreadable. index styles its hero copy `#fcf8b3`; this
   reuses that exact token rather than picking a new one.

   Appended, not regenerated. Provenance: homepage.css, md5 3a40e61733fc2296a2d97d9342a48ff6
   ============================================================================= */

.container {
  padding-right: 15px;
  padding-left: 15px;
  margin-right: auto;
  margin-left: auto;
  width: 100%;
}

@media only screen and (min-width: 1470px) {
  .container {
      width: 1470px;
    }
}

@media print {
  .container {
      min-width: 992px !important;
    }
}

.section-start .hero__content p {
  color: #fcf8b3;
}

/* The hero watch is real art now (Figma node 3520:49174, 249x393), so it needs the
   position the `art-stub--watch-chip` placeholder held -- same offsets, no dashed
   treatment, and sized from the asset's own intrinsic dimensions rather than the
   mockup's guess. The stub rule above stays: 13 other placeholders still use it. */


/* -----------------------------------------------------------------------------
   FIGMA PARITY PASS 1 -- layout, not tokens.

   Measured against Figma page node 3520:40614 on 2026-08-27. The finding that
   drove this: the type scale was ALREADY correct (H2 56/600 #268fd0, body
   20/400 #2c3e50, measured live at 1600px). What was wrong was the LAYOUT the
   text sat in, and the earlier read of "the sections are unstyled" was a
   misdiagnosis of that.

   Two Figma sections are a two-column split -- a text column beside one large
   art panel -- and the page shipped both as a full-width text grid instead:
     3520:46642  Why People Switch   682px text column + art panel, radius 40
     3523:50596  Calorie Counting on iPad   text left, 534x410 device art right
   Hence one shared `split-2026` block rather than two one-off section rules,
   because SRV-4561 and SRV-4562 reuse the same shape.

   `press-strip` is corrected in place: Figma 3520:46568 makes "Recognized by" a
   36px/600 blue HEADING with four source columns under it and a separate 56px
   line for the trust count. The page had a 12px grey uppercase eyebrow and the
   trust count crammed in as a fifth list item.

   rem base is 10px (see the note at the top of this file), so 5.6rem == 56px.

   Appended, not regenerated.
   ============================================================================= */

/* ---- shared two-column split -------------------------------------------- */

/* NO section padding here. `.split-2026` is always paired with `.page-section`
   in the markup -- 14 of 14 sections, checked -- so it inherits that class's
   responsive 8rem / 4rem / 3rem ladder and needs nothing of its own.
   It USED to set `padding: 6.4rem 0`, which sat below `.page-section` at :2547
   at the same specificity and so won on source order. Adjacent sections abut,
   so the gap between two of them is padBottom + padTop: 80+64 gave 144 and
   64+64 gave 128 against Figma's 160. Measured at 1440, only 23 of the 55
   adjacent pairs across the four pages were at 160. Removing this takes it to
   45 of 55, moves 24 pairs, breaks none of the 23 already correct, and
   overshoots nowhere. C-09.
   The remaining 10 are the four pairs around the reviews carousel, where
   `.user-reviews` (:7236) sets its own 64 with a full 64/56/48 responsive
   ladder, and the hero pairs, where four different sections follow the hero.
   Both are separate decisions and deliberately not made here. */

.split-2026__grid {
  display: grid;
  grid-template-columns: 68.2rem 1fr;
  gap: var(--space-32);
  align-items: start;
}

/* No `align-items` here -- the base grid's `start` above is what we want, and
   overriding it to `center` was C-09's biggest single cause. Measured: when the
   text column is shorter than the fixed art column beside it, centring the ROW
   pushes the whole text column down, and the slack lands entirely above the
   heading. `.split-2026__title` measured NINE different distances from its
   neighbour above across the four pages at 1440 -- 64, 76, 120, 121, 122, 144,
   154, 159, 165 -- against the mockup's uniform 64. The two instances on the
   plain `.split-2026__grid` were the only ones already at 64.
   Removing this returns all of them to 64: 13 header distances change, 199 do
   not, and nothing moves at 768 or 390 because the grid collapses there.
   If a particular art slot needs vertical centring against a TALLER text
   column, centre the ART and not the row -- `.split-2026__art--device` already
   does exactly that with `align-self`. */
.split-2026__grid--art-right {
  grid-template-columns: 1fr 53.5rem;
}

/* THE ONE EXCEPTION to the note above, and Figma is explicit about it. In the
   other 8 text+art sections the TEXT column is the taller one and sets the
   section height, so top-aligning is right. In the iPad section the ART is
   taller and the text is centred against it:
     Figma 3523:50596, section h=410
       text 3523:50597  y=45  h=320   -> 45px above, 410-(45+320)=45px below
       art  3523:50678  y=0   h=410   -> full height
   Equal gaps, so it is centred by design, not by accident. Removing
   `align-items` from `--art-right` would top-align this text and drop it 45px
   out of position. Applied to the grid rather than adding `align-self` to the
   text column, so the exception is visible where the layout is chosen. */
.split-2026__grid--art-tall {
  align-items: center;
}

.split-2026__title {
  margin: 0 0 var(--space-40);
  font-size: 5.6rem;
  font-weight: 600;
  line-height: 1.1;
  color: #268fd0;
}

/* C-11, Mikita: "here we have paragraph issue". Two separate faults, both here.
   THE WELD. This set `margin: 0`, and the plain <p> that follows it in 6 of its
   13 uses gets `margin: 0 0 2rem` from the base `p` rule (:1189). Margins
   collapse to the max, so the gap between the two paragraphs was ZERO -- they
   welded into one block while the second still threw 2rem below itself.
   `margin-bottom: 2rem` is not a new number: it is the base paragraph value, so
   the intro now shares the rhythm of the paragraphs it leads into. Checked for
   collision on the other 7 uses -- the two non-<p> followers that declare their
   own margin-top (`.switch-list` and `.watch-points`, both 2.4rem) keep it,
   because margins collapse to the max rather than adding; the rest close a grid
   column with nothing below, where a trailing margin has no visible effect.
   THE MEASURE. `max-width: 88rem` and `line-height: 1.45`, both copied from
   `.ai-features__intro` (:2233), the documented house body-paragraph style, so
   no new values enter the file. Of the 13 uses, 11 render 682, 843 or 964px wide
   -- the fixed art column constrains the 1fr text track in practice -- and two
   render the full 1410px: fct:807 at 420 characters and fct:948 at 924. At 20px
   a 1410px line holds about 140 characters against a 45-75 norm, so fct:948 was
   set at roughly twice the comfortable maximum. 88rem is 880px, so it is inert
   on the 682 and 843 renders, narrows the 964s by 84px, and is the actual fix on
   the two 1410s.
   NOT a type defect, and it was mis-diagnosed as one first: this class sets no
   `font-weight`, so it inherits 400, and 2rem IS the body size. Nothing here was
   ever oversized or bold. */
.split-2026__intro {
  margin: 0 0 var(--space-20);
  max-width: 88rem;
  font-size: 2rem;
  line-height: 1.45;
  color: #2c3e50;
}

.split-2026__art {
  align-self: stretch;
  min-height: 32rem;
  border-radius: 4rem;
  background: #ededed;
  overflow: hidden;
}

.split-2026__art--device {
  align-self: center;
  min-height: 41rem;
}

.split-2026__art img {
  display: block;
  width: 100%;
  height: auto;
}

/* The three stacked items in Why People Switch. Figma gives the item title 24px
   (H4), not the 28px (H3) the 3-up card grid was using, and only 4px between a
   title and its own body against 24px between items -- so the pairs read as
   pairs. */
.switch-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-24);
  margin-top: var(--space-24);
}

.switch-item__title {
  margin: 0 0 var(--space-4);
  font-size: 2.4rem;
  font-weight: 600;
  line-height: 1.15;
  color: #268fd0;
}

.switch-item__body {
  margin: 0;
  font-size: 2rem;
  line-height: 1.3;
  color: #2c3e50;
}

@media only screen and (max-width: 991px) {
  .split-2026__grid,
  .split-2026__grid--art-right {
      grid-template-columns: 1fr;
    }

  .split-2026__art {
      order: 2;
      min-height: 24rem;
    }

  .split-2026__title {
      margin-bottom: var(--space-24);
      font-size: 4rem;
    }
}

/* ---- press strip, corrected to Figma 3520:46568 ------------------------- */

.press-strip__title {
  margin: 0 0 var(--section-52);
  font-size: 3.6rem;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.108rem;
  text-align: center;
  color: #268fd0;
}

.press-strip__item {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
  flex: 1 0 0;
  max-width: none;
  min-width: 0;
  font-size: inherit;
  color: inherit;
}

.press-strip__source {
  font-size: 2.4rem;
  font-weight: 600;
  line-height: 1.15;
  color: #268fd0;
}

.press-strip__claim {
  font-size: 2rem;
  line-height: 1.3;
  color: #2c3e50;
}

.press-strip__trust {
  margin: var(--section-52) 0 0;
  font-size: 5.6rem;
  font-weight: 600;
  line-height: 1.1;
  text-align: center;
  color: #268fd0;
}

/* -----------------------------------------------------------------------------
   AT A GLANCE -- adopts the plans table's surface. rev. 26, 2026-08-31.
   Requested by Mikita: "use table from bottom, same settings".

   The two tables are the same KIND of object (a spec table) 400 lines apart, and
   the plain one looked unfinished beside the styled one. He is right. What follows
   is the surface, the corners, the row rules and the type scale of
   `.comparison-table` (2869+), transcribed with the source line for each value so
   the two can be re-verified mechanically rather than by eye:

     white fill, radius 3.2rem / 2.4rem at 767   .comparison-table            2885, 2903
     border-collapse separate, spacing 0         .comparison-table            2885
     cell padding 2rem 1.6rem / 1.6rem 1.2rem    .comparison-table tbody td   3170, 3183
     row rule 0.1rem solid #d8e0ea               .comparison-table tbody td   3170
     first row no top rule                       tbody tr:first-child         3197
     body type 2rem / 1.35 / #2c3e50             .comparison-table tbody td   3170
     row label 2.4rem / 1.25 / 500 / #2c3e50     .comparison-table__row-title 3202
     zebra #f7fafc on even rows                  (this file, S9 block)        5863

   WHY THIS IS TRANSCRIBED AND NOT SHARED. Genuinely sharing it means one rule
   naming both tables, and `.comparison-table` is an EXTRACTED block -- this file's
   header records a provenance md5 against homepage.css and its own prune note says
   editing an extracted block breaks the ability to re-diff it. A grouped
   `.comparison-table, .glance-table { }` also re-declares `.comparison-table` and
   would land in assert-no-duplicate-selectors.py as an undeclared override, which
   the gate is right to flag. So: transcribed, with the map above.
   The real extraction is a follow-up that has to re-record the provenance md5, and
   it is worth doing the moment a THIRD spec table appears. Two is not yet three.

   THE ONE VALUE I DID NOT TRANSCRIBE, and why. `.comparison-table` is a white card
   on the grunge-pattern ground of `.section-insights__wrapper` (2795) -- the ground
   is what makes the white fill and the 3.2rem corners read as a card. This section
   is a plain `.page-section` on white, so copying the fill alone would have given a
   white card on a white ground: corners doing nothing, only the row rules visible.
   The card gets a 0.1rem #d8e0ea hairline instead, in the same colour as its own
   row rules. Same object, drawn so it survives a different ground. "Same settings"
   cannot mean "same declarations" when half of one treatment is doing work against
   a background this section does not have.

   KEPT DELIBERATELY DIFFERENT -- see reports/p6-design.md for the full argument:
     - no min-width, so no horizontal scroll. `.comparison-table` is a MATRIX whose
       cells are meaningless without their column header, so the header must travel
       with the cell and sideways scroll is the honest cost. This is nine
       independent PAIRS with no second axis; nothing is lost by stacking it.
     - no highlighted column, no sticky column, no caption. There is no tier to
       highlight and nothing scrolls, so all three would be chrome for a mechanism
       that is not here.
     - cells stay LEFT-aligned. The plans table centres its body cells because they
       are single glyphs under a header; these are sentences, and a right-aligned
       value throws "None" half a card away from "Ads".
     - capped at 76.8rem and centred, where the plans table fills the container.
       Nine label/value pairs across 1440px is the exact failure this cap prevents.
   ============================================================================= */
.glance-table-wrap {
  max-width: 76.8rem;
  margin: 0 auto;
  padding-bottom: var(--space-40);
  overflow-x: auto;
}

.glance-table {
  width: 100%;
  border: 0.1rem solid #d8e0ea;
  border-radius: 3.2rem;
  border-collapse: separate;
  border-spacing: 0;
  background: #ffffff;
  overflow: hidden;
}

/* Shared cell properties hang off `tr > *` rather off `th, td`, so that `th` and
   `td` are each DECLARED EXACTLY ONCE per breakpoint. Writing the pair as
   `.glance-table th, .glance-table td { }` and then specialising `.glance-table th`
   is the ordinary way to do this, and it puts `.glance-table th` in the file twice
   with different bodies -- which assert-no-duplicate-selectors.py counts per
   selector, not per rule, and reports as an undeclared override. It did, on the
   first draft of this block. `tr > *` says the same thing and stays countable. */
.glance-table tr > * {
  padding: var(--space-20) var(--space-16);
  border-top: 0.1rem solid #d8e0ea;
  text-align: left;
  vertical-align: middle;
  font-size: 2rem;
  line-height: 1.35;
  color: #2c3e50;
}

/* Kill the border on the table's FIRST ROW ONLY -- the one with nothing above it
   to be separated from.

   This was `.glance-table > :first-child > tr:first-child > *`, and the comment
   here claimed `> :first-child` "resolves to `thead` when there is one and `tbody`
   when there is not". That is wrong, and it shipped a visible 1px line across the
   top of the free-app table, inside the rounded border. A `caption` is an ELEMENT
   CHILD of `table` and it comes FIRST, so on that table `> :first-child` resolves
   to `caption`, `caption > tr` matches nothing, and the whole rule silently did
   nothing. Measured: children [CAPTION, THEAD, TBODY], thead th border-top 1px
   #d8e0ea. The iPhone table has no caption, so the bug was invisible there.

   Lesson worth keeping: `> :first-child` is not a synonym for "first row group".
   `caption` and `colgroup` are both legal element children of `table` and both
   sort before the row groups.

   Written as two selectors that name the row groups explicitly, so a caption can
   never intercept either one:

     1. `> thead > tr:first-child` -- when a header row exists it IS the first row.
     2. `> tbody:first-of-type` -- but only when there is NO thead, because with a
        header row present the first body row needs its border: that border is what
        separates it from the header. `:not(:has(> thead))` states exactly that
        condition. `:first-of-type` is not decoration: a table may carry SEVERAL
        tbody elements, and without it every tbody's first row would lose its top
        border, deleting the dividers BETWEEN row groups. (An earlier draft of this
        comment said plain `> tbody`, which is what the selector does NOT do.)

   BROWSER SUPPORT, recorded because nothing in this repo states it. `:has()` needs
   Safari 15.4+, Chrome/Edge 105+, Firefox 121+ (ESR 128+). The only browserslist in
   the tree is the React app's `["defaults", "not ie 11"]`
   (src/mynetdiary-mui/package.json:11) and it does not govern these server-rendered
   pages, so there is no policy here to check this against -- that is a question for
   Mikita, not something the sheet can settle.

   What it costs if a browser does not support it: a selector list is NOT forgiving.
   One invalid selector invalidates the WHOLE rule, so selector 1 above dies with
   selector 2 even though it contains no `:has()`. Both tables then keep a 1px
   #d8e0ea line under the caption. Cosmetic, not broken -- this rule only ever
   REMOVES a border. Splitting the prelude into two rules would let selector 1
   survive independently; deliberately NOT done here, because this rule is signed
   off and the split is a separate decision.

   `:nth-child(1 of thead, tbody)` says all of this in one selector and was the
   first draft. It is rejected on tooling, not on support:
   assert-no-duplicate-selectors.py splits preludes on a bare `,`
   (scripts/assert-no-duplicate-selectors.py:191), so the comma INSIDE that
   pseudo-class would be shredded into two nonsense selectors. `:has()` needs no
   comma.

   Both selectors set `none` and nothing else, so this rule can only ever REMOVE a
   border. That is what makes it safe against the 575 stacked block below, which
   zeroes `tr > *` and redraws the dividers with `tr + tr`.

   Survives U-1 (reports/p6-design.md), which proposes deleting this table's thead:
   with the thead gone the table is [CAPTION, TBODY], selector 2's condition turns
   true, and the first body row correctly loses its border. No follow-up edit. */
.glance-table > thead > tr:first-child > *,
.glance-table:not(:has(> thead)) > tbody:first-of-type > tr:first-child > * {
  border-top: none;
}

.glance-table th {
  width: 42%;
  font-size: 2.4rem;
  line-height: 1.25;
  font-weight: 500;
}

.glance-table td {
  font-weight: 400;
}

.glance-table tr:nth-child(even) > * {
  background: #f7fafc;
}

/* The plans table drops its row title to 1.4rem at 767 because three tier columns
   are squeezing it. Nothing squeezes this one, so it takes the 991 step of that
   scale and stops -- copying the 767 value would be importing a constraint that
   does not exist here. */
@media only screen and (max-width: 991px) {
  .glance-table tr > * {
      padding: var(--space-16) var(--space-12);
      font-size: 1.8rem;
    }

  .glance-table th {
      font-size: 2rem;
    }
}

/* 375: STACK, do not scroll. This is the behaviour from the first pass and it is
   unchanged -- adopting the plans table's surface does not mean adopting its
   mechanics. The widest pair is "Apple Health / Writes 51 data types; reads 14";
   held as two columns at 375 that is a 14-character label beside a value wrapping
   to four lines, with the halves ragged against each other.

   Stacked, the label becomes an uppercase caption and the value becomes the
   statement under it. The inversion is the point: at 1440 the label is what you
   scan down, at 375 the VALUE is what you read. The card, its radius, its hairline
   and its row rules all survive the stack, so it is still visibly the same object
   as the table at the bottom of the page -- which is what was actually asked for. */
@media only screen and (max-width: 575px) {
  .glance-table,
  .glance-table tbody {
      display: block;
      width: auto;
    }

  .glance-table tr {
      display: block;
      padding: 1.4rem var(--space-16);
    }

  .glance-table tr > * {
      display: block;
      width: auto;
      padding: 0;
      border-top: none;
    }

  .glance-table tr + tr {
      border-top: 0.1rem solid #d8e0ea;
    }

  /* Stacked, the zebra has to paint the ROW, not its cells. The cells sit inside
     the row's 1.4rem/1.6rem padding, so the top-level `tr > *` tint stopped 16px
     short of the card on both sides and read as a floating grey block rather than a
     stripe. Caught at 375 in the render, not in review. */
  .glance-table tr:nth-child(even) {
      background: #f7fafc;
    }

  .glance-table th {
      font-size: 1.2rem;
      font-weight: 600;
      letter-spacing: 0.12rem;
      line-height: 1.4;
      text-transform: uppercase;
      color: #6b7a88;
    }

  .glance-table td {
      padding-top: var(--space-4);
      font-size: 1.7rem;
      font-weight: 600;
      line-height: 1.3;
      color: #2c3e50;
    }
}

/* The four sources are equal-width columns in Figma, not a centred wrap, so the
   flex defaults inherited from the old strip are overridden rather than removed
   -- the old rules still style nothing else, but this file is append-only. */
.press-strip .press-strip__list {
  flex-wrap: nowrap;
  gap: var(--space-16);
  align-items: flex-start;
  text-align: center;
}

@media only screen and (max-width: 991px) {
  .press-strip .press-strip__list {
      flex-wrap: wrap;
    }

  .press-strip__item {
      flex: 1 0 40%;
    }

  .press-strip__title {
      margin-bottom: var(--space-32);
      font-size: 2.8rem;
    }

  .press-strip__trust {
      margin-top: var(--space-32);
      font-size: 3.6rem;
    }
}

/* A large art placeholder. `art-stub--panel` differs from the existing stubs by
   filling its parent instead of declaring its own box, because the parent
   (.split-2026__art) already owns the Figma dimensions. */

/* ---- What You Get for Free, corrected to Figma 3520:43101 --------------- */

/* The section lead is 28px SEMIBOLD in Figma (node 3520:50286), not the 20px
   regular that `.ai-features__intro` gives every other section. Its own class
   rather than an override, because Figma uses this same 28px lead on other
   sections in the page family and SRV-4561 will want it too. */
.section-lead {
  margin: 0;
  font-size: 2.8rem;
  font-weight: 600;
  line-height: 1.15;
  text-align: center;
  color: #2c3e50;
}

/* Running body prose that needs `.section-lead`'s max-width cap but none of its
   heading scale -- C-16: `.section-lead` is a 28px semibold short intro line
   (Figma 3520:50286), and two full paragraphs on verified-food-database were
   wearing it instead of body copy. Values match `.ai-features__intro`, the
   house body-paragraph style, but unscoped like `.section-lead` and
   `.section-outro` above rather than BEM-scoped to one section. */
.section-prose {
  max-width: 88rem;
  margin: 0 auto;
  font-size: 2rem;
  font-weight: 400;
  line-height: 1.45;
  color: #2c3e50;
}

.section-prose--note {
  font-style: italic;
}

/* `.section-prose--left` (shared with `.section-intro--left`) is defined after
   `.section-intro`'s own rule below (pages-2026.css:~5100) on purpose: with
   equal specificity, CSS cascade order decides, and a modifier declared
   BEFORE the base rule it is meant to override loses to it. Placing both
   base classes' rule first and the shared `--left` modifier after both
   avoids that trap. */

/* `.section-prose`'s own max-width + margin:0 auto centers it as a narrower box,
   which is invisible everywhere else it's used (already inside a column near
   88rem wide) but shoves it right of `.split-2026__intro` above it inside the
   wide single-column `--text-only` grid on free-calorie-tracker's "Proven in a
   Peer-Reviewed Study" section -- the only place a `.section-prose` sits in a
   `.split-2026__text` column. Left flush, matching the intro paragraph above it
   and the sibling text-only sections that carry no footnote. */
.split-2026__text .section-prose {
  margin: 0;
}

/* Four 276x276 art tiles sit ABOVE the four text columns as their own row --
   they are not card media inside each column, which is why the text columns
   looked bare when the art was left out. Fixed 27.6rem from Figma, so the row
   keeps its proportions instead of stretching. */



/* Figma keeps the closing thought and its call to action on separate lines,
   centred, with the CTA in the green the rest of the page family uses for
   forward links. The page had both welded into one left-aligned paragraph. */
.section-outro {
  margin-top: var(--space-40);
  text-align: center;
}

/* Mikita, 2026-09-07: fct's "What You Get Free" closing paragraph is a full
   2-sentence body paragraph with no accompanying `.section-outro__cta` link --
   not the short "closing thought + CTA" pair this block was built for -- and
   reads better left-aligned like every other body paragraph on the page. A
   modifier, not a change to the shared centred pattern every other
   `.section-outro` use (short line + green CTA) still relies on. */
.section-outro--left {
  text-align: left;
}

.section-outro__line {
  margin: 0;
  font-size: 2rem;
  line-height: 1.3;
  color: #2c3e50;
}

.section-outro__cta {
  margin: 0;
  font-size: 2rem;
  line-height: 1.3;
}

.section-outro__cta a {
  color: var(--link);
}

@media only screen and (max-width: 991px) {

  .section-lead {
      font-size: 2.2rem;
    }

  .section-prose {
      font-size: 1.6rem;
    }
}

@media only screen and (max-width: 575px) {

  .section-prose {
      font-size: 1.4rem;
    }
}

/* The strip was a thin bordered band between sections when it held a 12px
   eyebrow. Figma 3520:46568 makes it a full section 323px tall with no rules
   above or below, so the hairlines and the 2.6rem band padding both have to go
   -- `.page-section` now owns the vertical rhythm. Overridden rather than edited
   in place because this file is append-only. */
.press-strip.page-section {
  padding: var(--section-80) 0;
  border-top: 0;
  border-bottom: 0;
}

@media only screen and (max-width: 991px) {
  .press-strip.page-section {
      padding: var(--space-40) 0;
    }
}

/* -----------------------------------------------------------------------------
   DEFECT FIX: the "Recognized by" columns never took, and the reason is
   specificity, not source order.

   Found by wM:p4 by hand-computing specificity, after I had already written the
   fix above and recorded it as done. The old band rule
   `.press-strip__list li` (line 3449) is (0,1,1) -- one class plus one element.
   The new `.press-strip__item` is (0,1,0) -- one class. (0,1,1) wins on every
   property they share, from anywhere in the file, so `max-width: 23rem`,
   `font-size: 1.4rem` and `color: #6b7a88` all survived and each column stayed
   capped at 230px in the wrong size and colour.

   Appending a later rule is exactly the move that does NOT work here, which is
   why this needs the element in the selector too rather than another flat class.
   Same failure family as the comparison table's positional `th:nth-child(2)`
   beating `is-highlight`: the page looked styled, and was styled wrong.
   ============================================================================= */
.press-strip__list li.press-strip__item {
  max-width: none;
  font-size: inherit;
  color: inherit;
}

/* A grid or flex child holding prose needs `min-width: 0` or a long unbroken
   token blows the column past its track. Real declaration, not a placeholder to
   satisfy the coverage gate -- the 682px text column and the item bodies both
   carry URLs and hyphenated product names. */
.split-2026__text {
  min-width: 0;
}

/* ---- Built for iPhone, corrected to Figma 3520:46918 -------------------- */

/* Figma is a 3x2 grid where each cell puts a 384x256 image ABOVE its own
   title and body. The page shipped a flat 3-up text grid, which is why six
   paragraphs of real copy read as an unstyled column: the art is the structure,
   and it was simply absent.

   Its own block rather than another `.ai-features__wrapper` modifier, because
   the art-above-text cell is a different shape from the ai-card the homepage
   uses (media beside text below 991px) and overloading that block is what made
   the first diagnosis of this page wrong. */
.feature-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-40) var(--space-32);
}

.feature-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-24);
  min-width: 0;
}



.feature-card__text {
  min-width: 0;
}

/* D-A note: `.feature-card__art` and `.feature-card__art img` were re-added here
   on 2026-08-31 as "restored after the prune". They were never actually pruned --
   the prune was reverted the same afternoon and the live rules are further down
   this file under "Built for iPhone art slots, restored", byte-identical. The
   second copy is removed; the surviving one is the original. */

.feature-card__title {
  margin: 0 0 var(--space-12);
  font-size: 2.8rem;
  font-weight: 600;
  line-height: 1.15;
  color: #268fd0;
}

.feature-card__text p {
  margin: 0 0 var(--space-12);
  font-size: 2rem;
  line-height: 1.3;
  color: #2c3e50;
}

.feature-card__text p:last-child {
  margin-bottom: 0;
}

.feature-card__text a {
  color: var(--link);
}

/* Section heading + intro for sections that are NOT an ai-features block. S5 and
   others previously borrowed `.ai-features__header`, which forced them into that
   block's spacing whether or not they were that block. */
/* 4rem, not 2.4rem: Figma's 40px h2 gap. C-09.
   This one rule fixes BOTH measured values. Of its 10 uses, 9 are followed by an
   element with margin-top: 0 and collapsed to 24; fct:548 is followed by
   `.icon-rows`, which carries its own margin-top: 3.2rem (:7457), and collapsing
   takes the max, so that instance read 32. 40 beats both in the collapse, so no
   second edit is needed at the call site. */
.section-title {
  margin: 0 0 var(--space-40);
  font-size: 5.6rem;
  font-weight: 600;
  line-height: 1.1;
  text-align: center;
  color: #268fd0;
}

.section-intro {
  margin: 0 0 var(--space-40);
  font-size: 2rem;
  line-height: 1.3;
  text-align: center;
  color: #2c3e50;
}

/* Mikita, 2026-09-07/08: long body-copy paragraphs on verified-food-database
   read better left-aligned than centred like the short lines `.section-prose`
   and `.section-intro` were each built for. One shared modifier rule for both
   base classes, not two near-duplicate ones -- also drops `.section-prose`'s
   own 88rem cap so that paragraph runs the full container width;
   `.section-intro` never had that cap, so the same declarations are a no-op
   there. A modifier, not a change to either shared centred rule above -- other
   uses of both classes still rely on them. Declared AFTER both base rules on
   purpose (equal specificity, cascade order decides -- see 2026-09-08 fix). */
.section-prose--left,
.section-intro--left {
  max-width: none;
  margin-left: 0;
  margin-right: 0;
  text-align: left;
}

/* ---- Apple Watch points, Figma 3520:50406 ------------------------------- */

/* Figma styles the four points as 24/600 blue lines, each with a 40px icon, not
   as a default bulleted list. The icons do not exist yet, so the list keeps its
   marker off and the type is what changes -- adding a fake icon would be worse
   than none. */
.watch-points {
  margin: var(--space-24) 0 0;
  padding-left: 0;
  list-style: none;
}

.watch-points__item {
  margin-bottom: var(--space-16);
  font-size: 2.4rem;
  font-weight: 600;
  line-height: 1.15;
  color: #268fd0;
}

.watch-points__item:last-child {
  margin-bottom: 0;
}

@media only screen and (max-width: 991px) {
  .feature-grid {
      grid-template-columns: repeat(2, 1fr);
      gap: var(--space-32) var(--space-16);
    }

  .section-title {
      font-size: 4rem;
    }

  .feature-card__title {
      font-size: 2.4rem;
    }

  .watch-points__item {
      font-size: 2rem;
    }
}

@media only screen and (max-width: 575px) {
  /* D-A, 9 cards. In one column the row gap is the ONLY thing separating card 4's
     body copy from card 5's artwork -- there is no column neighbour left to do it.
     Inside a card the art-to-text gap is 2.4rem, so a 3.2rem row gap (what the
     991 band sets) is only 0.8rem more than the gap it has to out-rank, and nine
     stacked cards read as one column of alternating pictures and paragraphs.
     4.8rem is twice the intra-card gap, which is the smallest ratio that still
     groups. Kept OFF the 3-col and 2-col bands: there the columns carry the
     grouping and Figma's 40px row gap (3520:46918) stands unchanged. */
  .feature-grid {
      grid-template-columns: 1fr;
      gap: var(--section-48);
    }

  .section-title {
      font-size: 2.8rem;
    }
}

/* ---- Closing CTA, layout from Figma 3520:44203 -------------------------- */

/* Figma's closing CTA is a dark full-bleed card with white type and a phone
   mockup on the right. The LAYOUT is adopted here; the COPY deliberately is not.
   Figma's copy for this block is "Ready to add AI to your tracking?" and it
   cross-sells www.plateai.com, which is a funnel decision for an iPhone landing
   page, not a styling one -- logged as C-7 for a human. So this keeps the page's
   own App-Store copy inside Figma's shape.
   Dark ground is the same #1f3348 family the footer already uses, not a new
   colour invented for one card. */
/* D-B (Mikita, 2026-08-31): the art column is cta-phone-dashboard.png at
   398x436 inside a 1200x436 frame. 398 + 436 are the frame's FULL height, so the
   phone is flush to the top and bottom edges -- it is not an image sitting inside
   the card's 6.4rem padding, it is the card's right edge. Padding therefore moves
   off the card and onto the text column, and the card clips at its own radius.
   `min-height` rather than `height`: 43.6rem is Figma's frame, but the copy is
   authored text and must be allowed to make the card taller rather than overflow. */
.closing-cta__card {
  display: grid;
  grid-template-columns: 1fr 39.8rem;
  gap: var(--space-32);
  align-items: center;
  padding: 0 0 0 var(--section-64);
  min-height: 43.6rem;
  overflow: hidden;
  border-radius: 4rem;
  background: #1f3348;
}

.closing-cta__text {
  min-width: 0;
  padding: var(--section-64) 0;
}

.closing-cta__title {
  margin: 0 0 var(--space-24);
  font-size: 5.6rem;
  font-weight: 600;
  line-height: 1.1;
  color: #fff;
}

/* White-on-dark, so the body cannot inherit `body { color: #2c3e50 }` -- that is
   the same navy-on-green mistake the hero already made once on this page. */
.closing-cta__body {
  margin: 0 0 var(--space-32);
  font-size: 2rem;
  line-height: 1.3;
  color: #e6edf3;
}



@media only screen and (max-width: 991px) {
  .closing-cta__card {
      grid-template-columns: 1fr;
      padding: var(--space-32);
      min-height: 0;
      border-radius: 2.4rem;
    }

  .closing-cta__text {
      padding: 0;
    }

  .closing-cta__title {
      font-size: 3.2rem;
    }

}

/* Inside the closing card the store badges are LEFT-aligned under the copy, per
   Figma 3520:44203. Everywhere else on the page `.comparison-cta` is a centred
   band under a centred section, so the centring is right there and wrong only
   here. Scoped to the card rather than changed at source. */
.closing-cta__text .comparison-cta {
  margin-top: 0;
  text-align: left;
}

.closing-cta__text .comparison-cta__stores {
  justify-content: flex-start;
}

@media only screen and (max-width: 991px) {
  .closing-cta__text .comparison-cta,
  .closing-cta__text .comparison-cta__stores {
      justify-content: center;
      text-align: center;
    }
}

/* D-B art rules moved to the SRV-4560 ROUND 2 block at the end of this file, and
   the 991 cap corrected from 38.9rem to the asset's real 398px. An earlier pass
   restored them here with the pre-D-B width; two copies of the same selector is
   exactly what assert-no-duplicate-selectors.py exists to catch, so there is one. */

/* The Apple Watch art column is 414px in Figma 3520:50406, not the 535px the
   iPad uses. Sharing one --art-right width would upscale the watch export past
   its intrinsic 414x654 and blur it -- the opposite of the retina problem, same
   root cause of not reading the asset's own dimensions. */
/* Same as `--art-right` above: no `align-items`, so the base grid's `start`
   applies. See that rule's note for the measurement. */
.split-2026__grid--art-watch {
  grid-template-columns: 1fr 41.4rem;
}

/* A slot holding real art must not keep the placeholder's grey ground or its
   min-height: the image sets the height, and any leftover #ededed shows as
   letterboxing around it. */
.split-2026__art--filled {
  min-height: 0;
  background: none;
}

@media only screen and (max-width: 991px) {
  .split-2026__grid--art-watch {
      grid-template-columns: 1fr;
    }

  .split-2026__art--filled {
      max-width: 41.4rem;
    }
}

/* -----------------------------------------------------------------------------
   RATINGS STRIP -- extracted for the Figma ratings block (3520:42033).

   Mikita's ruling: use Figma's numbers. Figma's hero carries NO rating line;
   the claim lives in its own strip, which reads "266K 5-Star Ratings" over
   "On App Store & Google Play", beside a Trustpilot box.

   static_index.st:86 already ships exactly that strip, so the markup was lifted
   from index verbatim rather than rebuilt -- same five star SVGs, same
   $rating_five_star_count_display()$ helper (266K), same live Trustpilot widget.
   Its CSS had never been extracted into this sheet, hence this block.

   Note on Figma's two Trustpilot numbers (115 reviews and 347 reviews): both are
   just SNAPSHOTS of a live widget. The widget renders the current TrustScore and
   count at page load, so there is nothing to hardcode and no conflict to resolve.

   Extracted verbatim from homepage.css:10231-10347. Provenance: homepage.css,
   md5 3a40e61733fc2296a2d97d9342a48ff6
   ============================================================================= */
.ratings-strip__container {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
@media only screen and (max-width: 1280px) {
  .ratings-strip__container {
    flex-direction: column;
  }
}
.rating-card--stores {
  display: flex;
  flex-direction: column;
  font-size: 2rem;
  text-align: left;
}
@media only screen and (max-width: 1280px) {
  .rating-card--stores {
    text-align: center;
  }
}
@media only screen and (max-width: 991px) {
  .rating-card--stores {
    align-items: center;
    font-size: 1.4rem;
    text-align: left;
  }
}
.rating-card--stores .rating-card__title {
  margin-left: var(--space-16);
  font-size: 2.8rem;
}
@media only screen and (max-width: 991px) {
  .rating-card--stores .rating-card__title {
    margin-left: 0;
    font-size: 2.2rem;
  }
}
.rating-card--trustpilot {
  max-width: 52rem;
  width: 100%;
}
@media only screen and (max-width: 1280px) {
  .rating-card--trustpilot {
    margin-top: var(--space-40);
    max-width: none;
    width: auto;
  }
}
.rating-card .trustpilot-widget iframe {
  transform: scale(1.5);
}
@media only screen and (max-width: 767px) {
  .rating-card .trustpilot-widget iframe {
    transform: scale(1.3);
  }
}
@media only screen and (max-width: 575px) {
  .rating-card .trustpilot-widget iframe {
    transform: scale(0.9);
  }
}
.rating-card__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}
@media only screen and (max-width: 991px) {
  .rating-card__row {
    flex-direction: column;
  }
}
.rating-card__icon {
  display: flex;
  align-items: center;
  vertical-align: middle;
}
.rating-card__icon--stars {
  gap: var(--space-8);
}
@media only screen and (max-width: 991px) {
  .rating-card__icon--stars {
    margin-bottom: var(--space-8);
  }
}
.rating-card__icon--trust-boxes {
  padding: 0 var(--space-24);
}
@media only screen and (max-width: 991px) {
  .rating-card__icon--trust-boxes {
    padding: 0 1.4rem;
  }
}
.rating-card__icon--trust-boxes > svg {
  margin-right: var(--space-4);
}
@media only screen and (max-width: 991px) {
  .rating-card__icon--trust-boxes > svg {
    width: auto;
    height: 2.4rem;
  }
}
.rating-card__title {
  margin: 0;
  font-size: 2.4rem;
  line-height: 1.25;
  color: #2c3e50;
}
@media only screen and (max-width: 991px) {
  .rating-card__title {
    font-size: 1.4rem;
  }
}
.rating-card__title strong {
  font-weight: 600;
}

/* C-01. The count line under the star rating was a bare <p> and rendered at 0px
   below the title, on all four pages. Figma frame 3520:42034 is a vertical
   auto-layout with itemSpacing 8 and no padding -- confirmed twice, from the
   design context (gap-[8px]) and from the geometry (line 1 ends at y=32, line 2
   starts at y=40, frame height 66 = 32 + 8 + 26).

   8px is a DESKTOP number. Figma draws no mobile frame for this card, so the
   phone value is a design question, not a measurement. */
.rating-card__note {
  margin-top: var(--space-8);
}

/* ---- competitor matrix additions, Figma 3520:48117 ---------------------- */

/* The old table was ticks and crosses only. Figma's competitor matrix has two cell
   shapes the existing rules never had to render:
     - a NUMBER cell ("108", "15", "4", "84")
     - a QUALIFIER line under a tick or cross ("2M+ staff", "mostly user-submitted",
       "Premium", "1.1M")
   The qualifier is part of the claim, not decoration: a bare cross next to
   MyFitnessPal says "no barcode scanner", while the same cross over "Premium" says
   "paid only". Dropping it would misstate a competitor, so it gets a real style
   rather than being folded into the mark. */
.comparison-table__value {
  display: block;
  font-size: 2rem;
  font-weight: 600;
  line-height: 1.15;
  color: #2c3e50;
}

.comparison-table__qualifier {
  display: block;
  margin-top: var(--space-4);
  font-size: 1.4rem;
  line-height: 1.25;
  color: #6b7a88;
}

@media only screen and (max-width: 767px) {
  .comparison-table__value {
      font-size: 1.6rem;
    }

  .comparison-table__qualifier {
      font-size: 1.2rem;
    }
}

/* -----------------------------------------------------------------------------
   ART-FREE RESTYLE. Mikita ruled the empty Figma slots do NOT wait for art, so
   four sections are deliberately diverged from the design of record.

   The bar is that a reader cannot tell anything is missing. Deleting the image
   and stopping is exactly the state the page was rejected in this morning -- and
   for S5 that failure is already documented in this file, in my own words: "the
   art is the structure, and it was simply absent." So three of the four sections
   need the structure the art was carrying to come from somewhere else.

   Proposal by wM:p6, ranked by its own confidence, worst first: S5, S3, S12, S4.
   I took its S3, S12 and S4 proposals as given. I did NOT take one part of its
   S5 proposal -- see the note there.

   Appended, not regenerated.
   ============================================================================= */

/* ---- S3: single column, dividers instead of a side panel ---------------- */

/* A new modifier rather than editing --art-right/--art-watch, which both still
   have real users (S6, S7). */
.split-2026__grid--text-only {
  grid-template-columns: 1fr;
}

/* NO divider between switch-items. I added a border-top here when the art panel
   was designed out, to give the eye something to separate the three points with.
   Mikita put the Figma frame up: the panel is there in the design, so it is back --
   and Figma has no rule between the items, only a 24px gap.

   Third time today: a fix that compensates for a missing input has to be reverted
   when the input arrives, and nothing tracks that. The other two were the
   .feature-card surface and the hero rating line. All three were caught by a human
   looking at the page, not by a gate. */

/* ---- S12: single column, capped measure -------------------------------- */

/* Padding moved to `.closing-cta__text` when D-B split the card, so the
   art-free variant has to put the full box back -- otherwise its copy runs to the
   card's right edge, which is exactly the bleed the split layout wants and the
   text-only layout does not. */
.closing-cta__card--text-only {
  grid-template-columns: 1fr;
  padding: var(--section-64);
}

/* Without the art column the copy would run the full width of a 6.4rem-padded
   card, which is far past a comfortable measure on a dark ground. */
.closing-cta__card--text-only .closing-cta__text {
  max-width: 72rem;
}

/* ---- S5: give the cards a surface -------------------------------------- */

/* This is the section wM:p6 was least sure about, and it was right to be: the
   grid has to keep reading as six tiles rather than six paragraphs, and the
   thing that made it read as tiles was the image.
   A light surface with the radius the art used to carry does that work.

   NOT DONE, deliberately: wM:p6 also proposed giving the three pill-less cards a
   "Free" tier pill so all six carry one. I checked the copy and it would be a
   FALSE claim -- "Meal Scan and the Free Barcode Scanner" says Meal Scan is on
   Premium, and "Planning for Any Diet" says the 600+ recipes and meal plans are
   on Premium. Both cards are mixed-tier, not free. A pill that misstates which
   tier a feature is in is worse than an uneven-looking grid, so the three real
   tier pills stay and the other three cards get none. */
/* NO surface on .feature-card. The border/background/padding I added here existed
   only to stop six art-free cards reading as bare paragraphs. Mikita compared the
   section against Figma side by side: Figma gives these cards no border, no fill and
   no padding -- the 384x256 art above each one IS the structure. With the art
   restored the surface is not just unnecessary, it is wrong. */

/* ---- S4: nothing needed ------------------------------------------------- */

/* The four text columns are the same shape S8 (Deep iOS Integration) already
   ships art-free and which verified correct against Figma. Removing the tile row
   leaves a pattern the reader has already met on this page, so it reads as
   consistent rather than as stripped. Only the header's air needed a look, and
   .ai-features__header already carries its own bottom margin. */

/* ---- reviews, Figma 3520:48552 ------------------------------------------ */

/* Figma draws these as a horizontal carousel on a 2068px track with arrows and
   dots. Shipped as a static 4-up grid instead: the page has no carousel component,
   and index's feature-slider is image-driven and would need porting. A grid shows
   all four at once, which on a download page is the better outcome anyway -- a
   carousel hides three quarters of your social proof behind an interaction. */
/* 2026-09-01, Mikita: three reviews must fill the row, and a fourth must still
   fit when he adds it. A fixed repeat(4, 1fr) did neither -- with three cards it
   left a dead 331px column on the right at 1440 (measured), and it hard-coded the
   count into the stylesheet so the copy owner could not change it.
   auto-fit sizes the count from the space instead: 28rem is the narrowest a quote
   stays readable at, so 1200px of container yields four tracks, and auto-fit
   COLLAPSES the empty ones -- three cards stretch to fill, four sit 4-up, five
   would wrap to a second row. No breakpoint knows the card count any more. */
.review-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(28rem, 1fr));
  gap: var(--space-24);
  align-items: start;
}

/* Card chrome straight from Figma: white, 1.2px #dbdbdb hairline, 20px radius. */
.review-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
  min-width: 0;
  padding: var(--space-12);
  border: 0.12rem solid #dbdbdb;
  border-radius: 2rem;
  background: #fff;
}

.review-card__head {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--space-8);
  align-items: center;
}

.review-card__avatar {
  width: 6.4rem;
  height: 6.4rem;
  border-radius: 50%;
  overflow: hidden;
}

.review-card__avatar img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* One reviewer's portrait is unusable in Figma, so that card shows an initial.
   Same circle, same footprint, so the row does not go ragged where a photo is
   missing. */
.review-card__avatar--initial {
  display: flex;
  align-items: center;
  justify-content: center;
  background: #e3eaf0;
  font-size: 2.4rem;
  font-weight: 600;
  color: #268fd0;
}

.review-card__name {
  margin: 0;
  min-width: 0;
  font-size: 2rem;
  font-weight: 600;
  color: #2c3e50;
}

.review-card__stars {
  display: flex;
  gap: 0.2rem;
  white-space: nowrap;
}

.review-card__star {
  font-size: 1.8rem;
  line-height: 1;
  color: #f5a623;
}

.review-card__quote {
  margin: 0;
  font-size: 2rem;
  line-height: 1.3;
  color: #2c3e50;
}

/* Every quote in this section is a weight-loss outcome, so the disclaimer is not
   boilerplate -- it is the thing that makes the section publishable. Quiet, but
   not hidden: 1.4rem and grey, never smaller.

   ROUND 2.1: `.sources-methodology` (vfd's dated provenance note under the
   comparison table) and `.trademark-line` (the legal line closing main) need
   these same four declarations and nothing else. wM:p3 withdrew its own proposal
   to add a new rule once it found this one, which is the check-first behaviour
   the family asks for -- so the selector list is extended here rather than
   appended as two more copies of the same body. Extending the list changes
   neither specificity nor source order for `.review-disclaimer` itself, so it
   does not touch the traps this sheet has recorded. `.trademark-line` may want
   `text-align: center`; wM:p3 flagged that it could not settle it from there and
   it is NOT set, pending design. */
.review-disclaimer,
.sources-methodology,
.trademark-line {
  margin: var(--space-24) 0 0;
  font-size: 1.4rem;
  line-height: 1.4;
  color: #6b7a88;
}

/* The old max-width:1280 two-column override is gone: it existed only to stop a
   fixed 4-up from crushing its cards, and auto-fit already drops a track when the
   space is not there. Keeping it would have OVERRIDDEN auto-fit and forced two
   606px-wide cards at 1280 -- wider than the design, and worse than what it
   replaced. */

@media only screen and (max-width: 767px) {
  .review-grid {
      grid-template-columns: 1fr;
    }

  .review-card__quote {
      font-size: 1.8rem;
    }
}

/* ---- QR code ------------------------------------------------------------ */

/* Three slots, one destination, one asset. Verified by wM:p7 to DECODE to the
   exact App Store URL at both densities, checked with three independent decoders
   (zbar, pyzbar, OpenCV) rather than the library that produced it -- a QR that
   renders but does not scan is a placeholder that looks finished.

   The white ground and padding are functional, not decorative: one of these sits
   on the green hero, and a QR needs its quiet zone against white to scan at all.
   The asset carries its own 4-module quiet zone; this adds the visual margin so
   the code never touches a coloured edge. */
.qr-code {
  flex: 0 0 auto;
  padding: 0.6rem;
  border-radius: 0.8rem;
  background: #fff;
  line-height: 0;
}

.qr-code img {
  display: block;
  width: 6.4rem;
  height: 6.4rem;
}

@media only screen and (max-width: 575px) {
  .qr-code {
      display: none;
    }
}

/* The "as of" line, added on Mikita's go 2026-08-27.

   Figma carries no date, asterisk or footnote on any competitor cell, which made
   seven quantified claims about three named rivals read as permanently current.
   One dated line turns them into a snapshot, which is both more defensible and
   more honest -- and it is the pattern the page already uses for its own data in
   S3 ("In our January 2026 test..."), so nothing new is being invented.

   It lives in the <caption>, not in a note below the table: a caption is read out
   with the table by assistive tech, so the qualification cannot be separated from
   the claims it qualifies. Quiet, but never smaller than 1.4rem -- a disclaimer
   nobody can read is not a disclaimer. */
.comparison-table__asof {
  display: block;
  margin-top: var(--space-8);
  font-size: 1.4rem;
  font-weight: 400;
  line-height: 1.4;
  color: #6b7a88;
}

/* -----------------------------------------------------------------------------
   PRUNE, on Mikita's go 2026-08-27. Rules I authored today whose slot was removed
   by a later ruling, so each targeted nothing on any page.

   UPDATE 2026-08-31: two of the rules this note describes as removed are back.
   .feature-card__art and .closing-cta__art are RESTORED (see their definitions
   above, near .feature-card__text and the closing-cta rules respectively) --
   rev. 26 / D-A / D-B put real art and stubs back on S5 and S12. This note is
   left as-is below for the history it records; it is no longer an accurate
   description of the current file for those two rules.

   Removed: .hero__watch (+ img) -- the hero is now one composed Figma export with
   the watch baked in, so the separate overlay is gone. .free-art, .free-art__tile
   (+ img), .feature-card__art (+ img), .closing-cta__art (+ img) -- their art slots
   were designed out. .art-stub--panel -- the large placeholder those slots used.

   NOT removed, deliberately:
   - the rest of the `.art-stub` family. That is the reusable placeholder system
     SRV-4561 and SRV-4562 will need; unused on THIS page is not unused.
   - anything extracted from homepage.css. Those blocks are transcriptions with a
     recorded provenance md5, and editing one breaks the ability to re-diff it
     against its source.

   If SRV-4561 needs a row of square art tiles above a text grid, `free-art` was
   exactly that pattern and is recoverable from this file's history -- the note is
   here so page 2 does not re-derive it from scratch.
   ============================================================================= */

/* -----------------------------------------------------------------------------
   S4 tile row RESTORED as stubs, on Mikita's request 2026-08-27.

   These are the rules pruned an hour earlier, brought back unchanged. The prune
   note in this file said `free-art` was "recoverable from this file's history --
   the note is here so page 2 does not re-derive it from scratch." It took one
   request, not one afternoon, so the note did its job.

   Sizes are Figma's (3520:46905-46908): four 276x276 squares, 24px radius, 32px
   gap, sitting ABOVE the four text columns rather than inside them. `#ededed` is
   the fill Figma uses and is what shows once real art lands; while a stub is in
   the slot the stub's own dashed treatment covers it completely.

   Each stub names its column and its size, so the slot is a brief rather than a
   hole -- "Log it fast, 276 x 276" tells a designer what to draw; "Icon 1
   (pending)" tells them nothing.
   ============================================================================= */

.free-art {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-32);
  margin-bottom: var(--space-24);
}

/* No max-width. Figma's row is 4 x 276 squares with 32px gaps in a 1200 container:
   1104 + 96 = 1200 exactly, so the squares FILL the content width. Capping each
   tile at 27.6rem inside a 1470 container left 60px of dead space in every track
   and pushed each square to the left of its column -- squares of the right size in
   the wrong place, which reads as a broken grid rather than as a designed row.
   Letting them fill the track keeps Figma's proportion at every container width. */
.free-art__tile {
  aspect-ratio: 1 / 1;
  border-radius: 2.4rem;
  background: #ededed;
  overflow: hidden;
}

.free-art__tile img {
  display: block;
  width: 100%;
  height: auto;
}

/* Fills its parent instead of declaring its own box, because the parent already
   owns the Figma dimensions. Same rule that was pruned with the S4 row. */
.art-stub--panel {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  min-height: inherit;
  text-align: center;
}

/* Staying 4-up much further down than the other grids on this page, on purpose.
   These are ICON squares, and an icon shrinks gracefully where a card of text does
   not. Dropping to 2-up at 991 made each tile 473x473 -- two squares the size of a
   phone screen, which is worse than four small ones and no longer reads as a row of
   icons over four columns. Only below 576 does 4-up get too tight. */
@media only screen and (max-width: 991px) {
  .free-art {
      gap: var(--space-16);
    }
}

@media only screen and (max-width: 575px) {
  .free-art {
      grid-template-columns: repeat(2, 1fr);
      gap: var(--space-12);
    }
}

/* ---- Built for iPhone art slots, restored ------------------------------- */

/* 384x256 with a 24px radius, from Figma 3520:47058/47060-47062/47078/47091.
   All six are still EMPTY #ededed placeholders in Figma, so these are stubs, and
   each names its card and its size so the slot reads as a brief. */
.feature-card__art {
  aspect-ratio: 384 / 256;
  border-radius: 2.4rem;
  background: #ededed;
  overflow: hidden;
}

.feature-card__art img {
  display: block;
  width: 100%;
  height: auto;
}

/* ---- tier badges, Figma 3520:47063 -------------------------------------- */

/* `.sr-only` did not exist in EITHER stylesheet this page loads -- I checked both
   before using it, because an undefined utility class does not fail, it just
   renders the text visibly. "Premium Plus feature" would have appeared on the page
   as a stray line. Standard clip-rect implementation; pages 2-6 will want it too. */
.sr-only {
  position: absolute;
  width: 0.1rem;
  height: 0.1rem;
  margin: -0.1rem;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* The badge is a flattened vector asset from Figma -- "Premium" in #1B1B1B beside
   a "PLUS" pill running #FF8A00 -> #DD3983 -> #A600FF -- with the type outlined to
   paths. It ships as the asset rather than as CSS because rebuilding it would mean
   inventing a font, a weight and a letter-spacing that no longer exist in the file;
   the gradient stops would be the only true part.

   Sized in rem off its 147x24 viewBox so it scales with the type rather than
   sitting at a fixed pixel size next to a 2.8rem heading. SVG, so there is no
   density ceiling to worry about and no @2x to get wrong. */
.feature-card__badge {
  margin: 0 0 var(--space-8);
  line-height: 0;
}

.feature-card__badge-img {
  display: block;
  width: 14.7rem;
  height: 2.4rem;
}

@media only screen and (max-width: 991px) {
  .feature-card__badge-img {
      width: 12.2rem;
      height: 2rem;
    }
}

/* The PREMIUM badge, corrected to Figma 3520:47101/47102 and 3520:49220/49221.

   Unlike its Premium Plus sibling this one is LIVE TEXT on a shape, so it is
   rebuilt here rather than shipped as a file -- real, editable data exists, and
   flattening it into an asset would throw that away.

   I had built the earlier version of this rule by eye from a screenshot. Almost
   every value was wrong, which is the whole argument for asking:

     property          my guess          Figma
     ---------------------------------------------------------------
     fill              flat #f07a1a      3-stop gradient, see below
     font-size         12px              16px
     font-weight       600               700
     letter-spacing    1px               3.2px
     padding           4px 12px          8.276px uniform
     size              intrinsic          120 x 24 fixed

   The fill is a left-to-right gradient whose two ends are the SAME hue
   (#FF6524 -> #FFA024 at 50% -> #FF6524), which is why it reads as flat orange in
   a screenshot and why eyeballing it produced a flat hex. Only this badge uses
   the class now -- Premium Plus became an asset -- so the 12rem x 2.4rem box can
   be Figma's exact size rather than something padding-derived. */
/* The tier marker is a graphic pill in Figma, above the title, not an inline
   `(Premium)` in parentheses inside the heading. Keeping it inside the <h3> also
   meant screen readers and the FAQ/structured-data extractors read the tier as
   part of the feature name.

   Re-anchored here 2026-09-03. It used to sit above an EARLIER duplicate of this
   rule; when that duplicate was removed the comment stayed behind and came to
   read as documentation for `.feature-card__title`, which it never described.
   A comment that survives the rule it explains is worse than no comment. */
.feature-card__tier {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 12rem;
  height: 2.4rem;
  margin: 0 0 var(--space-8);
  padding: 0;
  border-radius: 1.2rem;
  background: linear-gradient(to right, #FF6524 0%, #FFA024 50%, #FF6524 100%);
  font-size: 1.6rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.32rem;
  text-transform: uppercase;
  color: #fff;
}

/* Letter-spacing adds a trailing gap after the last character, which shifts the
   word off-centre inside a fixed-width pill. Pulling it back by one space keeps
   the text optically centred -- the same reason type designers letter-space with
   a negative right margin rather than accepting the drift. */
.feature-card__tier {
  text-indent: 0.32rem;
}

@media only screen and (max-width: 991px) {
  .feature-card__tier {
      width: 10rem;
      height: 2rem;
      font-size: 1.3rem;
      letter-spacing: 0.26rem;
      text-indent: 0.26rem;
    }
}

/* ---- hero rating line, restored from the mockup --------------------------- */

/* The mockup writes this as "★★★★★ 4.8 · 160,000+ App Store ratings" and it was
   deleted because Figma's hero has none. Content is the mockup's lane, and the
   ticket says "do not rewrite copy", so it is back. Mikita also ruled the Figma
   ratings strip stays, so the page now carries two rating claims -- which is fine
   only because each states its own scope: this one says "App Store ratings", the
   strip says "On App Store & Google Play". Unlabelled, they would contradict. */
.hero__rating {
  margin: 0 0 var(--space-16);
  font-size: 1.8rem;
  line-height: 1.3;
  color: #fcf8b3;
}

.hero__stars {
  display: inline-flex;
  align-items: center;
  gap: var(--space-4);
  margin-right: var(--space-8);
  vertical-align: -0.2rem;
}

/* The five stars are the Figma gold-gradient SVG (see static_iPhone.st). They ship at
   28x27 in the source markup; the hero needs them at text scale, so size them here
   rather than editing the viewBox. `color` no longer does anything - the fill is a
   gradient, not currentColor - so it was removed with the text stars it used to tint. */
.hero__stars svg {
  display: block;
  width: 1.8rem;
  height: auto;
}

/* rev. 26 results stat + footnote, added 2026-08-31. Colour comes from the existing
   `.section-start .hero__content p { color: #fcf8b3; }` rule -- these two just adjust
   weight/size so the claim reads as the headline number and the footnote reads as a
   citation, matching the mockup's visual hierarchy without a new colour token. */
.hero__results {
  font-weight: 700;
}

.hero__footnote {
  margin-top: -0.8rem;
  font-size: 1.3rem;
  opacity: 0.85;
}

/* A FILLED ART SLOT HOLDING A CARD MUST NOT CLIP IT.

   `.split-2026__art` is the PLACEHOLDER: a grey #ededed box with a 4rem radius and
   `overflow: hidden`, so a bare image dropped into it is rounded to the slot. The
   `--filled` modifier was written to undo that when the slot holds real content, and
   it removed two of the four properties -- `min-height` and `background` -- leaving
   the radius and the clip behind.

   That is invisible for an image, which wants the rounding. It is not invisible for
   `.speed-chart`, which draws its own 1px card with its own 12px radius: the card's
   bottom border lands EXACTLY on the clip boundary. Measured at 390, 768, 992, 1280,
   1440 and 1600 -- the spill is 0.00px at every one, and a 1px border sitting exactly
   on a fractional clip edge loses its last raster row. The card reads as open at the
   bottom, which is what Mikita saw.

   Scoped with `:has()` to the slots that hold this card, so the image slots keep the
   rounding they actually want. */
.split-2026__art--filled:has(> .speed-chart) {
  overflow: visible;
  border-radius: 0;
}

/* ONE JOINED CONTAINER, not detached cards. Figma nodes 3918:50936 (2 cells) and
   3919:50957 (4 cells), read 2026-09-04.

   Mikita asked for these two blocks "as a table". Figma says they are NOT tables --
   no header row, one row of cells -- so a real <table> would be false semantics for
   a screen reader. What Figma actually draws is ONE rounded, hairlined box divided
   into equal columns by 1px internal rules, gap 0. We shipped detached cards in a
   grid with a 3.2rem gap and no border at all. This closes that gap.

   Every number is Figma's: radius 32px, stroke 1px rgba(0,0,0,0.1) -- the same
   treatment the comparison tables carry, so `--hairline` covers both -- cell padding
   40px, container gap 0.

   Guarded at min-width 992 on purpose. Below that the base `.ai-features__wrapper`
   rule switches to `display: block` and the cells stack, which is the behaviour the
   --2up and --4up modifiers already rely on. Figma has no mobile frame for either
   block, so joining them into one bordered row on a phone would be inventing a shape
   the design does not specify. Stacked and unbordered is what ships below 992. */
@media only screen and (min-width: 992px) {
  .ai-features__wrapper--joined {
    gap: 0;
    border: 1px solid var(--hairline);
    border-radius: 3.2rem;
    overflow: hidden;
  }

  .ai-features__wrapper--joined > * {
    padding: var(--space-40);
  }

  .ai-features__wrapper--joined > * + * {
    border-left: 1px solid var(--hairline);
  }
}

/* A WIDER "AT A GLANCE" TABLE, for the two pages whose cells hold prose.

   `.glance-table-wrap` caps at 76.8rem for all four pages. That is right for
   iPhone and android, whose longest cell is 39 and 42 characters -- a spec sheet.
   It is wrong for free-calorie-tracker (121) and verified-food-database (177),
   where the second column carries sentences: at 768px inside a 1420px container
   the table used 54% of the width while both columns sat at 383px.

   96rem, not a new number: `.comparison-table` already sets `min-width: 96rem`,
   so the family's two table types now share one width floor/ceiling. Measured at
   1440, cap against rendered table height:

       76.8rem   fct 1046   vfd 909    <- shipping
       88rem     fct  992   vfd 774
       96rem     fct  938   vfd 747    <- here
       104rem    fct  911   vfd 720
       112rem    fct  884   vfd 693

   The curve knees at 96: the first 19rem buys 108px and 162px, every 8rem after
   buys about 25. Wider keeps helping slightly and stops being a table. */
.glance-table-wrap--wide {
  max-width: 96rem;
}

/* THE TABLE'S OWN EDGE. Figma node 3921:51042 (3-column) and 3923:51136 (6-column)
   both carry a 1px rgba(0,0,0,0.1) stroke on all four sides. We shipped none, and
   that is the whole answer to Mikita's "no rounded edges or I didn't see it?" --
   the table is #FFFFFF with a 32px radius standing on a #FFFFFF section, so with no
   stroke there is no edge for the radius to describe. Figma has no shadow and no
   tinted ground doing that job either; the hairline is the only thing. The radius
   was already correct at 3.2rem.

   Declared here rather than on the `.comparison-table` rule at :2990, which is in
   the machine-extracted half of this file. */
.comparison-table {
  border: 1px solid var(--hairline);
}

/* A HIGHLIGHTED ROW IS NOT A HIGHLIGHTED COLUMN, and Figma paints them differently.

   `.is-highlight` was built as a COLUMN mechanism -- #eef7f1 fill, a #16b453 2px
   edge and a 24px radius, drawn per cell so that stacked vertically the edges become
   the column's outside border. iPhone and android use it that way for Premium Plus.

   verified-food-database's two tables and free-calorie-tracker's compare apps down
   the ROWS, so the thing to mark is a row. Figma agrees and specifies it explicitly:
   nodes 3921:51046 and 3923:51142 fill the MyNetDiary row `rgba(38,143,208,0.1)`
   across every column, radius 0, and NO edge. Neither table has a highlighted column
   at all. Confirmed by pixel: a render of the page frame samples (233,243,250) inside
   that row, and #268FD0 at 10% over white computes to (233,244,250).

   So a highlighted row gets Figma's blue and loses the column treatment's edge and
   radius entirely. A highlighted COLUMN keeps everything it had -- Figma was not
   measured for the plan tables, and nothing here says their green is wrong.

   HOW THE TWO ARE TOLD APART: a row highlight is the case where the row's own
   `th[scope='row']` carries the class. A column highlight never highlights the row
   label. `:has()` makes that testable, and its specificity (0,4,3) beats both the
   sticky column's white (0,2,2) and the base column fill (0,2,1). */
.comparison-table tbody tr:has(> th[scope='row'].is-highlight) > th.is-highlight,
.comparison-table tbody tr:has(> th[scope='row'].is-highlight) > td.is-highlight {
  background: rgba(38, 143, 208, 0.1);
}

/* The column treatment's green edge and its radius, off for a highlighted row.
   `content: none` removes the whole pseudo-element, so there is nothing left to
   draw a border between two cells of the band either -- which is why the two
   adjacent-sibling rules this replaces are gone rather than kept. */
.comparison-table tbody tr:has(> th[scope='row'].is-highlight) > th.is-highlight::before,
.comparison-table tbody tr:has(> th[scope='row'].is-highlight) > td.is-highlight::before {
  content: none;
}

/* THE PROSE LINK'S COLOUR, added 2026-09-04 on Mikita's ruling that every link
   shares one CSS. The class itself is declared at :1214, in the machine-extracted
   half of this file, so it cannot be edited there -- this rule adds the colour from
   below the banner instead. Specificity 0,1,0 beats the base `a { color: #2c3e50 }`
   (0,0,1) regardless of order, so 31 in-prose links across four pages stop being the
   exact colour of the sentence around them. The underline at :1215 stays. */
.prose-link {
  color: var(--link);
}

/* C-01. "Free, with no ads and no account required." sat hard against the store
   badge -- measured 0px on both iPhone and android. 24px is what the same
   sentence already renders at on verified-food-database, where it sits above the
   badges and reads correctly. The line was a bare <p>, so no rule could reach it. */
.hero__note {
  margin-top: var(--space-24);
}

/* ---- a card link with no destination yet --------------------------------- */

/* The mockup asks all six Built-for-iPhone cards for a "See ..." link, but points
   three of them at "#" -- so the mockup does not know those destinations either.
   An href="#" on a live page is worse than no link: it looks clickable and does
   nothing. So the text ships as the mockup writes it, visibly de-emphasised, with
   the pending destination recorded in data-pending-url. It becomes a real anchor
   the moment someone supplies a URL.
   The earlier build simply dropped these three, which matched no source and told
   nobody. Present-but-pending is the honest state. */
.feature-card__link--pending {
  margin: 0;
  font-size: 2rem;
  line-height: 1.3;
  color: #8494a3;
  cursor: default;
}

/* -----------------------------------------------------------------------------
   DEFECT FIX: the tier badge and the pending card links were both being beaten
   by a rule I wrote myself, three blocks earlier in this same file.

   `.feature-card__text p` is (0,1,1) -- one class plus one element. Both
   `.feature-card__tier` and `.feature-card__link--pending` are (0,1,0). So the
   generic paragraph rule won on every property they share, and the measured
   result was:

     badge      color rgb(44,62,80) not #fff      font-size 20px not 16px
     pending    color rgb(44,62,80) not grey

   The badge rendered as dark text on orange, which is exactly what Mikita
   screenshotted. Both classes ARE defined, both HAVE rules, and neither rule
   applied -- the coverage gate cannot see this and the dedup gate cannot either.

   FOURTH time today. `.press-strip__list li` beat `.press-strip__item` this
   morning in the identical way. The lesson is not "be careful": it is that a
   bare-element descendant selector like `<class> p` is a trap in an append-only
   sheet, because every later single-class rule for a <p> inside it silently
   loses. Fixed by scoping to the parent, which makes these (0,2,0).
   ============================================================================= */
.feature-card__text .feature-card__tier {
  font-size: 1.6rem;
  color: #fff;
}

/* Figma renders all six card links green (#0cb04e), including the three whose
   destination does not exist yet -- so the pending ones are green too, and read
   as links rather than as disabled text. They are still not anchors: the mockup
   points them at href="#", and a dead anchor that looks clickable is worse than
   text that looks like a link and is not one. */
.feature-card__text .feature-card__link--pending {
  font-size: 2rem;
  color: var(--link);
}

/* -----------------------------------------------------------------------------
   CHROME SPLIT REVERTED, on Mikita's instruction 2026-08-28.

   `chrome-2026.css` briefly existed: 56 rules + 73 media blocks moved out of this
   file, because the chrome CSS here is a FOURTH copy -- 76 `.navbar-site` and 62
   `.footer-site` rules absorbed from iPhone.2019.css and already diverged from it.
   The split was verified inert by a computed-style diff over 16 header/footer
   selectors at 1600/991/390, empty twice.

   Reverted anyway, and correctly. Mikita ruled that the 2026 pages use the site
   chrome exactly as it ships, and that chrome is out of scope for a page ticket:
   `footer_2019` reaches 59 static pages against this family's 1. A change that
   renders identically is still a change to shared chrome made inside a page
   ticket, and that is precisely how the live `copyright__text` regression on the
   food pages happened -- ten stylesheets updated, one missed, broken on pages
   nobody rendered.

   So the fourth copy stays, deliberately and visibly, until chrome has its own
   ticket. It is recorded as OOS-3 in tasks/web-pages-2026/TODO.md along with the
   twelve chrome changes Figma proposes, all declined for now.

   How the revert was done, since a naive restore would have lost work: the
   pre-split snapshot was replayed, then the 3,251 bytes appended AFTER the split
   (the badge specificity completion, the card-link base rule, and the Apple Watch
   icon slots) were re-appended on top. That puts every chrome rule back at its
   ORIGINAL position in the cascade rather than at the end of the file -- appending
   them would have changed their order relative to everything above, which is the
   same hazard the split was gated against.
   ============================================================================= */

/* COMPLETING the badge fix, which was PARTIAL. Found by wM:p4.

   `.feature-card__text .feature-card__tier` fixed `color` and `font-size` and
   stopped there. `.feature-card__text p` declares FOUR properties, so it went on
   winning the other two -- measured: margin 0 0 12px where the badge wants 8px,
   and line-height 20.8px where it wants 1.

   That is the failure mode worth naming, because it is subtler than the original
   bug: a partial fix LOOKS fixed. The visible symptom -- dark text on orange --
   went away, so the diff read as done. A gate that stops checking once some
   shared properties are resolved would have agreed with me.

   wM:p4's rule, which is the right one: keep checking EVERY property the two
   rules share, not just the ones somebody already patched. It does not need to
   know intent -- only that a higher-specificity rule still wins a property the
   lower one declares.

   So: every property `.feature-card__text p` declares is now restated here. */
.feature-card__text .feature-card__tier {
  margin: 0 0 var(--space-8);
  line-height: 1;
}

/* `.feature-card__link` is used in the template as the base of
   `feature-card__link feature-card__link--pending` and had NO rule anywhere --
   the modifier carried everything. Giving the base the shared box means a real
   anchor and a pending one line up identically once the three missing URLs
   arrive, instead of the anchor inheriting `.feature-card__text p`'s 12px margin
   while the pending one gets 0. */
.feature-card__text .feature-card__link {
  margin: 0;
  font-size: 2rem;
  line-height: 1.3;
}

/* ---- Apple Watch points: icon slots ------------------------------------- */

/* Figma 3520:50406 gives each point a 40x40 icon.

   HISTORY, because the note that used to sit here is now wrong and someone will
   otherwise re-derive it: these four slots were stubs because Figma held ONE real
   pencil and THREE identical pie charts, and shipping 1 real + 3 fakes under
   distinct filenames would have looked intentional. wM:p7 has since exported four
   genuinely distinct icons -- pencil, pie chart, watch, bell -- so the reason for
   the stub treatment is gone and the treatment goes with it. The rule that
   replaced it is below.

   The SPACING is Figma's and is exact, and it did not depend on the art being
   finished, which is why none of it changes now that the art is: 40x40 icon, 24px
   gap to the label, 64px row pitch (40 icon + 24 gap). */
.watch-points__item {
  display: grid;
  grid-template-columns: 4rem 1fr;
  gap: var(--space-24);
  align-items: center;
  min-height: 4rem;
}

/* PLACEHOLDER TREATMENT REMOVED 2026-08-31 -- the dashed border, the 45-degree
   hatch and the 1rem radius that clipped them were the stub, and the stub is over.
   Every one of the four rendered a real icon inside a visible dashed box; Mikita
   caught it on a phone against the served page.

   What is left is a bare 40x40 box, which is the whole job: the slot exists to
   reserve Figma's spacing, and an icon slot holding a real icon should contribute
   nothing of its own. No radius either -- a radius only means something if there
   is a fill or a border to clip, and there is now neither. */
.watch-points__icon {
  width: 4rem;
  height: 4rem;
}

/* `object-fit: contain` is not decoration. The four assets are square today, but
   this is the rule a re-export lands under (see the alpha note in
   reports/p6-design.md), and a non-square replacement would otherwise be stretched
   to 40x40 rather than fitted inside it. Cheap insurance at the exact spot where
   the asset changes. */
.watch-points__icon img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.watch-points__label {
  min-width: 0;
}

@media only screen and (max-width: 991px) {
  .watch-points__item {
      grid-template-columns: 3.2rem 1fr;
      gap: var(--space-16);
      min-height: 3.2rem;
    }

  /* Size only. The 0.8rem radius that used to be here was the small-screen half
     of the same placeholder box and came out with it. */
  .watch-points__icon {
      width: 3.2rem;
      height: 3.2rem;
    }
}

/* =============================================================================
   SRV-4560 ROUND 2 -- rev. 26 rebuild. wM:p6, 2026-08-31.

   Four things the rev. 26 copy asks for that this sheet had no rule for:
   the 3x3 "Built for iPhone" grid with three stubs standing among six real
   photographs (D-A), the split closing CTA (D-B), a brand-new "At a Glance"
   spec table, and a 34-row plans table.

   Written against the TARGET markup wM:p3 is building right now, not against
   what http://127.0.0.1:8899/static_iPhone.html currently serves. The class
   contract this assumes is stated in
   tickets/SRV-4560/reports/p6-design.md -- one section, "class contract".
   ============================================================================= */


/* ---- S5: three stubs standing among six real photographs ----------------- */

/* THE PROBLEM, which is new and is not the one the stub system was built for.
   Until today every card in this section was a stub, so the dashed candy-stripe
   read as one honestly unfinished section. From rev. 26 six cards carry real
   Figma art and three (Community, Medication Tracking, Family Food Sharing) do
   not. The same treatment that reads as "this section is not drawn yet" when it
   is all twelve reads as "this page is broken" when it is three out of nine --
   the loudest thing in a section of finished photography is the hole.

   WHAT I DID NOT DO: collapse the slot. Keeping the space is my own earlier
   ruling on this page and it still holds -- a collapsed slot makes three cards a
   different shape from six, which breaks the 3x3 grid the section exists to be,
   and it hides the missing art from everyone who is not reading the ticket.

   WHAT I DID NOT DO EITHER: make the stub look finished. A flat neutral panel
   with no border would pass for a design choice, and this file's whole stub
   system exists because "looks intentional" is how missing art ships.

   THE SOLUTION is to keep both signals and change only the volume. Scoped to
   `.feature-grid`, because a stub inside THIS grid is by definition a stub beside
   real art -- so it needs no new class from wM:p3 and it cannot leak onto the
   S4 tile row or the hero, where the loud treatment is still correct.

     - the 45-degree candy stripe goes. That pattern is the single loudest thing
       in the section and it is pure noise -- it carries no information the dashed
       border does not already carry.
     - the fill becomes #eef2f7, one step off the #ededed the real art slots use,
       so the stub sits in the same tonal family as its six neighbours instead of
       glowing.
     - the dashed border stays, at the art slot's own 2.4rem radius rather than
       the stub family's 1.2rem, so the hole is the shape of the picture that
       belongs in it.
     - the label gains an explicit "ARTWORK PENDING" line. This is the honesty
       that the candy stripe used to carry, moved from decoration into words --
       and words survive a screenshot pasted into Jira, which a texture does not.

   Net: quieter than its neighbours instead of louder, and still impossible to
   mistake for finished work. */
.feature-grid .art-stub {
  flex-direction: column;
  gap: 0.6rem;
  padding: var(--space-16);
  border: 0.2rem dashed #c3d2df;
  border-radius: 2.4rem;
  background: #eef2f7;
  color: #8496a7;
  font-size: 1.5rem;
  font-style: normal;
  line-height: 1.35;
}

.feature-grid .art-stub::before {
  content: 'Artwork pending';
  font-size: 1.1rem;
  font-weight: 600;
  letter-spacing: 0.12rem;
  text-transform: uppercase;
  color: #a9b7c4;
}


/* ---- S12: the closing CTA's art column, D-B ------------------------------ */

/* Full-bleed on three sides -- the phone render IS the card's right edge, per the
   1200x436 frame. `align-self: stretch` plus `object-position: bottom` means a
   card taller than 436 (long copy, or a translation) grows downward from a phone
   still planted on the bottom edge, rather than floating it in the middle of a
   dark rectangle. */
.closing-cta__art {
  align-self: stretch;
  min-width: 0;
}

.closing-cta__art img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: bottom;
}

/* BELOW 992 THE PHONE GOES UNDER THE BUTTONS, AND IT STAYS.

   Dropping it was the real alternative and I am against it here, specifically.
   The rule I would normally apply -- decorative art is the first thing to go on a
   phone -- does not reach this image: it is the product, shown at the moment of
   the ask, on a page whose entire audience is holding the device it depicts. Of
   the page's images this is the last one I would cut.

   But it goes BELOW the App Store badge, never above it. A 436px-tall image
   between the headline and the download button pushes the only conversion on the
   section off a 375x667 screen. Source order already puts the art last, so the
   single-column stack does the right thing on its own -- this rule only stops it
   filling the width. Capped at 24rem below 576 so the phone reads as an
   illustration under the CTA rather than a second hero. */
@media only screen and (max-width: 991px) {
  .closing-cta__art {
      max-width: 39.8rem;
      margin: 0 auto;
    }

  .closing-cta__art img {
      height: auto;
    }
}

@media only screen and (max-width: 575px) {
  .closing-cta__art {
      max-width: 24rem;
    }
}


/* ---- "MyNetDiary for iPhone at a glance" --------------------------------

   The `.glance__eyebrow` / `.glance__table` block that stood here is DELETED, not
   moved. I wrote it against a class contract (reports/p6-design.md section 6) that
   wM:p3 did not adopt -- the shipped markup is `.glance-table-wrap` / `.glance-table`
   with an `<h2 class="section-title">` instead of an eyebrow. Every selector in it
   matched nothing on any page, including the two `.glance__table` breakpoints I
   reported as verified.

   Dead CSS that reads as authored and reasoned is worse than none: the next person
   to open this file would have found two glance-table implementations 1,500 lines
   apart and no way to tell which one the page uses. The live rules are the ones at
   "AT A GLANCE, new section" further UP this file; the treatment work has moved
   there. Nothing of value is lost -- the reasoning that block carried is restated
   at the rule it now applies to.

   Process note, because it is the second time today: the contract was published in
   a report and never confirmed by the pane that had to honour it. A contract nobody
   acknowledges is a guess. */


/* ---- glance table: caption + optional header row ------------------------
   Both added 2026-08-31 for /free-calorie-tracker.html, which reuses this block
   with two features the iPhone page's table does not have.

   THE CAPTION had no rule at all, so it fell through to the base layer's
   `caption { caption-side: bottom; ... }` (line 286) and rendered UNDER the card in
   14px grey left-aligned -- the browser default, not a design. `caption-side: top`
   has to be declared explicitly to beat that base rule; it is not a default.

   The treatment is deliberately quiet. That section already opens with a 56px
   `comparison-section__title` and a 20px `comparison-section__note`, and the
   caption ("What's included free, by category") says the same thing a third time.
   A third display-weight line would be noise, so this is a small muted label
   naming the card directly above it -- the eyebrow treatment I originally drew for
   the iPhone glance section, which turned out to be needed here instead. */
.glance-table__caption {
  caption-side: top;
  padding: 0 0 var(--space-16);
  font-size: 1.4rem;
  font-weight: 600;
  letter-spacing: 0.16rem;
  line-height: 1.4;
  text-align: center;
  text-transform: uppercase;
  color: #6b7a88;
}

/* THE HEADER ROW. My recommendation is that it should GO -- see the audit section
   in reports/p6-design.md, item U-1. A `thead` is a SECOND AXIS, and this table
   does not have one: every row already carries `<th scope="row">` naming its
   label, so "Category / Included free" restates the column meaning that the row
   headers and the caption both already carry.

   These rules exist so the page is not broken while that markup decision sits with
   another ticket. If the header row stays, it reads as a header. */
.glance-table thead th {
  font-size: 1.4rem;
  font-weight: 600;
  letter-spacing: 0.12rem;
  line-height: 1.4;
  text-transform: uppercase;
  color: #6b7a88;
}

/* Stacked, there ARE no columns, so a column header cannot describe anything --
   "CATEGORY" and "INCLUDED FREE" would stack as two more label/value rows saying
   nothing. Removing it also repairs the 575 rule below: `tr + tr` draws the row
   rules from sibling adjacency, which does not cross a thead/tbody boundary, so
   with the header gone every row divider is back. */
@media only screen and (max-width: 575px) {
  .glance-table thead {
      display: none;
    }

  /* Caught at 390 in the render, not in review. At this breakpoint `.glance-table`
     becomes `display: block`, so the caption is no longer a table caption inside a
     table -- it keeps `display: table-caption` under a block parent, which makes
     Chrome wrap it in an anonymous shrink-to-fit table box. Result: the label
     rendered as a narrow four-line column hanging off the card's left corner,
     ignoring both the centring and the width. Making it a block puts it back in the
     flow it thinks it is in. */
  .glance-table__caption {
      display: block;
      padding: 0 var(--space-16) var(--space-12);
    }
}

/* ---- S9 plans table: 17 rows -> 34 --------------------------------------- */

/* The existing rule survives the doubling. It was already built for a table
   longer than the viewport -- sticky row headers, sticky-column shadow, a
   horizontal scroll container below 992 -- and none of that degrades with row
   count. Two things do.

   ONE: at 34 rows the eye loses the row on the way across. Every cell in the body
   is #ffffff today, so between the sticky feature column and the ✓ under
   "Premium Plus" there is nothing to hold the line -- and that traverse is the
   whole reason someone reads this table. A zebra fixes it and costs no height,
   which matters on a section that is now roughly twice as tall.

   The highlight column is excluded and re-tinted separately, because it paints
   its own #eef7f1 through `.is-highlight` further up this file and a plain zebra
   appended after it would win on source order and erase the highlight on every
   other row. #e7f2ec is that same green, one step down, so the column stays one
   column while its rows stay striped.

   TWO: the striping must not defeat the sticky column. `tbody th[scope='row']`
   sets its own #ffffff at equal specificity earlier in the file, so the striped
   row header is restated here rather than left to inherit -- an unstriped sticky
   column against a striped body is worse than no stripe at all. */
.comparison-table tbody tr:nth-child(even) td:not(.is-highlight) {
  background: #f7fafc;
}

.comparison-table tbody tr:nth-child(even) th[scope='row'] {
  background: #f7fafc;
}

.comparison-table tbody tr:nth-child(even) td.is-highlight {
  background: #e7f2ec;
}

/* The tier columns hold one glyph. 16rem/12rem was sized for a header word, not
   for the cell, and below 576 that width is what starved the feature column.
   7.2rem still clears the 3rem ✓ plus its padding, and "Premium Plus" wraps to
   two lines in the header, which it already does at this breakpoint. */
@media only screen and (max-width: 575px) {
  .comparison-table__col {
      min-width: 7.2rem;
    }
}

/* =============================================================================
   MOBILE PASS, 390px. wM:p6, 2026-08-31.

   Raised by Mikita from a real phone, reported as "the press strip is CLIPPED --
   text runs off the right edge and is cut, not wrapped".

   IT IS NOT CLIPPED, and the distinction matters because it changes the fix.
   Measured on the served page at 390, in real Inter:

     .press-strip__item   x=15  w=165  scrollWidth=165   -> no overflow
     .press-strip__item   x=196 w=165  scrollWidth=165   -> no overflow
     .press-strip__list         w=345  scrollWidth=345   -> no overflow
     no ancestor of the strip has overflow other than visible

   Nothing is cut. What the reported fragments ("called MyN... simpler, quic...
   better-looking... competi...") actually are is the LINE BREAKS of that claim
   wrapping inside a 165px column: "called MyNetDiary / simpler, quicker, / and
   better-looking / than the / competition". Five lines, four words wide.

   The complaint is right; the mechanism is not. The defect is that a 991px
   breakpoint is the LAST one this section has, so a 390px phone is served a
   tablet's 2-up layout: five items in 165px columns, with "Journal of Medical
   Internet Research" taking four lines for its source alone and item five sitting
   by itself in a half-empty row. It reads as broken because it is too narrow, not
   because it is cut.

   `flex: 1 0 40%` does set flex-shrink to 0, but `.press-strip__item` already
   carries `min-width: 0` (line 4192), so the items shrink and wrap correctly. That
   was the right thing to check and it is not the cause here.
   ============================================================================= */

/* One column below 576. At 576-991 the two columns are ~265px, which holds a
   source and its claim; below that they are 165px, which does not. The 5-item
   orphan row also disappears, because in one column there is no orphan. */
@media only screen and (max-width: 575px) {
  .press-strip__item {
      flex: 1 0 100%;
    }

  /* 3.6rem is 36px. "32 million people trust MyNetDiary" cannot make one line at
     any phone width, so the size is not buying a headline -- it is buying a
     two-line block of 36px type directly under a 28px section title, which
     out-shouts the title above it. 2.8rem keeps the emphasis and the hierarchy. */
  .press-strip__trust {
      margin-top: var(--space-28);
      font-size: 2.8rem;
    }
}

/* ---- plans table caption, genuinely clipped at 390 ----------------------- */

/* This one IS the failure mode the report describes, in a different section, and
   the sweep is what found it. The caption is a child of `.comparison-table`, so it
   is 41rem wide -- the table's mobile floor -- inside a 360px scroll container. At
   scroll 0 its centred text starts off-centre and its tail is cut:
   "MyNetDiary plan feature comparison for iPhone (" and then the edge.

   A caption is not matrix content. It is the sentence that says what the table is,
   and nobody should have to scroll sideways to finish reading it. Capping it to
   the visible width and anchoring it left puts the whole sentence on screen at
   scroll 0, while the table underneath keeps scrolling as designed.
   Scoped to 991, which is where the wrap becomes a scroll container (2874). */
@media only screen and (max-width: 991px) {
  .comparison-table__caption {
      width: calc(100vw - 3rem);
      max-width: calc(100vw - 3rem);
      margin-left: 0;
      text-align: left;
    }
}

/* =============================================================================
   ADDITIONS -- SRV-4562, 2026-08-28
   Owner: Mikita handed the shared sheet to this ticket to fix and merge back.
   Three related changes to the comparison table. Each is evidenced by a
   measurement on the served page, not by reading the CSS.
   ============================================================================= */

/* 1. The scroll wrapper now scrolls at EVERY width, not only below 992px.
      The markup already ships `role="region"` and `tabindex="0"` on this
      element, and `:focus-visible` already sits outside the media query --
      that is the WAI-ARIA scrollable-region pattern, and it was only half
      wired. Above 991px the page shipped a focusable tab stop that could not
      scroll. Measured: at a 1024 viewport the 7-column table is 1212px wide
      (240 + 6x160 column min-widths), pushing documentElement.scrollWidth to
      1227. With this rule it is 1024, and the sticky first column pins while
      the rest slides under it.
      Verified no side effect: overflow-y computes to `auto` as the spec
      requires, but no wrap has any vertical scrollable overflow at 1024, 1440
      or 1600 -- scrollHeight equals clientHeight on all four. The decorative
      highlight cap (`::before { top: -16px }`) lands inside the caption's
      40px bottom padding, and the `bottom: -16px` counterpart inside this
      element's own 24px padding-bottom. The `:focus-visible` outline is
      painted on this element, so its own overflow cannot clip it. */
.comparison-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* 2. A two-column table must not carry a 960px floor.
      `.comparison-table { min-width: 96rem }` applies to every table whatever
      its column count. The two 2-column tables on this page sit inside
      `.split-2026__text`, whose column is 427px at 1024, 843px at 1440 and
      873px at 1600 -- so they overflowed their own column at EVERY desktop
      width (measured 87px at 1600, 117px at 1440, 533px at 1024) and painted
      over the adjacent art panel. Fix 1 alone would only clip that, leaving a
      hard-cut edge. `min()` keeps the 960px floor where there is room for it
      and yields to the container where there is not. */
.comparison-table {
  min-width: min(96rem, 100%);
}

/* 3. REMOVED 2026-09-04. This was a hover-only "this table scrolls" hint --
      first a painted white ::after rectangle, then (same day) a mask-image
      fading the wrap's own pixels. Both looked wrong: the painted version
      squared off the table's rounded corner and painted white over the
      beige area above the table (a <table>'s background never covers its
      own <caption>); the mask version fixed that but, on the last column,
      faded real column text ("Ads in free tier") toward invisible on
      hover -- fading real content is worse than a decorative glitch.
      `.comparison-table-wrap` already has `overflow-x: auto`, which gives
      every browser's native scrollbar/touch-scroll affordance for free.
      Two rounds of bugs from one purely decorative hint was not worth a
      third attempt. */
.comparison-table-wrap {
  position: relative;
}

/* -----------------------------------------------------------------------------
   SRV-4562, 2026-08-28 (round 2) -- two defects Mikita found by looking at the
   page, which no gate reports because neither is an overflow, a missing rule or
   a wrong class. Both are "it renders, and it looks wrong".
   ----------------------------------------------------------------------------- */

/* 1. RETIRED 2026-09-02 -- this page no longer has a hero art stub, because Figma
      node 3849:1678 has no hero art column at all and Mikita ruled Figma the layout
      authority. The rule that lived here gave the stub a 574/814 box so it would not
      collapse to a line of text. Nothing uses it now; see the hero comment in
      static_verified-food-database.st for the full ruling. */


/* 2. The ratings strip read as ragged: four cards of different heights (115, 145,
      80 and 160px measured at 1440) centred against each other, so no two star
      rows or titles sat on the same line. `align-items: center` is right when the
      cards are uniform -- which is why it looks fine on the homepage, whose cards
      all carry the same icon-row-plus-one-line shape. This page's cards are not
      uniform: Trustpilot has no star icon (its score is pending, D6) and the Diet
      App Scorecard carries a longer body.
      Top-aligning makes the first row of every card share a baseline, which is the
      row a reader actually compares. NOTE FOR THE MERGE: this also affects
      static_iPhone.st, which uses the same strip.

      SCOPED TO THE ROW, 2026-09-02. This was unscoped, and `align-items` means something
      completely different once `flex-direction` flips: at 1280 and below the container is
      a COLUMN (see the base block above), so `flex-start` stopped stretching the cards and
      shrank them to content width -- 420px -- and pinned them to the left edge at x=15.
      The Trustpilot iframe is 420px wide with `transform: scale(1.5)`, and a transform
      paints from the box CENTRE, so it painted 630px centred on x=225 and 90px of the
      widget landed left of the viewport. Measured on the served /android.html: iframe
      630x60 at x=-90 at every width from 768 to 1280, and 546x52 at x=-48 from 576 to 767.
      Mikita saw it as "Excellent" clipped to "ent".
      `document.scrollWidth` stayed equal to the viewport at every one of those widths,
      because a transform reserves no layout space -- which is why no overflow gate caught
      it and why the 575px clamp below does not help either.
      static_index.st never had this: homepage.css keeps `align-items: center`, so its card
      is centred and the painted 630 has room on both sides. Restricting this override to
      the row restores that behaviour below 1281 and keeps the top-alignment it was
      actually written for. */
@media only screen and (min-width: 1281px) {
  .ratings-strip__container {
    align-items: flex-start;
  }
}

/* 3. Hero paragraphs that fall BELOW the green band must not keep the on-green colour.
      `.section-start::before` -- the green -- is only `height: 84%` (82/80/75% at the
      breakpoints), so the bottom of the section is WHITE. But
      `.section-start .hero__content p { color: #fcf8b3 }` paints every hero paragraph
      pale yellow, tuned for the green. Two of this page's trailing paragraphs land in
      the white band.
      Measured at 1440: color rgb(252,248,179) on background rgb(255,255,255) -- about
      1.1:1, where WCAG 1.4.3 requires 4.5:1 for body text. The reviewer byline was
      effectively invisible; Mikita spotted it by looking, and no gate reports it because
      contrast has no gate here (see figma2html/WEAKNESSES.md).
      #2c3e50 is not a new token -- it is this sheet's dominant body colour, already used
      by every normal paragraph on the page (measured: rgb(44,62,80)), so
      assert-design-tokens.py stays clean. Scoped to a page-local class rather than
      changing the shared `.hero__content p` rule, which the pilot depends on. */
/* REMOVED 2026-09-03. `.hero-meta` and `.hero-meta .hero__aside` served exactly one
   element -- free-calorie-tracker's "Reviewed by Sue Heikkinen" byline section -- and
   C-08 removed that whole section, so both rules lost their only caller. Verified by
   grep rather than assumed: `class="hero-meta"` appears ZERO times in the repo, and the
   only remaining mentions of the name are inside the removal note left at
   static_free-calorie-tracker.st:152-174. The doc comment above described a contrast fix
   for a paragraph that no longer exists. */
/* No colour declared on purpose: outside `.section-start` these paragraphs inherit the
   page's body colour, which is what every other white-background paragraph already uses.
   An earlier attempt set the colour explicitly at `.hero__aside` (0,1,0) and LOST to
   `.section-start .hero__content p` (0,2,1) — deployed, and the served page still measured
   rgb(252,248,179). See P7 in references/house-patterns.md. Moving the element out of that
   ancestor removes the conflict instead of out-specifying it. */

/* -----------------------------------------------------------------------------
   SRV-4562, 2026-08-28 (round 3) -- the hero device cards and the eyebrow, taken
   from the v3 mockup on Mikita's instruction ("add that ones to design, add as is
   just adapt") and adapted rather than copied.

   ADAPTED, not lifted, in four ways:
     1. px -> rem against this sheet's 10px root (homepage.css:5015). 12px -> 1.2rem.
     2. v3's CSS variables mapped onto colours THIS SHEET ALREADY SHIPS, so no new
        token is introduced and assert-design-tokens.py stays clean:
          --primary #1274BC -> #268fd0 (21 existing uses)
          --ink     #1f2a33 -> #2c3e50 (33)
          --sub     #5a6a76 -> #6b7a88 (6)
          --line    #dfe8ee -> #e3eaf0 (3)
     3. BEM names in the house shape (`phone-card__bar`, not `.pbar`), so the block
        is greppable and matches every other block in this file.
     4. The two cards replace the pending-art stub that sat in `.hero__media`. They
        are markup and SVG, not delivered art -- which is how the mockup builds them
        too -- so this REDUCES the pending-art count from 7 to 6.

   DELIBERATE SUB-12px TEXT. `phone-card__bar`, `__macros`, `__mini` and `__more` are
   1rem-1.15rem. These are the contents of a SIMULATED PHONE SCREEN, where small text
   is the point -- it is what makes the graphic read as a phone. This is the case
   already anticipated in decision D8. assert-mobile-ready.py will flag them and they
   belong in tickets/SRV-4562/mobile-allow.txt with this reason, NOT silenced.
   ----------------------------------------------------------------------------- */

.hero__eyebrow {
  margin: 0 0 var(--space-12);
  font-size: 1.2rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.phone-cards {
  display: flex;
  gap: 1.8rem;
  justify-content: center;
}

.phone-card {
  width: 22.5rem;
  padding: 1.8rem var(--space-16);
  background: #fff;
  border: 0.15rem solid #e3eaf0;
  border-radius: 2.6rem;
  box-shadow: 0 1.6rem 3.6rem rgba(38, 143, 208, 0.1);
}

.phone-card--second {
  align-self: flex-end;
}

.phone-card__bar {
  display: flex;
  justify-content: space-between;
  margin-bottom: var(--space-12);
  font-size: 1rem;
  color: #6b7a88;
}

.phone-card__ring {
  position: relative;
  width: 13.2rem;
  height: 13.2rem;
  margin: 0.6rem auto var(--space-decimal-10);
}

.phone-card__ring svg {
  transform: rotate(-90deg);
}

.phone-card__ring-mid {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.phone-card__ring-mid b {
  font-size: 2.1rem;
  font-variant-numeric: tabular-nums;
}

.phone-card__ring-mid span {
  font-size: 1rem;
  color: #6b7a88;
}

.phone-card__macros {
  display: flex;
  justify-content: space-between;
  margin-top: 0.6rem;
  padding-top: var(--space-decimal-10);
  border-top: 0.1rem solid #e3eaf0;
  font-size: 1rem;
  color: #6b7a88;
}

.phone-card__macros b {
  display: block;
  font-size: 1.2rem;
  color: #2c3e50;
  font-variant-numeric: tabular-nums;
}

.phone-card__mini {
  padding-top: var(--space-4);
  border-top: 0.6rem solid #2c3e50;
  font-size: 1.15rem;
}

.phone-card__row {
  display: flex;
  justify-content: space-between;
  padding: var(--space-4) 0;
  border-bottom: 0.1rem solid #e3eaf0;
  font-variant-numeric: tabular-nums;
}

.phone-card__row--last {
  border-bottom: 0;
}

.phone-card__more {
  margin-top: var(--space-8);
  font-size: 1.1rem;
  font-weight: 600;
  color: #268fd0;
}

/* REMOVED 2026-09-03. This was `.section-start .hero__media { min-width: 0 }`, whose
   comment read "The hero art slot no longer holds a stub, so its reserved aspect-ratio
   box must not squash the cards" -- a verified-food-database condition. It sat AFTER the
   real box rule at :2766 at the same specificity (0,2,0), so it won on source order and
   removed the 58rem/50rem floor from EVERY `.section-start` page. Measured before
   removal, 24 readings across 4 pages x 1440/1200/1024/991/768/390: identical to a tenth
   of a pixel with the rule present or absent. `.hero__media` computes `flex: 0 1 auto`,
   so its base size is its 580px content, and the ladder never offers more than a 500px
   floor below the 1469 breakpoint -- inert under a 580 box by construction. A no-op
   cleanup, and the floor it removed is redundant only while the hero art is 580 wide. */

/* -----------------------------------------------------------------------------
   SRV-4574 — FLUID TABLES (renamed from --compact, C-17). `.comparison-table`
   carries `min-width: 96rem` (960px) on the base block, which scrolls a 6+
   column table under ~1024px. `--compact` originally paired that scroll fix
   with a second, independent squeeze -- smaller cell type, tighter padding,
   an uppercase caption -- and Mikita's "regular table design" ask (C-17) was
   about that second part, not the scroll fix.

   MEASURED (SRV-4574, 2026-09-03) with `min-width: 0` as the ONLY rule and
   regular 2rem cell type restored on vfd's two 6/3-column tables:
     991px viewport   table resolves to 961px, zero overflow
     1024px viewport  table resolves to 994px, zero overflow
   So `min-width: 0` alone does the whole job. The type/padding/caption
   shrink was bundled onto the scroll fix, not required by it -- do not
   re-bundle them; a table that only needs its min-width floor removed does
   not need its type shrunk too.

   Cell text wrapping was checked at both widths and does NOT hold cleanly at
   regular size. At 991px both tables' worst cell is 2 lines. At 1024px the
   6-column table (vfd's second one) has two cells at 3 lines: the "Free tier
   ads" column header, and MyNetDiary's "Staff-verified, 2,500-3,500
   foods/day" value in the Verification column. The 3-column table never
   exceeds 1 line at either width.
   COUNTERINTUITIVE PART, worth stating because it is the part a re-test
   would get backwards: wrapping is WORSE at the WIDER 1024px than at 991px.
   That points at the browser's table auto-layout reallocating column widths
   unevenly as available width changes, not a monotonic squeeze -- so do not
   assume narrower is the worse case; re-test both. Whether 3 lines in those
   two cells is acceptable is a product call, not settled by this comment.

   Kept as a MODIFIER, not a base-block change, for the same reason as before:
   `.comparison-table` is shared with static_iPhone.st and static_index.st,
   whose tables never needed this. `--compact` (SRV-4562, Mikita: "find how we
   work with tables in html and made them compact as in mock") originally also
   shrank cell type; that history is preserved in git blame, not repeated here
   because the type shrink is gone.
   ----------------------------------------------------------------------------- */
.comparison-table--fluid {
  min-width: 0;
}
.comparison-table--fluid .comparison-table__row-title {
  min-width: 0 !important;
}
.comparison-table--fluid .comparison-table__col,
.comparison-table--fluid .comparison-table__col--feature {
  min-width: 0;
}

/* SRV-4562 — the hero device cards must not widen the mobile viewport.
   Two 22.5rem cards plus a 1.8rem gap is 46.8rem = 468px, which does not fit a 390px
   phone. Measured before this rule: `window.innerWidth` reported **435, not 390** —
   Chrome had widened the layout viewport to fit the intrinsic width, so the whole page
   rendered zoomed out on a phone. `assert-responsive.mjs` reported ok/escaping=0 for it,
   correctly: the cards sit inside a clipping ancestor so nothing ESCAPES the document.
   Escaping and forcing-the-viewport-wider are different defects, and only the second one
   was happening.
   Neither the mockup nor any shipped page answers this: v3 only stacks its grid at 920px
   and never shrinks the phones, so the mockup has the same defect at phone widths. This
   is therefore a judgment call, recorded as D25 rather than presented as house style.
   Measured after: innerWidth 390, docScrollWidth 390. */
@media only screen and (max-width: 575px) {
  .phone-cards {
    flex-wrap: wrap;
  }
  .phone-card {
    width: 100%;
    max-width: 32rem;
  }
  .phone-card--second {
    align-self: auto;
  }
}

/* SRV-4562 — the Trustpilot iframe must not set the page's minimum width on a phone.
   The TrustBox script injects an iframe at the widget's `data-style-width` (420px). On a
   390px phone that alone forces the layout viewport to ~435, which is the same
   zoomed-out defect as the phone cards, from a different source.
   FOUND ONLY ON THE SERVED PAGE. The frozen bundle has no iframe -- the widget is live
   content -- so the bundle measured a clean 390 after the phone-card fix and would have
   shipped this. That is the documented limit of the freeze, demonstrated: iterate on the
   bundle, but confirm anything LIVE against the server. */
@media only screen and (max-width: 575px) {
  .rating-card--trustpilot {
    max-width: 100%;
    overflow: hidden;
  }
  .rating-card--trustpilot .trustpilot-widget,
  .rating-card--trustpilot .trustpilot-widget iframe {
    max-width: 100%;
  }
}

/* -----------------------------------------------------------------------------
   RETIRED 2026-09-02 -- the .nutrient-list block (11 selectors, SRV-4562's
   "NUTRIENT PANEL as the mockup builds it") is removed.

   Both pages that carried it have stopped rendering it. static_free-calorie-tracker.st
   traded the salmon panel for real art on 2026-09-01; static_verified-food-database.st
   traded it for a pending art stub on 2026-09-02, per Figma node 3919:51009. A search
   of all 1,134 templates found the string in comments only -- zero rendered markup.

   Removed on Mikita's ruling, after the same check stopped once for being SRV-4562's
   CSS rather than this ticket's. Same call he made on .art-stub--hero the same day:
   an orphan is an orphan whichever ticket wrote it.

   RESTORING THE PANEL IS NOW A TWO-PART JOB. The markup is parked at
   tasks/web-pages-2026/tickets/SRV-4574/REMOVED-nutrient-list-panel.html; these rules
   come back from git history, commit 1b1365f9543. A paste of the markup alone renders
   an unstyled definition list.

   Three comments elsewhere in this sheet still name these selectors as precedent
   (near the label/value-row, hero-results and free-page notes). They are left as
   written -- they are prose about a decision, not rules, and editing another block's
   reasoning to stay arithmetically current is how evidence gets destroyed.
   ----------------------------------------------------------------------------- */

/* --- C. "Is MyNetDiary Really Free?" barcode scanner --------------------------
   REUSED, not a second phone component: v3 writes this as class="phone scanphone",
   the same base as the two hero cards plus a modifier, so the card shell, border,
   radius, shadow and __bar all come from the .phone-card rules already in this
   file. Only the viewfinder and result card are new.
   v3's three invented colours are remapped onto families this sheet owns:
   viewfinder ground #0d1620 -> #1f3348 (the .closing-cta__card dark ground),
   chip tints #e6f4ec -> #eef7f1 and #e8f1fa -> #e6edf3.
   One card at 25rem cannot repeat D25, where two 22.5rem cards forced the layout
   viewport to 435px on a 390px phone. */
.phone-cards--scan {
  align-items: center;
  min-height: 100%;
  padding: var(--space-24);
}

.phone-card--scan {
  width: 25rem;
  max-width: 100%;
}

.phone-card__viewfinder {
  position: relative;
  height: 13rem;
  margin-bottom: var(--space-12);
  border-radius: 1.2rem;
  background: #1f3348;
  overflow: hidden;
}

.phone-card__corner {
  position: absolute;
  width: 2.6rem;
  height: 2.6rem;
  border: 0.3rem solid #fff;
  opacity: 0.9;
}

.phone-card__corner--tl { top: 1.4rem; left: 1.4rem; border-right: 0; border-bottom: 0; }
.phone-card__corner--tr { top: 1.4rem; right: 1.4rem; border-left: 0; border-bottom: 0; }
.phone-card__corner--bl { bottom: 1.4rem; left: 1.4rem; border-right: 0; border-top: 0; }
.phone-card__corner--br { bottom: 1.4rem; right: 1.4rem; border-left: 0; border-top: 0; }

.phone-card__scanline {
  position: absolute;
  left: 10%;
  right: 10%;
  top: 50%;
  height: 0.2rem;
  background: #0bb850;
  box-shadow: 0 0 1rem #0bb850;
  animation: scan-2026 2.6s ease-in-out infinite;
}

/* Page-scoped name so it cannot collide on /iPhone.html. */
@keyframes scan-2026 {
  0%,
  100% {
      top: 26%;
    }

  50% {
      top: 72%;
    }
}

@media (prefers-reduced-motion: reduce) {
  .phone-card__scanline {
      animation: none;
    }
}

.phone-card__result {
  padding: var(--space-decimal-10) var(--space-12);
  border: 0.1rem solid #e3eaf0;
  border-radius: 1rem;
  font-size: 1.3rem;
  color: #2c3e50;
}

.phone-card__result b {
  display: block;
  margin-bottom: var(--space-4);
}

.phone-card__chip {
  display: inline-block;
  padding: 0.2rem var(--space-decimal-10);
  border-radius: 2rem;
  font-size: 1.2rem;
  font-weight: 600;
}

.phone-card__chip--free { background: #eef7f1; color: #0bb850; }
.phone-card__chip--verified { background: #e6edf3; color: #268fd0; }

/* --- E. "How Fast Is Logging?" speed chart ------------------------------------
   The section shipped BOTH a two-column comparison-table AND an empty art stub, so
   the seven action counts were stated twice. v3 has only the chart. The table moved
   into the art column and became the chart, so the numbers are stated once.
   Kept as a real <table> with a real <caption>: seven apps measured on one variable
   and compared is a row set, and the caption is the graphic's accessible name. The
   bar is a DECORATION of the value cell (aria-hidden), not a third column -- an
   empty third cell would be announced on every row.
   Bar widths ride a custom property, not style="width:", so the sheet still owns
   width/height/background and a bad value degrades to the 0% fallback.
   table-layout:fixed means nothing scrolls, so no role="region"/tabindex trio.
   #b9c6d2 is used for the competitor bars: v3's #c9d6e0 is NOT in this sheet and is
   2-3 per channel away from one we own -- exactly the near-miss D7 is about. */
.speed-chart {
  margin-top: var(--space-24);
  padding: 1.8rem var(--space-20);
  background: #fff;
  border: 0.1rem solid #e3eaf0;
  border-radius: 1.2rem;
}

.speed-chart__table {
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
}

/* The base layer sets caption { caption-side: bottom }, which would drop the title
   under the bars. Reset explicitly. */
.speed-chart__caption {
  caption-side: top;
  padding: 0 0 0.6rem;
  text-align: left;
  font-size: 1.2rem;
  line-height: 1.35;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #6b7a88;
}

/* Fixed first column so all seven tracks start on the same x and the bars are
   actually comparable -- the whole point of the graphic. */
.speed-chart__who {
  width: 10rem;
  padding: var(--space-8) var(--space-12) var(--space-8) 0;
  font-size: 1.3rem;
  font-weight: 400;
  line-height: 1.3;
  text-align: left;
  vertical-align: middle;
  color: #6b7a88;
}

.speed-chart__row--us .speed-chart__who {
  font-weight: 700;
  color: #2c3e50;
}

.speed-chart__cell {
  padding: var(--space-8) 0;
  vertical-align: middle;
}

/* display:grid goes on a span INSIDE the cell, never on the <td> itself -- a cell
   that stops being table-cell stops participating in the fixed layout, which is
   what makes the tracks line up. Same lesson as D22. */
.speed-chart__meter {
  display: grid;
  grid-template-columns: 1fr 4.4rem;
  gap: var(--space-12);
  align-items: center;
}

.speed-chart__track {
  display: block;
  min-width: 0;
}

.speed-chart__bar {
  display: block;
  width: var(--speed-chart-fill, 0%);
  height: 1.9rem;
  border-radius: 0.4rem;
  background: #b9c6d2;
}

.speed-chart__bar--us {
  background: #268fd0;
}

.speed-chart__num {
  font-size: 1.3rem;
  line-height: 1.3;
  text-align: right;
  white-space: nowrap;
  color: #2c3e50;
  font-variant-numeric: tabular-nums;
}

.speed-chart__note {
  margin: var(--space-decimal-10) 0 0;
  font-size: 1.2rem;
  line-height: 1.35;
  color: #6b7a88;
}

@media only screen and (max-width: 575px) {
  .speed-chart {
      padding: 1.4rem var(--space-16);
    }

  .speed-chart__who {
      width: 8.6rem;
      padding-right: var(--space-8);
      font-size: 1.2rem;
    }

  .speed-chart__meter {
      grid-template-columns: 1fr 4rem;
      gap: var(--space-8);
    }

  .speed-chart__bar {
      height: 1.6rem;
    }

  .speed-chart__num {
      font-size: 1.2rem;
    }
}

/* =============================================================================
   cta-banner -- PORTED, not authored. wM:p6, 2026-08-31.

   /iPhone.html swapped its bespoke `.closing-cta` markup for the shared
   `cmp_cta_banner.st` component (Mikita's ruling: follow the homepage). The
   component's CSS lives in homepage.css, which this page does not load, so the
   banner arrived unstyled: measured on the served page at 1280,
   `.cta-banner__panel` had `background: rgba(0,0,0,0)`, `border-radius: 0px` and
   a height of 1822px, and `.cta-banner__phone` rendered at its natural size.
   This is the exact failure this file's own header warns about -- "a page that
   swaps homepage.css for this file loses EVERYTHING homepage.css was supplying."

   SOURCE, and why this one. The block exists in three sheets and all three are
   BYTE-IDENTICAL for every rule below (diffed, not assumed):
       homepage.css     8896-9005    md5 of file: see report
       glp-1.2019.css   9841-9950    identical
       blog.2019.css    13048-13157  identical
   All four sheets, including this one, are authored against `html{font-size:10px}`,
   so every rem transfers at face value. I verified that before copying -- an
   identical rule set under a different root would have meant different pixels.

   blog.2019.css carries five EXTRA rules the other two lack, scoped
   `.section-article .cta-banner*` (13160-13176). I took NONE of them. They are
   blog-article container patches, not fixes to the base block, and one of them is
   actively wrong for us:
       .section-article .cta-banner__panel { overflow: hidden; }
   That is the rule that would CUT THE PHONE OFF at the panel edge -- the exact
   defect the bespoke `.closing-cta` had and that this port must not reintroduce.
   The base block deliberately has no `overflow`, which is what lets the phone
   overhang the panel's top edge by its 5.6rem negative margin. Do not add one.

   NOT REMOVED: `.closing-cta*`. /free-calorie-tracker.html still ships two
   `closing-cta` sections on this same sheet, so those rules are live. They are
   dead on /iPhone.html only.
   ============================================================================= */

.cta-banner__panel {
  display: flex;
  justify-content: space-between;
  align-items: center;
  min-height: 38rem;
  padding: 0 var(--section-56);
  border-radius: 4rem;
  background: url(https://s3.amazonaws.com/img.mynetdiary.com/images/texture-noise@1x.png), radial-gradient(circle at 50% 50%, rgba(100, 240, 95, 0.28) 0%, rgba(20, 190, 55, 0) 42%), linear-gradient(90deg, #17892c 0%, #12c93e 50%, #17892c 100%);
}

@media only screen and (max-width: 1280px) {
  .cta-banner__panel {
      min-height: 35rem;
    }
}

@media only screen and (max-width: 991px) {
  .cta-banner__panel {
      min-height: 28rem;
    }
}

@media only screen and (max-width: 767px) {
  .cta-banner__panel {
      flex-direction: column;
      align-items: flex-start;
      padding: var(--space-24) var(--space-16) 0;
      max-width: 46rem;
      margin-left: auto;
      margin-right: auto;
    }
}

.cta-banner__content {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.cta-banner__title {
  margin: 0 0 var(--space-24);
  line-height: 1.1;
  color: #ffffff;
}

@media only screen and (max-width: 767px) {
  .cta-banner__title {
      margin-bottom: var(--space-20);
    }
}

.cta-banner__stores {
  display: flex;
  align-items: center;
  gap: var(--space-16);
  flex-wrap: wrap;
  margin-bottom: var(--space-24);
}

@media only screen and (max-width: 767px) {
  .cta-banner__stores {
      margin-bottom: var(--space-20);
    }
}

.cta-banner__store-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
}

.cta-banner__note {
  margin: 0;
  font-size: 2rem;
  line-height: 1.4;
  font-weight: 400;
  color: #ffffff;
}

@media only screen and (max-width: 767px) {
  .cta-banner__note {
      font-size: 1.2rem;
    }
}

.cta-banner__note a {
  color: #ffffff;
  text-decoration: none;
}

.cta-banner__note a:hover {
  text-decoration: underline;
}

/* `align-self: flex-end` plus the negative top margin is the whole trick: the
   phone sits on the panel's bottom edge and overhangs its top by 5.6rem, so it is
   FULLY VISIBLE rather than cropped. `width: 100%` on the image against this
   `max-width` is what keeps the 1677x1876 source from rendering at natural size --
   which is exactly what it was doing before this port. */
.cta-banner__media {
  align-self: flex-end;
  margin-right: var(--section-56);
  margin-top: -5.6rem;
  width: 100%;
  max-width: 39rem;
}

@media only screen and (max-width: 1280px) {
  .cta-banner__media {
      margin-right: 0;
      max-width: 37rem;
    }
}

@media only screen and (max-width: 991px) {
  .cta-banner__media {
      max-width: 28rem;
    }
}

@media only screen and (max-width: 767px) {
  .cta-banner__media {
      margin: var(--space-16) auto 0;
      padding-left: var(--space-16);
      padding-right: var(--space-16);
    }
}

.cta-banner__phone {
  width: 100%;
  height: auto;
}

/* ---- .cta-banner__body -- NEW, not ported ------------------------------- */

/* The homepage passes only a heading, so this element does not exist upstream and
   has no rule in any of the three sheets. /iPhone.html passes a body paragraph.

   Values are `.cta-banner__note`'s, not invented: 2rem / 1.4 / 400 / #ffffff, and
   1.2rem below 768. The body and the note are the same voice on the same green
   ground one above the other, and giving them two type treatments would read as
   two components.

   `max-width: 56rem` is the only value that is mine. The panel is
   `justify-content: space-between` with a 39rem media column, which leaves the
   content column free to take whatever the text asks for -- an uncapped paragraph
   would push the phone right and stretch to ~70rem of measure. 56rem holds the
   heading's own comfortable width and keeps the two-column balance the homepage
   panel has with a heading alone. */
.cta-banner__body {
  max-width: 56rem;
  margin: 0 0 var(--space-24);
  font-size: 2rem;
  line-height: 1.4;
  font-weight: 400;
  color: #ffffff;
}

/* 1.6rem, NOT the note's 1.2rem -- I departed from the "same voice" rule here and
   only after looking at it rendered. `.cta-banner__note` is ONE short aside line,
   and 12px is defensible for that. This is a four-line body paragraph, and 12px
   body copy on a 390px phone is unreadable; it would also be a regression, since
   the bespoke `.closing-cta__body` this replaced had no mobile step at all and
   rendered at 20px. 1.6rem steps down from desktop without going below what a
   paragraph needs. */
@media only screen and (max-width: 767px) {
  .cta-banner__body {
      margin-bottom: var(--space-20);
      font-size: 1.6rem;
    }
}


/* =============================================================================
   USER-REVIEWS CAROUSEL -- ported 2026-09-01 on Mikita's instruction:
   "index page has element for What Users Say correct and ready, re-use it".

   It was NOT ready to reuse, and that is the point of this header. The markup is
   in static_index.st and the JS is js/mnt-carousel.js, but every one of these 56
   rules lived ONLY in homepage.css -- a sheet the 2026 pages do not load. Dropping
   the index markup in without this port would have rendered an unstyled list of
   reviews and passed every gate, which is exactly what happened with
   cmp_cta_banner on 2026-08-31. assert-class-has-rule.py exists because of that
   incident and is what proves this port is complete.

   The card itself is NOT here. .review-card__top / __person / __avatar / __name /
   __rating / __text were already ported into this sheet from the same source, so
   only the carousel shell was missing. That earlier half-port is also why this
   sheet carries two competing .review-card blocks; see the duplicate-selector
   baseline.

   Extracted with scripts/extract-css-blocks.py, leftmost-compound scope, NOT
   hand-copied, so it can be re-diffed against the source.
   Provenance: homepage.css, md5 3a40e61733fc2296a2d97d9342a48ff6
   Blocks: mnt-carousel (28 rules), user-reviews (28 rules). 56 total.
   ============================================================================= */

.mnt-carousel {
  position: relative;
}

.mnt-carousel__viewport {
  overflow: visible;
}

.mnt-carousel__track {
  margin: 0;
  padding: 0;
  list-style: none;
}

.mnt-carousel__slide {
  min-width: 0;
  -webkit-tap-highlight-color: transparent;
}

.mnt-carousel__controls {
  display: none;
  align-items: center;
  justify-content: center;
  gap: var(--space-16);
  margin-top: var(--space-20);
}

.mnt-carousel__dots {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-16);
}

.mnt-carousel__arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 4.4rem;
  height: 4.4rem;
  padding: 0;
  border: 0.1rem solid #d0d5dd;
  border-radius: 50%;
  background: #ffffff;
  color: #344054;
  cursor: pointer;
  transition: border-color 0.2s ease, background-color 0.2s ease, color 0.2s ease, transform 0.2s ease;
}

@media only screen and (max-width: 767px) {
  .mnt-carousel__arrow {
      width: 4rem;
      height: 4rem;
    }
}

.mnt-carousel__arrow:hover,
.mnt-carousel__arrow:focus-visible {
  border-color: #0bb850;
  color: #0bb850;
  outline: none;
  transform: scale(1.04);
}

.mnt-carousel__arrow:disabled {
  opacity: 0.45;
  cursor: default;
  transform: none;
}

.mnt-carousel__dot {
  width: 1.2rem;
  height: 1.2rem;
  padding: 0;
  border: 0.1rem solid #cfcfcf;
  border-radius: 50%;
  background: #ffffff;
  cursor: pointer;
  transition: background-color 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}

.mnt-carousel__dot:hover,
.mnt-carousel__dot:focus-visible {
  border-color: #0bb850;
  outline: none;
  transform: scale(1.05);
}

.mnt-carousel__dot.is-active {
  border-color: #0bb850;
  background: #0bb850;
}

.mnt-carousel:not(.is-slider-active) .mnt-carousel__controls {
  display: none;
}

@media only screen and (max-width: 767px) {
  .mnt-carousel.is-slider-active {
      width: 100%;
      margin-right: 0;
    }
}

@media only screen and (max-width: 991px) {
  .mnt-carousel.is-slider-active {
      width: calc(100% + ((100vw - 100%) / 2));
      margin-right: calc((100vw - 100%) / -2);
    }
}

.mnt-carousel.is-slider-active .mnt-carousel__viewport {
  touch-action: pan-y;
  overscroll-behavior-x: contain;
  user-select: none;
  -webkit-user-select: none;
}

@media only screen and (max-width: 991px) {
  .mnt-carousel.is-slider-active .mnt-carousel__viewport {
      overflow: hidden;
    }
}

.mnt-carousel.is-slider-active .mnt-carousel__track {
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
}

@media only screen and (max-width: 991px) {
  .mnt-carousel.is-slider-active .mnt-carousel__track {
      display: flex;
      gap: var(--space-24);
      will-change: transform;
      transition: transform 0.45s ease;
      backface-visibility: hidden;
    }
}

.mnt-carousel.is-slider-active .mnt-carousel__slide {
  -webkit-tap-highlight-color: transparent;
}

.mnt-carousel.is-slider-active .mnt-carousel__controls {
  margin-top: var(--space-20);
}

@media only screen and (max-width: 991px) {
  .mnt-carousel.is-slider-active .mnt-carousel__controls {
      display: flex;
    }
}

@media only screen and (max-width: 767px) {
  .mnt-carousel.is-slider-active .mnt-carousel__controls {
      gap: 1.4rem;
      margin-top: 0;
    }
}

@media only screen and (max-width: 767px) {
  .mnt-carousel.is-slider-active .mnt-carousel__dots {
      gap: 1.4rem;
    }
}

.mnt-carousel.is-slider-active img {
  -webkit-user-drag: none;
  user-select: none;
}

@media only screen and (max-width: 991px) {
  .mnt-carousel.is-slider-active::after {
      content: "";
      position: absolute;
      top: 0;
      right: 0;
      width: 12rem;
      height: 100%;
      pointer-events: none;
      background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, #ffffff 100%);
    }
}

@media only screen and (max-width: 767px) {
  .mnt-carousel.is-slider-active::after {
      display: none;
    }
}

/* NO section padding here, and no responsive ladder of its own. Both
   `.user-reviews` sections carry `.page-section` in the markup -- 2 of 2,
   checked -- so they inherit its 8rem / 4rem / 3rem ladder.
   This USED to set 6.4rem, with 5.6rem at 991 and 4.8rem at 767. Adjacent
   sections abut, so the gap between two of them is padBottom + padTop, and
   this 64 was the last thing keeping four pairs off Figma's 160: the two
   either side of the reviews carousel on iPhone and android. Removing it
   takes the family from 45 of 55 adjacent pairs at 160 to 49 of 55, and
   every one of the six still off is in the hero region -- so the BODY
   rhythm is 49 of 49. C-09.
   `overflow: hidden` is deliberately kept. It is what clips the carousel
   track mid-slide, and it is the reason a padding change here needed
   checking for vertical cropping. Measured clean: carousel height unchanged
   at 1440/1200/768/390 on both pages, content insets tracking the padding
   exactly, and scrollHeight never exceeding clientHeight. */
.user-reviews {
  overflow: hidden;
}

.user-reviews__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-24);
  margin: 0 0 var(--space-32);
}

@media only screen and (max-width: 767px) {
  .user-reviews__header {
      align-items: flex-start;
      margin-bottom: var(--space-24);
    }
}

.user-reviews__title {
  margin: 0;
  color: #268fd0;
}

.user-reviews__subtitle {
  margin-top: 16px;
  max-width: 102.4rem;
}

.user-reviews__nav {
  display: flex;
  align-items: center;
  gap: var(--space-32);
  flex: 0 0 auto;
}

@media only screen and (max-width: 767px) {
  .user-reviews__nav {
      display: none;
    }
}

.user-reviews__arrow {
  width: 6.4rem;
  height: 4.8rem;
  border: none;
  background: transparent;
  color: #268fd0;
  font-size: 4rem;
  line-height: 1;
}

.user-reviews__arrow:hover,
.user-reviews__arrow:focus-visible {
  color: #1e7dc5;
  background: transparent;
  transform: none;
}

.user-reviews__arrow:hover svg path,
.user-reviews__arrow:focus-visible svg path {
  fill: #268fd0;
}

.user-reviews__arrow svg path {
  fill: #B8DFF8;
}

.user-reviews__carousel {
  overflow: visible;
}

@media only screen and (max-width: 991px) {
  .user-reviews__carousel::after {
      display: none;
    }
}

.user-reviews__carousel.is-slider-active {
  width: auto;
  margin-right: 0;
}

.user-reviews__track {
  padding-right: var(--section-120);
}

@media only screen and (max-width: 991px) {
  .user-reviews__track {
      padding-right: var(--section-80);
    }
}

@media only screen and (max-width: 767px) {
  .user-reviews__track {
      padding-right: var(--space-40);
    }
}

@media only screen and (max-width: 575px) {
  .user-reviews__track {
      padding-right: var(--space-24);
    }
}

.user-reviews__slide {
  flex: 0 0 46.4rem;
  max-width: 46.4rem;
  min-width: 0;
}

@media only screen and (max-width: 767px) {
  .user-reviews__slide {
      flex: 0 0 30rem;
      max-width: 30rem;
    }
}

.user-reviews__dots {
  display: flex;
  justify-content: center;
  margin-top: var(--space-20);
}

@media only screen and (max-width: 991px) {
  .user-reviews__dots {
      margin-top: var(--space-24);
    }
}

@media only screen and (min-width: 992px) {
  .user-reviews .mnt-carousel.is-slider-active .mnt-carousel__viewport {
      overflow: hidden;
    }
}

@media only screen and (min-width: 992px) {
  .user-reviews .mnt-carousel.is-slider-active .mnt-carousel__track {
      display: flex;
      gap: var(--space-24);
      will-change: transform;
      transition: transform 0.45s ease;
    }
}

.user-reviews .mnt-carousel__dot {
  width: 1.2rem;
  height: 1.2rem;
}

.user-reviews .mnt-carousel__controls {
  display: none;
}

/* -----------------------------------------------------------------------------
   ICON ROWS -- a full-width list of icon + title + text rows, separated by
   hairlines. Built for band 7b of Figma 3614:35585, "Where Does the Nutrition
   Data Come From?" (3614:41710, 1200 x 522; contents 3688:36179): three
   icon-and-text rows, two rules between them, NO image.

   PROVENANCE. The row internals are ported from homepage.css, md5
   3a40e61733fc2296a2d97d9342a48ff6, block `glp1-feature`, extracted with
   scripts/extract-css-blocks.py (leftmost-compound scope, 15 rules kept). Not
   hand-copied. static_index.st builds the same icon/title/text row as
   `.glp1-feature`, and p7 established by pixel comparison at 160px that two of
   band 7b's three icons ARE index icons (3688:36230 -> "GLP-1 meal plans and
   recipes", mean 0.36; 3688:36226 -> "Digestion symptom tracking", mean 0.37).

   P17 ancestor check, run before choosing the boundary and the reason this port
   is safe: `grep -c '\.glp1-companion[ .]' homepage.css` returns 3, and all three
   are `.glp1-companion` itself. There is NO `.glp1-companion .glp1-feature`
   descendant rule anywhere -- the extractor's kept-selector list confirms every
   one of the 15 rules starts at `.glp1-feature`. So the row rules carry no
   ancestor dependency and the markup needs no wrapper class. This is the check
   the user-reviews carousel skipped, whose desktop layout hung off `.user-reviews`
   and shipped three cards stacked in a one-third column.

   WHY THIS IS A NEW BLOCK AND NOT `.glp1-feature`. The index's CONTAINER,
   `.glp1-companion__features`, is `grid-template-columns: repeat(2, minmax(0,1fr))`
   -- a 2-up grid of icon cards sitting beside a photo (`__figure` / `__image`).
   Band 7b is three FULL-WIDTH rows with rules between and no photo. Porting that
   container verbatim would have shipped the wrong layout, which is the same class
   of failure it is meant to prevent. So: container rules NOT ported (`__features`,
   `__figure`, `__image` are all for the other shape), row internals ported.

   Also NOT ported: homepage's `.glp1-feature__icon img` steps (5.2rem at 991,
   5.6rem at 767). Band 7b's icons are inline SVG, not `img` (p7 delivered the one
   new icon as SVG, no PNG), so those rules would be dead here -- and their widths
   disagree with this block's 4.8rem slot, so importing them would import a bug.

   The heading dependency was verified rather than assumed: `__title` is an `<h3>`
   carrying no font-size of its own, so its size comes from the base layer. The
   `h3` rules are IDENTICAL in both sheets -- 2.8rem/1.15, stepping to 2.4rem at
   991 and 2.2rem at 575, plus print 2.4rem -- and both set `color: #268fd0`. The
   title travels with nothing left behind.
   ============================================================================= */
.icon-rows {
  margin: var(--space-32) 0 0;
  padding: 0;
  list-style: none;
}

/* Icon LEFT, text right. This is the one axis Figma did not pin down for me: p7
   recorded the band's icons and copy but no per-row geometry, and no cached dump
   carries 3688:36179's children. Icon-left is the reading a 1200px-wide row with a
   48px icon and a title-plus-paragraph supports, and it is what the house's own
   `.glp1-feature` does whenever its row is wide (its <=1280 step is exactly this
   grid). If p7 measures the rows as icon-ABOVE-text instead, delete the
   `grid-template-columns` line and this becomes a block -- a one-line change. */
.icon-rows__item {
  display: grid;
  grid-template-columns: 4.8rem minmax(0, 1fr);
  gap: var(--space-24);
  align-items: start;
  padding: var(--space-24) 0;
}

/* Two rules for three rows -- BETWEEN only, never above the first or below the
   last, which is what Figma's two zero-height vectors draw. `+` says exactly that
   and needs no :last-child counterpart. #e3eaf0 is this sheet's LIST-row hairline
   (already on .nutrient-list__row, .phone-card__row, .press-strip, .speed-chart --
   7 uses); #d8e0ea is its TABLE-border hairline (.glance-table, .comparison-table).
   These are list rows, so #e3eaf0. No new token, so assert-design-tokens stays
   clean. */
.icon-rows__item + .icon-rows__item {
  border-top: 0.1rem solid #e3eaf0;
}

.icon-rows__item:first-child {
  padding-top: 0;
}

.icon-rows__item:last-child {
  padding-bottom: 0;
}

/* 4.8rem, not homepage's 4rem: Figma renders this band's icons at 48 and Figma
   wins on dimensions. The slot is CSS-sized and the svg below is 100%/100%, so
   the icon's own viewBox never reaches the screen -- see the note on the 48 vs 40
   contract deviation in the report. */
/* display:block is LOAD-BEARING, not tidiness. This is a <span>, and above 575px it
   only obeys width/height because `.icon-rows__item { display: grid }` blockifies its
   children. The <=575px block below flips the item to `display: block`, the span goes
   back to `display: inline`, an inline box ignores width and height, and the svg's
   100%/100% then resolves against the container: measured 360x360 at 390px and 345x345
   at 375px instead of 48x48. Blockifying the span itself makes the size hold at every
   width without depending on the parent's display. */
.icon-rows__icon {
  display: block;
  margin: 0;
  width: 4.8rem;
  height: 4.8rem;
}

.icon-rows__icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

.icon-rows__title {
  margin: 0 0 var(--space-8);
  color: #268fd0;
}

.icon-rows__text {
  margin: 0;
  font-size: 2rem;
  line-height: 1.4;
  color: #2c3e50;
}

/* `margin: 0` above is on the WRAPPER; the paragraph inside it still takes
   `p { margin: 0 0 2rem }` from :1190. That 20px landed inside the row and pushed the
   hairline off centre: measured 44px of space above each divider (20px paragraph margin
   + 24px item padding-bottom) against 25px below it (1px border + 24px padding-top).
   Zeroing the last child's bottom margin makes it 24/25, which is the symmetry Figma's
   two zero-height vectors draw. Scoped to the last child so a two-paragraph row keeps
   its internal spacing. */
.icon-rows__text > :last-child {
  margin-bottom: 0;
}

@media only screen and (max-width: 991px) {
  .icon-rows__item {
      gap: var(--space-20);
      padding: var(--space-20) 0;
    }

  .icon-rows__title {
      margin-bottom: 0.6rem;
    }

  .icon-rows__text {
      font-size: 1.6rem;
      line-height: 1.4;
    }
}

@media only screen and (max-width: 767px) {
  .icon-rows__title {
      margin-bottom: var(--space-8);
      line-height: 1.2;
    }

  .icon-rows__text {
      font-size: 1.4rem;
    }
}

/* Stacked, matching what `.glp1-feature` does at this width. The icon goes back
   above the text and gets its bottom margin back, because a 48px icon plus two
   columns of text is too tight to read on a phone. */
@media only screen and (max-width: 575px) {
  .icon-rows__item {
      display: block;
    }

  .icon-rows__icon {
      margin: 0 0 var(--space-16);
    }
}

/* =============================================================================
   SRV-4574 -- /verified-food-database.html
   Appended 2026-09-02. APPEND-ONLY: nothing above this line is edited, so the
   iPhone, Android and free-calorie-tracker pages are byte-identical in output
   before and after this block.

   Four new blocks and three new modifiers, and each one was checked against the
   existing sheet before it was written (references/check-first.md). What already
   existed and is reused verbatim, so it is NOT here: .glance-table, .press-strip,
   .split-2026 (+ --art-right, __art--filled), .ai-features(+__wrapper--4up),
   .ai-card(+--text-only, __title, __body), .comparison-table(+--compact),
   .comparison-cta, .section-insights__wrapper, .faq-item, .art-stub--panel,
   .nutrient-list--label, .hero__results, .hero__footnote, .cta-banner.

   .hero__results and .hero__footnote deserve a note: pages-2026.css records them
   as DEAD CSS, orphaned when rev. 27 moved the iPhone page's study out of its
   hero. This page's mockup asks for exactly that pair, so they are revived rather
   than pruned. If anyone prunes them later, this page loses its hero footnote.

   Every colour here already appears in this sheet -- house-patterns P6. Counted:
   #2c3e50 (51 uses, the body text colour), #268fd0 (32), #6b7a88 (19),
   #e3eaf0 (14), #f7fafc (5). No new value is introduced.
   ============================================================================= */

/* ---- .chip-row -- a wrapping row of short stat pills ---------------------- */

/* The v3-2 mockup uses this shape three times: the hero proofline, the pipeline
   section's two throughput figures, and the five scale figures under "Who Relies
   on This Database". Checked first: this sheet had NO chip block. `.phone-card__chip`
   exists but is scoped to `.phone-card` and is a two-tone tint inside a device
   render, not a standalone stat pill, so reusing it would need the ancestor it does
   not have -- house-patterns P17, the trap that ships a component with no layout.

   A LIST, not a row of bare spans, because these are unordered peer items and the
   mockup's `<div class="chips"><span>...</span></div>` is presentational markup for
   what is semantically a list. Same reasoning as P11: the element matches what the
   content is. */
.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-12);
  margin: var(--space-24) 0 0;
  padding: 0;
  list-style: none;
}

.chip-row__item {
  padding: var(--space-8) var(--space-16);
  border: 0;
  border-radius: 10rem;
  /* Figma fills these chips blue, 2026-09-07 -- reuses #e6edf3, the same fill
     .ai-card__step/.callout/.phone-card__chip--verified already carry. TEXT STAYS
     #2c3e50, not the family's #268fd0 blue: at 1.4rem/600 (14px) this is far below
     the 18.66px bold "large text" line, so blue text here would need 4.5:1 and
     #268fd0 only clears 3.55:1 -- the same contrast trap .ai-card__step hit at 18px,
     worse at 14px. Border dropped rather than tinted; the fill alone reads against
     the white page background. */
  background-color: #e6edf3;
  color: #2c3e50;
  font-size: 1.4rem;
  font-weight: 600;
  line-height: 1.3;
}

/* `.chip-row--hero` STOOD HERE AND IS DELETED, 2026-09-02, with its reasoning kept so
   nobody re-derives it. It reversed the chips to white-on-rgba(255,255,255,0.12) for the
   hero's green band. Two things killed it:

     1. The chips left the hero entirely. They pushed the hero's text column to 760px,
        which made the text column -- not the art -- drive the section height, which put
        two hero paragraphs onto the white bottom sixth of the section in #fcf8b3, about
        1.09:1. See the long comment in static_verified-food-database.st, and P1.
     2. Its contrast was never verified. A translucent fill over a gradient-plus-texture
        background is exactly what design-sweep D8 reports as "contrast UNRESOLVED" -- 42%
        of this page's text blocks at 1440px. Keeping a colour pairing no instrument here
        can measure is the opposite of P6.

   `.chip-row--centered` below replaces it and is trivial by comparison, which is the
   tell that the original was solving a problem that should not have existed. */
.chip-row--centered {
  justify-content: center;
}

@media only screen and (max-width: 1280px) {
  .chip-row {
      justify-content: center;
    }
}

/* ---- .stat-panel -- one headline number with its caption ------------------ */

/* Used twice: the hero's "0.2%" evidence card, and the same figure again inside
   the validation-studies section. Checked first: no existing block does this. The
   sheet has no `.stat-*`, `.kpi`, `.metric` or `.figure-stat` -- the same gap
   `.nutrient-list`'s own header records for label/value rows.

   `.speed-chart` was considered and rejected: it is a bar-chart-as-table, one
   value per row across several rows, and this is a single number with prose under
   it. P13's rule applied to a different shape -- pick by what the content is. */
.stat-panel {
  padding: var(--space-32);
  border-radius: 2.4rem;
  background-color: #ffffff;
  box-shadow: 0 1.2rem 3.2rem rgba(44, 62, 80, 0.12);
}

.stat-panel__value {
  margin: 0 0 var(--space-12);
  color: #268fd0;
  font-size: 5.6rem;
  font-weight: 700;
  line-height: 1;
}

/* CONTRAST FIX 2026-09-02, measured not guessed. #6b7a88 on #ffffff computes 4.41:1 at
   15px/400, and WCAG AA wants 4.5:1 -- design-sweep D8 measured it off the rendered page.
   #6c757d is already in this sheet (4 uses) and computes 4.67:1 on white. The near-miss is
   the point: 4.41 and 4.67 are visually indistinguishable and only one of them passes. */
.stat-panel__caption {
  margin: 0;
  /* Was #6c757d (grey) -- Mikita, 2026-09-07: this box and .callout should share the
     same approach. #2c3e50 matches .callout's body text and is this sheet's standard
     dark body color (51+ uses), not literal black -- computes ~11:1 on #e6edf3, well
     past AA either way. */
  color: #2c3e50;
  font-size: 1.5rem;
  line-height: 1.5;
}

.stat-panel__caption + .stat-panel__caption {
  margin-top: 1.4rem;
}

/* RESTORED TO FIGMA'S ROUNDED BLUE FILL 2026-09-07, overriding the flattened
   left-rule treatment below (built against the mockup, not checked against Figma).
   Base `.stat-panel` is never used unflattened anywhere in this family -- this is
   the only stat-panel on any of the four pages -- so there is no second, "real"
   card look this change could clash with. Reuses #e6edf3, the same light-blue fill
   already established for .ai-card__step/.callout/.phone-card__chip--verified. */
.stat-panel--inline {
  padding: var(--space-24);
  border-left: 0;
  border-radius: 2.4rem;
  background-color: #e6edf3;
  box-shadow: none;
}

.stat-panel--inline .stat-panel__value {
  font-size: 4rem;
}

@media only screen and (max-width: 991px) {
  .stat-panel {
      padding: var(--space-24);
    }

  .stat-panel__value {
      font-size: 4.4rem;
    }
}

/* REMOVED 2026-09-02: `.hero__media .stat-panel` and `.hero__media .stat-panel +
   .art-stub`. A stat panel inside the hero ART column was K-1 option A, which was not
   the option chosen, and no shipped page ever matched either selector. Recorded rather
   than silently dropped. */


/* RETIRED 2026-09-02 along with the stub itself. This is worth keeping as a note
   because the constraint it encoded was real and is now answered a different way.
   It forced the hero stub to 125rem so the MEDIA column stayed taller than the text
   column, which is what keeps pale-yellow hero text off the white sixth below the
   84% green band. Figma removes the media column entirely and runs the green the
   full height instead, so the height race no longer exists to be won. The full-band
   modifier further down is the replacement. */


/* A band that carries one row of chips and nothing else. .page-section's 8rem/4rem
   padding is built for a section with a heading and a grid in it; on a single chip row it
   reads as a gap rather than a band. */
.page-section--tight {
  padding: var(--space-32) 0;
}

/* ---- .callout -- a defined term, set apart from the prose ----------------- */

/* The mockup's nutrient-completeness definition. Checked first: no `.callout`,
   `.note`, `.definition` or `.highlight-box` in this sheet. It is a `<p>` carrying
   this class rather than a wrapper div, because the content is one paragraph. */
.callout {
  margin: var(--space-24) 0;
  padding: var(--space-20) var(--space-24);
  /* Figma shows this callout blue, not green -- 2026-09-07. No comment ever justified
     #0bb850/#eef7f1 against Figma or the mockup; it was this sheet's generic green accent,
     picked because a callout needed some accent. Reuses #268fd0/#e6edf3, the same pair
     .ai-card__step and .phone-card__chip--verified already carry, rather than adding a
     third blue swatch. Border-left dropped, matching .stat-panel--inline's treatment --
     Mikita: the two should share the same approach, a flat blue fill, no accent bar. */
  border: 0;
  border-radius: 1.2rem;
  background-color: #e6edf3;
  color: #2c3e50;
  /* 2rem, matching body prose, NOT smaller. It was 1.7rem, and design-sweep D1 flagged it:
     the page's own body prose computes 20px, so an EMPHASISED definition was rendering
     3px smaller than the paragraphs it is meant to stand out from -- a callout wearing
     footnote type. This is the defect class D1 exists for, pointed at emphasis rather
     than at prose. */
  font-size: 2rem;
  line-height: 1.6;
}

.callout__term {
  color: #2c3e50;
  font-weight: 700;
}

/* ---- .ai-features__wrapper--2up ------------------------------------------- */

/* Sibling of the existing --4up modifier, in the same block and behind the same
   min-width: 992px guard, for the same reason its comment gives: below 991px the
   base rule switches the wrapper to display:block and this goes inert, which is
   the mobile-first behaviour we want.

   Needed because the base wrapper is `repeat(3, 1fr)` and this page's data-sources
   section has TWO cards -- they would sit in two of three columns with a hole
   beside them. */
@media only screen and (min-width: 992px) {
  .ai-features__wrapper--2up {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* ---- .ai-features__wrapper--ol -- the wrapper when it is an ordered list --- */

/* MEASURED DEFECT, 2026-09-02. The pipeline steps are an `ol` (four numbered stages in a
   fixed order really are an ordered list), and this sheet resets `ol, ul, dl` MARGIN only
   -- pages-2026.css:216 -- never padding. So the browser default
   `padding-inline-start: 40px` survived, and the rendered numbers were:

       ol.ai-features__wrapper--4up   computed padding-left 40px, items at 55, 406, 756, 1107
       div.ai-features__wrapper--2up  computed padding-left  0px, items at 15, 736

   The pipeline row sat 40px right of every other row on the page. The geometry gate PASSED
   it -- correctly, because it asks "is this a row", and a row inset by 40px is still a row.
   The numbers were in that gate's own output from the first run and went unread, which is
   P17 rule 3's actual lesson: read the numbers, not the verdict.

   Its own modifier rather than a `padding-left: 0` on `--4up`, because `--4up` is shared
   with static_iPhone.st, where it sits on divs that never had the padding. Touching a
   shared modifier to fix a caller's element choice is how a shared sheet rots. */
.ai-features__wrapper--ol {
  padding-left: 0;
  margin-bottom: 0;
  list-style: none;
}

/* ---- .ai-card__tier and the numbered step card ---------------------------- */

/* Two small additions INSIDE the existing .ai-card, not new card blocks. The tier
   label is the mockup's "Public" / "Commercial license" marker above the source
   name; the step number is the mockup's 1-4 pipeline marker.

   `.ai-card--step` exists only to reset the ordered list the steps live in: the
   markup is an `<ol>` of `<li class="ai-card">`, because four numbered stages in a
   fixed order are an ordered list, and the visible digits come from
   `.ai-card__step` so the list marker must go. */
/* CONTRAST FIX 2026-09-02. #268fd0 on white computes 3.55:1. At 12px/700 that is not
   WCAG "large text" (which starts at 18.66px bold), so the 4.5:1 threshold applies and it
   fails. #2c3e50 -- this sheet's body text colour, 51 uses -- computes about 11:1. The
   eyebrow reading comes from the uppercase and the letter-spacing, not from the blue.
   NOTE the sheet does put #268fd0 on small text elsewhere (.phone-card__chip--verified),
   so this is a family-wide near-miss, not a defect unique to this page. Not fixed there:
   that is somebody else's block. */
.ai-card__tier {
  margin: 0 0 var(--space-12);
  color: #2c3e50;
  font-size: 1.2rem;
  font-weight: 700;
  letter-spacing: 0.08rem;
  text-transform: uppercase;
}

.ai-card--step {
  list-style: none;
}

.ai-card__step {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 4rem;
  height: 4rem;
  margin: 0 0 var(--space-16);
  border-radius: 50%;
  /* RESTORED TO FIGMA'S BLUE 2026-09-07. The #2c3e50/white swap above was correct for
     18px/700 (just under WCAG's 18.66px bold "large text" line, so 4.5:1 applied and
     #268fd0/white's 3.55:1 failed). Bumping the digit to 2rem/700 (20px) crosses that
     line, dropping the requirement to 3:1 -- #268fd0 on #e6edf3 (the same pair already
     used at .phone-card__chip--verified) computes comfortably above it. Reuses an
     existing sheet color, not a new one. */
  background-color: #e6edf3;
  color: #268fd0;
  font-size: 2rem;
  font-weight: 700;
  line-height: 1;
}

/* Below 991px the base `.ai-card` rule becomes a 40%/1fr two-column grid, which
   would put the number in a 40%-wide column of its own. The step cards are not
   media-beside-text cards, so they opt out and stay stacked. */
@media only screen and (max-width: 991px) {
  .ai-card--step {
      display: block;
    }
}

/* =============================================================================
   SRV-4574 -- hero reconciled with Figma node 3849:1678, 2026-09-02.
   Mikita ruled Figma the layout authority for this page. Two rules follow from
   that, and both are PAGE-SCOPED on purpose: fifteen other templates use
   `.section-start` and none of them should move.
   ============================================================================= */

/* REMOVED 2026-09-07. Kept as a tombstone because the reasoning was sound and the
   PREMISE EXPIRED -- a future reader will otherwise re-derive it from the same
   stale note.

   It forced `.section-start::before` to `height: 100%` on this page only. The
   stated reason, 2026-09-02: the Figma hero was text-only, so "this page can drop
   its hero art", and with no media column the TEXT column set the section height,
   which left pale-yellow hero text able to land on the white strip the 84% band
   leaves below itself.

   The hero now CARRIES A DEVICE -- Figma 3973:53894 with 3973:54393 "iPhone_top",
   580x720 -- so the media column is the taller one again and the 84% contract holds
   as originally designed. The rule's own escape clause ("the 84% is a contract with
   a hero whose MEDIA column is the taller one") is exactly what came back true.

   Its cost was visible: at 100% there is no white inside the section for the device
   to break into, so the phones sat entirely within the green while the homepage's
   overlap 160px past it. Reported from a screenshot by Mikita.

   Measured after removal, with the device present, at eight widths -- art overflow
   past the green, and the clearance of the LOWEST hero text element above the band:

     1920  84%  art +144   text +90     1280  82%  art +243  text +501
     1700  84%  art +144   text +90      992  82%  art +243  text +501
     1470  84%  art +144   text +90      768  82%  art +232  text +512
     1469 100%  art   +0   text +290      390  75%  art +265  text +187

   No hero text falls on white at any width, which is the single risk the rule
   existed to prevent. 1469 shows +0 because the pre-existing `max-width: 1469px`
   block already sets 100% there -- unchanged, and the same on the homepage. */

/* The right-hand column of the frame's two-column text hero (Texts 3849:2172, two
   613px columns). It takes the box `.hero__media` used to hold, because the hero is
   still the same flex row and the column still has to be the same width -- what
   changed is that it carries text, not art. Widths mirror `.section-start
   .hero__media` exactly so the two hero shapes line up across the family. */
.section-start .hero__aside {
  max-width: 72rem;
  min-width: 58rem;
}

@media only screen and (max-width: 1469px) {
  .section-start .hero__aside {
      min-width: 50rem;
    }
}

@media only screen and (max-width: 991px) {
  .section-start .hero__aside {
      min-width: auto;
    }
}

/* `.hero__results` and `.hero__footnote` took their colour from
   `.section-start .hero__content p`, and they no longer live in `.hero__content`.
   Same token, same value -- this restores what the move would otherwise have taken
   away. `.hero__subtitle` already carries its own colour and does not need it. */
.section-start .hero__aside p {
  color: #fcf8b3;
}

/* ---- a comparison table standing in normal flow, not in a grid cell ------- */

/* SRV-4574 round 2. The Validation studies table moved out of a `.split-2026__art`
   grid cell and into the section's normal flow, because Figma node 3920:51018 is
   full width. A grid cell supplied vertical rhythm through the grid `gap`; normal
   flow supplies none, and the table has no margin of its own. Measured immediately
   after the move, identical at 1440, 768 and 390:

       stat panel bottom -> caption top   0px    (Figma: 40)
       caption bottom    -> thead top     0px    (Figma: 40)

   Both numbers come from the frame: its Section block ends at y=188, the caption
   sits at y=228, and the table container starts at y=294 against a caption bottom
   of 254. So 4rem twice, which is 40px at this page's root size.

   Scoped to a NEW wrap modifier rather than to `.comparison-table--compact`,
   because both tables on this page carry `--compact` and the other one sits inside
   `.section-insights__wrapper`, which already spaces it. Scoping on the shared
   modifier would have moved a table nobody asked to move. */
.comparison-table-wrap--inflow {
  margin-top: var(--space-40);
}

/* Beats `.comparison-table--compact .comparison-table__caption` (0,2,0 against
   0,2,0) on source order, being appended after it. That rule sets 0.6rem, which is
   right for a caption inside a bordered card and far too tight in open flow. */
.comparison-table-wrap--inflow .comparison-table__caption {
  padding-bottom: var(--space-40);
}

/* -----------------------------------------------------------------------------
   F-A -- A FILLED ART COLUMN MUST NOT KEEP THE PLACEHOLDER'S `align-self: stretch`
   Found 2026-09-02 by design-critic on static_verified-food-database, round 6.
   ============================================================================= */

/* THE CONTRADICTION, and it is three rules deep. NOTE the first premise changed
   on 2026-09-03: `--art-right` no longer sets `align-items` at all, so the row is
   now `start` from the base grid and only `--art-tall` centres. F-A's own rule
   below is unaffected and its geometry check still passes -- a filled art column
   must not keep the stub's `align-self: stretch` whether the row is centred or
   top-aligned. Only this stated premise was stale.
     `.split-2026__grid--art-right`  set `align-items: center`    (REMOVED 2026-09-03)
     `.split-2026__art`              sets `align-self: stretch`   (:4165)  <- wins
     `.split-2026__art--filled`      resets min-height and background, NOT
                                     align-self                   (:4915)
   So the art column stretches to the row height, `img { height: auto }` parks the
   photo at the TOP of that stretched box, and `background: none` -- correct in
   itself -- makes the leftover slack invisible. The row asked for a centred image
   and got a top-aligned one with empty space under it.

   WHY NO GATE CAUGHT IT AND FOUR ROUNDS PASSED: the STUB HID IT. A stretched grey
   `#ededed` box fills the row edge to edge and reads as deliberate. Only real art
   -- installed in round 4 -- turned the slack into a visible symptom. The bug was
   there the whole time; nothing could see it.

   `align-self: stretch` on `.split-2026__art` is right for a STUB and wrong for
   real art, which is the same distinction `--filled` already draws for min-height
   and background. This rule finishes the reset it started.

   PRECEDENT, not invention: `.split-2026__art--device` (:4173) already pairs
   `align-self: center` with a min-height reset for exactly this reason. `--filled`
   is the same kind of variant and was simply missing the line.

   BOTH CLASSES ON PURPOSE (0,2,0). A bare `.split-2026__art--filled` is 0,1,0 --
   a tie with `.split-2026__art` at :4165, won only by being appended later. That
   is true today and silently false the moment anyone appends below this block.
   The doubled selector wins on specificity and does not depend on source order.
   Same idiom, same reason, as the `.ai-card.ai-card--text-only` rule at :3449.

   APPENDED, NOT EDITED IN PLACE. :4165 must keep `stretch` -- unfilled stubs still
   need the grey ground to fill the row, which is the whole reason round 3 refused
   to put `--filled` on a stub. Editing :4165 would fix the art and break every
   placeholder. :4915 is left alone for the same append-only reason.

   THIS IS A SHARED-SHEET FIX AND IT MOVES FOUR PAGES, NOT ONE. Measured before:
     static_android                 -376px at 992, -352 at 1024, -158 at 1280
     static_iPhone                  -370px at 992, -345 at 1024, -144 at 1280
     static_free-calorie-tracker    -205px at 992, -192 at 1024
     static_verified-food-database  -168px at 992, -126 at 1024
   The two shipped platform pages are the WORST affected. This is not a
   verified-food-database defect that leaked; it is a sheet defect that
   verified-food-database happened to expose. Scoping the fix to one page would
   have left the two worst cases shipping. Flagged for Mikita -- the other three
   pages are other panes' work.

   The band is 992..1280 (and the widths between). Outside it the art column is the
   TALLER of the two, so there is no slack to mis-place and the rule changes
   nothing. At <=991 the grid is one column and align-items does not apply. */
.split-2026__art.split-2026__art--filled {
  align-self: center;
}

/* -----------------------------------------------------------------------------
   S5 SOURCE LOGOS -- a LOGO in an .ai-card__media, not a photograph
   Added 2026-09-02, round 7, with the USDA and NCC marks. Mikita: "wire them now".
   ============================================================================= */

/* THE PROBLEM THE HOUSE BLOCK CREATES HERE. `.ai-card__media img` is
   `width: 100%` (:2300), which is exactly right for the full-bleed photographs
   index and glp-1-app put in this slot. An S5 card measures 689px at 1440. The
   marks are 128x88 and 88x88. Left alone, the house rule would blow the USDA seal
   up 5.4x and the NCC mark 7.8x -- both far past the ~1.2 ratio that means the
   SLOT is wrong for the art. A logo enlarged five times is a worse page than no
   logo, so the sizing rule is the job, not a footnote to it.

   `width: auto` restores the intrinsic size the <img> already declares, so each
   mark renders at its natural width and the ratio is 1.00 by construction rather
   than by a hand-tuned max-width that would need re-tuning per logo. `max-width:
   100%` keeps that honest at narrow widths, where the card is narrower than the
   mark.

   SCOPED TO `--2up`, DELIBERATELY, AND NOT TO `.ai-card__media`. That class is
   shared: static_index.st:620 and static_glp-1-app.st:117 both put full-bleed
   photographs in it, and those must not move. `--2up` is this ticket's own
   modifier and S5 is its only user, so the blast radius is this one block.
   Verified after the change by re-measuring index's cards -- see decisions.md R7-4.

   TWO HOUSE DECLARATIONS ARE CANCELLED HERE, both on purpose:

   `border-radius: 0` -- `.ai-card__media` rounds 2.4rem with `overflow: hidden`
   (:2289-2291). On a 4:3 photograph that is the house look. On a 128x88 logo a
   24px radius bites the corners off the mark, and the USDA seal's green field
   runs to both bottom corners. Rounding a trademark is not a style choice.

   `margin-bottom: 2.4rem` -- the house value is 4rem, and 0 below 991px. Figma
   puts the icon at y=40..128 and the section title at y=152, so the gap the frame
   draws is 24px, not 40. The mobile 0 is also wrong here: these cards keep
   `--text-only` (see decisions.md R7-2), so the logo stays stacked ABOVE the text
   at every width and always needs the gap. This rule sits outside a media query
   and is 0,2,0, so it beats the 0,1,0 mobile reset structurally.

   Specificity 0,2,0 and 0,2,1 against the house 0,1,0 and 0,1,1: these win by
   being more specific, not by being appended later. Same reasoning as
   `.ai-card.ai-card--text-only` (:3449) and the F-A rule above. */
.ai-features__wrapper--2up .ai-card__media {
  margin-bottom: var(--space-24);
  border-radius: 0;
}

.ai-features__wrapper--2up .ai-card__media img {
  width: auto;
  max-width: 100%;
}

/* ---- Round 2.1 -------------------------------------------------------------
   Two rules, both requested by a page pane that correctly refused to add them
   itself. `pages-2026.css` has one owner per round.
   ========================================================================== */

/* fct's FAQ section closes with a paragraph that is NOT an answer: v4-6 places
   it unindented between the last Q/A pair and the three new ones, and it talks
   about licensing rather than answering "which app tracks the most nutrients".
   It therefore stays out of the FAQPage graph and needs a section-level style,
   which `.faq-section__list` (a grid of `.faq-item`) does not provide. */
.faq-section__note {
  margin-top: 2.4rem;
  font-size: 1.6rem;
  line-height: 1.6;
  color: #2c3e50;
}

/* "sticky table headers" -- rev25 changes .9 / rev22 changes .10 -- IS NOT
   BUILDABLE HERE, and the rule that was here has been REVERTED. Recording why,
   because the CSS looked correct, rendered with zero errors, and did nothing.

   wM:p6 measured it under real scroll (headless Chrome, same-origin iframe) and
   found the thead scrolling straight off screen at all six widths despite `top`
   resolving correctly (140/120/100px). Cause: `.comparison-table-wrap` has
   `overflow-x: auto` (:6658). Per the overflow spec, one axis non-visible forces
   the companion axis to compute non-visible too, so `overflow-y` computes `auto`
   with no rule setting it. The wrap is therefore a scroll container, and a
   sticky descendant positions against IT, not the viewport -- and that
   scrollport never moves, so the thead can never detach.

   Its proposed `overflow-y: clip` does NOT work, tested here in isolation at
   1440 rather than assumed:
     overflow-x:auto                    -> overflow-y computes auto   sticks=false
     overflow-x:auto; overflow-y:clip   -> overflow-y computes HIDDEN  sticks=false
     no overflow (control)              -> visible/visible            sticks=true
     overflow-x:clip                    -> overflow-y stays visible   sticks=true
   Chrome downgrades `clip` to `hidden` when the other axis is a scrolling value,
   and `hidden` is still a scroll container. So the fix is impossible in
   principle, not merely unimplemented.

   The only thing that works is dropping horizontal scroll (`overflow-x: clip`).
   Measured on the real page, the wrap does NOT overflow at 1440/1280/992
   (clientW == scrollW: 1408, 1248, 960) -- so that would be safe TODAY at wide
   widths. But at 992 clientW is 960px against `.comparison-table`'s own 96rem
   (=960px) min-width: it fits EXACTLY, with zero headroom, so any future cell or
   padding change would start silently clipping instead of scrolling.

   Trading a table's horizontal scroll for a sticky header is a layout decision
   on a shared wrap used by four pages, which is outside a copy round (RULES.md
   s4). Escalated. Dead CSS that reads as a shipped feature is worse than none,
   so nothing is left behind here. */

/* NOT a second `.press-strip .press-strip__list` body by accident -- the
   pre-existing one at :4812 sets `flex-wrap: nowrap` for the four-item Figma
   row, and that is exactly what has to change now the strip holds four, five or
   six. assert-no-duplicate-selectors flags the pair (wM:p3 found it); this
   comment is the "say so" that gate asks for, and the sheet is append-only by
   its own convention so the earlier body stays. */
.press-strip .press-strip__list {
  flex-wrap: wrap;
  justify-content: center;
}

/* SCOPED to >=992 deliberately. Unscoped, this (0,1,1) selector also beat the
   `flex: 1 0 40%` in the max-width:991px block above -- (0,1,0) -- and silently
   reshaped the MOBILE strip on all four pages: vfd measured a 4-item strip going
   4 rows -> 2 at 575, and items 361px -> 235px at 768. Neither overflowed, but
   neither was asked for, and three of those pages are not the one that needed
   the fix. The 992 pinch is the only defect here, so the fix stops at 992. */
@media only screen and (min-width: 992px) {
  .press-strip__list li.press-strip__item {
      flex: 1 1 22rem;
    }
}

/* ---- The swoosh lands ON the plans heading above 1280px --------------------
   Reported from a screenshot of /iPhone.html: "white part too close to text
   Choose the Plan That Fits You". Measured, not eyeballed -- clearance from
   `.section-insights::before`'s bottom to `.comparison-section__title`'s top:

                    1440  1281  1280   992   768   390
     iPhone            0     0    20    20    20    14
     android           0     0    20    20    20    14
     vfd               0     0    20    20    20    14
     index           100   100   100   100    80    70

   So it is not a padding value that is wrong, it is a BREAKPOINT MISMATCH.
   The swoosh's dip moves with width -- `::before` top goes -48rem above 1280
   and -50rem at/below it, against a fixed 60rem height, so it dips 12rem above
   1280 and 10rem below. The heading's clearance does NOT move: it is
   `margin-top: 6rem` for everything above 991px. The lower tiers therefore
   clear by 20px and the top tier, where the dip is 2rem deeper, clears by
   exactly 0 -- the heading's cap-line sits on the curve.

   +2rem at the top tier only, which is the swoosh's own extra dip, restoring
   the same 20px the tiers below already have. Not a new number: it is parity
   with a clearance Mikita already tuned and accepted at 1280 and under.

   SCOPED WITH `:has(.section-intro)` DELIBERATELY, and this is the whole
   reason the rule is shaped this way. `.section-insights` +
   `.comparison-section__title` is not unique to this family -- static_index.st
   carries the identical class trio `comparison-section section-insights
   page-section` on its own swoosh sections, so a plain
   `.section-insights .comparison-section__title` override would move the
   homepage too. The homepage is out of scope for this ticket, and measured it
   has no defect: 100px of clearance, five times what the family pages have.
   The three family sections each contain a `.section-intro` between the
   heading and the table; neither of index's two sections does. That structural
   difference is what the scope keys on. `:has()` is already used 17 times in
   this sheet, so this is the sheet's own idiom, not a new dependency.

   NOTE the stale comment at the `.section-insights .comparison-section__title`
   rule above: it says free-calorie-tracker uses this class as the C-09 control
   "that must not move", and that iPhone/android/vfd are "the only three
   sections that nest this wrapper". Both are now false --
   static_free-calorie-tracker.st carries ZERO `.section-insights`, and NINE
   diet pages plus index nest the wrapper. The diet pages are unaffected only
   because none of them carries `.comparison-section__title`. Verified by grep
   across all 288 templates, 2026-09-07. */
@media only screen and (min-width: 1281px) {
  .section-insights:has(.section-intro) .comparison-section__title {
      margin-top: 8rem;
    }
}

/* ---- Hero note vs the green band's curved bottom edge --------------------
   Reported from a screenshot of /free-calorie-tracker.html: the note
   "Everything or just calorie counting: you choose during setup." reads as
   sitting on the band's edge.

   MEASURED IN A REAL BROWSER over CDP, not offline. That distinction is the
   whole reason this rule is what it is -- see the two corrections at the end.

   The band is `.section-start::before`, `height: 84%` above 1469px and
   `height: 100%` at/below it. Clearance under the START of the note's line
   (which is what matters: the band's bottom corners are `border-radius:
   100rem 5rem`, a 1000px-wide 50px-tall arc, so the edge RISES toward the
   corners and is highest exactly where the line begins):

     width   band    clear at the line's left end
      1281   100%        +76      ok
      1366   100%       +174      ok
      1440   100%       +176      ok
      1469   100%       +176      ok
      1470    84%        -24      BROKEN
      1500    84%        -23      BROKEN
      1600    84%        -18      BROKEN
      1723    84%        -13      BROKEN   <- the reported window
      1920    84%         -7      BROKEN

   So the defect is not "too tight", it is NEGATIVE -- the text sits inside the
   curve -- and it exists only from 1470px up, where the band stops covering the
   whole section. Hence `min-width: 1470px`, matching the `max-width: 1469px`
   boundary that sets `height: 100%`.

   THE LEVER IS THE SECTION, NOT THE NOTE. `.hero__media`'s art renders 763px
   tall while the text column's last line is 30px, so the ART drives the
   section height and any margin added to the note is simply absorbed. Growing
   the section works because the band is a PERCENTAGE of it: +80px of section
   moves the band's bottom edge down ~67px while the note stays put. 8rem takes
   the worst case (1470px) from -24 to +43 and 1920px to +60.

   TWO EARLIER ATTEMPTS WERE WRONG, recorded so the next reader does not repeat
   them:
   1. `margin-bottom` on `.hero__note` -- measured +30px per 3rem offline, and
      did NOTHING in the browser. Offline the CDN art could not load (no network
      in headless), so the text column appeared to drive the height. It does not.
   2. `min-width: 1281px` -- the defect starts at 1470, so that scope added 80px
      of hero height across 1281-1469 where clearance was already +76 to +176.

   Scoped to the `--note-clear` modifier, which only free-calorie-tracker
   carries. `.section-start` is used by SIXTEEN templates including the diet
   pages and the homepage, so an unscoped `padding-bottom` would resize all of
   them. iPhone and android have the identical hero shape and almost certainly
   the identical negative clearance above 1470 -- they can take the same class,
   but only this page was reported and measured. */
@media only screen and (min-width: 1470px) {
  .section-start--note-clear {
      padding-bottom: 8rem;
    }
}

/* ---- vfd hero: the headline is TWO type tiers, not one -------------------
   Figma node 3973:54386 "Texts" is a flex column, `gap: 24px`, holding two
   separate text nodes where we shipped one welded `h1`:

     3973:54387  "The Staff-Verified Food Database"        72px / 600 / #fff / 1.1
     3973:55762  "Every Food Checked Before You Log It"     56px / 600 / #fff / 1.1

   The 56px tier is the design system's own NAMED style, `Desktop/H2` -- a
   deliberate library choice, not a one-off, and the strongest evidence that
   Figma is the intent here rather than the mockup's single 44px `h1`. That
   size already exists in this sheet as `.h2` (:1057, `5.6rem` / `1.1`), so
   this reuses the value instead of introducing a second 56px.

   Not given `.h2` directly: `.section-start .hero__title` is (0,2,0) and would
   win over `.h2`'s (0,1,0), leaving the second tier at 72px -- the same
   specificity trap this sheet has recorded four times. Scoped under
   `.section-start` for the same reason, and so it cannot reach another page.

   `display: block` supplies Figma's line break; `margin-top` supplies its
   `gap: 24px`. `font: inherit` is NOT used -- the tier differs from its parent
   only in size, so only size is restated.

   Colon removed from the markup: Figma has two sentences in two nodes and no
   colon. Mockup governs words, Figma governs design, and the colon existed
   only because the mockup wrote one `h1`. */
.section-start .hero__title-second {
  display: block;
  margin-top: var(--space-24);
  font-size: 5.6rem;
  line-height: 1.1;
}

/* ---- The plans heading is centered, like the intro under it ---------------
   Reported by Mikita, 2026-09-07: "Choose the Plan That Fits You" reads as
   left-aligned while the `.section-intro` directly under it, and the
   `.comparison-section__note` directly under the table, are both centered.
   Nothing in the cascade sets `text-align` on `.comparison-section__title` or
   on any of its ancestors, so it was falling through to the document default.

   SAME `:has(.section-intro)` SCOPE as the swoosh-clearance rule above, and
   for the same reason: static_index.st carries the identical class trio on its
   own two swoosh sections and is out of scope. Those two sections have no
   `.section-intro` between the heading and the table, which is what the scope
   keys on. */
.section-insights:has(.section-intro) .comparison-section__title {
  text-align: center;
}
