/*
 * The public site's whole stylesheet.
 *
 * Hand-written and served straight from public/, not built. The application has
 * Vite and Tailwind scaffolded but no node_modules, and `@vite` throws rather
 * than degrades when the manifest is missing - so a Tailwind lander would mean
 * the marketing site is down on any box where `npm install && npm run build`
 * has not been run, including a fresh clone. Six static pages do not need a
 * build step to pay for that risk. Filament brings its own compiled CSS and is
 * untouched by this file.
 *
 * The look is a printed one: bone ground, ink type, a 3 px rule where a section
 * ends and a 1 px hairline where a row does. Nothing is rounded, nothing casts
 * a shadow. The header rides along as you scroll, but it does it as a printed
 * masthead does - same height, same opacity, same ink rule - rather than
 * shrinking or fading into a floating bar. That is a decision rather than a
 * style: the page should read as a document about food rather than as an app
 * that wants installing.
 *
 * The one rule worth knowing before editing anything below: red, amber and
 * green never appear in site chrome. They are the verdict colours - a band, a
 * front-of-pack warning, a failed field - so a coloured element anywhere on a
 * Zabel page always means a judgement is being made about something. A button
 * or a link that borrows one of them quietly spends that.
 */

/* ---------------------------------------------------------------- fonts - */

/*
 * Self-hosted, and that is not a preference. The privacy page claims these
 * pages load nothing from a third party, and a Google Fonts <link> would send
 * every visitor's IP address to Google on the very page promising it does not -
 * `PublicSiteTest` fails the build for exactly that. The files are the latin
 * subsets Google serves, dropped into public/fonts/site/ and committed.
 *
 * Archivo and Spline Sans Mono are variable fonts, so one file each covers the
 * whole weight range the design uses. `font-display: swap` because bone-on-ink
 * text in the fallback face is worth more than a blank page on a slow phone.
 */
