/* ==========================================================================
   Greensnake — shared components
   --------------------------------------------------------------------------
   Surfaces, cards, headers, badges and form controls that more than one page
   uses. Anything here must be page-agnostic: if a rule only ever applies to
   one page, it belongs in styles/pages/<page>.css instead.

   Two context classes do a lot of work and are worth knowing:

     .on-dark   applied to a section on a green/black ground. Re-points the
                ink ramp, hairlines and focus rings so every component inside
                adapts without a single dark-mode duplicate of its own rules.

     .prose     applied to rendered Markdown. The only place where bare tag
                selectors are allowed, because the markup comes from content.
   ========================================================================== */

/* ==========================================================================
   Context
   ========================================================================== */
.on-dark {
  color: var(--on-dark-2);
  --hairline: var(--on-dark-line);
  --surface: var(--on-dark-fill);
  --ink: var(--on-dark);
  --ink-2: var(--on-dark-2);
  --ink-3: var(--on-dark-3);
  --accent: var(--lime);
  --focus-glow: rgba(228, 254, 0, 0.16);
}

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

/* ==========================================================================
   Section rhythm
   --------------------------------------------------------------------------
   One vertical scale for every page, so sections never drift apart. The
   values are fluid (tokens.css) — a phone gets 64px between blocks where a
   desktop gets 140px, instead of both getting 140px.
   ========================================================================== */
.section--pad { padding-block: var(--section-y); }
.section--pad-sm { padding-block: var(--section-y-sm); }
.section--top { padding-top: var(--section-y); }
.section--bottom { padding-bottom: var(--section-y); }

.section--green { background: var(--green-900); }
.section--cream { background: var(--cream); }
.section--white { background: var(--white); }

/* ==========================================================================
   Section header
   --------------------------------------------------------------------------
   A label on the left, optional meta on the right, a hairline underneath.
   Used to open every list on the site so scanning down a page finds the same
   landmark shape each time.
   ========================================================================== */
.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--hairline);
}

.section-head__label {
  margin: 0;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: var(--step-small);
  letter-spacing: -0.01em;
  color: var(--ink);
}

.section-head__meta {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--step-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* ==========================================================================
   Page header
   --------------------------------------------------------------------------
   The opening block of every page that isn't Home. Deliberately typographic:
   a kicker, one headline, one lede at a readable measure, then a hairline
   fact row. No hero image, because these pages earn attention with what they
   say rather than with a photograph behind it.
   ========================================================================== */
.page-head { padding-block: calc(var(--nav-h) + var(--space-10)) var(--space-9); }

.page-head__kicker {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-6);
  padding: 7px 16px 7px 12px;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-pill);
  font-family: var(--font-mono);
  font-size: var(--step-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.page-head__kicker::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  /* a slow pulse, once every four seconds — a sign of life, not a strobe */
  animation: pulse-dot 4s var(--ease-in-out) infinite;
}

@keyframes pulse-dot {
  0%, 70%, 100% { opacity: 1; transform: scale(1); }
  85% { opacity: 0.45; transform: scale(0.8); }
}

.page-head__title {
  max-width: 20ch;
  margin: 0 0 var(--space-6);
  color: var(--ink);
  text-wrap: balance;
}

.page-head__lede {
  max-width: 58ch;
  margin: 0;
  font-family: var(--font-alt);
  font-size: var(--step-lead);
  line-height: 1.45;
  letter-spacing: -0.02em;
  color: var(--ink-2);
  text-wrap: pretty;
}

/* ---------- fact row ---------- */
.facts {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  margin-top: var(--gap-block);
  padding-top: var(--space-6);
  border-top: 1px solid var(--hairline);
  list-style: none;
}

.facts > li {
  padding-inline: var(--space-7);
  border-left: 1px solid var(--hairline);
}
.facts > li:first-child { padding-left: 0; border-left: 0; }

.facts b {
  display: block;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: var(--step-body);
  color: var(--ink);
}

.facts span {
  display: block;
  margin-top: 2px;
  font-family: var(--font-mono);
  font-size: var(--step-micro);
  letter-spacing: 0.04em;
  color: var(--ink-3);
}

