/* ══════════════════════════════════════════════════════════════════════
   links.tnaado.ca, the directory and the social accounts page.

   Both pages load this file and css/chrome.css, in that order, so the
   chrome's own --tnc-* tokens always win the cascade tie against anything
   here. Nothing below styles .eh-* or .ef-*.

   WHITE, NOT INK, since 2026-09-14. Ethan: "i wnat links white with palm
   trees", then "site white not darkc olour". Every other property in the
   estate is ink; this one is the directory, the page a person lands on to
   find something and leave, and it is the one that should feel like paper.
   The pages carry data-theme="light", which css/chrome.css already supports,
   so the header and footer come with it rather than needing a second set of
   declarations.

   PALETTE is still the estate's: ink #0a0a0a, bone #faf8f3, red #c8102e. The
   GROUND and the TYPE swapped places, nothing was invented.

   THE RED CHANGED ROLE, and this is the one thing to get right on a light
   ground. On ink, red type has to be lightened to #e8455a to clear AA.
   Measured on bone that same lightened red is 3.64:1 and FAILS, while the
   brand red itself is 5.54:1 and passes. So --red-text is the brand red here.
   It is the same rule the estate already follows, arrived at from the other
   side: use the red that clears AA against the ground you actually have.

   NO CARD GRIDS. The page is rules and rows, which is also why it can
   carry thirty-odd entries without reading as a wall: a row is one line
   of type with a hairline under it, not a box competing for attention.

   CONTRAST. Every muted alpha below was RECOMPUTED against the real
   composited pixel on #faf8f3, because an alpha tuned for a dark ground is
   meaningless on a light one:
     --dim   .80  ->  10.73:1
     --mute  .70  ->   7.46:1
     --faint .64  ->   5.94:1
     --red-text   ->   5.54:1
   .58 measures 4.80:1, which passes and is tight; .50, the dark file's own
   floor, measures 3.67:1 and fails outright. Do not carry an alpha across a
   ground swap without recomputing it.
   ══════════════════════════════════════════════════════════════════════ */

