/* logbookprecision.com
   LogBook's own world: the app's Night ground and Bone type, OD green for the
   one highlight, Chakra Petch for words, JetBrains Mono for every measured
   figure. Faces are subset from the app's own TTFs. */

@font-face { font-family: 'Chakra Petch'; font-weight: 400; font-display: swap; src: url(/fonts/chakra-petch-400.woff2) format('woff2'); }
@font-face { font-family: 'Chakra Petch'; font-weight: 500; font-display: swap; src: url(/fonts/chakra-petch-500.woff2) format('woff2'); }
@font-face { font-family: 'Chakra Petch'; font-weight: 700; font-display: swap; src: url(/fonts/chakra-petch-700.woff2) format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-weight: 400; font-display: swap; src: url(/fonts/jetbrains-mono-400.woff2?v=2) format('woff2');
  unicode-range: U+0020, U+0022, U+0025, U+0027-0029, U+002B-003A, U+003C-003E, U+0041, U+0043-0049, U+004B-004F, U+0052-0054, U+0056-0058, U+0061, U+0063-0069, U+006B-0070, U+0072-0076, U+0078-007A, U+007E, U+00A0, U+00B0-00B1, U+00B7, U+00D7, U+2212; }
@font-face { font-family: 'JetBrains Mono'; font-weight: 500; font-display: swap; src: url(/fonts/jetbrains-mono-500.woff2?v=2) format('woff2');
  unicode-range: U+0020, U+0022, U+0025, U+0027-0029, U+002B-003A, U+003C-003E, U+0041, U+0043-0049, U+004B-004F, U+0052-0054, U+0056-0058, U+0061, U+0063-0069, U+006B-0070, U+0072-0076, U+0078-007A, U+007E, U+00A0, U+00B0-00B1, U+00B7, U+00D7, U+2212; }

:root {
  /* the LogBook ramp, from logbook-brand-tokens.css */
  --night:    #0F1216;
  --graphite: #171C22;
  --grid:     #1F262E;
  --hairline: #2A323C;
  --steel:    #6E7784;   /* lines, rings, marks: 4.1:1, never small text */
  --label:    #7D8693;   /* Steel lifted for small text: 5.1:1 on Night */
  --text-2:   #9AA3AE;
  --bone:     #F2EEE6;
  --od:       #8C9A5B;
  --od-hover: #A9B67C;

  --ui:   'Chakra Petch', 'Helvetica Neue', Helvetica, sans-serif;
  --data: 'JetBrains Mono', ui-monospace, Menlo, monospace;

  /* where the horizon sits in the hero photograph, as a fraction of its
     height; object-position uses the same fraction, so the horizon lands at
     this fraction of the viewport whichever way the frame is cropped */
  --horizon: 0.32;
  --gutter: clamp(1rem, 5vw, 4.5rem);

  /* the type steps below the display sizes, so sections share a scale
     rather than each picking its own */
  --fs-h-md:  clamp(min(1.6rem, 8vw), 2.8vw, 2.3rem);    /* section headings beside a figure */
  --fs-h-sm:  clamp(min(1.35rem, 7vw), 2.5vw, 1.75rem);  /* reading-page headings, lead-in questions */
  --fs-lede:  clamp(1.2rem, 1.8vw, 1.45rem);   /* a lede, a line of figures */
  --fs-small: .9rem;                           /* captions, tables, contents */
  --fs-fine:  .82rem;                          /* legal and trademark lines */
  --ease: cubic-bezier(.16, 1, .3, 1);
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; color-scheme: dark; scrollbar-color: var(--hairline) var(--night); }
body {
  margin: 0;
  background: var(--night);
  color: var(--bone);
  font: 400 1.0625rem/1.55 var(--ui);
  -webkit-font-smoothing: antialiased;
}
::selection { background: var(--od); color: var(--night); }
h1, h2, h3, p, li, dd, figcaption { overflow-wrap: break-word; }
img { display: block; max-width: 100%; height: auto; }
a { color: inherit; }
:focus-visible { outline: 2px solid var(--od-hover); outline-offset: 3px; }

