/* ------------------------------------------------------------------
   solomondworsky.com

   STRUCTURE from the editorial reference (solomon-dworsky_4.html):
   hairline rules instead of boxes, nothing in a tinted panel, a narrow
   measure inside a wide container, large quiet figures, 2px controls.
   That is also what BUILD-PACKAGE section 1 asked for, so the two now
   agree and the earlier bands-and-cards override is retired.

   TOKENS from ArGaze / tryswd (BRAND-GUIDELINES sections 4 and 5):
   navy #1f3c7a in place of the reference's green, and Fraunces / Inter /
   JetBrains Mono in place of Palatino and the system stacks.

   Light only. The brand has no dark theme; ArGaze pins color-scheme
   because dark mode put navy headings on near-black (08-GAP-01). The
   reference ships a dark palette, deliberately not carried over.
   See BUILD-CONFLICTS.md.
   ------------------------------------------------------------------ */

:root {
  /* Surface and ink: ArGaze values in the reference's roles. */
  --paper:       #ffffff;
  --paper-2:     #f5f6fa;
  --ink:         #101728;
  --ink-2:       #3f4859;
  --ink-3:       #606a80;
  --rule:        #d6dae4;
  --rule-2:      #e0e3eb;
  --accent:      #1f3c7a;
  --accent-2:    #254b9d;
  --accent-soft: #f0f3fa;

  /* Type families, BRAND-GUIDELINES section 5. */
  --serif: 'Fraunces', ui-serif, Georgia, Cambria, 'Times New Roman', serif;
  --sans:  'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
           'Helvetica Neue', Arial, sans-serif;
  --mono:  'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --measure: 38rem;
  --maxw:    74rem;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: 5.5rem;
  -webkit-text-size-adjust: 100%;
  max-width: 100vw;
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  /* Fluid and materially larger than the previous 15px base, which was too
     small for sustained reading. */
  font-size: clamp(18px, 0.6vw + 16px, 21px);
  line-height: 1.62;
  font-kerning: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  max-width: 100vw;
  overflow-x: clip;
  overflow-wrap: break-word;
}

::selection { background: var(--accent-soft); }

.wrap {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 clamp(1.25rem, 4vw, 3.5rem);
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  padding: 0.6rem 1rem;
  background: var(--paper);
  color: var(--accent);
  border: 1px solid var(--rule);
  border-radius: 2px;
  z-index: 60;
}
.skip:focus { left: 1rem; top: 1rem; }

/* --- Header ---------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(160%) blur(12px);
  -webkit-backdrop-filter: saturate(160%) blur(12px);
  border-bottom: 1px solid var(--rule-2);
}

.site-header .wrap {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  padding-top: 0.85rem;
  padding-bottom: 0.85rem;
}

.site-name {
  font-family: var(--serif);
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
  color: var(--ink);
  text-decoration: none;
}

.site-nav { display: flex; gap: 1.2rem; flex-wrap: wrap; justify-content: flex-end; }
.site-nav a {
  font-family: var(--sans);
  font-size: 0.84rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
  text-decoration: none;
  padding-bottom: 2px;
  border-bottom: 1.5px solid transparent;
  transition: color 0.18s var(--ease), border-color 0.18s var(--ease);
}
.site-nav a:hover { color: var(--ink); }
.site-nav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--accent); }

@media (max-width: 900px) {
  .site-nav { display: none; }
  .site-header .wrap { justify-content: center; }
}

/* --- Sections: rules, not bands -------------------------------------- */
/* `.band` is kept as a class name so the content fragments did not need
   rewriting, but it no longer paints a background. Separation is a hairline
   rule plus vertical space. */

.band {
  padding: clamp(3.2rem, 6vw, 5.5rem) 0;
  border-top: 1px solid var(--rule-2);
  background: none;
}
main > .band:first-child { border-top: 0; padding-top: clamp(3rem, 8vw, 6.5rem); }

/* --- Type ------------------------------------------------------------- */

h1, h2, h3 {
  margin: 0;
  font-family: var(--serif);
  font-optical-sizing: auto;
  font-weight: 600;
  line-height: 1.16;
  letter-spacing: -0.012em;
  color: var(--ink);
}

h1 {
  font-size: clamp(2.5rem, 5.6vw, 4rem);
  letter-spacing: -0.028em;
  margin-bottom: 0.9rem;
  text-wrap: balance;
}