:root {
  --ink: #0a0a0a;
  --bone: #faf8f3;
  --bone-rgb: 250, 248, 243;
  --ink-rgb: 10, 10, 10;
  --red: #c8102e;
  --red-rgb: 200, 16, 46;
  /* The brand red, not the lightened one. See the header.
     DARKENED AGAIN 2026-09-14 once the palms went in behind the page. On flat
     bone the brand red measures 5.54:1 and passes; over the opened palm ground
     the eyebrow measured 4.23:1 at 1440 and 4.32:1 at 390, because the ground
     under it is no longer bone. #a80c26 measures 7.21:1 on bone and clears the
     photograph with room. The brand red itself is untouched everywhere it is a
     FILL rather than type: --red still paints the rules and the focus rings. */
  --red-text: #a80c26;

  --dim: rgba(var(--ink-rgb), .80);
  --mute: rgba(var(--ink-rgb), .70);
  --faint: rgba(var(--ink-rgb), .64);

  --rule: rgba(var(--ink-rgb), .16);
  --rule-soft: rgba(var(--ink-rgb), .09);

  --display: "Fraunces", Georgia, "Times New Roman", serif;
  --body: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --gutter: clamp(1.15rem, 4vw, 3.5rem);
  --measure: 78rem;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* THE GROUND MOVES TO html, so the palm layer below can sit behind the page
   without body's own fill painting over it. body stays transparent. */
html { background: var(--bone); }

body {
  background: transparent;
  color: var(--ink);
  font-family: var(--body);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}

::selection { background: var(--red); color: var(--bone); }

a { color: inherit; }

:focus-visible {
  outline: 2px solid var(--red-text);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 1000;
  padding: .7rem 1.1rem;
  background: var(--bone);
  color: var(--ink);
  font-family: var(--mono);
  font-size: .75rem;
  text-decoration: none;
}
.skip-link:focus { left: .75rem; top: .75rem; }

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

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


/* ── hero ───────────────────────────────────────────────────────────────
   The layered-art contract from tnaado-media-next/ART-GUIDE.md, at its
   quietest setting: one red radial in one corner, plus static grain. No
   photo and no film loop, because this page's subject is a list and art
   behind a list is noise. Content sits at z-index 2 as the contract
   requires; the art layers never rise above z1. */
.hero {
  position: relative;
  overflow: hidden;
  border-bottom: 1px solid var(--rule);
  padding-block: clamp(3.25rem, 9vw, 6.5rem) clamp(2.25rem, 5vw, 3.5rem);
}
.hero > * { position: relative; z-index: 2; }

.hero-glow {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(ellipse 62% 70% at 8% 6%, rgba(var(--red-rgb), .22) 0%, transparent 64%);
  animation: glowBreath 13s cubic-bezier(.45, 0, .55, 1) infinite alternate;
  transform-origin: 18% 20%;
}
@keyframes glowBreath {
  from { opacity: .5; transform: scale(.97); }
  to   { opacity: .95; transform: scale(1.06); }
}

/* Static, never animated. ART-GUIDE keeps grain in the .05 to .14 band. */
.hero-grain {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: .07;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

.eyebrow {
  display: block;
  font-family: var(--mono);
  font-size: .66rem;
  font-weight: 500;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--red-text);
  margin-bottom: 1.15rem;
}

/* css/chrome.css carries global `h1 { ... !important }` and `h2 { ... !important }`
   rules, migrated there on 2026-09-08 out of a stale inline block that used to
   win every cascade tie on 35 newsroom pages. They are element selectors, so a
   class-scoped rule outranks them, but only if it is also marked important.
   That is the only reason !important appears in this file, and it is load
   bearing: without it the h1 renders at chrome's 5rem instead of this page's
   5.4rem, and the band labels render at 48px instead of 11px.
   Do NOT fix this by editing chrome.css. Chrome drifting apart across the
   properties is the exact failure that file was written to end. */
.hero h1 {
  font-family: var(--display);
  font-weight: 300;
  font-size: clamp(2.6rem, 7.4vw, 5.4rem) !important;
  line-height: .98;
  letter-spacing: -.024em;
  max-width: 16ch;
}
.hero h1 em {
  font-style: italic;
  color: var(--red-text);
}

.lede {
  margin-top: 1.35rem;
  max-width: 54ch;
  font-size: clamp(1rem, 1.5vw, 1.15rem);
  font-weight: 300;
  line-height: 1.62;
  color: var(--dim);
}

.hero-aside {
  margin-top: 1.6rem;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .5rem 1.25rem;
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .05em;
  color: var(--faint);
}
.hero-aside a {
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid rgba(var(--red-rgb), .8);
  padding-bottom: 1px;
  transition: color .2s ease, border-color .2s ease;
}
.hero-aside a:hover { color: var(--red-text); border-color: var(--red-text); }


/* ── the doors ──────────────────────────────────────────────────────────
   Five, and they are the whole point of the redesign. A visitor who wants
   one of these five never has to look at the index below. */
.doors-band { padding-block: clamp(2.25rem, 5vw, 3.75rem); }

.band-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 1.15rem;
  border-bottom: 1px solid var(--rule);
}
.band-head h2 {
  font-family: var(--mono);
  font-size: .68rem !important;  /* see the note on .hero h1 above */
  line-height: 1.4;
  font-weight: 500;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--ink);
}
.band-head p {
  font-size: .82rem;
  color: var(--faint);
  max-width: 46ch;
  text-align: right;
}

.doors { list-style: none; }

.door + .door { border-top: 1px solid var(--rule-soft); }

.door-link {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: baseline;
  gap: 0 clamp(.9rem, 2.4vw, 2rem);
  padding-block: clamp(1.05rem, 2.4vw, 1.6rem);
  text-decoration: none;
  transition: background-color .22s ease;
}
.door-link:hover { background: rgba(var(--ink-rgb), .035); }