/* skip to the content: off screen until it takes keyboard focus */
.skip {
  position: absolute; z-index: 20; left: var(--gutter); top: .75rem;
  padding: .7rem 1rem; border-radius: .6rem;
  background: var(--bone); color: var(--night); font: 500 .95rem/1 var(--ui); text-decoration: none;
  transform: translateY(-200%);
}
.skip:focus-visible { transform: none; }

.data { font-family: var(--data); font-variant-numeric: tabular-nums slashed-zero; }

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

.top {
  position: fixed; inset: 0 0 auto 0; z-index: 10;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 1.1rem var(--gutter);
  color: var(--bone);
  --mark-reticle: var(--steel); --mark-shot: var(--bone);
  transition: background-color .5s var(--ease), border-color .5s var(--ease);
}
.is-dark .top {
  background: color-mix(in srgb, var(--night) 82%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--grid);
}
.at-top .top { background: transparent; border-bottom-color: transparent; backdrop-filter: none; }
.lockup { display: flex; align-items: center; gap: .75rem; text-decoration: none; }
.lockup svg { width: 2.75rem; height: 2.75rem; }
.lockup svg .r { fill: var(--mark-reticle); transition: fill .5s var(--ease); }
.lockup svg .s { fill: var(--mark-shot); transition: fill .5s var(--ease); }
.lockup svg .ring { fill: none; stroke: var(--mark-reticle); stroke-width: 8; transition: stroke .5s var(--ease); }
.lockup b { font-weight: 700; font-size: 1.7rem; letter-spacing: -0.022em; }
.top .status { font: 500 .75rem/1 var(--ui); letter-spacing: .12em; text-transform: uppercase; opacity: .72; }
.top nav { display: flex; align-items: center; gap: 1.25rem; min-width: 0; }

/* the one action, until the store link exists */
.launch {
  /* 2.75rem is Apple's 44pt touch target, at every width */
  display: inline-flex; white-space: nowrap; align-items: center; gap: .5rem; min-height: 2.75rem;
  font: 500 .95rem/1 var(--ui); letter-spacing: .01em; text-decoration: none;
  padding: .8rem 1.15rem; border-radius: .6rem;
  background: var(--bone); color: var(--night);
  transition: transform .3s var(--ease);
}
.launch:hover { transform: translateY(-1px); }
.launch svg { width: 1rem; height: 1rem; }

/* ---- the season: one sticky stage, driven by one scroll value ---------- */

.season { position: relative; }
.stage {
  position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden;
  background: var(--night);
}
/* the app's graph-paper ruling, Grid at 48px, under the chart once the photo
   has gone; faded at the edges so it reads as paper, not a pattern */
