/* ═══════════════════════════════════════════════════════════════════════════
   Grey Café

   Text sits directly on the paper — all of it, now including the masthead and
   the footer, which were the last two glass panels and are flat. Nothing on
   the page is fixed or sticky, so nothing overlays anything. The page is type,
   hairlines and one photograph, with structure carried by alignment and space
   rather than by panels.

   Corners are 2px. Motion is coupled to scroll position, and no text moves.
   ═══════════════════════════════════════════════════════════════════════════ */

:root{
  color-scheme: light only;              /* Chrome auto-dark must not invert a white site */

  /* ── ground ──────────────────────────────────────────────── */
  --paper:       #F4F6F8;   /* L* 96.79 — page base. Never #fff anywhere. */
  --paper-lift:  #F8FAFB;
  --paper-deep:  #EDF0F4;

  /* ── ink ─────────  contrast ratio on --paper ────────────── */
  --ink:    #1A1D21;   /* 15.61:1 */
  --ink-2:  #4A515A;   /*  7.41:1 */
  --ink-3:  #5C6472;   /*  5.51:1  ← palest text on the site */

  /* ── the one light source ────────────────────────────────── */
  --gold:       #E8B66A;   /* LIGHT ONLY. 1.9:1 — never a glyph. Three uses total. */
  --gold-ink:   #8A5A12;   /* 5.46:1 — the only gold that carries meaning */

  /* ── chrome ──
     The masthead and the footer were the last two glass panels on the site.
     Both are flat now: they sit in the flow on the paper with everything else,
     so there is nothing behind either one to refract and nothing to float
     over. --chrome-rule survives only because .skip still borders with it. */
  --chrome-rule: rgba(20,30,46,.20);

  /* ── structure ───────────────────────────────────────────── */
  --shell:      1280px;
  --gutter:     clamp(16px, 3vw, 32px);
  --sec-lead:   clamp(48px, 5vw, 80px);      /* above a section's opening rule */
  --sec-trail:  clamp(72px, 7.5vw, 116px);   /* below its last element */
  --air-lg:     clamp(36px, 4.4vw, 64px);
  --air-md:     clamp(20px, 2.4vw, 32px);
  --air-sm:     16px;
  --rail:       clamp(104px, 12vw, 144px);
  --hair:       rgba(20,30,46,.13);
  --masthead:   56px;

  --r-tag: 2px;  --r-focus: 2px;

  /* ── type ────────────────────────────────────────────────── */
  --sans:  "Archivo", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --serif: "Cormorant Garamond", ui-serif, Georgia, "Times New Roman", serif;
  --mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --t-hero:  clamp(4rem, 10.5vw, 9rem);    /* stacking frees the width the serif wanted */
  --t-h2:    clamp(1.75rem, 3vw, 2.375rem);
  --t-line:  clamp(1.375rem, 2.4vw, 1.875rem);   /* the two closing lines */
  --t-item:  clamp(1.0625rem, 1.2vw, 1.1875rem);
  --t-lead:  clamp(1.0625rem, 1.2vw, 1.25rem);
  --t-body:  1.0625rem;
  --t-desc:  .9375rem;
  --t-num:   .9375rem;
  --t-micro: .6875rem;

  /* ── motion ──────────────────────────────────────────────── */
  --ease: cubic-bezier(.22,.61,.36,1);
  --rev:  640ms;      /* hero copy load-in only */
  --ui:   180ms;
}

/* ─────────────────────────── base ─────────────────────────── */

*, *::before, *::after{ box-sizing: border-box; }

html{
  background: var(--paper);
  scroll-behavior: smooth;
  scroll-padding-top: 24px;   /* nothing overlays content now; this is just air */
  -webkit-text-size-adjust: 100%;
}