@font-face {
    font-family: "Archivo";
    src: url("../fonts/site/archivo.woff2") format("woff2");
    font-weight: 400 700;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Archivo Black";
    src: url("../fonts/site/archivo-black.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Spline Sans Mono";
    src: url("../fonts/site/spline-sans-mono.woff2") format("woff2");
    font-weight: 400 600;
    font-style: normal;
    font-display: swap;
}

/*
 * Devanagari, for the handful of Hindi words on these pages. The unicode-range
 * is what keeps this 120 KB file off the wire for a visitor who never scrolls
 * past a line of English - the browser fetches it only when it has a glyph in
 * that block to paint.
 */
@font-face {
    font-family: "Noto Sans Devanagari";
    src: url("../fonts/site/noto-sans-devanagari-deva.woff2") format("woff2");
    font-weight: 400 700;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FF;
}

/* ---------------------------------------------------------------- tokens - */

:root {
    /*
     * One palette, no dark variant. The design commits to a single printed
     * look, and the verdict colours - the point of the whole product - were
     * chosen for contrast against bone. Inverting the ground would mean
     * re-deriving all five band colours to keep them legible, which is a
     * second design rather than a token swap. `color-scheme: light` tells the
     * browser to stop painting dark scrollbars and form controls around a page
     * that is not going to match them.
     */
    color-scheme: light;

    --bone: #f3f2ed;
    --bone-sunken: #e2e1da;
    --surface: #ffffff;

    --ink: #161813;
    --ink-hover: #2c332e;
    --ink-line: #333730;

    --prose: #3a453f;
    --prose-soft: #53584e;
    --muted: #646a5f;
    --placeholder: #8a8f84;

    --line: #c9c8c0;

    /* Type on an ink ground: bone for statements, sage for the supporting
       line, and a paler sage for links so a list of them is not a wall. */
    --on-ink: #f3f2ed;
    --on-ink-muted: #9ba295;
    --on-ink-link: #c4c9be;

    /* The verdicts. Never used on chrome - see the note at the top. */
    --red: #c6321e;
    --red-deep: #8c2917;
    --red-light: #e8705b;
    --amber: #a8730b;
    --amber-deep: #7a540a;
    --green: #1c7a4b;
    --green-deep: #14603a;
    --green-light: #6dbe8a;

    --wash-red: #f8e4df;
    --wash-amber: #f7ecd6;
    --wash-green: #dff0e5;

    --sans: "Archivo", "Helvetica Neue", Arial, "Noto Sans Devanagari", sans-serif;
    --display: "Archivo Black", "Archivo", "Helvetica Neue", Arial, sans-serif;
    --mono: "Spline Sans Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

    --wrap: 1160px;
    --gutter: 40px;

    /* The masthead's full height - the 88 px bar *plus* its 3 px rule - and so
       the offset every in-page anchor has to clear now that it is sticky. One
       token rather than a number repeated at four call sites, because the day
       the header changes height is the day three of them get missed and links
       start landing under it. Leaving the rule out of this is how an anchor
       lands three pixels short and the heading sits behind a black line. */
    --header-h: 91px;
    --prose-measure: 68ch;
}

@media (max-width: 760px) {
    :root {
        --gutter: 22px;
    }
}

@media (max-width: 860px) {
    :root {
        /* 64 px bar plus the same 3 px rule. */
        --header-h: 67px;
    }
}

/* ------------------------------------------------------------- elements - */

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

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

body {
    margin: 0;
    background: var(--bone);
    color: var(--ink);
    font-family: var(--sans);
    font-size: 16px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

h1,
h2,
h3 {
    margin: 0;
    font-family: var(--display);
    font-weight: 400;
    letter-spacing: -0.022em;
    line-height: 1.06;
    text-wrap: balance;
}

h1 {
    font-size: clamp(38px, 6vw, 70px);
}

h2 {
    font-size: clamp(28px, 3.6vw, 42px);
}

h3 {
    font-size: clamp(19px, 1.7vw, 23px);
}

p {
    margin: 0 0 1em;
}

p:last-child {
    margin-bottom: 0;
}

a {
    color: inherit;
    text-decoration: none;
}

a:hover {
    color: var(--red);
}

strong {
    font-weight: 700;
}

/*
 * A visible focus ring on everything, in ink rather than the browser's blue,
 * because the browser's blue is the one colour on this page that belongs to
 * nothing. Two pixels offset so it does not sit on top of a field's own border.
 */
:focus-visible {
    outline: 2px solid var(--ink);
    outline-offset: 2px;
}

img,
svg {
    max-width: 100%;
}

/* --------------------------------------------------------------- layout - */

.wrap {
    max-width: var(--wrap);
    margin: 0 auto;
    padding-inline: var(--gutter);
}

.section {
    padding-block: clamp(52px, 7vw, 86px);
    /* #how, #method and #early-access are all linked from the nav and the
       footer, and a sticky header would otherwise park itself on top of the
       heading the visitor just asked to see. */
    scroll-margin-top: var(--header-h);
}

/* The sunken band. Used where a section is a worked example or an exhibit
   rather than an argument - it steps back from the page instead of forward. */
.section--sunken {
    background: var(--bone-sunken);
}

/* The ink band. Reserved for the two places the site makes a promise about
   itself: the pledge and the closing call to action. */
.section--ink {
    background: var(--ink);
    color: var(--on-ink);
}

.section--ink h1,
.section--ink h2,
.section--ink h3 {
    color: var(--on-ink);
}

.section--tight {
    padding-block: clamp(36px, 4.5vw, 56px);
}

/* A section whose first element is a rule. The rule is what ends the section
   above it, so it sits directly under that section's own bottom padding -
   another 86 px on top of it leaves a band of empty page nobody asked for. */
.section--joined {
    padding-top: 0;
}

.section-head {
    max-width: 60ch;
    margin-bottom: 40px;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.section-head p {
    margin: 0;
    font-size: 16.5px;
    line-height: 1.6;
    color: var(--prose);
}

.section--ink .section-head p {
    color: var(--on-ink-link);
}

.page-head {
    padding-top: clamp(44px, 6vw, 72px);
    padding-bottom: clamp(32px, 4vw, 48px);
    display: flex;
    flex-direction: column;
    gap: 18px;
}

.page-head--split {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: 56px;
    align-items: end;
}

.page-head--split > div:first-child {
    display: flex;
    flex-direction: column;
    gap: 18px;
}

.page-head h1 {
    font-size: clamp(36px, 5vw, 54px);
    max-width: 20ch;
}

/* ------------------------------------------------------------ type parts - */

/*
 * The mono label. Small caps letter-spaced wide, in mono so a label sitting
 * above a column of figures lines up with them. This is the only thing on the
 * site that is uppercase, which is what makes it read as a label rather than
 * as shouting.
 */
.eyebrow,
.lab {
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--muted);
}

.section--ink .eyebrow,
.section--ink .lab {
    color: var(--on-ink-muted);
}

/* Every figure on the site. `tabular-nums` so a column of numbers is a column
   and not a ragged edge, which matters on the score breakdowns. */
.n {
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
}

.lede {
    font-size: clamp(17px, 1.4vw, 19px);
    line-height: 1.5;
    color: var(--prose);
    max-width: 52ch;
}

.updated {
    font-family: var(--mono);
    font-size: 12px;
    color: var(--muted);
    letter-spacing: 0.02em;
}

/* The rules. Three of them, and nothing else divides anything. */
.rule {
    height: 3px;
    background: var(--ink);
    border: 0;
    margin: 0;
}

.rule--hair {
    height: 1px;
    background: var(--line);
}

.section--ink .rule--hair {
    background: var(--ink-line);
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

.skip {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 10;
    background: var(--ink);
    color: var(--on-ink);
    padding: 12px 18px;
    font-weight: 600;
}

.skip:focus {
    left: 0;
    color: var(--on-ink);
}

/* -------------------------------------------------------------- controls - */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 11px;
    height: 56px;
    padding: 0 28px;
    border: 0;
    font-family: inherit;
    font-size: 16px;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    /* No radius and no shadow anywhere. A button here is a block of ink, and
       the hover shifts the fill rather than the size - a control that grows
       under the pointer moves the text you were about to read. */
    transition: background-color 0.12s ease;
}

.btn--primary {
    background: var(--ink);
    color: var(--on-ink);
}

.btn--primary:hover {
    background: var(--ink-hover);
    color: var(--on-ink);
}

.btn--secondary {
    height: 52px;
    padding: 0 24px;
    background: transparent;
    border: 2px solid var(--ink);
    color: var(--ink);
    font-size: 15px;
}

.btn--secondary:hover {
    border-color: var(--red);
    color: var(--ink);
}

/* On an ink ground the fill and the ink swap, so the button is still the
   densest thing in the band. */
.section--ink .btn--primary,
.btn--on-ink {
    background: var(--bone);
    color: var(--ink);
    font-weight: 700;
}

.section--ink .btn--primary:hover,
.btn--on-ink:hover {
    background: var(--on-ink-link);
    color: var(--ink);
}

.btn-row {
    display: flex;
    align-items: center;
    gap: 20px;
    flex-wrap: wrap;
    margin-top: 28px;
}

.link {
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 4px;
}

/* ---------------------------------------------------------------- header - */

/*
 * Sticky, but still a masthead rather than a floating bar: it never becomes
 * translucent, never shrinks on scroll, and never gains a shadow. The 3 px rule
 * is what separates it from the page as content passes under it - a shadow
 * would be a second separator doing the same job in a softer language than
 * anything else on the site speaks.
 *
 * Opaque by necessity, not taste. A translucent header over the ink pledge band
 * or the footer would put bone type on a bone-over-ink blur, and the wordmark
 * would disappear for the length of a section.
 */
.site-header {
    position: sticky;
    top: 0;
    /* Above the page, below the skip link. The mobile nav sheet is painted
       inside this stacking context, so it needs nothing of its own. */
    z-index: 8;
    background: var(--bone);
    border-bottom: 3px solid var(--ink);
}

.site-header__inner {
    height: 88px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 48px;
}

.wordmark {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    font-family: var(--display);
    font-size: 21px;
    letter-spacing: 0.01em;
}

.wordmark:hover {
    color: var(--ink);
}

.wordmark svg {
    display: block;
    flex: none;
}

.nav {
    display: flex;
    align-items: center;
    gap: 36px;
}

.nav a {
    font-size: 14.5px;
    font-weight: 500;
}

/* The current page carries an underline and a heavier weight. No colour and no
   pill: the nav is type, and a filled shape in it would be the only chrome on
   the site competing with a verdict badge. */
.nav a[aria-current="page"] {
    font-weight: 600;
    border-bottom: 2px solid var(--ink);
    padding-bottom: 2px;
}

.nav .btn {
    height: 44px;
    padding: 0 20px;
    font-size: 14.5px;
}

/* The mobile nav is a <details>, which is the whole reason this site still
   ships no JavaScript. The summary is the 44 px hamburger; open, the panel is
   a full ink sheet so the nav inherits the footer's contrast. */
.nav-toggle {
    display: none;
}

.nav-toggle > summary {
    list-style: none;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    width: 44px;
    height: 44px;
    cursor: pointer;
}

.nav-toggle > summary::-webkit-details-marker {
    display: none;
}

.nav-toggle .icon-close,
.nav-toggle[open] .icon-open {
    display: none;
}

.nav-toggle[open] .icon-close {
    display: block;
}

.nav-panel {
    position: absolute;
    left: 0;
    right: 0;
    z-index: 5;
    background: var(--ink);
    padding: 8px var(--gutter) 24px;
    display: flex;
    flex-direction: column;
}

.nav-panel a {
    color: var(--on-ink-link);
    font-size: 19px;
    font-weight: 600;
    padding: 14px 0;
    border-bottom: 1px solid var(--ink-line);
}

.nav-panel a:hover,
.nav-panel a[aria-current="page"] {
    color: var(--on-ink);
}

.nav-panel .btn {
    margin-top: 18px;
    height: 52px;
    width: 100%;
    font-size: 15px;
}

@media (max-width: 860px) {
    .site-header__inner {
        height: 64px;
        position: relative;
    }

    .wordmark {
        font-size: 18px;
    }

    .wordmark svg {
        width: 26px;
        height: 26px;
    }

    .nav {
        display: none;
    }

    .nav-toggle {
        display: block;
    }

    /* Ink summary on an ink panel: once the sheet is open the bar above it has
       to belong to the sheet, or the close control floats on bone over a black
       page. */
    .nav-toggle[open] > summary {
        position: relative;
        z-index: 6;
    }
}

/* ------------------------------------------------------------------ hero - */

.hero {
    padding-block: clamp(48px, 6vw, 86px);
}

.hero__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 72px;
    align-items: center;
}

.hero h1 {
    margin-bottom: 28px;
}

.badge {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 24px;
    font-family: var(--mono);
    font-size: 12px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--muted);
}