.door-idx {
  font-family: var(--mono);
  font-size: .72rem;
  font-weight: 500;
  letter-spacing: .1em;
  color: var(--red-text);
  align-self: center;
}
.door-body { min-width: 0; }
.door-name {
  display: block;
  font-family: var(--display);
  font-weight: 300;
  font-size: clamp(1.55rem, 3.4vw, 2.5rem);
  line-height: 1.08;
  letter-spacing: -.018em;
  transition: color .22s ease;
}
.door-link:hover .door-name { color: var(--red-text); }
.door-note {
  display: block;
  margin-top: .3rem;
  font-size: .88rem;
  font-weight: 300;
  color: var(--dim);
  max-width: 48ch;
}
.door-host {
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .04em;
  color: var(--faint);
  align-self: center;
  white-space: nowrap;
}
.ic-arrow {
  width: 18px;
  height: 18px;
  flex: none;
  align-self: center;
  color: var(--faint);
  transition: transform .22s ease, color .22s ease;
}
.door-link:hover .ic-arrow { transform: translateX(4px); color: var(--red-text); }

@media (max-width: 720px) {
  .door-link { grid-template-columns: auto 1fr auto; }
  .door-host {
    grid-column: 2;
    grid-row: 2;
    align-self: start;
    margin-top: .45rem;
  }
}


/* ── search + the index ─────────────────────────────────────────────────── */
.index-band {
  padding-block: clamp(1.5rem, 4vw, 2.5rem) clamp(3rem, 7vw, 5rem);
}

.index-tools[hidden] { display: none; }
.index-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .75rem 1rem;
  padding-block: 1.1rem;
  border-bottom: 1px solid var(--rule);
}

.search {
  position: relative;
  flex: 1 1 16rem;
  min-width: 0;
}
.search input {
  width: 100%;
  background: rgba(var(--ink-rgb), .035);
  border: 1px solid var(--rule);
  border-radius: 2px;
  color: var(--ink);
  font-family: var(--mono);
  font-size: .8rem;
  letter-spacing: .02em;
  padding: .68rem .85rem;
  transition: border-color .2s ease, background-color .2s ease;
}
.search input::placeholder { color: var(--faint); }
.search input:focus {
  outline: none;
  border-color: rgba(var(--red-rgb), .75);
  background: rgba(var(--ink-rgb), .055);
}
.search input:focus-visible { outline: 2px solid var(--red-text); outline-offset: 2px; }

.btn-plain {
  background: none;
  border: 1px solid var(--rule);
  border-radius: 2px;
  color: var(--dim);
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  padding: .68rem 1rem;
  cursor: pointer;
  transition: color .2s ease, border-color .2s ease;
}
.btn-plain:hover { color: var(--ink); border-color: rgba(var(--ink-rgb), .32); }

.count-line {
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .08em;
  color: var(--faint);
  margin-left: auto;
}

.no-results {
  padding: 2.5rem 0;
  font-family: var(--mono);
  font-size: .8rem;
  color: var(--faint);
}
.no-results[hidden] { display: none; }

.sec { border-bottom: 1px solid var(--rule); }
.sec[hidden] { display: none; }

.sec-d > summary {
  list-style: none;
  cursor: pointer;
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: 0 1.1rem;
  padding-block: clamp(1rem, 2.2vw, 1.35rem);
  transition: color .2s ease;
}
.sec-d > summary::-webkit-details-marker { display: none; }
.sec-d > summary:hover .sec-name { color: var(--red-text); }

.sec-head { min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: .3rem .8rem; }
.sec-name {
  font-family: var(--display);
  font-weight: 300;
  font-size: clamp(1.35rem, 2.6vw, 1.9rem);
  line-height: 1.1;
  letter-spacing: -.014em;
  transition: color .2s ease;
}
.sec-note {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .06em;
  color: var(--faint);
}
.sec-count {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .08em;
  color: var(--faint);
  white-space: nowrap;
}
.sec-count-n { color: var(--dim); }

.sec-caret {
  width: 11px;
  height: 11px;
  border-right: 1.5px solid var(--faint);
  border-bottom: 1.5px solid var(--faint);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .24s ease, border-color .2s ease;
}
.sec-d[open] > summary .sec-caret { transform: rotate(-135deg) translate(-3px, -3px); }
.sec-d > summary:hover .sec-caret { border-color: var(--red-text); }

.rows { list-style: none; padding-bottom: .6rem; }

.row {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: .35rem clamp(.9rem, 2.2vw, 1.75rem);
  padding-block: .85rem;
  border-top: 1px solid var(--rule-soft);
  transition: background-color .2s ease;
}
.row[hidden] { display: none; }
.row:hover { background: rgba(var(--ink-rgb), .03); }

.row-body { min-width: 0; }