/* ==========================================================================
   Badge / chip
   --------------------------------------------------------------------------
   Badge = a static label on content. Chip = an interactive filter. They look
   related on purpose but are never interchangeable: if it can be clicked it
   is a chip, and a chip is always a real <button>.
   ========================================================================== */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: var(--radius-xs);
  background: var(--accent);
  color: var(--green-900);
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.badge--quiet {
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--hairline);
  color: var(--ink-2);
  font-weight: 500;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 38px;
  padding: 0 16px;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--hairline);
  color: var(--ink-2);
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: var(--step-small);
  letter-spacing: -0.01em;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease-out),
              color var(--t-fast) var(--ease-out),
              box-shadow var(--t-fast) var(--ease-out);
}

.chip:hover { color: var(--ink); box-shadow: inset 0 0 0 1px var(--ink-3); }
.chip:focus-visible { outline: 2px solid var(--btn-ring, var(--blue-assist)); outline-offset: 3px; }
.on-dark .chip { --btn-ring: var(--lime); }

.chip[aria-pressed="true"] {
  background: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
  color: var(--green-900);
}
.on-dark .chip[aria-pressed="true"] { color: var(--green-900); }

.chip__count {
  font-family: var(--font-mono);
  font-size: 11px;
  opacity: 0.65;
}

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* ==========================================================================
   Search field
   ========================================================================== */
.field {
  position: relative;
  display: flex;
  align-items: center;
}

.field__icon {
  position: absolute;
  left: 20px;
  width: 17px;
  height: 17px;
  color: var(--ink-3);
  pointer-events: none;
}

.field input {
  width: 100%;
  height: 56px;
  padding: 0 52px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--hairline);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: var(--step-body);
  letter-spacing: -0.02em;
  transition: box-shadow var(--t-base) var(--ease-out),
              background var(--t-base) var(--ease-out);
}

.field input::placeholder { color: var(--ink-3); }

/* The field ships its own clear button, so suppress the browser's — two
   clear affordances in one input is one too many. */
.field input[type="search"]::-webkit-search-cancel-button,
.field input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }
.field input:hover { box-shadow: inset 0 0 0 1px var(--ink-3); }
.field input:focus {
  outline: none;
  box-shadow: inset 0 0 0 1.5px var(--accent), 0 0 0 4px var(--focus-glow);
}

.field__clear {
  position: absolute;
  right: 10px;
}

/* ==========================================================================
   Card
   --------------------------------------------------------------------------
   The one surface treatment on the site: a 1px hairline, a soft radius, and
   a lift that comes from the border and a shadow — not from a colour change,
   which would fight the photography inside it.
   ========================================================================== */
.card {
  position: relative;
  display: flex;
  flex-direction: column;
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--hairline);
  overflow: hidden;
  transition: box-shadow var(--t-base) var(--ease-out),
              transform var(--t-base) var(--ease-out);
}

.card:hover {
  transform: translateY(-3px);
  box-shadow: inset 0 0 0 1px transparent, var(--shadow-md);
}
.on-dark .card:hover {
  box-shadow: inset 0 0 0 1px rgba(228, 254, 0, 0.35);
  transform: translateY(-3px);
}

.card__media {
  position: relative;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--cream-2);
}

.card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--t-slower) var(--ease-out);
}
.card:hover .card__media img { transform: scale(1.04); }

.card__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-6);
}

.card__title {
  margin: 0;
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: var(--step-h3);
  line-height: 1.25;
  letter-spacing: -0.03em;
  color: var(--ink);
  text-wrap: balance;
}

.card__text {
  margin: 0;
  font-size: var(--step-small);
  line-height: 1.6;
  color: var(--ink-2);
}

.card__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: auto;
  padding-top: var(--space-3);
}

/* The whole card is the click target, but only the title is the link —
   so the accessible name stays the title and not "read more". */
.card__link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: var(--space-6);
}

/* ==========================================================================
   Disclosure row
   --------------------------------------------------------------------------
   A list where each row expands in place. Built on <details>, so it works
   with no JavaScript at all, is keyboard operable for free, and is findable
   by the browser's own in-page search in supporting engines.
   ========================================================================== */
.rows {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.row {
  border-radius: var(--radius-md);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--hairline);
  transition: box-shadow var(--t-base) var(--ease-out),
              background var(--t-base) var(--ease-out);
}
.row:hover { box-shadow: inset 0 0 0 1px var(--ink-3); }
.row[open] { box-shadow: inset 0 0 0 1px var(--accent); }