.badge::before {
    content: "";
    width: 9px;
    height: 9px;
    background: var(--green);
    flex: none;
}

.hero .lede {
    max-width: 44ch;
}

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

.grid {
    display: grid;
    gap: 56px;
}

.grid--2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.grid--3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.grid--4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 40px;
}

/*
 * Column spans, as classes rather than inline styles - and that is not tidiness.
 * A `grid-column: span 2` written inline survives into the one-column
 * breakpoint, where it makes the grid invent a second column and the whole page
 * grows wider than the phone holding it. Declared here, the media queries below
 * can put them back to a single column, which is the only place that can be
 * done once for every page.
 */
.span-1 { grid-column: span 1; }
.span-2 { grid-column: span 2; }
.span-3 { grid-column: span 3; }
.span-5 { grid-column: span 5; }

/*
 * A card is not a box. There is no border, no fill and no shadow on it - the
 * grid gap is what separates one from the next, and the numeral does the rest.
 * Boxing these was tried and turned a page of arguments into a dashboard.
 */
.card {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.card h3 {
    margin: 0;
}

.card p {
    margin: 0;
    font-size: 15px;
    line-height: 1.55;
    color: var(--prose);
}

.card__num {
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--muted);
}

/* The exception: a panel that holds figures, which does get a frame because it
   is quoting something rather than saying it. */
.panel {
    background: var(--surface);
    border: 1px solid var(--line);
}

.panel--framed {
    background: var(--bone);
    border: 3px solid var(--ink);
}