h2, .page-heading {
  font-size: clamp(1.7rem, 2.9vw, 2.3rem);
  letter-spacing: -0.021em;
  max-width: 40rem;
  margin: 0 0 1.2rem;
}

h3 { font-size: clamp(1.15rem, 1.65vw, 1.36rem); margin: 2.4rem 0 0.7rem; }

p { margin: 0 0 1.15em; max-width: var(--measure); }

a { color: var(--accent); text-underline-offset: 2px; text-decoration-thickness: 1px; }
a:hover { color: var(--accent-2); }

strong { font-weight: 640; color: var(--ink); }

/* Section label. Was 0.78rem uppercase mono with 0.16em tracking, which was
   too small and too spaced to read at arm's length on a phone. Now the same
   serif as the headings, at heading scale, sentence case. It labels a section
   and is meant to be read, not decoded. */
.section-eyebrow, .eyebrow {
  display: block;
  margin: 0 0 1rem;
  font-family: var(--serif);
  font-size: clamp(1.15rem, 1.65vw, 1.36rem);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.012em;
  text-transform: none;
  color: var(--ink);
  max-width: none;
}

.role-line {
  font-family: var(--sans);
  font-size: 0.78rem;
  font-weight: 640;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 1.7rem;
  max-width: none;
}

.deck {
  font-family: var(--serif);
  font-size: clamp(1.45rem, 2.3vw, 1.95rem);
  line-height: 1.42;
  font-weight: 500;
  letter-spacing: -0.011em;
  max-width: 43rem;
  margin: 0 0 1.7rem;
  color: var(--ink);
}

.measure { max-width: 40rem; }
.measure p { color: var(--ink-2); max-width: 40rem; }
.section-intro { color: var(--ink-2); max-width: 40rem; }

.small-print, .note {
  font-family: var(--sans);
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--ink-3);
  max-width: 46rem;
}

.stat-line {
  display: block;
  font-family: var(--mono);
  font-size: 0.82rem;
  letter-spacing: 0.02em;
  color: var(--ink-3);
  margin: 0.15rem 0 0.8rem;
  line-height: 1.7;
  max-width: none;
}

/* Chip is metadata, not a control. The bordered box wrapped onto its own line
   under the heading and read as an empty text input. Now a quiet mono line
   that sits under the heading on purpose. */
.chip {
  display: block;
  margin: 0.35rem 0 0;
  font-family: var(--mono);
  font-size: 0.76rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
  border: 0;
  padding: 0;
  white-space: normal;
}

/* --- Mission ---------------------------------------------------------- */

.mission { border-left: 2px solid var(--accent); padding-left: 1.2rem; max-width: 42rem; }
.mission p { margin: 0; color: var(--ink-2); max-width: none; }

/* --- Buttons: 2px, quiet ---------------------------------------------- */

.cta-row { display: flex; gap: 0.7rem; flex-wrap: wrap; margin-top: 1.9rem; }

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--sans);
  font-size: 0.95rem;
  font-weight: 560;
  text-decoration: none;
  color: var(--ink);
  background: none;
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: 0.6rem 1.1rem;
  cursor: pointer;
  transition: background 0.18s var(--ease), border-color 0.18s var(--ease);
}
.btn:hover { background: var(--paper-2); border-color: var(--ink-3); }