.ruled::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(var(--grid) 1px, transparent 1px) 0 0 / 48px 48px,
    linear-gradient(90deg, var(--grid) 1px, transparent 1px) 0 0 / 48px 48px;
  -webkit-mask-image: radial-gradient(ellipse 75% 70% at 50% 50%, #000 40%, transparent 100%);
          mask-image: radial-gradient(ellipse 75% 70% at 50% 50%, #000 40%, transparent 100%);
}
.photo, .photo img {
  position: absolute; inset: 0; width: 100%; height: 100%;
}
.photo img {
  object-fit: cover;
  object-position: 50% calc(var(--horizon) * 100%);
}
.photo { opacity: calc(1 - var(--fade, 0)); will-change: opacity; }
/* phones crop the same frame on the tripod; the horizon stays where it is */
@media (max-width: 700px) {
  .photo img { object-position: 22% calc(var(--horizon) * 100%); }
}

.hero-copy {
  /* the headline stands on the horizon: its box ends at the horizon line, and
     the type sits at the bottom of it, so it never falls onto the land */
  position: absolute; left: var(--gutter); right: var(--gutter);
  /* below the header's real height (season.js measures it), so a larger
     text setting grows the header without covering the headline; if the
     headline then outgrows the sky, safe alignment lets it run down onto
     the land rather than up under the header */
  top: calc(var(--header-h, 5.5rem) + .25rem); bottom: calc((1 - var(--horizon)) * 100%);
  display: flex; align-items: flex-end; align-items: safe flex-end;
  padding-bottom: min(2rem, 4vh);
  color: var(--bone);
  opacity: calc(1 - var(--fade, 0) * 1.6);
  transform: translateY(calc(var(--fade, 0) * -2.5rem));
}
.hero-copy h1 {
  /* measured in its own em, so it breaks into two balanced lines at any
     width rather than three crowding the header */
  margin: 0; max-width: 18em;
  /* sized to the sky as well as the width, so two lines always fit above
     the horizon on a short laptop screen */
  font: 700 clamp(min(2rem, 9vw), min(4.6vw, 8.5vh), 4.6rem)/1.02 var(--ui);
  font-size: var(--h1-fit, clamp(min(2rem, 9vw), min(4.6vw, 8.5vh), 4.6rem));
  letter-spacing: -0.025em;
  text-wrap: balance;
}

/* the one hint that the page goes on: it only shows on arrival, and goes as
   soon as the photograph starts to fade. Purely visual, so hidden from
   screen readers, which reach the sections below anyway */
.scroll-cue {
  position: absolute; left: 50%; bottom: clamp(1.25rem, 4.5vh, 2.75rem); margin: 0;
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: .7rem;
  font: 500 .9rem/1.2 var(--ui); letter-spacing: .02em; color: var(--bone); text-align: center;
  /* one line normally; with large text on a phone it wraps inside the screen */
  width: max-content; max-width: calc(100% - 2 * var(--gutter));
  text-shadow: 0 1px 2px rgb(15 18 22 / .7), 0 0 1em rgb(15 18 22 / .55);
  /* a soft pool of shade under it, so bright grass behind it can't wash it out */
  padding: 1.4rem min(2.75rem, 8vw) 0;
  background: radial-gradient(closest-side, rgb(15 18 22 / .6), rgb(15 18 22 / 0));
  opacity: max(0, 1 - var(--fade, 0) * 6);
  pointer-events: none;
}
.scroll-cue::after {
  /* a thin rule pointing down, drifting once after the page settles */
  content: ''; width: 1px; height: 2.25rem;
  background: linear-gradient(var(--bone), color-mix(in srgb, var(--bone) 0%, transparent));
  animation: cue-drift 1.8s var(--ease) 1.2s both;
}
@keyframes cue-drift { from { transform: translateY(-.6rem); opacity: 0; } to { transform: none; opacity: 1; } }

/* the horizon, then the season's axis */
.axis {
  position: absolute; left: var(--gutter); right: var(--gutter);
  top: calc(var(--axis-y, var(--horizon)) * 100%);
  height: 0; border-top: 1px solid currentColor;
  /* a dark rule on the pale band, Bone at 55% once the photograph has gone */
  color: color-mix(in srgb, color-mix(in srgb, var(--bone) 55%, transparent) calc(var(--fade, 0) * 100%), rgb(15 18 22 / .6));
}
.axis span {
  position: absolute; bottom: .5rem;
  font: 500 .72rem/1 var(--ui); letter-spacing: .16em;
}
.axis .from { left: 0; } .axis .to { right: 0; }
.axis span { transition: opacity .4s var(--ease); }
.axis.ticked span { opacity: 0; }
/* if even the fitted headline needs the labels' room, they step aside */
.axis.crowded span { opacity: 0; }

/* Dusk: the owner's edit of frame 137 carries its own evening sky, blue to a
   pale band at the horizon. Night shades only the top, enough to seat the
   header and to hold Bone type over that band at 3:1 or better. */
.stage.dusk .photo::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom,
    rgb(15 18 22 / .70) 0%,
    rgb(15 18 22 / .55) calc(var(--horizon) * 60%),
    rgb(15 18 22 / .20) calc(var(--horizon) * 100%),
    rgb(15 18 22 / 0)   calc(var(--horizon) * 100% + 6%),
    rgb(15 18 22 / 0)   70%,
    rgb(15 18 22 / .45) 100%);
}
/* FEB and OCT sit on the pale band above the horizon, where only dark type
   reads (Night measures about 10:1 there, Bone 1.5:1); they turn Bone as the
   photograph fades to Night, so they read at both ends of the fade */