.panel__head {
    padding: 16px 24px;
    border-bottom: 3px solid var(--ink);
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
}

.panel__body {
    padding: 20px 24px;
}

/* A row inside a panel: label and figure, hairline between. */
.row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 20px;
    padding: 13px 24px;
    border-bottom: 1px solid var(--line);
}

.row:last-child {
    border-bottom: 0;
}

.row__label {
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: 15px;
}

.row__note {
    font-family: var(--mono);
    font-size: 11.5px;
    color: var(--muted);
}

.row__value {
    font-family: var(--mono);
    font-size: 15px;
    font-weight: 600;
    white-space: nowrap;
}

.row--total {
    border-top: 3px solid var(--ink);
    border-bottom: 0;
    padding-block: 16px;
    font-weight: 700;
}

.row--total .row__label {
    font-weight: 700;
}

.row--total .row__value {
    font-size: 18px;
    font-weight: 700;
}

/* The three figures a value can carry. Nothing else on the site may use them. */
.v-bad {
    color: var(--red);
}

.v-mid {
    color: var(--amber);
}

.v-good {
    color: var(--green);
}

/* ------------------------------------------------------- numbered claims - */

/*
 * The claims list. A hairline above each row rather than a bullet: these are
 * rows of a specification, and a disc in front of a two-line claim reads as an
 * afterthought.
 */
.claims {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
}

.claims li {
    display: flex;
    gap: 18px;
    padding: 18px 0;
    border-top: 1px solid var(--line);
    align-items: flex-start;
}

.claims li:last-child {
    border-bottom: 1px solid var(--line);
}

.claims li::before {
    counter-increment: claim;
    content: counter(claim, decimal-leading-zero);
    font-family: var(--mono);
    font-size: 12px;
    color: var(--muted);
    padding-top: 3px;
    width: 22px;
    flex: none;
}

.claims {
    counter-reset: claim;
}

.claims strong {
    display: block;
    font-size: 15.5px;
    font-weight: 600;
    margin-bottom: 4px;
}

.claims span {
    display: block;
    font-size: 14px;
    line-height: 1.5;
    color: var(--prose-soft);
}

.section--ink .claims li {
    border-color: var(--ink-line);
}

.section--ink .claims span {
    color: var(--on-ink-link);
}

/* The pledge rows: a cross or a tick, then a statement. The tick is the one
   green thing in a band of crosses, which is the point of the last line. */
.pledge {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
}

.pledge li {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 16px 0;
    border-bottom: 1px solid var(--ink-line);
    font-size: 17px;
}

.pledge li:last-child {
    border-bottom: 0;
}

.pledge svg {
    flex: none;
}

/* ----------------------------------------------------------------- stats - */

/*
 * Figures with a source under each one. The hairline grid is drawn with a
 * background showing through 1 px gaps rather than with borders, so the
 * interior lines are single-width however the cells wrap.
 */
.stats {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1px;
    background: var(--line);
    border: 1px solid var(--line);
}