/* The primary link stretches over the whole row, so the row is one big hit
   target without nesting anchors. .row-second sits above it, which is what
   lets a row carry an App Store link alongside the product's own site. */
.row-link {
  font-size: 1.02rem;
  font-weight: 500;
  text-decoration: none;
  transition: color .2s ease;
}
.row-link::after { content: ""; position: absolute; inset: 0; }
.row:hover .row-link { color: var(--red-text); }

.row-meta {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .4rem;
  margin-left: .6rem;
}

.row-owner {
  font-family: var(--mono);
  font-size: .6rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: .12rem .4rem;
}

/* Status. Red is the estate's only accent, so the three states are told
   apart by weight, alpha and a leading mark, not by inventing a green. */
.row-status {
  display: inline-flex;
  align-items: center;
  gap: .38rem;
  font-family: var(--mono);
  font-size: .6rem;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.row-status::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex: none;
}
.row-status.is-live { color: var(--ink); }
.row-status.is-live::before { background: var(--ink); }
.row-status.is-coming { color: var(--dim); }
.row-status.is-coming::before { background: none; box-shadow: inset 0 0 0 1.5px var(--dim); }
.row-status.is-hold { color: var(--faint); }
.row-status.is-hold::before { height: 1.5px; width: 8px; border-radius: 0; background: var(--faint); }

.row-note {
  display: block;
  margin-top: .22rem;
  font-size: .86rem;
  font-weight: 300;
  color: var(--dim);
  max-width: 62ch;
}

.row-tail {
  display: flex;
  align-items: center;
  gap: .9rem;
  white-space: nowrap;
}
.row-host {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .03em;
  color: var(--faint);
}
.row-second {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--dim);
  text-decoration: none;
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: .3rem .55rem;
  transition: color .2s ease, border-color .2s ease;
}
.row-second .ic-arrow { width: 13px; height: 13px; }
.row-second:hover { color: var(--red-text); border-color: rgba(var(--red-rgb), .7); }
.row-second:hover .ic-arrow { color: var(--red-text); }

.sec-foot {
  padding: .35rem 0 1.35rem;
  font-size: .82rem;
  font-weight: 300;
  color: var(--faint);
  max-width: 62ch;
}

@media (max-width: 720px) {
  .row { grid-template-columns: 1fr; }
  .row-tail { margin-top: .35rem; flex-wrap: wrap; white-space: normal; }
  .row-meta { margin-left: 0; display: flex; margin-top: .3rem; }
  .row-link { display: block; }
  .band-head { flex-direction: column; align-items: flex-start; gap: .5rem; }
  .band-head p { text-align: left; }
  .count-line { margin-left: 0; width: 100%; }
}


/* ── social accounts page ───────────────────────────────────────────────── */
.soc-band { padding-block: clamp(2rem, 5vw, 3.25rem); }
.soc-band + .soc-band { border-top: 1px solid var(--rule); }

.soc-band-head {
  font-family: var(--mono);
  font-size: .68rem !important;  /* see the note on .hero h1 above */
  line-height: 1.4;
  font-weight: 500;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--ink);
  padding-bottom: 1.15rem;
  border-bottom: 1px solid var(--rule);
  margin-bottom: .35rem;
}

/* Two companies, four platforms each. Ethan's list makes that a matched
   pair, so it is laid out as one at 900px and up rather than stacked into
   a list that hides the symmetry. */
.soc-band-company { display: grid; gap: 0 clamp(1.5rem, 4vw, 3.5rem); }
@media (min-width: 900px) {
  .soc-band-company { grid-template-columns: 1fr 1fr; }
  .soc-band-company > .soc-band-head { grid-column: 1 / -1; }
}

.soc-band-product { display: grid; gap: 0 clamp(1.5rem, 4vw, 3.5rem); }
@media (min-width: 900px) {
  .soc-band-product { grid-template-columns: 1fr 1fr; }
  .soc-band-product > .soc-band-head { grid-column: 1 / -1; }
}

.soc-group { padding-block: 1.5rem .5rem; }

.soc-group-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .35rem .8rem;
  padding-bottom: .85rem;
}