.stage.dusk .axis span {
  color: color-mix(in srgb, var(--bone) calc(var(--fade, 0) * 100%), var(--night));
  /* where a vignette darkens the band, a soft Bone glow keeps the ground
     behind the letters light; it goes as the photograph goes */
  text-shadow: 0 0 .2em color-mix(in srgb, var(--bone) calc((1 - var(--fade, 0)) * 90%), transparent),
               0 0 .5em color-mix(in srgb, var(--bone) calc((1 - var(--fade, 0)) * 80%), transparent),
               0 0 1em color-mix(in srgb, var(--bone) calc((1 - var(--fade, 0)) * 50%), transparent);
}
/* OCT sits where the edit's vignette is darkest, so its glow is a step stronger */
.stage.dusk .axis .to {
  text-shadow: 0 0 .2em color-mix(in srgb, var(--bone) calc((1 - var(--fade, 0)) * 100%), transparent),
               0 0 .45em color-mix(in srgb, var(--bone) calc((1 - var(--fade, 0)) * 95%), transparent),
               0 0 .8em color-mix(in srgb, var(--bone) calc((1 - var(--fade, 0)) * 75%), transparent),
               0 0 1.3em color-mix(in srgb, var(--bone) calc((1 - var(--fade, 0)) * 45%), transparent);
}