.stat {
    background: var(--bone);
    padding: 28px 26px 24px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.stat__figure {
    font-family: var(--display);
    font-size: clamp(36px, 3.4vw, 46px);
    line-height: 1;
    letter-spacing: -0.03em;
}

.stat p {
    margin: 0;
    font-size: 15px;
    line-height: 1.45;
    color: var(--prose);
}

.stat__source {
    font-family: var(--mono);
    font-size: 11px;
    color: var(--muted);
    padding-top: 4px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

/* ------------------------------------------------------------------- faq - */

.faq {
    display: flex;
    flex-direction: column;
    border-top: 3px solid var(--ink);
}

.faq > div {
    padding: 22px 0;
    border-bottom: 1px solid var(--line);
}

.faq > div:last-child {
    border-bottom: 3px solid var(--ink);
}

.faq h3 {
    font-family: var(--sans);
    font-size: 17px;
    font-weight: 600;
    letter-spacing: 0;
    line-height: 1.4;
    margin-bottom: 7px;
}

.faq p {
    margin: 0;
    font-size: 15px;
    line-height: 1.55;
    color: var(--prose-soft);
    max-width: 62ch;
}

/* ----------------------------------------------------------------- notes - */

/*
 * The three washes. Each one is a verdict about the text inside it, which is
 * why they are the only tinted blocks on the site: amber warns, green invites,
 * and the plain note states a limitation.
 */
.note {
    border-left: 5px solid var(--ink);
    padding: 22px 26px;
    background: var(--surface);
    font-size: 15px;
    line-height: 1.6;
    color: var(--prose);
}

.note--warn {
    border-left-color: var(--amber);
    background: var(--wash-amber);
    color: var(--amber-deep);
}

.note--good {
    border-left-color: var(--green);
    background: var(--wash-green);
    color: var(--green-deep);
}

.note--good .eyebrow,
.note--good .lab {
    color: var(--green);
}

.note strong {
    color: var(--ink);
}

.note--warn strong {
    color: var(--amber-deep);
}

.note--good strong {
    color: var(--green-deep);
}

/* --------------------------------------------------------------- verdict - */

/*
 * The band badge, and the front-of-pack flag. Word and colour always travel
 * together so a band still reads in greyscale or to someone who is colour
 * blind - the colour is the second signal, never the only one.
 */
.band {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 5px 12px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--on-ink);
}

.band--excellent,
.band--good {
    background: var(--green);
}

.band--fair {
    background: var(--amber);
}

.band--poor {
    background: var(--red);
}

.band--avoid {
    background: var(--red-deep);
}

.band--none {
    background: transparent;
    border: 1.5px solid var(--muted);
    color: var(--prose-soft);
}

/* The hexagon is the front-of-pack warning shape, borrowed from the labels
   these packs would carry if the rule were notified. */
.flag {
    clip-path: polygon(9% 0, 91% 0, 100% 50%, 91% 100%, 9% 100%, 0 50%);
    background: var(--red);
    color: var(--on-ink);
    padding: 8px 16px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

/* ---------------------------------------------------------------- proof - */

/*
 * The worked example in the hero, drawn as the app's own result screen. It is
 * a table because it is one; the caption says it is an illustration because
 * the numbers are invented, and a page whose argument is "we show our working"
 * cannot open with a figure it will not stand behind.
 */
.proof {
    width: 100%;
    max-width: 380px;
    margin-left: auto;
    border: 3px solid var(--ink);
    background: var(--bone);
}

.proof__head {
    padding: 22px 20px 16px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.proof__title {
    margin: 0;
    font-family: var(--display);
    font-size: 22px;
    line-height: 1.1;
    letter-spacing: -0.015em;
}

.proof__verdict {
    background: var(--ink);
    color: var(--on-ink);
    padding: 18px 20px;
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 16px;
}

.proof__score {
    font-family: var(--display);
    font-size: 60px;
    line-height: 0.82;
    letter-spacing: -0.04em;
    /* The lighter red, not the flat one: this figure sits on the ink verdict
       bar, where #c6321e goes muddy and stops reading as a warning. */
    color: var(--red-light);
}

.proof__outof {
    font-family: var(--mono);
    font-size: 15px;
    color: var(--on-ink-muted);
}

.proof__flags {
    background: var(--wash-red);
    padding: 14px 20px;
    display: flex;
    gap: 7px;
    flex-wrap: wrap;
}

.proof table {
    width: 100%;
    border-collapse: collapse;
    border-top: 3px solid var(--ink);
}

.proof caption {
    caption-side: bottom;
    padding: 14px 20px 18px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--muted);
    text-align: left;
    border-top: 1px solid var(--line);
}

.proof th,
.proof td {
    padding: 11px 20px;
    text-align: left;
    font-size: 13.5px;
    font-weight: 400;
    border-bottom: 1px solid var(--line);
}

.proof thead th {
    font-family: var(--mono);
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--muted);
    padding-block: 12px;
}

.proof tbody th {
    font-weight: 500;
    color: var(--ink);
    padding-right: 8px;
}

.delta {
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    text-align: right;
    white-space: nowrap;
    color: var(--green);
}

.delta--down {
    color: var(--red);
}

.delta--mid {
    color: var(--amber);
}

/* ------------------------------------------------------------ the method - */

/* The four-component table. Twelve columns on desktop so the weight column can
   be narrow and the source column wide; one column stacked on a phone, where a
   12-column table of prose is unreadable at any font size. */
.method-table {
    background: var(--surface);
    border: 1px solid var(--line);
}

.method-table__head,
.method-row {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: 24px;
    padding: 22px 26px;
}

.method-table__head {
    padding-block: 14px;
    border-bottom: 3px solid var(--ink);
    background: var(--bone);
}

.method-row {
    border-bottom: 1px solid var(--line);
    align-items: start;
}

.method-row:last-child {
    border-bottom: 0;
}

.method-row__name {
    grid-column: span 3;
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 16px;
    font-weight: 700;
}

.method-row__what {
    grid-column: span 5;
    font-size: 14.5px;
    line-height: 1.5;
    color: var(--prose);
}

.method-row__weight {
    grid-column: span 1;
    font-family: var(--mono);
    font-size: 22px;
    font-weight: 600;
    text-align: right;
}

.method-row__source {
    grid-column: span 3;
    font-size: 13px;
    line-height: 1.5;
    color: var(--prose-soft);
}

.method-table__head .lab:nth-child(3) {
    text-align: right;
}

/* The facts rail beside a page title: version, date, who reviewed it. */
.facts {
    display: flex;
    flex-direction: column;
    gap: 0;
}

.facts div {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    padding: 9px 0;
    border-bottom: 1px solid var(--line);
    font-family: var(--mono);
    font-size: 12px;
    color: var(--muted);
}

.facts strong {
    font-weight: 600;
    color: var(--ink);
    text-align: right;
}

/* The band table and the change log share the rule system and nothing else. */
.bands {
    display: flex;
    flex-direction: column;
    border-top: 3px solid var(--ink);
}

.bands div {
    display: flex;
    align-items: center;
    gap: 20px;
    padding: 12px 0;
    border-bottom: 1px solid var(--line);
}

.bands .band {
    width: 124px;
    flex: none;
}

.bands span:last-child {
    font-size: 14px;
    color: var(--prose-soft);
}

.log {
    display: flex;
    flex-direction: column;
    border-top: 3px solid var(--ink);
}

.log div {
    display: flex;
    gap: 22px;
    align-items: flex-start;
    padding: 18px 0;
    border-bottom: 1px solid var(--line);
}

.log .n {
    font-size: 13px;
    font-weight: 600;
    width: 72px;
    flex: none;
}

.log strong {
    display: block;
    font-size: 15px;
    font-weight: 600;
    margin-bottom: 4px;
}

.log small {
    font-family: var(--mono);
    font-size: 11.5px;
    color: var(--muted);
}

.log div.log--planned {
    opacity: 0.55;
}

/* Chips: an INS code, a processing marker. Mono, square, quiet. */
.chip {
    display: inline-flex;
    align-items: center;
    font-family: var(--mono);
    font-size: 11px;
    padding: 3px 7px;
    background: var(--bone-sunken);
    color: var(--prose-soft);
    white-space: nowrap;
}

.chip--mid {
    background: var(--amber);
    color: var(--on-ink);
}

.chip--outline {
    background: transparent;
    border: 1.5px solid var(--line);
    padding: 5px 9px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.chips {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
}

/* The total strip that closes the worked example. */
.total-strip {
    background: var(--ink);
    color: var(--on-ink);
    padding: 26px 32px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 40px;
    flex-wrap: wrap;
}

.total-strip__score {
    font-family: var(--display);
    font-size: 52px;
    line-height: 1;
    color: var(--red-light);
}

/* ---------------------------------------------------------------- prose - */

/*
 * The policy pages. Wider line height and a hard measure, because these are
 * the only pages on the site somebody reads top to bottom rather than scans.
 */
.prose {
    max-width: var(--prose-measure);
    font-size: 16.5px;
    line-height: 1.7;
    color: var(--prose);
}

.prose h2 {
    font-size: 24px;
    margin: 44px 0 14px;
    color: var(--ink);
    scroll-margin-top: calc(var(--header-h) + 24px);
}

.prose h2:first-child {
    margin-top: 0;
}

.prose h3 {
    font-family: var(--sans);
    font-size: 17px;
    font-weight: 700;
    letter-spacing: 0;
    margin: 28px 0 8px;
    color: var(--ink);
}

.prose p {
    margin: 0 0 1em;
}

.prose ul,
.prose ol {
    margin: 0 0 1em;
    padding-left: 1.2em;
}

.prose li {
    margin-bottom: 0.5em;
}

.prose a {
    text-decoration: underline;
    text-underline-offset: 3px;
}

.prose table {
    width: 100%;
    border-collapse: collapse;
    background: var(--surface);
    border: 1px solid var(--line);
    margin: 0 0 1.4em;
    font-size: 14.5px;
}

.prose thead th {
    font-family: var(--mono);
    font-size: 10.5px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--muted);
    background: var(--bone);
    border-bottom: 3px solid var(--ink);
    padding: 12px 22px;
    text-align: left;
}

.prose tbody th,
.prose tbody td {
    padding: 16px 22px;
    border-bottom: 1px solid var(--line);
    text-align: left;
    vertical-align: top;
    line-height: 1.5;
}

.prose tbody tr:last-child th,
.prose tbody tr:last-child td {
    border-bottom: 0;
}

.prose tbody th {
    font-weight: 600;
    color: var(--ink);
}

/* The table of contents beside a policy page. Anchors only - the page is the
   document, and this is its spine. */
.toc {
    display: flex;
    flex-direction: column;
    gap: 2px;
    position: sticky;
    top: calc(var(--header-h) + 24px);
}

.toc .lab {
    padding-bottom: 10px;
}

.toc .rule {
    margin-bottom: 6px;
}

.toc a {
    font-size: 14px;
    line-height: 1.4;
    color: var(--prose-soft);
    padding: 7px 0;
    border-bottom: 1px solid var(--line);
}

.toc a:hover {
    color: var(--red);
}

.legal-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 64px;
    align-items: start;
}