/* ── the group's own mark ───────────────────────────────────────────────
   Ethan, 2026-09-14: "for socials we need to show atcual loogs and icons
   instead of just text headers."

   TWO SIZES, BECAUSE TWO KINDS. A wordmark is wide and reads at a height; an
   app icon is square and reads at a width. Sizing both the same way makes one
   of them wrong, so they get their own rule and the alignment is set from the
   type beside them either way.

   The Labs wordmark is red ink on transparent, which is correct as-is on this
   page's bone ground: the estate's ink-ground rule re-inks it with a filter,
   and applying that here would paint it white on white. */
.soc-group-mark {
  align-self: center;
  display: block;
  flex: none;
  width: auto;
}
.soc-group-mark--wordmark { height: 1.15rem; }
.soc-group-mark--icon {
  height: 2rem;
  width: 2rem;
  border-radius: 6px;
  box-shadow: 0 0 0 1px rgba(var(--ink-rgb), .10);
}
.soc-group-name {
  font-family: var(--display);
  font-weight: 300;
  font-size: clamp(1.4rem, 2.6vw, 1.85rem);
  line-height: 1.1;
  letter-spacing: -.014em;
}
.soc-group-note,
.soc-owner {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .06em;
  color: var(--faint);
}
.soc-owner {
  text-transform: uppercase;
  letter-spacing: .1em;
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: .12rem .4rem;
}

.soc-rows { list-style: none; }
.soc-row { border-top: 1px solid var(--rule-soft); }

.soc-link {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: 0 .9rem;
  padding-block: .82rem;
  text-decoration: none;
  transition: background-color .2s ease;
}
a.soc-link:hover { background: rgba(var(--ink-rgb), .035); }

.soc-glyph { width: 17px; height: 17px; fill: currentColor; color: var(--dim); flex: none; transition: color .2s ease; }
a.soc-link:hover .soc-glyph { color: var(--red-text); }

.soc-plat { font-size: .98rem; font-weight: 500; }
.soc-handle {
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .03em;
  color: var(--faint);
  white-space: nowrap;
}
a.soc-link:hover .soc-plat { color: var(--red-text); }

/* A row whose handle has not been supplied. It renders as a row with no
   link and no destination, which is the honest shape: the account exists,
   the URL does not yet. Filling it in is an edit to data/socials.json. */
.soc-row.is-pending .soc-glyph { color: var(--faint); }
.soc-row.is-pending .soc-plat { color: var(--mute); font-weight: 400; }
.soc-handle-pending {
  font-size: .64rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
  border: 1px dashed var(--rule);
  border-radius: 2px;
  padding: .16rem .45rem;
}

/* The rule spans the full measure; the paragraph itself stays at a readable
   62ch. Putting the border on the paragraph made it stop where the text did. */
.soc-foot {
  border-top: 1px solid var(--rule);
  padding-block: clamp(2rem, 5vw, 3rem);
}
.soc-note {
  max-width: 62ch;
  font-size: .88rem;
  font-weight: 300;
  color: var(--dim);
}
.soc-note strong { font-weight: 500; color: var(--ink); }
.soc-note a { color: var(--ink); border-bottom: 1px solid rgba(var(--red-rgb), .8); text-decoration: none; }
.soc-note a:hover { color: var(--red-text); border-color: var(--red-text); }

@media (max-width: 560px) {
  .soc-link { grid-template-columns: auto 1fr auto; }
  /* justify-self, or the grid stretches the bordered pending chip across the
     whole row and it stops reading as a chip. */
  .soc-handle { grid-column: 2 / -1; grid-row: 2; margin-top: .2rem; justify-self: start; }
}