.btn-primary { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.btn-primary:hover { background: var(--accent); border-color: var(--accent); color: var(--paper); }

.btn-ghost { color: var(--ink); }
.btn-disabled { color: var(--ink-3); cursor: default; }
.btn-disabled:hover { background: none; border-color: var(--rule); }
.btn .meta { font-family: var(--mono); font-size: 0.82rem; opacity: 0.8; }

/* --- Proof strip ------------------------------------------------------ */

.proof-strip { display: grid; grid-template-columns: repeat(2, 1fr); border-top: 1px solid var(--rule); }
.proof { padding: 1.6rem 1.5rem 1.5rem 0; border-bottom: 1px solid var(--rule-2); }
.proof:nth-child(even) { padding-left: 1.5rem; border-left: 1px solid var(--rule-2); }

.proof-figure {
  display: block;
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(2.1rem, 3.6vw, 3rem);
  letter-spacing: -0.028em;
  font-variant-numeric: tabular-nums;
  margin-bottom: 0.35rem;
  color: var(--ink);
}
.proof-label {
  display: block;
  font-family: var(--sans);
  font-size: 0.9rem;
  line-height: 1.45;
  color: var(--ink-3);
  max-width: 20rem;
}

@media (max-width: 600px) {
  .proof-strip { grid-template-columns: 1fr; }
  .proof, .proof:nth-child(even) { padding: 1.3rem 0; border-left: 0; }
}

/* --- Destinations ----------------------------------------------------- */

.destinations { border-top: 1px solid var(--rule); }
.destination {
  display: flex;
  gap: 1.15rem;
  align-items: baseline;
  padding: 1.25rem 0;
  border-bottom: 1px solid var(--rule-2);
  text-decoration: none;
  max-width: 46rem;
}
/* The number is what separates this index from the proof strip above it. Both
   were hairline rows with a trailing arrow and read as the same component. */
.destination-index {
  flex: 0 0 auto;
  font-family: var(--mono);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
  opacity: 0.7;
  transition: color .2s var(--ease), opacity .2s var(--ease);
}
.destination:hover .destination-index,
.destination:focus-visible .destination-index { color: var(--accent); opacity: 1; }
.destination-body { display: block; min-width: 0; }
.destination-label {
  display: block;
  font-family: var(--sans);
  font-size: 1.12rem;
  font-weight: 640;
  color: var(--ink);
}
.destination:hover .destination-label { color: var(--accent); }
.destination-desc {
  display: block;
  margin-top: 0.25rem;
  font-family: var(--sans);
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--ink-3);
}

/* --- Expandable entries ------------------------------------------------ */

/* Reviewer note: the pages read as walls to be got through rather than
   material to be found in. Each entry now shows its heading, its numbers and
   one line, and opens on click. Native <details>, so it works with no JS, is
   keyboard operable, announces its own state to screen readers, and keeps the
   full text in the HTML for crawlers. ui.js forces every one open before
   printing. */
details.entry > summary {
  list-style: none;
  cursor: pointer;
  display: block;
  position: relative;
  padding-right: 6.5rem;
}
details.entry > summary::-webkit-details-marker { display: none; }
details.entry > summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
}

.entry-lede { display: block; color: var(--ink-2); max-width: 44rem; margin-top: 0.5rem; }

/* The control reads as a word rather than a glyph: a bare chevron next to a
   serif heading looked like decoration, and nothing said it was clickable. */
.entry-more {
  position: absolute; right: 0; top: 0.15rem;
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
  transition: color .18s var(--ease);
}
.entry-more::after {
  content: '+';
  font-size: 0.95rem;
  line-height: 1;
  transition: transform .22s var(--ease);
}
details.entry[open] > summary .entry-more::after { transform: rotate(45deg); }
details.entry > summary:hover .entry-more,
details.entry[open] > summary .entry-more { color: var(--accent); }
details.entry[open] > summary .entry-more .label-closed { display: none; }
details.entry:not([open]) > summary .entry-more .label-open { display: none; }

.entry-detail { padding-top: 1.1rem; }
.entry-detail > :first-child { margin-top: 0; }

/* Progressive enhancement: browsers supporting ::details-content animate the
   open. Everywhere else it simply snaps, which is the native behaviour. */
@supports selector(details::details-content) {
  :root { interpolate-size: allow-keywords; }
  details.entry::details-content {
    block-size: 0;
    overflow: hidden;
    opacity: 0;
    transition: block-size .32s var(--ease), opacity .26s var(--ease),
                content-visibility .32s allow-discrete;
  }
  details.entry[open]::details-content { block-size: auto; opacity: 1; }
}

@media (max-width: 600px) {
  /* The label would crowd the heading at this width; the sign carries it. */
  details.entry > summary { padding-right: 2.2rem; }
  .entry-more span { display: none; }
}

/* --- Entries ---------------------------------------------------------- */

/* Sibling-based rather than :first-of-type, which keys off element type and
   broke when entries became <details> alongside <article>. */
.entry { padding: 1.9rem 0; border-top: 1px solid var(--rule); }
.entry + .entry { border-top-color: var(--rule-2); }
.entry h2, .entry h3 {
  font-family: var(--serif);
  font-size: clamp(1.15rem, 1.65vw, 1.36rem);
  margin: 0 0 0.7rem;
  max-width: none;
}
.entry p { margin-bottom: 0; color: var(--ink-2); max-width: 44rem; }
.entry p + p { margin-top: 0.85em; }
/* Entries that mix prose and bullets: .entry p zeroes margin-bottom and
   .lead-in-list zeroes margin-top, so without these a p -> ul -> p run sits
   flush with no gap at either seam. */