.legal-grid > .prose {
    grid-column: span 3;
    max-width: none;
}

/* ----------------------------------------------------------------- forms - */

/*
 * Labels are mono caps above the field, never placeholders inside it. A
 * placeholder disappears the moment somebody starts typing, which is exactly
 * when they want to check what the field was asking for.
 */
.field {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 18px;
}

.field > label {
    font-family: var(--mono);
    font-size: 10.5px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--muted);
}

.input,
.select,
.textarea {
    width: 100%;
    font-family: inherit;
    font-size: 15px;
    color: var(--ink);
    background: var(--surface);
    border: 1.5px solid var(--line);
    padding: 0 16px;
    height: 52px;
}

.textarea {
    min-height: 150px;
    padding: 15px 16px;
    line-height: 1.55;
    height: auto;
    resize: vertical;
}

.select {
    /* The UA's own arrow, kept. A hand-drawn one would need a background image
       on a site that ships none, and the native control is the one a phone
       already knows how to open. */
    appearance: auto;
    padding-right: 12px;
}

.input:focus,
.select:focus,
.textarea:focus {
    border-color: var(--ink);
    outline: none;
}

.input::placeholder,
.textarea::placeholder {
    color: var(--placeholder);
}

.input[aria-invalid="true"],
.textarea[aria-invalid="true"],
.select[aria-invalid="true"] {
    border-color: var(--red);
}

.hint {
    display: block;
    font-size: 13px;
    line-height: 1.5;
    color: var(--muted);
}

/* The one place chrome is allowed to be red: a field the visitor has to go
   back to. */
.error {
    display: block;
    font-size: 13px;
    color: var(--red);
}

.flash {
    background: var(--wash-green);
    border-left: 5px solid var(--green);
    color: var(--green-deep);
    padding: 16px 20px;
    margin-bottom: 24px;
    font-size: 15px;
}

/* The honeypot. Hidden here rather than with a `hidden` attribute so that the
   markup gives a bot nothing to key on - anything that arrives in it filled in
   was filling every field on the page. */