body{
  margin: 0;
  color: var(--ink);
  font: 400 var(--t-body)/1.55 var(--sans);
  letter-spacing: -.002em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img{ max-width: 100%; display: block; }
/* a class-level `display` beats the UA stylesheet's [hidden], which would leave
   the status chip on screen as an empty capsule when app.js never runs */
[hidden]{ display: none !important; }
h1, h2, h3, p, dl, dd, figure, blockquote{ margin: 0; }
ol, ul{ margin: 0; padding: 0; list-style: none; }
address{ font-style: normal; }
a{ color: inherit; }

:focus-visible{
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  border-radius: var(--r-focus);
  box-shadow: 0 0 0 5px rgba(255,255,255,.85);
}

.shell{ max-width: var(--shell); margin-inline: auto; padding-inline: var(--gutter); }

.mono{ font-family: var(--mono); font-variant-numeric: tabular-nums; }

.micro{
  font: 500 var(--t-micro)/1 var(--mono);
  letter-spacing: .10em;
  color: var(--ink-3);
  text-transform: lowercase;
  font-variant-numeric: tabular-nums;
}
.micro--dim{ font-weight: 400; }

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

/* The skip link, hidden the way .vh hides things rather than nudged off the
   top edge. It used to hide with transform: translateY(-160%), which on a
   375px phone put its box at -40.8 .. -7.8 — under 8px of clearance. iOS moves
   the visual viewport independently of the layout viewport, so any overscroll
   at the top, or a URL-bar collapse, slid those 8px back and the chip appeared
   in the corner. A clipped, zero-opacity box has nothing to slide into view.

   It stays focusable, so a keyboard user still gets it — neither clip-path nor
   opacity removes an element from the focus order. Opaque ground and
   deliberately no box-shadow: .skip and :focus-visible tie on specificity, so
   a shadow here would silently delete the white focus halo. */
.skip{
  position: fixed; top: calc(12px + env(safe-area-inset-top, 0px)); left: 12px;
  z-index: 60;
  padding: 10px 16px; border-radius: var(--r-tag);
  font: 500 var(--t-micro)/1 var(--mono); letter-spacing: .10em;
  color: var(--ink); text-decoration: none;
  background: var(--paper-lift);
  border: 1px solid var(--chrome-rule);
  clip-path: inset(50%);
  opacity: 0;
  pointer-events: none;
}
.skip:focus{ clip-path: none; opacity: 1; pointer-events: auto; }

.h2{
  font: 500 var(--t-h2)/1.04 var(--sans);
  font-stretch: 104%;
  letter-spacing: -.020em;
  color: var(--ink);
  text-wrap: balance;
}
.h2 .line{ display: block; }
@media (max-width: 599px){ .h2 .line{ display: inline; } }

/* ══════════════════ background system ══════════════════ */

body::before{                           /* the bloom field */
  content: ""; position: fixed; inset: -20vh 0; z-index: -3; pointer-events: none;
  background:
    radial-gradient(60vw 48vh at 50% -8vh, rgba(232,182,106,.20), transparent 68%),
    radial-gradient(48vw 40vh at  4%  34%, rgba(148,180,220,.16), transparent 70%),
    radial-gradient(52vw 44vh at 96%  70%, rgba(196,182,220,.13), transparent 72%),
    linear-gradient(180deg, var(--paper-lift) 0%, var(--paper) 46%,
                            var(--paper-deep) 72%, var(--paper) 100%);
}

body::after{                            /* grain, against banding */
  content: ""; position: fixed; inset: 0; z-index: -2; pointer-events: none; opacity: .035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='2'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* a single hairline opening each section, with a registration mark at centre */
.band{ position: absolute; top: 0; left: 0; right: 0; height: 1px; pointer-events: none; }
.band__line{
  position: absolute; inset: 0; background: var(--hair);
  transform-origin: 50% 50%; transform: scaleX(1);
}
.band::after{
  content: ""; position: absolute; left: 50%; top: 0;
  width: 14px; height: 1px; margin-left: -7px; background: var(--gold-ink);
}


/* ══════════════════ the wordmark ══════════════════ */

.mark{
  display: inline-flex; align-items: baseline; white-space: nowrap;
  font: 500 1em/1 var(--sans); letter-spacing: -.02em; color: var(--ink);
}
.mark__gate{
  align-self: center; display: inline-block;
  width: 1px; height: .62em; margin-inline: .30em;
  background: var(--gold-ink);
}

/* ══════════════════ masthead ══════════════════
   In the flow, at the top of the page, and gone once you scroll past it.

   It used to be a fixed glass eyebrow: a sentinel in the markup drove an
   IntersectionObserver that faded the bar's backdrop-filter in past 24px, and
   the glass was a blur chain plus a specular ::after sheen, with an SVG
   displacement warp before that. All of it is gone. Nothing overlays content
   any more, so there is nothing behind the bar to refract and nothing to
   separate from — what is left is the wordmark, the clock and the nav sitting
   on the paper like every other line of type on the page.

   position: relative stays, and is not decorative: the clock is absolutely
   centred and needs this as its containing block. */

.masthead{
  position: relative;
  height: calc(var(--masthead) + env(safe-area-inset-top, 0px));
  padding: env(safe-area-inset-top, 0px) var(--gutter) 0;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
}

/* The café's clock. Absolutely centred rather than a third flex item, because
   the wordmark and the nav are different widths and space-between would put it
   slightly off the middle. Tabular figures so the digits do not jitter as they
   tick. */
.masthead__clock{
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  margin-top: calc(env(safe-area-inset-top, 0px) / 2);
  font: 500 var(--t-micro)/1 var(--mono); letter-spacing: .10em;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap; pointer-events: none;
}
/* The bar is wordmark | clock | nav, and the clock is centred on the bar rather
   than on the space between them, so the question is only whether it clears
   both. Measured with the real strings: at 360px it has 23px to the wordmark
   and 25px to the nav, and it only runs out at 320px (3px and 5px, touching).
   360px is this sheet's stated floor, so the clock shows everywhere the layout
   is supported and steps aside below it. */
@media (max-width: 359px){ .masthead__clock{ display: none; } }

.masthead__mark{ font-size: 19px; text-decoration: none; padding: 6px 2px; }
.masthead__nav{ display: flex; align-items: center; gap: 22px; }
.masthead__nav a{
  font: 500 var(--t-micro)/1 var(--mono); letter-spacing: .10em;
  color: var(--ink); text-decoration: none;
  padding: 16px 2px; min-height: 44px; display: inline-flex; align-items: center;
  transition: color var(--ui) linear;
}
/* feedback that does not depend on a contrast shift, since the ground behind a
   clear bar is whatever happens to be scrolling past */
.masthead__nav a:hover{ text-decoration: underline; text-underline-offset: .4em;
                        text-decoration-thickness: 1px; }


/* ══════════════════ hero ══════════════════
   No mask, no scrim, no darkening, no parallax. The copy sits directly on the
   photograph, over the one genuinely flat region of it: the white plinth in the
   lower left, x 0–44%, y 68–100%. The 46vw cap keeps it clear of the gate at
   x=50%; left:gutter is subtracted from the width so the cap means what it says. */

.hero{
  position: relative;
  /* the masthead is in the flow above this now, so its height comes off the
     viewport explicitly rather than being absorbed by a round number; 24px is
     the deliberate peek of the menu band below the fold */
  height: min(calc(100svh - var(--masthead) - env(safe-area-inset-top, 0px) - 24px), 860px);
  min-height: 520px;
  background: #EEF2F6;
}
@supports not (height: 100svh){
  .hero{ height: min(calc(100vh - var(--masthead) - env(safe-area-inset-top, 0px) - 24px), 860px); }
}

.hero__pic, .hero__pic img{ position: absolute; inset: 0; width: 100%; height: 100%; }
.hero__pic img{ object-fit: cover; object-position: 50% 46%; }
@media (min-width: 700px) and (max-width: 999px){ .hero__pic img{ object-position: 50% 38%; } }
@media (max-width: 699px){
  .hero__pic img{ object-position: 50% 34%; }
  .hero{ background: #EEF2F6 url(assets/hero-lqip.jpg) center / cover no-repeat; }
}

.hero__copy{
  position: absolute; left: var(--gutter); bottom: clamp(36px, 6vh, 64px); z-index: 2;
  width: min(calc(46vw - var(--gutter)), 560px);
}
/* Every word in the hero is --ink, not a tonal hierarchy. Measured against the
   actual pixels of the crop at 390px, --ink-2 falls to 2.94:1 on the subtitle
   and 3.62:1 on the label where they cross the water channel; --ink holds
   5.81:1 and 7.14:1 in the same places. Hierarchy here comes from size and
   weight, which cost no contrast. */
.hero__copy .micro,
.hero__copy .hero__sub,
.hero__copy .chip,
.hero__copy .chip__detail{ color: var(--ink); }
/* The original's hero setting: the two words stacked, the second in italic and
   stepped in. Tight tracking is a grotesk habit — a garalde is fitted by its
   designer, so letter-spacing goes back to ~0. */
.hero__title{
  font-family: var(--serif); font-weight: 300;
  font-size: var(--t-hero);
  line-height: .84; letter-spacing: -.005em;
  margin: 10px 0 0; padding-bottom: .22em;
}
.hero__w{ display: block; }
/* .5em, not a token gap: at this leading the acute on the é runs up into the
   descender of the y above it, and the step is what carries it clear. The y's
   tail sweeps down and to the LEFT, so the clash only breaks once the é is past
   the whole letter. In em, so it holds at every size the clamp produces. */
.hero__w--2{ font-style: italic; padding-left: .5em; }
.hero__sub{
  margin-top: 12px;
  font: 400 var(--t-lead)/1.4 var(--sans); color: var(--ink-2);
}
.hero__foot{
  margin-top: 18px; display: flex; align-items: center;
  gap: 20px; flex-wrap: wrap;
}
@media (max-width: 859px){
  .hero__copy{ left: var(--gutter); right: var(--gutter); width: auto; }
}

/* the status chip — a mark and two words, no capsule */
.chip{
  display: inline-flex; align-items: center; gap: 9px;
  padding-left: 10px; border-left: 2px solid var(--gold-ink);
  font: 500 var(--t-micro)/1 var(--mono); letter-spacing: .10em;
  color: var(--ink-2); white-space: nowrap;
}
.chip__dot{
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  border: 1.5px solid var(--gold-ink); background: transparent;   /* closed: hollow */
}
.chip.is-open .chip__dot{ background: var(--gold-ink); }          /* open: filled */
.chip__state{ color: var(--ink); }
.chip__detail{ color: var(--ink-2); font-weight: 400; }

.rail{ margin-bottom: var(--air-md); }

/* ══════════════════ menu ══════════════════
   No plates. Twelve rows of type on the paper, ruled edge to edge, with a gold
   index rule hanging in the margin of each group. */

.menu{ position: relative; padding-top: var(--sec-lead); padding-bottom: var(--sec-trail); }
.hero + .menu{ padding-top: clamp(72px, 8vw, 112px); }   /* it opens the page now */
/* drop its opening rule clear of the photograph's own bottom edge, or the two
   sit on the same line and read as one doubled seam */
.hero + .menu > .band{ top: clamp(40px, 5vw, 64px); }
.menu__shell{ position: relative; }
.groups{ margin-top: var(--air-lg); display: flex; flex-direction: column; gap: var(--air-lg); }

.group{ position: relative; }
.group__ix{
  position: absolute; left: -14px; top: 0; bottom: 0; width: 2px;
  background: var(--gold-ink); opacity: .5;
  transform-origin: 50% 0; transform: scaleY(1);
}
/* Static, not sticky: the label stays at the head of its own group instead of
   following a sticky bar down the page. Nothing on this page is fixed or
   sticky any more, the masthead included. */
.group__head{
  height: 40px;
  display: flex; align-items: center; justify-content: space-between;
  border-bottom: 1px solid var(--hair);
  background: transparent;
}

.row{
  position: relative;
  display: grid; grid-template-columns: 3.25rem 1fr auto;
  column-gap: 12px; align-items: baseline;
  padding: 13px 0 15px;
}
.row__no{
  grid-column: 1; grid-row: 1;
  font: 400 var(--t-micro)/1 var(--mono); letter-spacing: .08em;
  color: var(--ink-3); padding-top: .55em;
}
.row__name{
  grid-column: 2; grid-row: 1;
  font: 500 var(--t-item)/1.2 var(--sans); letter-spacing: -.012em; color: var(--ink);
}
.row__desc{
  grid-column: 2; grid-row: 2; margin-top: 3px; max-width: 58ch;
  font: 400 var(--t-desc)/1.5 var(--sans); color: var(--ink-2);
}
.row__price{
  grid-column: 3; grid-row: 1; text-align: right;
  font: 500 var(--t-num)/1 var(--mono); color: var(--ink);
}
.row__sig{ color: var(--gold-ink); white-space: nowrap; }

.row + .row::before{
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: var(--hair);
}

/* The signature carries no margin mark: that position is already occupied by
   the group's index rule, in the same gold, so a bar there is invisible. It is
   marked instead by weight and by a literal label — the label being the
   channel that does not depend on colour at all. */
.row--signature .row__name{ font-weight: 600; }
.row--signature .row__no{ color: var(--gold-ink); }

.note{
  margin-top: var(--air-lg); max-width: 56ch;
  font: 400 .8125rem/1.7 var(--mono); letter-spacing: 0; color: var(--ink-2);
}

@media (min-width: 980px){
  .menu__shell > *{ margin-left: calc(var(--rail) + var(--air-md)); }
  .group{ max-width: 680px; }
  .group__head{
    position: absolute; top: 2px;
    left: calc(-1 * (var(--rail) + var(--air-md)));
    width: var(--rail); height: auto;
    display: block; border: 0; background: none;
  }
  .group__when{ display: block; margin-top: 6px; }
}

@media (max-width: 599px){
  .row{ grid-template-columns: auto 1fr auto; column-gap: 10px; padding: 12px 0 14px; }
  .row__no{ padding-top: .35em; }
  .row__desc{ grid-column: 1 / -1; font-size: .90625rem; max-width: none; }
  .group__ix, .row--signature::after{ left: -10px; }
}

/* ══════════════════ visit ══════════════════ */

.visit{ position: relative; padding-top: var(--sec-lead); padding-bottom: var(--sec-trail); }
.visit__shell{ position: relative; }
.visit__head{ display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--air-md); }
.visit__head .h2{ max-width: 30ch; }

.plates{
  margin-top: var(--air-lg);
  display: grid; grid-template-columns: 1fr; gap: var(--air-lg);
  align-items: start;
  max-width: min(820px, 100%);
}
.plate .micro{ display: block; margin-bottom: 14px; }

.hours{ display: grid; }
.hrow{
  position: relative;
  display: grid; grid-template-columns: 1fr auto; align-items: baseline;
  gap: 12px; min-height: 44px; padding-block: 9px;
}
.hrow + .hrow{ border-top: 1px solid var(--hair); }
.hrow dt{ font-size: var(--t-body); color: var(--ink-2); }
.hrow dd{
  margin: 0; font-size: var(--t-num); color: var(--ink);
  display: inline-flex; align-items: baseline; gap: .7ch;
}
/* 5ch is exactly the width of "10 pm" in a mono face, so right-aligning both
   ends keeps the column ruling to the pixel the way 24h times did for free */
.hrow .t{ min-width: 5ch; text-align: right; }
.hrow .t-to{ color: var(--ink-2); }
.hrow[aria-current]{ font-weight: 500; }
.hrow[aria-current] dt, .hrow[aria-current] dd{ color: var(--ink); }
.hrow[aria-current]::before{
  content: ""; position: absolute; left: -14px; top: 50%; margin-top: -5px;
  width: 2px; height: 10px; background: var(--gold-ink);
}

/* Same row geometry as .hrow, and the same number of rows, so the two plates
   rule across the gap: hairlines and column bottoms land on the same lines.
   Each dt is .vh — out of flow, kept for the dl and for screen readers — so
   the row is a single column and the value rules to the plate's right edge */
.find{ display: grid; }
.frow{
  position: relative;
  display: grid; align-items: baseline;
  min-height: 44px; padding-block: 9px;
}
.frow + .frow{ border-top: 1px solid var(--hair); }
.frow dd{ margin: 0; font-size: var(--t-body); color: var(--ink); text-align: right; }
/* -9px cancels the row padding, so the 44px tap target fills the row's full
   height without making the row taller than an hours row */
.find a{
  display: inline-flex; align-items: center; min-height: 44px; margin-block: -9px;
  color: var(--gold-ink); text-decoration: underline;
  text-decoration-thickness: 1px; text-underline-offset: .28em;
  transition: text-decoration-thickness var(--ui) linear, color var(--ui) linear;
}
.find a:hover{ text-decoration-thickness: 2px; }

@media (min-width: 680px){
  .plates{ grid-template-columns: 1fr 1fr; gap: var(--air-lg); }
}
@media (min-width: 980px){
  .visit__head, .plates{ margin-left: calc(var(--rail) + var(--air-md)); }
  .plates{ max-width: min(820px, calc(100% - var(--rail) - var(--air-md))); }
  .rail--visit{
    position: absolute; left: var(--gutter); top: 0; z-index: 2;
    width: var(--rail); margin: 0;
  }
}

/* ══════════════════ closing ══════════════════
   The one symmetric moment on the page, and the only section whose padding is
   symmetric. That is the same guard as its centred layout. */

.closing{ position: relative; padding-block: var(--sec-trail); text-align: center; }
.closing__line{
  font-size: var(--t-line); line-height: 1.26; letter-spacing: -.012em;
  text-wrap: balance;
}
.closing__line--1{ font-weight: 400; color: var(--ink-2); }
.closing__line--2{ font-weight: 500; color: var(--ink); margin-top: clamp(32px, 5vw, 64px); }

.seam--end{
  display: block; width: 6px; height: 6px;
  background: var(--gold-ink);
  margin: 48px auto 0; transform: scale(1); opacity: 1;
}

/* ══════════════════ footer ══════════════════
   Flat, for the same reason the masthead is: it sits at the end of the flow on
   the same paper, so blurring what is "behind" it only ever blurred the page
   background. A hairline opens it, the way a hairline opens every section. */

.foot{
  border-top: 1px solid var(--hair);
  padding-block: 32px;
  padding-bottom: calc(32px + env(safe-area-inset-bottom, 0px));
}
.foot__inner{
  display: flex; flex-direction: column; align-items: center; gap: 16px; text-align: center;
}
.foot__mark{ font-size: 19px; }
.foot__nav{ display: flex; gap: 22px; }
.foot__nav a{
  font: 500 var(--t-micro)/1 var(--mono); letter-spacing: .10em;
  color: var(--ink-2); text-decoration: none;
  min-height: 44px; display: inline-flex; align-items: center; padding-inline: 2px;
  transition: color var(--ui) linear;
}
.foot__nav a:hover{ color: var(--ink); }

.social{ display: flex; gap: 8px; }
.social a{
  width: 44px; height: 44px; display: grid; place-items: center;
  color: var(--ink-3); transition: color var(--ui) linear;
}
.social a:hover{ color: var(--ink); }
.social svg{
  width: 20px; height: 20px; fill: none;
  stroke: currentColor; stroke-width: 1.4;
  stroke-linecap: round; stroke-linejoin: round;
}
.social .glyph-dot{ fill: currentColor; stroke: none; }

/* ══════════════════ scroll coupling ══════════════════

   (a) EVERY @keyframes to{} IS BYTE-IDENTICAL TO THE ELEMENT'S STATIC RULE, so
       "no animation" is always the correct finished page and every degradation
       path is free. There are now no exceptions.
   (b) A TIMELINE SUBJECT IS ALWAYS A .tl CONTAINER THAT NEVER ANIMATES.
   (c) NEVER THE `animation` SHORTHAND ON .sd — it resets animation-timeline to
       auto and animation-range to normal. Longhands only. */

.tl{ view-timeline-name: --tl; view-timeline-axis: block; }

.sd{
  animation-name:            var(--sd-kf);
  animation-duration:        0s;          /* no JS + no support => fill:both holds to{} */
  animation-timing-function: linear;      /* scroll position IS the easing */
  animation-fill-mode:       both;
  animation-iteration-count: 1;
}

@supports (animation-timeline: view()){
  html:not(.sd-off):not(.sd-js) .sd{
    animation-duration: auto;
    animation-timeline: --tl;
    animation-range:    var(--sd-r0) var(--sd-r1);
  }
  html:not(.sd-off):not(.sd-js) .sd--root{ animation-timeline: scroll(root block); }
}

html.sd-js .sd{
  animation-duration: 1000ms;
  animation-timeline: auto;
  animation-play-state: paused;
}

@media (prefers-reduced-motion: reduce){ .sd{ animation-name: none !important; } }
html.sd-off .sd{ animation-name: none !important; animation-timeline: none !important; }

@keyframes rule-draw    { from{ transform: scaleX(0) }            to{ transform: scaleX(1) } }
@keyframes ix-draw      { from{ transform: scaleY(0) }            to{ transform: scaleY(1) } }
@keyframes mark-set     { from{ transform: scale(0); opacity: 0 } to{ transform: scale(1); opacity: 1 } }

.band__line{     --sd-kf: rule-draw;    --sd-r0: entry  8%; --sd-r1: entry 34%; }
.group__ix{      --sd-kf: ix-draw;      --sd-r0: entry  6%; --sd-r1: entry 38%; }
.seam--end{      --sd-kf: mark-set;     --sd-r0: entry 14%; --sd-r1: entry 42%; }

.band__line{ transform-origin: 50% 50%; }
.group__ix{ transform-origin: 50% 0; }
.seam--end{ transform-origin: 50% 50%; }

/* NOTHING WITH TEXT IN IT ANIMATES. Scroll-coupled motion has no timer to
   rescue it: a reader who stops scrolling parks whatever is mid-flight forever. */

/* ══════════════════ the hero copy load-in ══════════════════ */

.js .reveal{
  opacity: 0; transform: translate3d(0, 12px, 0);
  transition: opacity var(--rev) var(--ease), transform var(--rev) var(--ease);
}
.js .reveal.in{ opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .reveal{ opacity: 1 !important; transform: none !important; }
  /* reduced motion removes movement, not feedback */
  a, .row, .social a{
    transition: color 120ms linear, background-color 120ms linear,
                border-color 120ms linear, text-decoration-color 120ms linear,
                text-decoration-thickness 120ms linear !important;
  }
}

@media (prefers-contrast: more){
  /* The bars carried a glass tint and a specular sheen that both had to be
     overridden here. Neither exists now, so all that is left is to firm up the
     hairlines and take the bloom field down. */
  :root{ --ink-3: #4A515A; --hair: rgba(20,30,46,.24); }
  .foot{ border-top-color: rgba(20,30,46,.42); }
  body::before{ opacity: .40; }
}

/* ══════════════════ 360px floor ══════════════════ */

@media (max-width: 400px){
  .masthead__nav{ gap: 16px; }
}