.entry p + .lead-in-list,
.entry .lead-in-list + p { margin-top: 0.85em; }
.entry .lead-in-list:last-child { margin-bottom: 0; }
.entry-list { list-style: none; margin: 0; padding: 0; }

/* --- Lists and quotes -------------------------------------------------- */

.lead-in-list { padding-left: 1.05rem; margin: 0 0 1.15em; max-width: 45rem; }
.lead-in-list li { margin-bottom: 0.65em; color: var(--ink-2); line-height: 1.5; }
.lead-in-list li:last-child { margin-bottom: 0; }
.lead-in-list li::marker { color: var(--ink-3); }

blockquote { border-left: 2px solid var(--accent); margin: 1.7rem 0; padding: 0.1rem 0 0.1rem 1.2rem; }
blockquote, blockquote p {
  font-family: var(--serif);
  font-style: italic;
  color: var(--ink-2);
  margin: 0;
  max-width: 42rem;
}

/* --- Tables: ruled, not boxed ----------------------------------------- */

.table-wrap { margin: 0 0 1.4rem; }

table.ruled {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--sans);
  font-size: 0.98rem;
  line-height: 1.5;
}
table.ruled th {
  text-align: left;
  font-weight: 640;
  font-size: 0.78rem;
  letter-spacing: 0.085em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 0 1.3rem 0.7rem 0;
  border-bottom: 1px solid var(--rule);
}
table.ruled th:last-child, table.ruled td:last-child { padding-right: 0; }
table.ruled td {
  padding: 0.9rem 1.3rem 0.9rem 0;
  border-bottom: 1px solid var(--rule-2);
  color: var(--ink-2);
  vertical-align: top;
}
table.ruled td:first-child { color: var(--ink); font-weight: 560; width: 15rem; }
table.ruled.figures td:last-child {
  text-align: right;
  font-family: var(--mono);
  font-size: 0.8rem;
  color: var(--ink);
  white-space: nowrap;
}
table.ruled.figures td:first-child { width: auto; font-weight: 400; color: var(--ink-2); }

@media (max-width: 720px) {
  table.ruled:not(.figures),
  table.ruled:not(.figures) tbody,
  table.ruled:not(.figures) tr,
  table.ruled:not(.figures) td { display: block; width: 100%; }
  table.ruled:not(.figures) thead { display: none; }
  table.ruled:not(.figures) tr { border-bottom: 1px solid var(--rule-2); padding: 1rem 0; }
  table.ruled:not(.figures) td { border: 0; padding: 0.15rem 0; }
  table.ruled:not(.figures) td:first-child { width: auto; font-weight: 640; margin-bottom: 0.25rem; }
}

/* --- Specimens (Work Examples) ---------------------------------------- */

.specimen-list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--rule); }
.specimen {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1.5rem 0;
  border-bottom: 1px solid var(--rule-2);
}
.specimen-body { flex: 1 1 20rem; }
.specimen h3 { margin: 0 0 0.35rem; }
.specimen p { margin: 0 0 0.35rem; color: var(--ink-2); max-width: 40rem; }
.specimen .tags { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.5rem; }
.specimen .tags span {
  font-family: var(--mono);
  font-size: 0.76rem;
  color: var(--ink-3);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: 0.2rem 0.45rem;
}

/* --- Page nav (Home and Continue) -------------------------------------- */

.page-nav .wrap { display: flex; flex-direction: column; gap: 1.5rem; }
.home-control { align-self: flex-start; }
.continue { border-top: 1px solid var(--rule-2); padding-top: 1rem; }
.continue a {
  display: inline-block;
  margin: 0 1.2rem 0.5rem 0;
  font-family: var(--sans);
  font-size: 0.9rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
  text-decoration: none;
}
.continue a:hover { color: var(--ink); }

/* --- Contact and footer ------------------------------------------------ */

.contact-name { font-family: var(--serif); font-size: 1.15rem; font-weight: 600; color: var(--ink); margin: 0 0 0.5rem; }
.contact-links { font-family: var(--sans); font-size: 1rem; color: var(--ink-3); margin: 0 0 0.8rem; max-width: none; }
.contact-links .pending { color: var(--ink-3); }
.contact-blurb { font-family: var(--sans); font-size: 0.95rem; color: var(--ink-3); max-width: 40rem; margin: 0; }

.site-footer { border-top: 1px solid var(--rule-2); padding: 2.5rem 0 3.5rem; }
.site-footer p {
  font-family: var(--sans);
  font-size: 0.85rem;
  color: var(--ink-3);
  line-height: 1.6;
  max-width: 46rem;
  margin: 0 0 0.5em;
}