.trap {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.form-card {
    background: var(--surface);
    border: 1px solid var(--line);
    padding: 36px 36px 40px;
}

.form-card h2 {
    font-size: 26px;
    margin-bottom: 8px;
}

.form-card > p {
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--prose-soft);
    margin-bottom: 24px;
}

.form-card .btn {
    width: 100%;
}

/* The early-access strip: one field and one button on a single line, wrapping
   to two on a phone. */
.signup {
    background: var(--ink);
    color: var(--on-ink);
    padding: clamp(32px, 4vw, 48px);
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.signup h2 {
    color: var(--on-ink);
    max-width: 22ch;
}

.signup > p {
    margin: 0;
    font-size: 16.5px;
    color: var(--on-ink-muted);
    max-width: 56ch;
}

.signup__form {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    margin-top: 12px;
    align-items: flex-start;
}

.signup__form .input {
    flex: 1 1 260px;
    width: auto;
    border-color: var(--ink-line);
}

.signup__form .btn {
    flex: none;
}

.signup .flash {
    background: transparent;
    border-left-color: var(--green-light);
    color: var(--green-light);
    margin: 0;
}

.signup .error {
    color: var(--red-light);
}

/* The channel list on the contact page: an icon, a heading, a line of prose
   and the address to write to. */
.channels {
    display: flex;
    flex-direction: column;
    border-top: 3px solid var(--ink);
}

.channels > div {
    display: flex;
    gap: 20px;
    align-items: flex-start;
    padding: 24px 0;
    border-bottom: 1px solid var(--line);
}

.channels > div:last-child {
    border-bottom: 3px solid var(--ink);
}

.channels svg {
    flex: none;
    margin-top: 3px;
}

.channels h3 {
    font-size: 19px;
    margin-bottom: 6px;
}

.channels p {
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--prose-soft);
    max-width: 44ch;
    margin-bottom: 6px;
}

.channels a {
    font-family: var(--mono);
    font-size: 13.5px;
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* ---------------------------------------------------------------- footer - */

.site-footer {
    background: var(--ink);
    color: var(--on-ink);
    /* Visible only where an ink band runs straight into the footer - the
       closing call to action, the right of reply - which would otherwise read
       as one undivided field of black half a screen tall. */
    border-top: 1px solid var(--ink-line);
}

.site-footer__grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 48px;
    align-items: start;
    padding-top: 60px;
    padding-bottom: 44px;
}

.site-footer .wordmark {
    color: var(--on-ink);
    font-size: 19px;
}

.site-footer h2 {
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 13px;
}

.site-footer ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 13px;
}

.site-footer a {
    color: var(--on-ink-link);
    font-size: 14.5px;
}

.site-footer a:hover {
    color: var(--on-ink);
}

.site-footer__note {
    margin: 16px 0 0;
    font-size: 14px;
    line-height: 1.55;
    color: var(--on-ink-muted);
    max-width: 26ch;
}

.site-footer__bar {
    border-top: 1px solid var(--ink-line);
}

.site-footer__legal {
    margin: 0;
    padding-top: 20px;
    padding-bottom: 28px;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 24px;
    flex-wrap: wrap;
    font-family: var(--mono);
    font-size: 11.5px;
    line-height: 1.6;
    color: var(--muted);
}

