/* Nightwell. Night above the fold, daylight everywhere a record is read.
 * Class prefix ngh, per site-dna.json. */

:root {
  --night: #0B0A1F;
  --night-deep: #05040E;
  --night-rgb: 11 10 31;
  --moon: #F4EFE4;
  --moon-rgb: 244 239 228;
  --amethyst: #8B5CF6;
  --amethyst-rgb: 139 92 246;
  --amethyst-deep: #3B1E78;
  --verdant: #42D392;
  --verdant-rgb: 66 211 146;
  --verdant-deep: #177F55;

  --ground: #F7F8FC;
  --panel: #EDEEF6;
  --panel-2: #E3E5F1;
  --ink: #141327;
  --ink-rgb: 20 19 39;
  --ink-soft: #4A4866;
  --ink-faint: #605E78; /* was #6E6C89, which ran 4.36 against --panel and needs 4.5 */
  --rule: #D7D9E8;

  --ok: #177F55;
  --warn: #8A5A00;
  --alarm: #9B2226;

  --display: Fraunces, "Iowan Old Style", Georgia, serif;
  --body: Archivo, "Helvetica Neue", Arial, sans-serif;

  --measure: 66ch;
  --gutter: 16px;
  --radius: 3px;
}

*, *::before, *::after { box-sizing: border-box }
html { -webkit-text-size-adjust: 100% }
body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font: 400 clamp(16px, 0.97rem + 0.12vw, 17.5px)/1.62 var(--body);
  font-synthesis-weight: none;
}
figure, blockquote, dl, dd, fieldset { margin: 0 }
[hidden] { display: none !important }
img, svg.ngh-inline { max-width: 100%; height: auto; display: block }
a { color: inherit }
h1, h2, h3, h4 { margin: 0; font-family: var(--display); font-weight: 600; line-height: 1.12; letter-spacing: -0.012em }
h1 { font-size: clamp(2rem, 1.2rem + 3.4vw, 3.9rem); font-variation-settings: "SOFT" 40, "WONK" 1 }
h2 { font-size: clamp(1.45rem, 1.1rem + 1.5vw, 2.25rem); font-variation-settings: "SOFT" 28, "WONK" 1 }
h3 { font-size: clamp(1.13rem, 1rem + 0.5vw, 1.4rem) }
p { margin: 0 0 1em }
p:last-child { margin-bottom: 0 }
:focus-visible { outline: 2.5px solid var(--amethyst); outline-offset: 2px; border-radius: 2px }

.ngh-wrap { width: min(1140px, 100% - (var(--gutter) * 2)); margin-inline: auto }
.ngh-narrow { width: min(760px, 100% - (var(--gutter) * 2)); margin-inline: auto }
.ngh-skip {
  position: absolute; left: -9999px; top: 0; z-index: 99;
  background: var(--night); color: var(--moon); padding: 12px 18px;
}
.ngh-skip:focus { left: 8px; top: 8px }

/* ---------- masthead ---------- */
.ngh-mast { position: relative; z-index: 6; padding: 18px 0 }
.ngh-mast__row { display: flex; align-items: center; gap: 22px; flex-wrap: wrap }
.ngh-logo { display: inline-flex; align-items: center; gap: 9px; text-decoration: none; font-family: var(--display); font-size: 1.32rem; font-weight: 600; letter-spacing: -0.02em }
.ngh-logo svg { width: 26px; height: 26px; flex: none }
.ngh-nav { display: flex; gap: 20px; flex-wrap: wrap; margin-left: auto; font-size: 0.95rem }
.ngh-nav a { text-decoration: none; padding-bottom: 2px; border-bottom: 1.5px solid transparent }
.ngh-nav a:hover, .ngh-nav a[aria-current] { border-bottom-color: currentColor }

.ngh-mast--night { color: var(--moon) }
.ngh-mast--night .ngh-logo { color: var(--moon) }
/* On a night page the masthead floats over the hero rather than sitting on the
 * page background, where it would be pale ink on a pale ground. */
.ngh-night { position: relative }
.ngh-night .ngh-mast { position: absolute; left: 0; right: 0; top: 0 }