svg.chart { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.chart .layer { opacity: 0; transition: opacity .9s var(--ease); }
.chart .layer.on { opacity: 1; }
.chart .scale text { font: 500 11px var(--data); fill: var(--text-2); letter-spacing: .06em; }
.chart .tick text { font: 500 11px var(--ui); fill: var(--text-2); letter-spacing: .14em; }
.chart .tick line { stroke: var(--hairline); }
.chart .session { fill: var(--bone); }
.chart .temp { fill: url(#tempfill); }
.chart .temp-line { fill: none; stroke: var(--steel); stroke-width: 1.25; stroke-dasharray: 3 4; }
.chart .mv { fill: var(--bone); }
.chart .mv { transition: fill .8s var(--ease); }
.chart.lot-on .lot2-dot { fill: var(--od); }
.chart .fit { fill: none; stroke: var(--od); stroke-width: 2; }
/* once lot 2 is named, lot 1's line past June is only where lot 2 would have been */
.chart.lot-on .fit-lot1 { opacity: .3; }
.chart .name { font: 500 11px var(--ui); letter-spacing: .16em; fill: var(--text-2); }
.chart .data-name { font-family: var(--data); letter-spacing: .08em; }
.chart .fitname { fill: var(--od); }
.chart [data-layer="2"], .chart [data-layer="3"] { transition: opacity .9s var(--ease); }
.chart.cold-on [data-layer="2"].on, .chart.cold-on [data-layer="3"].on { opacity: .16; }
.chart [data-layer="2"] .scale { transition: opacity .6s var(--ease); }
.chart.cold-on [data-layer="2"] .scale { opacity: 0; }
.chart .mgrid { stroke: var(--hairline); stroke-dasharray: 2 5; }
.chart .stem { stroke: var(--bone); stroke-width: 1.5; }
.chart .tip { fill: var(--bone); }
.chart .cbmean { stroke: var(--od); stroke-width: 1.25; stroke-dasharray: 5 5; }
.chart .lotmark line { stroke: var(--od); stroke-dasharray: 2 4; }
.chart .lotmark text { font: 500 12px var(--ui); fill: var(--od); letter-spacing: .12em; }

/* the question each layer answers */
.caption {
  position: absolute; left: var(--gutter); bottom: clamp(1.5rem, 6vh, 4rem);
  max-width: 34rem;
}
.caption .q {
  color: var(--bone);
  margin: 0 0 .5rem; font: 700 clamp(min(1.5rem, 8vw), 2.6vw, 2.4rem)/1.08 var(--ui); letter-spacing: -0.02em;
}
.caption .a { margin: 0; color: var(--text-2); font-size: 1.05rem; }
.caption .figure { color: var(--od); }
.caption[data-for] { opacity: 0; transform: translateY(.75rem); transition: opacity .6s var(--ease), transform .6s var(--ease); }
.caption.on { opacity: 1; transform: none; }
.sample {
  position: absolute; right: var(--gutter); bottom: clamp(1.5rem, 6vh, 4rem);
  font: 500 .72rem/1 var(--ui); letter-spacing: .16em; text-transform: uppercase; color: var(--label);
  opacity: var(--fade, 0);
}

@media (max-width: 700px) {
  .caption { right: var(--gutter); }
  .sample { bottom: auto; top: calc(var(--header-h, 4.6rem) + .6rem); }
}
/* the header compacts by em, so it follows a reader's larger text setting as
   well as a narrow screen: 43.75em is 700px at the default size */
@media (max-width: 43.75em) {
  .top { padding-block: .8rem; }
  .top .status { display: none; }
  .lockup svg { width: 2.35rem; height: 2.35rem; }
  .lockup b { font-size: 1.45rem; }
  .launch { padding: .7rem .9rem; font-size: var(--fs-small); }
}
/* on the narrowest phones the mark stands alone, so the button keeps its
   words on one line; the wordmark stays as the link's accessible name */
@media (max-width: 23em) {
  .lockup b { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  /* with large text on a phone the buttons wrap to two lines rather than run
     off the screen; at normal sizes they still fit on one */
  .launch { white-space: normal; text-align: center; line-height: 1.15; }
}

/* Reduced motion: the same sequence, with the movement taken out. Opacity
   still carries each step; nothing slides, glides or draws itself on. */
@media (prefers-reduced-motion: reduce) {
  .scroll-cue::after { animation: none; }
  .hero-copy { transform: none; }
  .caption[data-for] { transform: none; }
  .launch:hover { transform: none; }
  .chart .fit { transition: none !important; }
}

/* Without JavaScript the chart is never drawn, so the season collapses to
   the hero rather than pinning a still photograph for five screens. */
.season { height: auto; }
html.js .season { height: 560vh; }
html:not(.js) .caption, html:not(.js) .sample { display: none; }

/* ---- the sections after the season -------------------------------------- */

.wrap { max-width: 76rem; margin: 0 auto; padding: 0 var(--gutter); }
main > section:not(.season) { padding-block: clamp(5rem, 11vw, 9.5rem); }
main > section:not(.season) + section:not(.season) { border-top: 1px solid var(--grid); }
h2 {
  margin: 0 0 1.25rem;
  font: 700 clamp(min(2rem, 9vw), 4.2vw, 3.5rem)/1.04 var(--ui);
  letter-spacing: -0.022em; text-wrap: balance;
}
main p { color: var(--text-2); max-width: 36rem; text-wrap: pretty; }
main p a { color: var(--bone); text-underline-offset: .2em; text-decoration-thickness: 1px; }
.sample-tag { font: 500 .72rem/1 var(--ui); letter-spacing: .16em; text-transform: uppercase; color: var(--label); margin-top: 1.75rem; }

/* which load: the answer is the graphic */
.loads h2 { color: var(--text-2); font-size: var(--fs-h-sm); margin-bottom: 2.5rem; }
.loads { position: relative; }
.loads .wrap { position: relative; }
.loads-figure { margin: 0; }
.loads-chart { width: 100%; height: auto; overflow: visible; }
.loads-chart.narrow { display: none; }
.loads-chart.narrow .name { font-size: 19px; }
.loads-chart.narrow .fig { font-size: 15px; }
.loads-chart.narrow .ticks text { font-size: 13px; }
@media (max-width: 640px) { .loads-chart.wide { display: none; } .loads-chart.narrow { display: block; } }
.loads-chart .name { font: 500 20px var(--ui); fill: var(--bone); }
.loads-chart .fig { font: 400 16px var(--data); fill: var(--text-2); }
.loads-chart .track { stroke: var(--hairline); }
.loads-chart .bar { stroke: var(--steel); stroke-width: 7; stroke-linecap: round; }
.loads-chart .ring { fill: none; stroke: var(--steel); stroke-width: 1.5; }
.loads-chart .mean { fill: var(--steel); }
.loads-chart .lead .bar { stroke: var(--od); }
.loads-chart .lead .ring { stroke: var(--od); }
.loads-chart .lead .mean { fill: var(--od); stroke: var(--night); stroke-width: 3; }
.loads-chart .band { fill: var(--od); opacity: .15; }
.loads-chart .ticks line { stroke: var(--grid); }
.loads-chart .ticks text { font: 400 14px var(--data); fill: var(--text-2); }
.loads-chart .legend { font: 400 14px var(--ui); fill: var(--label); }
.loads figcaption { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); gap: 1rem 4rem; margin-top: 3rem; align-items: start; }
.loads .verdict { grid-row: span 2; margin: 0; max-width: none; color: var(--bone); font: 700 clamp(min(2.6rem, 12vw), 5.6vw, 4.8rem)/1 var(--ui); letter-spacing: -0.025em; }
.loads .figline { margin: 0; color: var(--od); font-size: 1.05rem; }
.loads figcaption > p:not(.verdict):not(.figline) { margin: 0; }
.loads .sample-tag { grid-column: 2; margin: .5rem 0 0; }

/* the one reveal outside the season: rings, then the ranges, then the band */
html.js .loads-chart .ring, html.js .loads-chart .mean, html.js .loads-chart .band { opacity: 0; }
html.js .loads-chart .bar { transform: scaleX(0); transform-box: fill-box; transform-origin: center; }
html.js .loads-figure.in .ring { opacity: 1; transition: opacity .5s var(--ease); }
html.js .loads-figure.in .mean { opacity: 1; transition: opacity .5s var(--ease) .5s; }
html.js .loads-figure.in .bar { transform: none; transition: transform 1s var(--ease) .7s; }
html.js .loads-figure.in .band { opacity: .15; transition: opacity 1.2s var(--ease) 1.5s; }

/* text beside an app screen */
.split .wrap { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 22rem); gap: clamp(2.5rem, 7vw, 7rem); align-items: center; }
.split.flip .wrap { grid-template-columns: minmax(0, 22rem) minmax(0, 1fr); }
.split.flip .text { order: 2; }
/* the app on an iPhone, drawn as pennanti.com/logbook/ draws it: the frame is a
   physical object, so its colours stay literal, and the screenshot is a real
   full-screen capture carrying the app's own status bar and island */
.device {
  position: relative; justify-self: center;
  width: max-content; max-width: 100%; margin: 0;
  padding: .6875rem; border-radius: 2.875rem;
  background: linear-gradient(150deg, #39414B 0%, #161C22 26%, #10151A 74%, #39414B 100%);
  box-shadow: 0 2px 3px rgb(255 255 255 / .10) inset, 0 34px 60px -20px rgb(0 0 0 / .7), 0 12px 26px -12px rgb(0 0 0 / .5);
}
/* the screen is an image, not text: it never outgrows the screen it is viewed on,
   whatever the reader's text size */
.device img { display: block; width: min(17.375rem, calc(100vw - 2 * var(--gutter) - 1.375rem)); max-width: 100%; height: auto; border-radius: 2.25rem; }


/* two figures: as measured, and with the weather taken out */
.barrel .pair { display: flex; flex-wrap: wrap; gap: 1.5rem clamp(2.5rem, 8vw, 7rem); margin: 2.5rem 0 2rem; }
.barrel .pair p { margin: 0; max-width: none; display: grid; gap: .6rem; }
.barrel .big { font-size: clamp(min(3.2rem, 15vw), 9vw, 7.5rem); line-height: .9; font-weight: 500; letter-spacing: -0.03em; color: var(--od); }
.barrel .big.muted { color: var(--steel); }
.barrel .lab { font: 500 var(--fs-small)/1.35 var(--ui); color: var(--text-2); }
.barrel .lede { color: var(--bone); font-size: var(--fs-lede); max-width: 34rem; }

/* work-ups and zero targets */
.pairs .wrap { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(3rem, 7vw, 7rem); align-items: start; }
.pairs h2 { font-size: var(--fs-h-md); }
.ladder { margin: 2.25rem 0 0; }
.ladder-chart { width: 100%; max-width: 32rem; height: auto; overflow: visible; }
.ladder-chart .lband { fill: var(--od); opacity: .13; }
.ladder-chart .trend { stroke: var(--od); stroke-width: 1.75; }
.ladder-chart .shot { fill: var(--steel); }
.ladder-chart .avg { fill: var(--bone); }
.ladder-chart .step { font: 400 12px var(--data); fill: var(--text-2); }
.ladder-chart .axlab { font: 500 10px var(--ui); letter-spacing: .16em; text-transform: uppercase; fill: var(--label); }
.ladder .sample-tag { margin-top: 1rem; }
.zero figure { margin: 2rem 0 0; }
.zero img { width: 100%; max-width: 21rem; border-radius: .4rem; box-shadow: 0 30px 60px -24px rgb(0 0 0 / .7), 0 8px 20px -10px rgb(0 0 0 / .6); }
.zero figcaption { margin-top: 1.25rem; color: var(--text-2); font-size: var(--fs-small); max-width: 26rem; }
.zero figcaption .answer { color: var(--od); }

/* catalogs: the counts are proof, read as one line, not display numbers */
.counts { list-style: none; margin: 1.75rem 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: .75rem 2.5rem; font-size: var(--fs-lede); color: var(--text-2); }
.counts b { color: var(--bone); font-weight: 500; font-variant-numeric: tabular-nums; margin-right: .3em; }

/* the quiet passage before the close */
.quiet .wrap { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(2.5rem, 7vw, 7rem); }
.quiet h2 { font-size: var(--fs-h-md); }

/* the close */
.close { position: relative; overflow: hidden; text-align: center; padding-bottom: clamp(14rem, 34vw, 26rem) !important; }
.close .wrap { position: relative; }
/* the owner's forest frame in a band under the closing words: the dark
   trees at its top meet the Night ground, and the rifle sits in its patch of
   light under the button */
.close { padding-bottom: calc(40vw - 2rem) !important; }
.close-photo { position: absolute; inset: auto 0 0 0; height: 44vw; }
.close-photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 48%; }
/* phones: a taller band, cropped on the rifle so it is not lost in the trees */
@media (max-width: 600px) {
  .close { padding-bottom: 80vw !important; }
  .close-photo { height: 90vw; }
  .close-photo img { object-position: 52% 48%; }
}
.close-photo::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(to bottom, var(--night) 0%, rgb(15 18 22 / .6) 15%, rgb(15 18 22 / .15) 35%, rgb(15 18 22 / 0) 50%, rgb(15 18 22 / .45) 100%);
}
.close .wrap { display: flex; flex-direction: column; align-items: center; }
.close p { margin-inline: auto; }
.lockup-big { display: flex; align-items: center; gap: min(1rem, 4vw); margin-bottom: 3rem; text-align: left; }
.lockup-big svg { width: min(5rem, 20vw); height: min(5rem, 20vw); flex: none; }
.lockup-big .r { fill: var(--steel); } .lockup-big .s { fill: var(--bone); }
.lockup-big .ring { fill: none; stroke: var(--steel); stroke-width: 8; }
.lockup-big b { display: block; font: 700 min(3rem, 12vw)/1 var(--ui); letter-spacing: -0.025em; }
.lockup-big span { display: block; margin-top: .55rem; font: 500 .72rem/1 var(--ui); letter-spacing: .32em; text-transform: uppercase; color: var(--text-2); }
.close h2 { max-width: 24ch; }
/* the narrowest phones: the closing lockup steps down so the tagline holds one line */
.lockup-big span { white-space: nowrap; }
@media (max-width: 23em) {
  .lockup-big svg { width: min(4rem, 18vw); height: min(4rem, 18vw); }
  .lockup-big b { font-size: min(2.4rem, 11vw); }
  .lockup-big span { letter-spacing: .24em; font-size: min(.72rem, 2.9vw); }
}
.launch.big { margin-top: 1.5rem; padding: 1.05rem 1.6rem; font-size: 1.05rem; }

/* footer */
.foot { border-top: 1px solid var(--grid); padding: 3rem 0 4rem; }
.foot .wrap { display: grid; grid-template-columns: auto 1fr; gap: 1rem 2rem; align-items: baseline; }
.foot .by { margin: 0; font-weight: 500; }
.foot nav { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .5rem 1.75rem; }
.foot nav a { color: var(--text-2); text-decoration: none; padding: .7rem 0; margin: -.7rem 0; min-width: 0; overflow-wrap: anywhere; }
.foot nav a:hover { color: var(--bone); }
.foot .tm, .foot .legal { grid-column: 1 / -1; margin: 0; color: var(--label); font-size: var(--fs-fine); max-width: 52rem; }
.foot .tm { margin-top: 1.5rem; }

@media (max-width: 820px) {
  .split .wrap, .split.flip .wrap, .pairs .wrap, .quiet .wrap { grid-template-columns: minmax(0, 1fr); }
  .split.flip .text { order: 0; }
  .loads figcaption { grid-template-columns: minmax(0, 1fr); }
  .loads .verdict { grid-row: auto; }
  .loads .sample-tag { grid-column: 1; }
  .foot .wrap { grid-template-columns: minmax(0, 1fr); }
  .foot nav { justify-content: flex-start; }
}
@media (prefers-reduced-motion: reduce) {
  html.js .loads-chart .ring, html.js .loads-chart .mean, html.js .loads-chart .band { opacity: 1; }
  html.js .loads-chart .band { opacity: .15; }
  html.js .loads-chart .bar { transform: none; }
}

/* ---- reading pages: support, privacy, terms, targets ------------------- */

.doc { padding: clamp(7rem, 14vw, 9.5rem) 0 clamp(4rem, 9vw, 7rem); }
.doc .wrap { max-width: 46rem; }
.doc h1 { margin: 0 0 1rem; font: 700 clamp(min(2.2rem, 10vw), 5.4vw, 3.6rem)/1.03 var(--ui); letter-spacing: -0.025em; text-wrap: balance; }
.doc .meta { margin: 0 0 2rem; font: 500 .75rem/1 var(--ui); letter-spacing: .14em; text-transform: uppercase; color: var(--label); }
.doc h2 { margin: 3.5rem 0 1rem; font-size: var(--fs-h-sm); scroll-margin-top: 6rem; }
.doc p, .doc li { color: var(--text-2); max-width: none; }
.doc p { margin: 0 0 1rem; }
.doc ul { margin: 0 0 1rem; padding-left: 1.2rem; }
.doc li { margin-bottom: .5rem; }
.doc li::marker { color: var(--steel); }
.doc strong { color: var(--bone); font-weight: 500; }
.doc a { color: var(--bone); text-underline-offset: .2em; text-decoration-thickness: 1px; text-decoration-color: var(--steel); }
.doc a:hover { text-decoration-color: var(--bone); }
.doc .toc { margin: 0 0 1rem; padding: 1.25rem 0; border-block: 1px solid var(--grid); }
.doc .toc ul { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: .4rem 1.4rem; }
.doc .toc li { margin: 0; }
.doc .toc a { color: var(--text-2); text-decoration: none; font-size: var(--fs-small); display: inline-block; padding: .35rem 0; }
.doc .toc a:hover { color: var(--bone); }


/* the targets tables: /targets/, built by dev/targets.py */
.doc table.sheets { width: 100%; border-collapse: collapse; margin: 0 0 1rem; font-size: var(--fs-small); }
.sheets th, .sheets td { text-align: left; padding: .7rem .5rem; border-bottom: 1px solid var(--grid); }
.sheets thead th { font: 500 .72rem/1 var(--ui); letter-spacing: .14em; text-transform: uppercase; color: var(--label); }
.sheets tbody th { font: 400 var(--fs-small)/1.2 var(--data); color: var(--bone); font-variant-numeric: tabular-nums; }
.sheets td a { font-family: var(--data); display: block; padding: .4rem 0; }
/* yd over m, each link the full width of its cell, so a tap lands */

/* Five columns of mono cannot shrink, so where the table no longer fits (a
   narrow screen, or large text: the query is in em, so it follows the reader's
   text size) each grid becomes its own block, one line per distance. At the
   default size that is never: 15em is 240px. At 200% text it is 480px, and the
   grid needs about 430. */
@media (max-width: 15em) {
  .doc table.sheets, .sheets tbody, .sheets tr, .sheets th, .sheets td { display: block; }
  .sheets thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .sheets tr { padding: .9rem 0 .6rem; border-bottom: 1px solid var(--grid); }
  .sheets th, .sheets td { padding: 0; border: 0; }
  .sheets tbody th { margin-bottom: .3rem; }
  .sheets td { display: flex; align-items: center; gap: 1.5rem; }
  .sheets td::before { content: attr(data-d); flex: 0 0 3em; font: 500 .72rem/1 var(--ui); letter-spacing: .14em; color: var(--label); }
  .sheets td a { display: inline-block; padding: .55rem .5rem; margin-left: -.5rem; }
}