.site-footer__legal a {
    font-size: inherit;
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* ------------------------------------------------------------ responsive - */

/*
 * Two breakpoints and no more. 980 px folds the two-column page layouts into
 * one; 760 px is the phone, where the multi-column grids become single file
 * and the 12-column method table stops being a table.
 */
@media (max-width: 980px) {
    .hero__grid,
    .grid--2,
    .grid--3,
    .legal-grid,
    .page-head--split {
        grid-template-columns: minmax(0, 1fr);
        gap: 48px;
    }

    /* Every span goes back to one column with its grid. A span left behind in
       a single-column grid is what pushes the page wider than the screen. */
    .span-2,
    .span-3,
    .span-5 {
        grid-column: auto;
    }

    .page-head--split {
        gap: 28px;
        align-items: start;
    }

    .grid--4 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .legal-grid > .prose {
        grid-column: auto;
    }

    /* Sticky is worth nothing once the contents sit above the document rather
       than beside it, and a sticky block that scrolls with the page is just a
       block that jumps. */
    .toc {
        position: static;
    }

    .proof {
        margin-inline: 0;
        max-width: none;
    }

    .stats {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 760px) {
    .grid--4,
    .stats {
        grid-template-columns: minmax(0, 1fr);
    }

    .method-table__head {
        display: none;
    }

    .method-row {
        grid-template-columns: minmax(0, 1fr);
        gap: 10px;
    }

    .method-row > * {
        grid-column: auto !important;
        text-align: left !important;
    }

    .method-row__weight {
        order: -1;
        font-size: 18px;
        text-align: left;
    }

    .total-strip,
    .site-footer__legal {
        flex-direction: column;
        align-items: flex-start;
        gap: 16px;
    }

    .site-footer__grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 36px;
    }

    .form-card {
        padding: 26px 22px 30px;
    }

    .bands .band {
        width: 104px;
    }
}

/* ------------------------------------------------------------ not found - */

/*
 * The 404, and the only page on the site with a drawing on it. Centred rather
 * than set to the left margin like every other page head: there is no content
 * under it to line up with, and a dead end that keeps the reading grid looks
 * like a page that failed to finish loading rather than one that has nothing
 * to show.
 */
.notfound {
    padding-top: clamp(40px, 6vw, 72px);
    padding-bottom: clamp(48px, 8vw, 96px);
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 18px;
}

.notfound__mascot {
    max-width: 60vw;
    margin-bottom: 6px;

    /*
     * The one placement that is centred on the page rather than aligned to an
     * edge, and so the one that notices that the drawing is not centred in its
     * own box: the body sits at x=34..166 of a box running -16..248, which is
     * 16 units left of centre, because the clear space on the right is where
     * the props go. Centring the box leaves the character visibly left of the
     * headline under it. This puts those 16 units back at the size this
     * placement draws at. A static offset - nothing on this site moves.
     */
    position: relative;
    left: 13px;
}

.notfound h1 {
    max-width: 18ch;
}

.notfound .lede {
    max-width: 44ch;
}

.notfound .btn-row {
    margin-top: 10px;
}

/* --------------------------------------------------------------- mascot - */

/*
 * The character's placements on the site.
 *
 * The drawing itself is resources/views/site/_mascot.blade.php, and the comment
 * at the top of that file is the list of which blocks may carry it and which
 * are bare on purpose. What lives here is only how it is fitted to a block.
 *
 * Three mechanics, and they are all the same idea - the character is a sticker
 * stuck on a printed page, so it is always partly behind something rather than
 * floating beside it:
 *
 *   .mascot-crop    clipped by its own wrapper, whose bottom edge is a rule -
 *                   the character stands behind the line
 *   .mascot-perch   overlapped by the block underneath, which is opaque and
 *                   carries .mascot-occluder - it stands on that block's edge
 *   .mascot--aside  no occlusion, in the room a page head leaves to its right
 *
 * Nothing here moves, on hover or otherwise. The app spends its one animation
 * on the onboarding wave and the site has no JavaScript at all; a drawing that
 * reacted to the pointer would be the first moving thing on either.
 */

.mascot {
    /* One ink, one ground, taken from whatever the block is. Reversed out of an
       ink band the same markup gives a bone character with an ink belly, which
       is why the body fill is a variable rather than a colour. */
    color: var(--ink);
    --mascot-ground: var(--bone);
    display: block;
    height: auto;
    flex: none;
}

.section--ink .mascot {
    color: var(--on-ink);
    --mascot-ground: var(--ink);
}

/* Clipped at a rule. The wrapper's height is how much of the drawing clears the
   line: about the top half, which is the face and one raised arm. Anything less
   and it reads as a smudge above a rule rather than as somebody behind it. */
.mascot-crop {
    display: flex;
    justify-content: flex-end;
    align-items: flex-start;
    overflow: hidden;
    height: 104px;
    padding-right: clamp(0px, 5vw, 72px);
}

/*
 * Standing on the leading edge of the block below, feet behind it.
 *
 * The bottom margin is the part worth getting right: it has to swallow the
 * 16 px of empty box under the feet and then about half the legs, and no more.
 * Bury the whole leg and the drawing stops being somebody standing behind a
 * band and becomes a card resting on a shelf - which was the first attempt, and
 * it read as a floating box.
 *
 * The top margin takes the gap back out of the previous block's padding, so a
 * perch does not open a band of empty page above whatever it is standing on.
 */
.mascot-perch {
    display: flex;
    justify-content: flex-end;
    margin-top: -30px;
    margin-bottom: -14px;
    position: relative;
    z-index: 0;
    padding-right: clamp(0px, 4vw, 56px);
}

/*
 * The block that does the hiding. It needs a stacking position of its own: an
 * SVG in normal flow is inline-level content and paints above a later sibling's
 * background, so without this the character sits on top of the band it is
 * supposed to be standing behind.
 */
.mascot-occluder {
    position: relative;
    z-index: 1;
}

/* Beside a page head, in the room the measure leaves on the right. Absolute
   rather than floated because .page-head is a flex column and a float inside
   one is just an ordinary item. */
.page-head {
    position: relative;
}

.mascot--aside {
    position: absolute;
    right: var(--gutter);
    bottom: 0;
}

/* Small, in the prose, beside a heading that asks a question. */
.mascot--inline {
    float: right;
    margin: 0 0 16px 28px;
}

/*
 * Narrow screens. The aside has no room left of the gutter once the heading
 * reaches the full width, so rather than dropping the character - phones are
 * where most of these pages are read - it moves above the eyebrow at a size
 * that does not push the headline off the first screen.
 */
@media (max-width: 1020px) {
    .mascot--aside {
        position: static;
        order: -1;
        width: 105px;
        margin-bottom: 4px;
    }
}

@media (max-width: 700px) {
    .mascot-crop {
        height: 78px;
    }

    .mascot-crop .mascot,
    .mascot-perch .mascot {
        width: 118px;
    }

    .mascot-perch {
        margin-top: -18px;
        margin-bottom: -12px;
    }

    .mascot--inline {
        float: none;
        margin: 0 0 18px;
        width: 100px;
    }
}

/* -------------------------------------------------------------- printing - */

/*
 * The policy pages get printed and filed, and the method page gets printed and
 * argued with. Both are already black type on a pale ground, so printing only
 * has to drop the furniture that means nothing on paper.
 */
@media print {
    .site-header,
    .site-footer,
    .skip,
    .toc,
    .btn-row,
    .signup,
    .mascot,
    .mascot-crop {
        display: none;
    }

    body {
        background: #ffffff;
        font-size: 11pt;
    }

    .section--ink,
    .total-strip {
        background: #ffffff;
        color: #000000;
        border: 1px solid #000000;
    }

    .legal-grid {
        display: block;
    }
}