.row__summary {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  padding: var(--space-5) var(--space-6);
  cursor: pointer;
  list-style: none;
}
.row__summary::-webkit-details-marker { display: none; }
.row__summary:focus-visible {
  outline: 2px solid var(--btn-ring, var(--blue-assist));
  outline-offset: -2px;
  border-radius: var(--radius-md);
}
.on-dark .row__summary { --btn-ring: var(--lime); }

.row__main { flex: 1; min-width: 0; }

.row__title {
  margin: var(--space-2) 0 0;
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: 1.0625rem;
  line-height: 1.4;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-wrap: pretty;
}

.row__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-2) 0 0;
  font-family: var(--font-mono);
  font-size: var(--step-micro);
  letter-spacing: 0.03em;
  color: var(--ink-3);
}

.row__chev {
  flex: none;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  margin-top: 2px;
  border-radius: 50%;
  color: var(--ink-3);
  transition: transform var(--t-base) var(--ease-out),
              background var(--t-base) var(--ease-out),
              color var(--t-base) var(--ease-out);
}
.row__chev svg { width: 14px; height: 14px; }
.row:hover .row__chev { background: var(--hairline); color: var(--ink); }
.row[open] .row__chev { transform: rotate(180deg); background: var(--accent); color: var(--green-900); }

.row__body {
  padding: 0 var(--space-6) var(--space-6);
  padding-left: calc(var(--space-6));
  font-size: var(--step-small);
  line-height: 1.7;
  color: var(--ink-2);
}

/* The panel unrolls rather than snapping open. `interpolate-size` is what
   makes height:auto animatable; where it is unsupported the panel simply
   appears, which is the correct fallback. */
@supports (interpolate-size: allow-keywords) {
  :root { interpolate-size: allow-keywords; }
  .row::details-content {
    block-size: 0;
    overflow: clip;
    transition: block-size var(--t-slow) var(--ease-out),
                content-visibility var(--t-slow) allow-discrete;
  }
  .row[open]::details-content { block-size: auto; }
}

/* ==========================================================================
   Empty state
   ========================================================================== */
.empty {
  padding: var(--space-10) var(--space-6);
  border: 1px dashed var(--hairline);
  border-radius: var(--radius-md);
  text-align: center;
  color: var(--ink-3);
}
.empty b { display: block; margin-bottom: var(--space-2); color: var(--ink); font-weight: 500; }

/* ==========================================================================
   Ticker
   --------------------------------------------------------------------------
   A single marquee, duplicated once and translated by exactly -50%, so the
   loop is seamless without measuring anything. It pauses on hover and stops
   completely under prefers-reduced-motion — a permanently moving element is
   an accessibility problem, not a flourish.
   ========================================================================== */