/* ══════════════════════════════════════════════════════════════════════
   THE PALMS, LAYERED INTO THE PAGE
   ----------------------------------------------------------------------
   Ethan, 2026-09-14: "i wnat paym tree slayerd into backhorund not used as
   app images." The first pass put a frame on each site door, which is a
   thumbnail, not a background. This is the background: one photograph behind
   the whole page, fixed, with a bone veil over it, so scrolling moves the
   type across a still picture.

   NOT background-attachment: fixed. That property repaints on every scroll
   frame on mobile Safari and cannot be feature-tested away; the estate's own
   backdrop.css carries the same note. A position: fixed layer costs nothing
   per frame because it never moves.

   WHY IT IS A PAIR OF PSEUDO-ELEMENTS and not markup: nothing here is content,
   nothing needs alt text, and both pages get it from one rule rather than from
   a partial that has to stay in sync.

   THE VEIL IS DERIVED FROM THE WEAKEST TYPE ON THE PAGE, not chosen. The plate
   measures mean 93, p10 3 (the palm silhouettes) and p90 200 (sky). Composited
   bone-over-photo, --faint, the lowest token here, measures against its own
   ground:

       photo pixel     veil .94   veil .86   veil .82
       3 (silhouette)    5.66       5.25       5.03
       93 (mean)         5.77       5.52       5.39
       200 (sky)         5.90       5.82       5.78

   So even the darkest frond under the most open veil clears 4.5 with room.
   .88 easing to .96 is what shipped: strongest where the type is densest,
   most open at the top right, which is where the plate's own sky already is.
   ══════════════════════════════════════════════════════════════════════ */

body::before,
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

body::before {
  background-image: url("/assets/palms/palms-ground.jpg");
  background-size: cover;
  background-position: 62% 18%;
  /* Eased, never full. The page has one accent and a fully saturated palm is
     a second one. */
  filter: saturate(.72) contrast(1.02);
}

body::after {
  /* ONE gradient, not two. The first pass stacked a radial over a linear and
     they MULTIPLY: .88 under .80 composites to .976, which is why the
     photograph was measurably present and visually absent. Everything the
     table above says about .82 was true and none of it was reaching the page.

     So: a single radial anchored to the top right, where the hero leaves the
     frame empty. .46 in the corner, up to .82 by the time it reaches anything
     set in type, which is the measured floor for --faint over the darkest
     frond (4.92:1 at .80, 4.45:1 at .72, so .80 is where it stops). */
  background:
    radial-gradient(135% 105% at 92% 0%,
      rgba(var(--bone-rgb), .46) 0%,
      rgba(var(--bone-rgb), .62) 18%,
      rgba(var(--bone-rgb), .82) 44%,
      rgba(var(--bone-rgb), .90) 72%,
      rgba(var(--bone-rgb), .95) 100%);
}

/* Below `lg` the copy runs the full width, so there is no empty region for a
   picture to live in and every line of type crosses the whole frame. The plate
   stays, one step further back, as texture rather than as a photograph. */
@media (max-width: 60rem) {
  body::after {
    background:
      radial-gradient(150% 60% at 100% 0%,
        rgba(var(--bone-rgb), .70) 0%,
        rgba(var(--bone-rgb), .88) 34%,
        rgba(var(--bone-rgb), .95) 70%,
        rgba(var(--bone-rgb), .975) 100%);
  }
}


/* ── SUBLINKS UNDER A ROW ────────────────────────────────────────────────
   Ethan, 2026-09-14: "yoou need sections to be more dyamnic/ better roahnzie
   of main links and sublinks".

   A property is not one link. tnaado.com alone has nine pages worth listing
   and the directory carried a single row for the whole site, which is why it
   kept reading as incomplete however many hosts were added to it.

   THEY SIT ABOVE THE ROW'S OWN STRETCHED HIT AREA. .row-link::after covers
   the whole row so the row is one big target; a child link inside that area
   would be unclickable without raising it, which is the same device
   .row-second already uses. Hence the z-index and the position.

   Mono and small on purpose: these are addresses, not names, and they must
   not compete with the row's own title. */
.row-kids {
  position: relative;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  gap: .3rem .4rem;
  margin-top: .5rem;
}
.row-kid {
  font-family: var(--mono);
  font-size: .62rem;
  letter-spacing: .04em;
  color: var(--mute);
  text-decoration: none;
  padding: .16rem .42rem;
  border: 1px solid var(--rule);
  border-radius: 2px;
  background: rgba(var(--bone-rgb), .5);
  transition: color .18s ease, border-color .18s ease, background-color .18s ease;
}
.row-kid:hover,
.row-kid:focus-visible {
  color: var(--ink);
  border-color: rgba(var(--ink-rgb), .38);
  background: rgba(var(--bone-rgb), .85);
}