/* --- Download gate ----------------------------------------------------- */

.gate {
  width: min(440px, calc(100vw - 2rem));
  padding: 2rem;
  border: 1px solid var(--rule);
  border-radius: 2px;
  background: var(--paper);
  color: var(--ink);
}
.gate::backdrop { background: rgba(16, 23, 40, 0.5); }
.gate h2 { font-size: 1.4rem; margin: 0 0 0.5rem; max-width: none; }
.gate-intro { font-family: var(--sans); font-size: 0.95rem; color: var(--ink-3); margin: 0 0 1.5rem; }
.gate-close-form { margin: 0; }
.gate-close {
  position: absolute; top: 0.75rem; right: 0.75rem;
  width: 2rem; height: 2rem; border: 0; background: none;
  color: var(--ink-3); font-size: 1.4rem; line-height: 1; cursor: pointer;
}
.gate-close:hover { color: var(--ink); }
.gate label { display: block; margin-bottom: 0.35rem; font-family: var(--sans); font-size: 0.9rem; font-weight: 640; }
.gate input[type="email"], .gate input[type="url"], .gate input[type="text"] {
  width: 100%;
  padding: 0.65rem 0.75rem;
  border: 1px solid var(--rule);
  border-radius: 2px;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  /* 16px minimum, or iOS Safari zooms the page on focus. */
  font-size: 16px;
}
.gate input:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent); }
.gate input[aria-invalid="true"] { border-color: #b3261e; }
.field-err { min-height: 1rem; margin: 0.25rem 0 0.9rem; font-family: var(--sans); font-size: 0.85rem; color: #b3261e; }
.gate .btn { width: 100%; justify-content: center; margin-top: 0.5rem; }
.gate .btn:disabled { opacity: 0.6; cursor: default; }
.gate-toggle {
  display: flex; align-items: center; gap: 0.5rem;
  margin: 0.25rem 0 1rem;
  font-family: var(--sans); font-size: 0.9rem; font-weight: 400; color: var(--ink-3); cursor: pointer;
}
.gate-toggle input { width: 1rem; height: 1rem; margin: 0; accent-color: var(--accent); flex: 0 0 auto; }
#gate-code { font-family: var(--mono); font-size: 1.3rem; letter-spacing: 0.3em; text-align: center; }
.gate-status { margin: 0.75rem 0 0; font-family: var(--sans); font-size: 0.95rem; text-align: center; }
.gate-status.is-ok { color: var(--accent); font-weight: 600; }
.gate-status.is-error { color: #b3261e; }
.gate-privacy {
  margin: 1rem 0 0; padding-top: 1rem; border-top: 1px solid var(--rule-2);
  font-family: var(--sans); font-size: 0.82rem; color: var(--ink-3); text-align: center;
}
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* --- Focus, motion, print ---------------------------------------------- */

a:focus-visible, .btn:focus-visible, button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition: none !important; animation: none !important; }
}

@media print {
  .site-header, .page-nav, .skip { display: none; }
  body { background: #fff; color: #000; font-size: 10.5pt; }
  .band { break-inside: avoid; border-top: 1px solid #ccc; padding: 1.1rem 0; }
  h1, h2, h3 { break-after: avoid; }
  a { color: #000; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #555; }
}

/* ------------------------------------------------------------------
   Interaction layer (ui.js)
   All motion gated on prefers-reduced-motion. Reveal styles apply only
   under .js-reveal, which ui.js sets after wiring the observer, so a
   blocked script can never leave content permanently hidden.
   ------------------------------------------------------------------ */

.progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 60;
  background: var(--accent); transform: scaleX(0); transform-origin: 0 50%;
  will-change: transform; pointer-events: none;
}

.js-reveal .band > .wrap > * {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .5s var(--ease), transform .5s var(--ease);
  transition-delay: var(--reveal-delay, 0ms);
}
.js-reveal .band > .wrap > .is-in { opacity: 1; transform: none; }

.to-top {
  position: fixed; right: clamp(1rem, 3vw, 2rem); bottom: clamp(1rem, 3vw, 2rem);
  width: 2.6rem; height: 2.6rem; z-index: 55;
  display: grid; place-items: center;
  border: 1px solid var(--rule); border-radius: 2px;
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter: blur(8px);
  color: var(--ink-3); font-size: 1rem; cursor: pointer;
  opacity: 0; visibility: hidden; transform: translateY(6px);
  transition: opacity .22s var(--ease), transform .22s var(--ease),
              visibility .22s, color .18s, border-color .18s;
}
.to-top.is-shown { opacity: 1; visibility: visible; transform: none; }
.to-top:hover { color: var(--ink); border-color: var(--ink-3); }

@media (max-width: 600px) {
  /* Lifted clear of the browser's own bottom toolbar, which on iOS Safari
     overlays the viewport and sat directly under the button. env() resolves
     to 0 unless the viewport meta opts into viewport-fit=cover, so max()
     keeps a usable floor on every device either way. */
  .to-top {
    bottom: max(1.6rem, calc(env(safe-area-inset-bottom, 0px) + 0.9rem));
  }
}

/* Back to top crossfades rather than scrolling. A native smooth scroll from the
   foot of Projects covers ~7,700px and blurs past every section on the way, so
   the page fades out, jumps instantly, and fades back in at the top. Fade-out
   is quicker than fade-in: leaving feels immediate, arriving feels settled.
   The fixed controls are excluded so the button does not blink out under the
   cursor that just pressed it. Duration is mirrored by WARP_MS in ui.js. */
body > header, body > main, body > footer {
  transition: opacity .28s var(--ease);
}
body.is-warping > header,
body.is-warping > main,
body.is-warping > footer {
  opacity: 0;
  transition-duration: .2s;
}

/* Sits on the text baseline rather than floating mid-line, and says what it
   copies: a bare "COPY" beside three links did not identify its target. */
.copy-email {
  margin-left: .4rem;
  vertical-align: baseline;
  font-family: var(--mono); font-size: .62rem; letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-3); background: none;
  border: 1px solid var(--rule); border-radius: 2px;
  padding: .12rem .4rem; cursor: pointer;
  transition: color .18s var(--ease), border-color .18s var(--ease);
}
.copy-email:hover { color: var(--ink); border-color: var(--ink-3); }
.copy-email.is-done { color: var(--accent); border-color: var(--accent); }

/* Destination rows: the arrow is the click affordance. */
.destination { position: relative; padding-right: 2rem; }
/* Arrow is ALWAYS visible: it is the only signal these rows are links, and
   hover is not a signal that exists on touch at all. It moves and darkens on
   hover rather than appearing from nothing. */
.destination::after {
  content: '\2192'; position: absolute; right: .5rem; top: 1.4rem;
  font-size: 1.1rem; line-height: 1;
  color: var(--ink-3); opacity: .75;
  transition: opacity .2s var(--ease), transform .2s var(--ease), color .2s var(--ease);
}
.destination:hover::after,
.destination:focus-visible::after { opacity: 1; transform: translateX(4px); color: var(--accent); }

/* Table rows respond to the cursor so long tables stay trackable. */
table.ruled tbody tr { transition: background .15s var(--ease); }
table.ruled tbody tr:hover { background: var(--paper-2); }

/* Entries lift their rule on hover: a hairline cue, not a card. */
.entry { transition: border-color .2s var(--ease); }
.entry:hover { border-top-color: var(--rule); }

@media (prefers-reduced-motion: reduce) {
  .progress { display: none; }
  .js-reveal .band > .wrap > * { opacity: 1; transform: none; transition: none; }
  .to-top { transition: opacity .01ms; }
  .destination::after { transition: none; }
  .destination-index { transition: none; }
  /* ui.js skips the crossfade entirely under reduced motion; this covers the
     class being applied by anything else. */
  body > header, body > main, body > footer { opacity: 1; transition: none; }
}

@media print { .progress, .to-top, .copy-email { display: none; } }
/* Proof figures link to the page that substantiates them. Each carries a
   visible arrow so the affordance does not depend on hover, which does not
   exist on touch. */
a.proof {
  display: block; position: relative; text-decoration: none; color: inherit;
  padding-right: 2rem;
  transition: background .18s var(--ease);
}
a.proof::after {
  content: '\2192'; position: absolute; right: .6rem; top: 1.7rem;
  font-size: 1rem; color: var(--ink-3); opacity: .7;
  transition: transform .2s var(--ease), color .2s var(--ease), opacity .2s var(--ease);
}
a.proof:hover { background: var(--paper-2); }
a.proof:hover .proof-figure { color: var(--accent); }
a.proof:hover::after { opacity: 1; color: var(--accent); transform: translateX(4px); }