.ticker {
  --ticker-duration: 46s;
  position: relative;
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.ticker__track {
  display: flex;
  width: max-content;
  animation: ticker-slide var(--ticker-duration) linear infinite;
}
.ticker:hover .ticker__track { animation-play-state: paused; }

.ticker__group {
  display: flex;
  align-items: center;
  flex: none;
}

@keyframes ticker-slide {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .ticker__track { animation: none; }
  .ticker { mask-image: none; overflow-x: auto; }
}

/* ==========================================================================
   Prose — rendered Markdown
   ========================================================================== */
.prose {
  max-width: var(--container-text);
  font-family: var(--font-ui);
  font-size: 1.0625rem;
  line-height: 1.75;
  color: var(--ink-2);
}

.prose > * + * { margin-top: 1.1em; }
.prose h2, .prose h3, .prose h4 {
  margin-top: 1.9em;
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: -0.03em;
  color: var(--ink);
  text-wrap: balance;
}
.prose h2 { font-size: var(--step-h3); }
.prose h3 { font-size: 1.25rem; }
.prose h4 { font-size: 1.0625rem; }
.prose a { color: var(--accent); text-underline-offset: 3px; text-decoration: underline; }
.prose a:hover { text-decoration-thickness: 2px; }
.prose ul, .prose ol { padding-left: 1.25em; }
.prose li + li { margin-top: 0.4em; }
.prose img { border-radius: var(--radius-md); }
.prose blockquote {
  padding-left: var(--space-5);
  border-left: 2px solid var(--accent);
  font-family: var(--font-alt);
  font-size: var(--step-lead);
  line-height: 1.4;
  color: var(--ink);
}
.prose code {
  padding: 2px 6px;
  border-radius: var(--radius-xs);
  background: var(--hairline);
  font-family: var(--font-mono);
  font-size: 0.9em;
}
.prose pre {
  padding: var(--space-5);
  border-radius: var(--radius-md);
  background: var(--green-900);
  color: var(--on-dark-2);
  overflow-x: auto;
}
.prose pre code { padding: 0; background: none; }

/* ==========================================================================
   Responsive
   ========================================================================== */
@media (max-width: 860px) {
  .facts > li {
    padding-inline: var(--space-5);
  }
  .facts > li:first-child { padding-left: 0; }
}

@media (max-width: 560px) {
  .page-head { padding-block: calc(var(--nav-h) + var(--space-8)) var(--space-8); }
  .page-head__title { max-width: none; }
  .facts { gap: var(--space-5) 0; }
  .facts > li {
    flex: 1 1 45%;
    padding-inline: 0;
    border-left: 0;
  }
  .card__body { padding: var(--space-5); }
  .row__summary { padding: var(--space-4) var(--space-4); }
  .row__body { padding: 0 var(--space-4) var(--space-5); }
  .field input { height: 52px; padding-inline: 46px 16px; }
}

/* ==========================================================================
   Reveal plate
   --------------------------------------------------------------------------
   A photograph that rests in monochrome and returns to colour under the
   pointer. Two modes, one component:

     .plate--wash   hovering anywhere brings the whole photograph back.
                    Used on the pre-footer diver, which is how the original
                    site behaved.

     .plate--lens   an aperture follows the pointer, so colour arrives only
                    where you are looking. Used on the community group photo,
                    where the point is to meet people one cluster at a time.

   ONE image file is fetched. The <img> is the monochrome base and carries
   the alt text; the colour layer re-uses the same URL as a background, so
   the browser serves it from cache rather than over the network. Set that
   URL on the element:  style="--plate-img: url('/assets/img/x.webp')"

   Deliberately NOT built on backdrop-filter: masking a backdrop-filtered
   layer is unreliable across engines, and a photograph that fails to appear
   is a worse outcome than a slightly larger stylesheet.
   ========================================================================== */
.plate {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.plate__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform-origin: center;
  will-change: transform;
  filter: grayscale(1) contrast(1.06) brightness(0.92);
  transition: filter 760ms var(--ease-soft);
}

.plate__colour {
  position: absolute;
  inset: 0;
  z-index: 1;
  background-image: var(--plate-img);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  pointer-events: none;
}

/* ---------- wash: the whole photograph returns ---------- */
.plate--wash .plate__colour {
  opacity: 0;
  transition: opacity 720ms var(--ease-soft);
}
.plate--wash:hover .plate__colour,
.plate--wash:focus-within .plate__colour { opacity: 1; }

/* ---------- lens: an aperture that follows the pointer ----------
   --plate-r has to be registered before a transition can interpolate it;
   without @property the length would jump instead of easing, which is the
   acceptable fallback where the feature is missing. */
@property --plate-r {
  syntax: "<length>";
  inherits: true;
  initial-value: 0px;
}

.plate--lens .plate__colour {
  --plate-r: 0px;
  -webkit-mask-image: radial-gradient(circle at var(--plate-x, 50%) var(--plate-y, 50%),
    #000 0, #000 var(--plate-r), transparent calc(var(--plate-r) + var(--plate-feather, 120px)));
  mask-image: radial-gradient(circle at var(--plate-x, 50%) var(--plate-y, 50%),
    #000 0, #000 var(--plate-r), transparent calc(var(--plate-r) + var(--plate-feather, 120px)));
  transition: --plate-r 680ms var(--ease-soft);
}
.plate--lens.is-open .plate__colour { --plate-r: var(--plate-r-open, 130px); }

/* The invitation. Without it nobody knows there is anything to find, so it
   states the affordance once and then gets out of the way for good. */
.plate__invite {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--space-4);
  pointer-events: none;
  transition: opacity 620ms var(--ease-soft), transform 620ms var(--ease-soft);
}
.plate.is-touched .plate__invite {
  opacity: 0;
  transform: scale(1.06);
}

.plate__invite-mark {
  /* Fixed, and stated on the component rather than left to the page — a page
     rule like `.gc__plate img { width: 100% }` will otherwise capture this
     one and blow the mark up to the size of the whole photograph.

     This is logo-mark-alpha.webp, a genuinely transparent cut of the mark.
     Screen-blending the opaque original cannot work here: .plate__invite is
     a stacking context of its own, so the mark would blend against nothing
     and simply paint its dark square. */
  width: 76px !important;
  height: 76px !important;
  object-fit: contain;
  filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.55));
}