/* ---------- the hero ---------- */
.ngh-hero {
  position: relative; isolation: isolate; overflow: clip;
  background: var(--night-deep); color: var(--moon);
  min-height: 100vh; min-height: 100svh; /* fill the fold, no next section peeking */
  display: grid; align-items: end;
}
.ngh-hero__scene { position: absolute; inset: 0; z-index: 0 }
.ngh-scene { width: 100%; height: 100%; display: block }
.ngh-hero__veil {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    radial-gradient(70% 34% at 50% 68%, rgb(5 4 14 / .68) 0%, rgb(5 4 14 / 0) 100%),
    linear-gradient(to bottom, rgb(var(--night-rgb) / .44) 0 10%, rgb(var(--night-rgb) / 0) 32% 62%, rgb(5 4 14 / .5) 100%);
}
.ngh-hero__body { position: relative; z-index: 2; padding: 0 0 clamp(44px, 7vh, 84px); text-align: center }
.ngh-hero__lede { font-family: var(--display); font-size: clamp(1.9rem, 1rem + 4vw, 4.1rem); line-height: 1.06; font-weight: 500; font-variation-settings: "SOFT" 60, "WONK" 1; margin: 0 auto; max-width: 17ch; text-wrap: balance; text-shadow: 0 2px 34px rgb(var(--night-rgb) / .85) }
.ngh-hero__sub { margin: 20px auto 0; max-width: 46ch; color: rgb(var(--moon-rgb) / .84); font-size: clamp(1rem, .95rem + .3vw, 1.16rem); text-wrap: pretty; text-shadow: 0 1px 20px rgb(var(--night-rgb) / .9) }

/* the well, which is the search */
.ngh-well { margin: clamp(30px, 5vh, 54px) auto 0; width: min(620px, 100%) }
.ngh-well__form { display: flex; gap: 8px; padding: 8px; border-radius: 999px; background: rgb(var(--night-rgb) / .58); border: 1px solid rgb(var(--moon-rgb) / .22); backdrop-filter: blur(9px); box-shadow: 0 0 0 1px rgb(var(--amethyst-rgb) / .16), 0 18px 60px -18px rgb(var(--amethyst-rgb) / .5) }
.ngh-well__input { flex: 1 1 auto; min-width: 0; background: none; border: 0; color: var(--moon); font: inherit; padding: 11px 18px }
.ngh-well__input::placeholder { color: rgb(var(--moon-rgb) / .5) }
.ngh-well__input:focus { outline: none }
.ngh-well__form:focus-within { box-shadow: 0 0 0 2px var(--amethyst), 0 18px 60px -18px rgb(var(--amethyst-rgb) / .6) }
.ngh-tally { margin: 18px auto 0; display: flex; gap: 8px 26px; justify-content: center; flex-wrap: wrap; font-size: .86rem; color: rgb(var(--moon-rgb) / .62) }
.ngh-tally b { color: var(--moon); font-weight: 600; font-variant-numeric: tabular-nums }