/* ══════════════════════════════════════════════════════════════════════
   THE DIRECTORY, TWO PANES
   ----------------------------------------------------------------------
   Ethan, 2026-09-14: "the scroll display needs on the left maincatagroies
   like comany and then scroll on the right", after "the way links are layed
   out its just overleming they need goruping and catagoriation".

   Forty-five links down one column is a wall however many headings are in
   it. The rail on the left holds the two companies and their categories and
   stays put; the links scroll past on the right.

   THE RAIL IS REAL NAVIGATION. Every item is an anchor to an id that exists,
   so it works with the script blocked. js/links.js only adds the highlight.

   `align-self: start` is load bearing: a grid item stretches to the row's
   height by default and a stretched item cannot stick.
   ══════════════════════════════════════════════════════════════════════ */

.dir {
  display: grid;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: start;
}
@media (min-width: 64rem) {
  .dir { grid-template-columns: minmax(12rem, 15rem) minmax(0, 1fr); }
}

.dir-rail {
  align-self: start;
  min-width: 0;
}
@media (min-width: 64rem) {
  .dir-rail { position: sticky; top: calc(var(--tnc-header-h, 96px) + 1.25rem); }
}

.dir-rail-co + .dir-rail-co { margin-top: 1.35rem; }

.dir-rail-head {
  display: flex;
  align-items: baseline;
  gap: .45rem;
  font-family: var(--mono);
  font-size: .64rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
  padding-bottom: .5rem;
  border-bottom: 1px solid var(--rule);
}
.dir-rail-head i { font-style: normal; color: var(--faint); letter-spacing: .1em; }
.dir-rail-dot { width: 7px; height: 7px; flex: none; align-self: center; }
.dir-rail-dot--ca { background: var(--red); }
.dir-rail-dot--us { background: #1466b5; }
.dir-rail-dot--none { background: var(--faint); }

.dir-rail-list { list-style: none; margin-top: .35rem; }
.dir-rail-list a {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .5rem;
  font-size: .84rem;
  color: var(--mute);
  text-decoration: none;
  padding: .3rem 0;
  border-left: 2px solid transparent;
  padding-left: .6rem;
  margin-left: -.6rem;
  transition: color .18s ease, border-color .18s ease;
}
.dir-rail-list a b { font-family: var(--mono); font-size: .62rem; font-weight: 400; color: var(--faint); }
.dir-rail-list a:hover { color: var(--ink); }
/* The reader's position, written by js/links.js. */
.dir-rail-list a.is-here { color: var(--ink); border-left-color: var(--red); }
.dir-rail-list a.is-here b { color: var(--mute); }

/* ── the right pane ─────────────────────────────────────────────────── */
.dir-body { min-width: 0; }

.dir-co + .dir-co { margin-top: clamp(2.5rem, 6vw, 4.5rem); }

.dir-co-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .3rem .75rem;
  padding: .55rem 0 .75rem;
  border-top: 2px solid var(--ink);
}
/* The company's own colour, the same pair the header rail uses, as a 2px
   edge rather than a fill: a filled band per company would put two big
   coloured blocks in the middle of a white page and fight the photograph. */
.dir-co-head--ca { border-top-color: var(--red); }
.dir-co-head--us { border-top-color: #1466b5; }
.dir-co-head h2 {
  font-family: var(--display);
  font-weight: 300;
  font-size: clamp(1.5rem, 3vw, 2.1rem);
  letter-spacing: -.016em;
  line-height: 1.1;
}
.dir-co-head span {
  font-family: var(--mono);
  font-size: .62rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--faint);
}
.dir-co-head p { flex: 1 1 100%; font-size: .88rem; color: var(--mute); }

.grp { scroll-margin-top: calc(var(--tnc-header-h, 96px) + 1.25rem); }
.grp + .grp { margin-top: 1.9rem; }

.grp-head {
  display: flex;
  align-items: baseline;
  gap: .3rem .7rem;
  flex-wrap: wrap;
  padding-bottom: .4rem;
  border-bottom: 1px solid var(--rule);
}
.grp-label {
  font-family: var(--mono);
  font-size: .68rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--red-text);
}
.grp-note { font-size: .78rem; color: var(--faint); flex: 1 1 auto; }
.grp-count { font-family: var(--mono); font-size: .62rem; color: var(--faint); }

/* The rows themselves are unchanged; only what wraps them moved. */