.plate__invite-text {
  padding: 7px 14px;
  border-radius: var(--radius-pill);
  background: rgba(2, 20, 11, 0.55);
  backdrop-filter: blur(6px);
  font-family: var(--font-mono);
  font-size: var(--step-micro);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.92);
}

/* ---------- no hover, or no motion: just show the photograph ----------
   On a touch screen there is no pointer to reveal anything with, and under
   reduced motion an aperture chasing the cursor is exactly the kind of
   thing being asked for less of. Both get the picture, in colour, at rest. */
@media (hover: none), (prefers-reduced-motion: reduce) {
  .plate__img { filter: none; }
  .plate__colour { display: none; }
  .plate__invite { display: none; }
}

/* ==========================================================================
   Closing panel
   --------------------------------------------------------------------------
   The block that ends Science, Programs, FAQ and the legal pages: a short
   pitch on the left, one or two actions on the right.

   This lived three separate times — `.contribute__panel`, `.hosting__inner`
   and `.panel` — with three slightly different paddings, which is precisely
   how a set of pages stops feeling like one site. One definition now.
   ========================================================================== */
.panel {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: end;
  gap: var(--space-8);
  padding: var(--panel-pad);
  border-radius: var(--radius-xl);
  background: rgba(255, 255, 255, 0.04);
  box-shadow: inset 0 0 0 1px var(--hairline);
}

.panel__title {
  max-width: 18ch;
  margin: var(--space-4) 0;
  color: var(--ink);
  text-wrap: balance;
}

.panel__text {
  max-width: 54ch;
  margin: 0;
  font-size: var(--step-small);
  line-height: 1.7;
  color: var(--ink-2);
}

.panel__actions { flex-direction: column; align-items: stretch; }

@media (max-width: 900px) {
  .panel { grid-template-columns: 1fr; align-items: start; }
  .panel__actions { flex-direction: row; }
}

@media (max-width: 560px) {
  .panel { border-radius: var(--radius-lg); }
  .panel__actions { flex-direction: column; align-items: stretch; }
  .panel__actions .btn { justify-content: space-between; }
}

/* ==========================================================================
   Vertical rhythm helpers
   --------------------------------------------------------------------------
   Two numbers, used everywhere, so no page invents its own:

     --gap-head     from a section header to the content under it
     --gap-block    between sibling blocks inside one section
   ========================================================================== */
.section-head + * { margin-top: var(--gap-head); }

/* ==========================================================================
   Touch targets
   --------------------------------------------------------------------------
   On a coarse pointer every control goes to the 44px floor. The compact
   sizes are right for a mouse and wrong for a thumb, and the difference is
   measurable: a 36px icon button and a 38px chip both missed it.

   Where growing the box would wreck the layout (footer links in a dense
   list), the TARGET grows instead of the box, using padding that costs no
   visual space because the rows already have room between them.
   ========================================================================== */
@media (pointer: coarse) {
  .btn-icon--sm { width: 44px; height: 44px; }
  .btn-icon--sm svg { width: 17px; height: 17px; }

  .chip { min-height: 44px; padding-inline: 18px; }

  /* A 22px-tall link is a miss waiting to happen. */
  .footer__col a,
  .menu__terms,
  .menu__social a { min-height: 44px; display: inline-flex; align-items: center; }

  .footer__col li + li { margin-top: var(--space-2); }

  /* The toggle's 44px target came from a negative-inset pseudo-element,
     which works but is invisible to anyone measuring the button. Make the
     box itself the target on touch. */
  .nav__toggle, .menu__close { width: 44px; height: 44px; }
}