/* ---------- buttons ---------- */
.ngh-btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 11px 22px; border-radius: 999px; border: 1px solid transparent;
  font: 600 .95rem/1 var(--body); text-decoration: none; cursor: pointer; white-space: nowrap;
}
.ngh-btn--go { background: var(--moon); color: var(--night) }
.ngh-btn--go:hover { background: #fff }
.ngh-btn--solid { background: var(--amethyst-deep); color: var(--moon) }
.ngh-btn--quiet { background: transparent; border-color: var(--rule); color: var(--ink) }
.ngh-btn--quiet:hover { background: var(--panel) }
/* restated after the region rules below, because .ngh-nav a and .ngh-prose a
 * both out-specify a bare .ngh-btn and would repaint the label body ink */

/* ---------- page furniture ---------- */
.ngh-band { padding: clamp(44px, 6vw, 80px) 0 }
.ngh-band--panel { background: var(--panel) }
.ngh-band--night { background: var(--night); color: var(--moon) }
.ngh-band--night h2 { color: var(--moon) }
.ngh-crumbs { font-size: .84rem; color: var(--ink-faint); padding: 14px 0 0 }
.ngh-crumbs a { text-decoration: none; border-bottom: 1px solid var(--rule) }
.ngh-crumbs ol { list-style: none; display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0 }
.ngh-crumbs li::after { content: "›"; padding-left: 6px; color: var(--rule) }
.ngh-crumbs li:last-child::after { content: none }

.ngh-lead { font-size: clamp(1.06rem, 1rem + .4vw, 1.24rem); color: var(--ink-soft); max-width: var(--measure); text-wrap: pretty }
.ngh-prose { max-width: var(--measure) }
.ngh-prose h2 { margin: 1.9em 0 .5em }
.ngh-prose h3 { margin: 1.5em 0 .4em }
.ngh-prose ul, .ngh-prose ol { padding-left: 1.2em; margin: 0 0 1em }
.ngh-prose li { margin-bottom: .45em }
.ngh-prose a { color: var(--amethyst-deep); text-underline-offset: 2px }

/* bite, snack, meal */
.ngh-bite { border-left: 3px solid var(--amethyst); padding: 2px 0 2px 18px; margin: 0 0 26px; font-size: clamp(1.1rem, 1rem + .5vw, 1.34rem); line-height: 1.45; font-family: var(--display); font-variation-settings: "SOFT" 30 }
.ngh-snack { background: var(--panel); border: 1px solid var(--rule); border-radius: var(--radius); padding: 20px 22px; margin: 0 0 30px }
.ngh-snack h2, .ngh-snack h3 { font-family: var(--body); font-size: .82rem; font-weight: 700; letter-spacing: .06em; margin: 0 0 10px; color: var(--ink-faint) }
.ngh-snack ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px }
.ngh-snack li { padding-left: 20px; position: relative; font-size: .96rem }
.ngh-snack li::before { content: ""; position: absolute; left: 2px; top: .56em; width: 7px; height: 7px; border-radius: 50%; background: var(--verdant-deep) }

/* ---------- the consensus meter, this site's one real invention ---------- */
.ngh-consensus { display: grid; gap: 14px }
.ngh-meter { display: grid; grid-template-columns: 5.6rem 1fr; gap: 10px 14px; align-items: center; font-size: .9rem }
.ngh-meter__label { color: var(--ink-soft); font-weight: 600 }
.ngh-meter__track { position: relative; height: 26px; background: var(--panel-2); border-radius: 2px; overflow: hidden }
.ngh-meter__fill { position: absolute; inset-block: 0; left: 0; border-radius: 2px }
.ngh-meter__fill--google { background: #6E7CA8 }
.ngh-meter__fill--yelp { background: #A8565A }
.ngh-meter__fill--facebook { background: #4A6BA8 }
/* The label is right aligned inside the track and the fill can end under
 * it, which had 4.2 out of 5 sitting half on the bar and half off. A
 * backdrop keeps it legible wherever the fill happens to stop. */
.ngh-meter__val { position: absolute; right: 5px; top: 50%; transform: translateY(-50%); font-size: .78rem; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; background: rgb(247 248 252 / .93); padding: 2px 6px; border-radius: 2px }
.ngh-meter__none { color: var(--ink-faint); font-size: .86rem; padding-left: 2px }

.ngh-verdict { display: flex; align-items: flex-start; gap: 11px; padding: 15px 17px; border-radius: var(--radius); font-size: .95rem; border: 1px solid }
.ngh-verdict--agree { background: #EAF6F0; border-color: #B6DFCB; color: #10553A }
.ngh-verdict--some { background: #FCF3E2; border-color: #EAD4A8; color: #6E4700 }
.ngh-verdict--split { background: #FBEBEC; border-color: #EEC2C4; color: #7E1D21 }
.ngh-verdict--thin { background: var(--panel); border-color: var(--rule); color: var(--ink-soft) }
.ngh-verdict b { display: block; margin-bottom: 2px }
.ngh-gapdot { flex: none; width: 10px; height: 10px; border-radius: 50%; margin-top: .42em; background: currentColor }

/* ---------- records ---------- */
.ngh-ranked { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule); border-radius: var(--radius); overflow: hidden }
.ngh-ranked > li { background: var(--ground); padding: 18px 20px; display: grid; grid-template-columns: 2.3rem 1fr auto; gap: 4px 16px; align-items: start }
.ngh-ranked__n { font-family: var(--display); font-size: 1.3rem; color: var(--ink-faint); font-variant-numeric: tabular-nums; line-height: 1.3 }
.ngh-ranked__name { font-size: 1.07rem; font-weight: 600; text-decoration: none }
.ngh-ranked__name:hover { text-decoration: underline; text-underline-offset: 2px }
.ngh-ranked__meta { grid-column: 2; font-size: .88rem; color: var(--ink-faint) }
.ngh-ranked__scores { grid-column: 3; grid-row: 1 / span 3; display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; max-width: 15rem }

.ngh-chip { display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px; border-radius: 999px; font-size: .78rem; font-weight: 600; background: var(--panel); border: 1px solid var(--rule); white-space: nowrap }
.ngh-chip--g { background: #EDF0F7; border-color: #C9D2E6 }
.ngh-chip--y { background: #F8ECEC; border-color: #E7C8C9 }
.ngh-chip--f { background: #EAEFF8; border-color: #C6D2EA }
.ngh-chip--mode { background: #EAF6F0; border-color: #BFE0CF; color: #115B3D; font-weight: 500 }
.ngh-chip--flag { background: #FBEBEC; border-color: #EEC2C4; color: #7E1D21 }
.ngh-chip__src { font-weight: 400; color: var(--ink-faint) }

.ngh-modes { display: flex; gap: 6px; flex-wrap: wrap; margin: 12px 0 0; padding: 0; list-style: none }

.ngh-kv { display: grid; grid-template-columns: max-content 1fr; gap: 7px 18px; font-size: .94rem; margin: 0 }
.ngh-kv dt { color: var(--ink-faint) }
.ngh-kv dd { margin: 0 }

.ngh-grid { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); list-style: none; margin: 0; padding: 0 }
.ngh-grid a { text-decoration: none; display: block; padding: 15px 17px; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--ground) }
.ngh-grid a:hover { border-color: var(--amethyst); background: var(--panel) }
.ngh-grid b { display: block; font-size: 1rem }
.ngh-grid span { font-size: .85rem; color: var(--ink-faint) }
.ngh-grid li[aria-disabled] > div { padding: 15px 17px; border: 1px dashed var(--rule); border-radius: var(--radius); color: var(--ink-faint) }

.ngh-empty { border: 1px dashed var(--rule); border-radius: var(--radius); padding: 22px; color: var(--ink-soft) }

.ngh-source { font-size: .82rem; color: var(--ink-faint); margin-top: 10px }
.ngh-basis { font-size: .8rem; color: var(--ink-faint); font-style: italic }


/* ---------- media cards ----------
 * Every image ships width and height so the row reserves its space before
 * the file arrives. A media grid that reflows as photos land is the single
 * biggest CLS source on a page like this. */
.ngh-cards { list-style: none; margin: 0; padding: 0; display: grid; gap: 18px; grid-template-columns: repeat(auto-fill, minmax(258px, 1fr)) }
.ngh-cards--feature { grid-template-columns: repeat(auto-fill, minmax(258px, 1fr)) }
.ngh-cards--feature .ngh-card--big { grid-column: span 2; grid-row: span 2 }

.ngh-card__link {
  display: flex; flex-direction: column; height: 100%; text-decoration: none;
  background: var(--ground); border: 1px solid var(--rule); border-radius: var(--radius);
  overflow: hidden;
}
.ngh-card__link:hover { border-color: var(--amethyst) }
.ngh-card__link:hover .ngh-card__name { text-decoration: underline; text-underline-offset: 2px }
.ngh-card__media { position: relative; display: block; aspect-ratio: 3 / 2; background: var(--panel-2); overflow: hidden }
/* The big card spans two rows, so its photo grows to fill whatever is left
 * after the text rather than leaving a pane of empty card under it. */
.ngh-card--big .ngh-card__media { aspect-ratio: auto; flex: 1 1 auto; min-height: 260px }
.ngh-card__img { width: 100%; height: 100%; object-fit: cover; display: block }
/* No photo is not a broken frame. The initials panel is a deliberate object. */
/* No photo is a deliberate panel, not a gap. Dark, so a card without one
 * reads as a different kind of object rather than as a broken card. */
.ngh-card__stand {
  width: 100%; height: 100%; display: grid; place-items: center;
  background: radial-gradient(120% 120% at 30% 20%, #241a4e 0%, #12102b 55%, #0b0a1f 100%);
}
.ngh-card__stand span {
  font-family: var(--display); font-size: 3.1rem; letter-spacing: .04em;
  color: rgb(var(--moon-rgb) / .58);
}
.ngh-card__verdict {
  position: absolute; left: 10px; bottom: 10px; font-size: .72rem; font-weight: 700;
  padding: 4px 9px; border-radius: 999px; background: rgb(255 255 255 / .94); color: var(--ink);
  border: 1px solid var(--rule);
}
.ngh-card--split .ngh-card__verdict { background: #FBEBEC; border-color: #EEC2C4; color: #7E1D21 }
.ngh-card--agree .ngh-card__verdict { background: #EAF6F0; border-color: #B6DFCB; color: #10553A }
.ngh-card--some  .ngh-card__verdict { background: #FCF3E2; border-color: #EAD4A8; color: #6E4700 }
.ngh-card__body { display: flex; flex-direction: column; gap: 7px; padding: 14px 15px 15px }
.ngh-card__name { font-size: 1rem; line-height: 1.28; color: var(--ink) }
.ngh-card--big .ngh-card__name { font-family: var(--display); font-size: 1.45rem; line-height: 1.16 }
.ngh-card__where { font-size: .85rem; color: var(--ink-faint) }
.ngh-card__scores { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 2px }

/* the worked example beside the explainer */
.ngh-split { display: grid; gap: 34px; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); align-items: start }
.ngh-worked { background: var(--panel); border: 1px solid var(--rule); border-radius: var(--radius); padding: 20px 22px }
.ngh-worked__cap { font-family: var(--display); font-size: 1.15rem; font-weight: 600; margin-bottom: 14px }
.ngh-worked__note { font-size: .88rem; color: var(--ink-faint); margin: 14px 0 0 }

/* modality and city tiles, photo led */
.ngh-modegrid, .ngh-citygrid { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px }
.ngh-modegrid { grid-template-columns: repeat(auto-fill, minmax(232px, 1fr)) }
.ngh-citygrid { grid-template-columns: repeat(auto-fill, minmax(186px, 1fr)) }
.ngh-modegrid a, .ngh-citygrid a {
  position: relative; display: block; overflow: hidden; text-decoration: none;
  border-radius: var(--radius); border: 1px solid var(--rule); background: var(--night);
  aspect-ratio: 16 / 10;
}
.ngh-citygrid a { aspect-ratio: 4 / 3 }
.ngh-modegrid img, .ngh-citygrid img { width: 100%; height: 100%; object-fit: cover; opacity: .42; transition: opacity .25s, transform .4s }
.ngh-modegrid a:hover img, .ngh-citygrid a:hover img { opacity: .58; transform: scale(1.04) }
.ngh-modegrid__stand { display: block; width: 100%; height: 100%; background: linear-gradient(160deg, #1d1645, #0b0a1f) }
.ngh-modegrid__text, .ngh-citygrid__text {
  position: absolute; inset: auto 0 0 0; padding: 14px 15px; color: var(--moon);
  background: linear-gradient(to top, rgb(5 4 14 / .92), rgb(5 4 14 / .55) 55%, rgb(5 4 14 / 0));
}
.ngh-modegrid__text b, .ngh-citygrid__text b { display: block; font-size: .98rem; line-height: 1.22 }
.ngh-modegrid__text span, .ngh-citygrid__text span { font-size: .82rem; color: rgb(var(--moon-rgb) / .72) }

/* the photo at the top of a record page */
.ngh-hero-photo { margin: 22px 0 0; max-width: 760px }
.ngh-hero-photo img { width: 100%; height: auto; border-radius: var(--radius); border: 1px solid var(--rule) }
.ngh-hero-photo figcaption { font-size: .8rem; color: var(--ink-faint); margin-top: 7px }

@media (max-width: 700px) {
  .ngh-cards--feature .ngh-card--big { grid-column: auto; grid-row: auto }
  .ngh-cards { gap: 14px }
}

/* ---------- forms ---------- */
.ngh-form { display: grid; gap: 14px; max-width: 34rem }
.ngh-field { display: grid; gap: 5px }
.ngh-field label { font-size: .88rem; font-weight: 600 }
.ngh-field input, .ngh-field textarea, .ngh-field select {
  font: inherit; padding: 10px 12px; border: 1px solid var(--rule);
  border-radius: var(--radius); background: #fff; color: var(--ink); width: 100%;
}
.ngh-field small { font-size: .8rem; color: var(--ink-faint) }

/* ---------- footer ---------- */
.ngh-foot { background: var(--night); color: rgb(var(--moon-rgb) / .72); padding: 48px 0 34px; font-size: .9rem; margin-top: 60px }
.ngh-foot a { color: rgb(var(--moon-rgb) / .9) }
.ngh-foot__cols { display: grid; gap: 26px; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); margin-bottom: 30px }
.ngh-foot h2 { font-family: var(--body); font-size: .78rem; letter-spacing: .07em; font-weight: 700; color: rgb(var(--moon-rgb) / .5); margin: 0 0 10px }
.ngh-foot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px }
.ngh-foot__fine { border-top: 1px solid rgb(var(--moon-rgb) / .14); padding-top: 18px; display: flex; gap: 8px 24px; flex-wrap: wrap; color: rgb(var(--moon-rgb) / .5); font-size: .84rem }

/* Specificity restatement. .ngh-foot a and .ngh-prose a are 0,2,0 and would
 * otherwise repaint a button label sitting inside either region. */
.ngh-foot a.ngh-btn--go, .ngh-prose a.ngh-btn--go, .ngh-band a.ngh-btn--go { color: var(--night) }
.ngh-foot a.ngh-btn--solid, .ngh-prose a.ngh-btn--solid, .ngh-band a.ngh-btn--solid { color: var(--moon) }
.ngh-foot a.ngh-btn--quiet, .ngh-prose a.ngh-btn--quiet, .ngh-band a.ngh-btn--quiet { color: var(--ink) }

/* ---------- the scene ----------
 * Colours only here. Every transform lives in the motion block below, so a
 * reduced motion reader gets the same picture, just still. */
.ngh-limb, .ngh-root { fill: none; stroke-linecap: round }
.ngh-ta { stroke: #A579F5 }
.ngh-tb { stroke: #9A6FF0 }
.ngh-tc { stroke: #54DCA0 }
.ngh-root.ngh-ta { stroke: #6E4FB8 }
.ngh-root.ngh-tb { stroke: #7557C4 }
.ngh-root.ngh-tc { stroke: #2A8C63 }
.ngh-hills { fill: #0d0a26; opacity: .85 }

/* Foliage. The mass gives the crown weight, the leaves give it texture.
 * Without them the outer twigs read as chevrons rather than as a tree. */
.ngh-mass { fill: #1d8f60; opacity: .085 }
.ngh-leaf--g { fill: #4FD69A }
.ngh-leaf--v { fill: #A987F7 }

.ngh-light--g .ngh-light__core { fill: #D6FFEC }
.ngh-light--g .ngh-light__halo { fill: #42D392; opacity: .16 }
.ngh-light--v .ngh-light__core { fill: #EDE2FF }
.ngh-light--v .ngh-light__halo { fill: #8B5CF6; opacity: .2 }
.ngh-fly__core { fill: #FFF6D8 }
.ngh-fly__halo { fill: #FFD873; opacity: .14 }
.ngh-mote { fill: #DCCFF7 }
.ngh-star { fill: #F4EFE4; opacity: var(--o, .5) }
/* Was a blurred group. The filter re-ran on every frame of the drift, so it
 * is a wide soft stroke instead, which reads the same and costs nothing. */
.ngh-aurora { fill: none; stroke-width: 88; opacity: .05; stroke-linecap: round; filter: blur(22px) }
.ngh-shaft { opacity: .5 }
.ngh-wave { fill: none; stroke: #b9a9e8; stroke-width: 1 }
.ngh-ring { fill: none; stroke: #c3b3ee; stroke-width: 1.1; opacity: 0 }

/* The parallax layers are moved by transform from script. Giving them a
 * transform up front puts each on its own layer instead of promoting nine
 * groups mid gesture. */
.ngh-par { transform: translate3d(0, 0, 0); will-change: transform }

/* ---------- motion ----------
 * Two rules hold this together.
 *
 * One, nothing that moves sits inside an SVG filter. A filter re-rasterizes
 * its whole subtree every frame, and the bloom that used to wrap the tree
 * would have made a 780px canvas repaint continuously. Glow is a second
 * larger circle instead.
 *
 * Two, every duration is a different prime-ish number. Tiers on 7.9, 9.4,
 * 11.3 and 13.7 seconds drift in and out of phase for minutes at a time,
 * which is what stops a four layer sway from reading as a metronome. */
@media (prefers-reduced-motion: no-preference) {

  /* The tree. Each tier pivots about the trunk base, and the further out the
   * tier the further it swings, so the crown lags the trunk the way a real
   * canopy does. transform-box: view-box makes --o, set per group in the
   * markup, resolve in viewBox units. */
  .ngh-tier {
    transform-box: view-box;
    transform-origin: var(--o);
    will-change: transform;
    animation: ngh-sway var(--sd) ease-in-out var(--sdl, 0s) infinite alternate;
  }
  .ngh-tier--0 { --sd: 13.7s; --sway: .10deg }
  .ngh-tier--1 { --sd: 11.3s; --sway: .34deg; --sdl: -1.4s }
  .ngh-tier--2 { --sd: 9.4s;  --sway: .78deg; --sdl: -2.9s }
  .ngh-tier--3 { --sd: 7.9s;  --sway: 1.5deg; --sdl: -4.1s }
  .ngh-roots  { --sd: 17.3s; --sway: .16deg }

  /* The limbs also draw themselves once on load. The sway runs underneath
   * from the first frame, so the tree is never a still image. */
  .ngh-limb, .ngh-root {
    stroke-dasharray: 380; stroke-dashoffset: 380;
    animation: ngh-draw 1.5s cubic-bezier(.22,.7,.3,1) forwards;
  }
  .ngh-ta { animation-delay: .15s }
  .ngh-tb { animation-delay: .5s }
  .ngh-tc { animation-delay: .85s }

  .ngh-light { animation: ngh-breathe var(--d, 5s) ease-in-out var(--dl, 0s) infinite }


  /* Fireflies. A long drift carrying them across the frame, and an irregular
   * flicker on top of it. The flicker keyframes are deliberately uneven,
   * because a smooth pulse reads as a machine and an insect does not pulse. */
  .ngh-fly { animation: ngh-wander var(--drift, 20s) ease-in-out var(--dl, 0s) infinite alternate }
  .ngh-fly__core, .ngh-fly__halo { animation: ngh-flicker var(--fl, 1.6s) steps(1, end) var(--dl, 0s) infinite }

  .ngh-mote { opacity: 0; animation: ngh-drift var(--d, 14s) linear var(--dl, 0s) infinite }
  .ngh-star--live { animation: ngh-twinkle var(--d, 4s) ease-in-out var(--dl, 0s) infinite }
  .ngh-moon { animation: ngh-rise 2.4s cubic-bezier(.2,.8,.25,1) both, ngh-moonglow 19s ease-in-out 2.4s infinite }
  .ngh-canopyglow { animation: ngh-glowfade 15.1s ease-in-out infinite }
  .ngh-auroras { animation: ngh-aur var(--d, 56s) ease-in-out infinite alternate }
  .ngh-aurora { animation: ngh-aurfade var(--d, 50s) ease-in-out var(--dl, 0s) infinite alternate }
  .ngh-shaft { animation: ngh-shaftdrift var(--d, 20s) ease-in-out var(--dl, 0s) infinite alternate }

  /* Water. The bands slide sideways at their own speeds, which is the thing
   * that actually reads as a moving surface, and the reflection shears with
   * them so the tree in the water is never quite the tree above it. */
  .ngh-wave { animation: ngh-lap var(--d, 9s) ease-in-out var(--dl, 0s) infinite alternate }
  .ngh-ring { animation: ngh-ripple var(--d, 8s) ease-out var(--dl, 0s) infinite }
  .ngh-reflection__tree { transform-box: view-box; transform-origin: 50% 0; animation: ngh-wobble 8.6s ease-in-out infinite alternate }
  .ngh-waterline { animation: ngh-shimmer 11.7s ease-in-out infinite }

  .ngh-hero__lede, .ngh-hero__sub, .ngh-well, .ngh-tally { animation: ngh-lift .9s cubic-bezier(.2,.75,.3,1) both }
  .ngh-hero__sub { animation-delay: .12s }
  .ngh-well { animation-delay: .24s }
  .ngh-tally { animation-delay: .36s }
}

@keyframes ngh-sway { from { transform: rotate(calc(var(--sway) * -1)) } to { transform: rotate(var(--sway)) } }
@keyframes ngh-draw { to { stroke-dashoffset: 0 } }
@keyframes ngh-breathe { 0%, 100% { opacity: .35 } 50% { opacity: 1 } }

@keyframes ngh-wander {
  0%   { transform: translate(0, 0) }
  35%  { transform: translate(calc(var(--dx) * .5), calc(var(--dy) * .7)) }
  65%  { transform: translate(calc(var(--dx) * .2), calc(var(--dy) * .3)) }
  100% { transform: translate(var(--dx), var(--dy)) }
}
/* Uneven on purpose. Long dark stretches, short bright ones. */
@keyframes ngh-flicker {
  0%   { opacity: 0 }
  8%   { opacity: 1 }
  14%  { opacity: .2 }
  21%  { opacity: .95 }
  46%  { opacity: 0 }
  58%  { opacity: .8 }
  63%  { opacity: .1 }
  71%  { opacity: 1 }
  88%  { opacity: 0 }
  100% { opacity: 0 }
}
@keyframes ngh-drift {
  0%   { opacity: 0; transform: translate(0, 0) }
  14%  { opacity: .75 }
  50%  { transform: translate(var(--sw, 0), calc(var(--rise, -40px) * .5)) }
  86%  { opacity: .45 }
  100% { opacity: 0; transform: translate(0, var(--rise, -40px)) }
}
@keyframes ngh-twinkle { 0%, 100% { opacity: calc(var(--o, .5) * .3) } 50% { opacity: var(--o, .5) } }
@keyframes ngh-rise { from { opacity: 0; transform: translateY(26px) } to { opacity: 1; transform: none } }
@keyframes ngh-moonglow { 0%, 100% { opacity: .92 } 50% { opacity: 1 } }
/* Opacity only. Scaling a 64px blur re-ran the whole filter every frame and
 * that one rule cost about 25fps on its own. */
@keyframes ngh-glowfade { 0%, 100% { opacity: .22 } 50% { opacity: .36 } }
@keyframes ngh-aur { from { transform: translate(-34px, -8px) } to { transform: translate(34px, 12px) } }
@keyframes ngh-aurfade { 0%, 100% { opacity: .03 } 50% { opacity: .075 } }
@keyframes ngh-shaftdrift { from { opacity: .3; transform: translateX(-16px) } to { opacity: .68; transform: translateX(16px) } }
@keyframes ngh-lap { from { transform: translateX(0) } to { transform: translateX(calc(var(--amp, 20px) * -1)) } }
@keyframes ngh-ripple {
  0%   { opacity: 0; transform: scale(1) }
  10%  { opacity: .5 }
  100% { opacity: 0; transform: scale(11) }
}
@keyframes ngh-wobble { from { transform: skewX(-1.1deg) scaleY(.985) } to { transform: skewX(1.1deg) scaleY(1.02) } }
@keyframes ngh-shimmer { 0%, 100% { opacity: .55 } 50% { opacity: 1 } }
@keyframes ngh-lift { from { opacity: 0; transform: translateY(16px) } to { opacity: 1; transform: none } }

/* Still, but not empty. A reader who asked for no motion still gets the
 * lights on and the fireflies visible, they just do not travel. */
@media (prefers-reduced-motion: reduce) {
  .ngh-light { opacity: .9 }
  .ngh-fly__core, .ngh-fly__halo { opacity: .8 }
  .ngh-mote { opacity: .4 }
  .ngh-ring { opacity: .18 }
}

/* ---------- widths. Tiers touch, so no range is uncovered. ---------- */
@media (max-width: 860px) {
  .ngh-nav { margin-left: 0; width: 100%; gap: 14px; font-size: .9rem }
  .ngh-ranked > li { grid-template-columns: 1.9rem 1fr }
  .ngh-ranked__scores { grid-column: 1 / -1; grid-row: auto; justify-content: flex-start; max-width: none; margin-top: 8px }
}
@media (max-width: 560px) {
  :root { --gutter: 14px }
  .ngh-hero__body { padding-block: 34px 44px }
  .ngh-well__form { flex-wrap: wrap; border-radius: 18px }
  .ngh-well__input { flex-basis: 100%; text-align: center }
  .ngh-btn { width: 100% }
  .ngh-meter { grid-template-columns: 1fr; gap: 4px }
  .ngh-kv { grid-template-columns: 1fr; gap: 2px 0 }
  .ngh-kv dd { margin-bottom: 9px }
}
