/* UST Protocol — landing styles.
   Rebuilt 2026-08-16 from the single-file design export: what was 99 inline style
   attributes and one <style> block inside the runtime template is now one stylesheet,
   addressed by class. Only three data- attributes survive, and each is STATE the page
   changes at runtime rather than a styling hook:
     [data-seat="1..4"]  which seat this is
     [data-ready="1"]    that seat's portrait has loaded — the "connecting" overlay lifts
     [data-speaking="n"] who is speaking right now
   The 2x2 -> filmstrip morph is a scroll-driven CSS animation (animation-timeline:
   scroll()), so it needs no JavaScript at all; browsers without it simply keep the grid.
*/

/* ---- layout, lifted from the export's inline attributes ---- */
.bar {
  position: sticky;
  top: 0;
  z-index: 30;
  height: clamp(48px, 6.2vw, 56px);
  background: #1e1c1a;
  color: #f4f2ec;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: clamp(10px, 2vw, 24px);
  padding: 0 clamp(12px, 1.6vw, 20px);
}
.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  text-decoration: none;
  transition: opacity 90ms linear;
}
.topic--inline {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-width: 0;
}
.rec {
  width: 6px;
  height: 6px;
  background: #0c7c78;
  display: block;
}
.bar-links {
  display: flex;
  align-items: center;
  gap: clamp(10px, 1.2vw, 16px);
  flex: none;
}
.topic--bar {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  height: 28px;
  align-items: center;
  gap: 6px;
  padding: 0 clamp(12px, 1.6vw, 20px);
  background: #1e1c1a;
  border-top: 1px solid rgba(244, 242, 236, 0.16);
  pointer-events: none;
}
.seats {
  position: sticky;
  top: clamp(48px, 6.2vw, 56px);
  z-index: 20;
  height: clamp(70px, min(11vw, 26vh), 400px);
  overflow: visible;
}
.seats-bg {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: calc(100dvh - clamp(48px, 6.2vw, 56px));
  background: #1e1c1a;
  display: block;
  z-index: 0;
}
.seat {
  display: block;
  background: #1e1c1a;
  color: #f4f2ec;
}
.seat-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 26%;
  display: block;
}
.seat-tag--full {
  position: absolute;
  left: 12px;
  bottom: 12px;
  max-width: calc(100% - 24px);
  padding: 7px 11px;
  background: rgba(30, 28, 26, 0.84);
  font: 400 clamp(10.5px, 0.85vw, 12px)/1.3 'JetBrains Mono', monospace;
  letter-spacing: 0.01em;
  color: #f4f2ec;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background 90ms linear;
}
.seat-tag--short {
  position: absolute;
  left: 0;
  bottom: 0;
  max-width: 100%;
  padding: 4px 7px;
  background: rgba(30, 28, 26, 0.8);
  font: 400 9.5px/1 'JetBrains Mono', monospace;
  letter-spacing: 0.06em;
  color: #f4f2ec;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 0;
}
.call-spacer {
  height: calc(100dvh - clamp(48px, 6.2vw, 56px) - clamp(70px, min(11vw, 26vh), 400px));
}
.stage-body {
  flex: 1 1 auto;
  min-height: max-content;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(14px, 2.2vh, 26px);
  padding: clamp(24px, 4vh, 56px) clamp(20px, 5vw, 64px);
  text-align: center;
}
.stage {
  scroll-snap-align: start;
  scroll-margin-top: calc(clamp(48px, 6.2vw, 56px) + clamp(70px, min(11vw, 26vh), 400px));
  background: #efe8da;
  display: flex;
  flex-direction: column;
}
.title {
  margin: 0;
  font: 700 clamp(34px, 9.4vw, 60px)/1.14 'Merriweather', Georgia, serif;
  letter-spacing: -0.01em;
  color: #1e1c1a;
  max-width: min(20ch, 720px);
  text-wrap: pretty;
}
.rule {
  /* The export drew this as a <span>. As an <hr> it inherits the browser default
     `border: 1px inset` plus block margins, which put a bevelled edge above and below
     the one-pixel fill — the divider read as embossed rather than as a hairline. */
  border: 0;
  margin: 0;
  display: block;
  width: min(100%, 720px);
  height: 1px;
  background: rgba(30, 28, 26, 0.2);
}
.quote {
  width: 100%;
  max-width: min(100%, 720px);
  margin: 0 auto;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 0.3em;
  font: 400 clamp(15px, 1.5vw, 19px)/1.6 'JetBrains Mono', monospace;
  color: #1e1c1a;
  transition: opacity 400ms linear;
  /* The runtime drove this from a template value; the quote is simply hidden until
     someone is speaking, which the presence of a name expresses on its own. */
  opacity: 0;
}
.quote-text {
  display: block;
  min-height: calc(1.6em * 2);
}
.caret {
  color: #0c7c78;
}
.bridge {
  margin: 0;
  font: 400 clamp(11.5px, 1.05vw, 13px)/1.5 'JetBrains Mono', monospace;
  letter-spacing: 0.02em;
  color: rgba(30, 28, 26, 0.58);
}
.seatrow {
  width: 100%;
  max-width: 720px;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(5px, 1.2vw, 12px);
  margin-top: clamp(4px, 1vh, 10px);
}
.seatbtn {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  height: calc(30px - 0.1em);
  padding: 0.1em clamp(6px, 2vw, 18px) 0;
  border: 1px solid rgba(30, 28, 26, 0.28);
  border-radius: 2px;
  font: 500 clamp(10px, 2.7vw, 12px)/1 'JetBrains Mono', monospace;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #1e1c1a;
  white-space: nowrap;
  transition: background 90ms linear, border-color 90ms linear;
}
.foot {
  margin-top: auto;
  border-top: 8px solid #1e1c1a;
  background: #1e1c1a;
  color: #f4f2ec;
  padding: clamp(20px, 2.6vh, 28px) clamp(20px, 5vw, 64px) clamp(12px, 1.6vh, 16px);
  display: flex;
  flex-direction: column;
  gap: clamp(16px, 2vh, 22px);
}
.legal {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.seal {
  display: block;
  color: rgba(244, 242, 236, 0.5);
  cursor: default;
}
.seal pre {
  font: 400 clamp(4.2px, 0.44vw, 5.2px)/1.2 'JetBrains Mono', monospace;
  margin: 0;
  color: inherit;
  user-select: none;
}

/* ---- pieces the export left implicit ---- */
.brand-mark { font: 500 15px/1 'JetBrains Mono', monospace; color: #f4f2ec; }
.brand-name { font: 400 clamp(11px, 1.05vw, 13px)/1 'JetBrains Mono', monospace; letter-spacing: 0.02em; color: #f4f2ec; }
.bar-links a { font: 500 clamp(10px, 0.95vw, 11.5px)/1 'JetBrains Mono', monospace; letter-spacing: 0.1em; text-transform: uppercase; color: #f4f2ec; opacity: 0.66; }
.bar-links a:hover { color: #0c7c78; opacity: 1; }
/* Qualified with the `a` and the parent because this is a button that happens to sit among
   nav links, and unqualified it lost to them on every property they share: `.bar-links a`
   (0,1,1) outranks `.bar-cta` (0,1,0), and `.bar-links a:hover` (0,2,1) outranks
   `.bar-cta:hover` (0,2,0). So the button never wore its own colour or its own opacity, and
   on hover the label was painted #0c7c78 onto the #0c7c78 fill it had just been given —
   contrast 1.00:1, the word gone while the pointer was on it. The declarations below were
   all present; three of them had simply never applied. */
.bar-links a.bar-cta {
  display: inline-flex;
  align-items: center;
  height: 30px;
  padding: 0 clamp(9px, 1vw, 13px);
  border: 1px solid #0c7c78;
  border-radius: 2px;
  color: #f4f2ec;
  opacity: 1;              /* a button, not one of the 0.66 nav links beside it */
  white-space: nowrap;
  transition: background 90ms linear, color 90ms linear;
}
.bar-links a.bar-cta:hover { background: #0c7c78; border-color: #0c7c78; color: #1e1c1a; }
/* Same white as the brand, and at full strength: the caption names what the page is, so it
   is not secondary to the logo beside it. Two things were dimming it — 0.62 alpha here, and
   the inline variant's fade opening at 0.84 instead of 1, which left desktop paler than
   phone for no reason either. */
.topic-text { font: 400 clamp(10px, 1vw, 11.5px)/1 'JetBrains Mono', monospace; letter-spacing: 0.08em; text-transform: uppercase; color: #f4f2ec; }

.seats { list-style: none; margin: 0; padding: 0; }
.seat { display: block; background: #1e1c1a; color: #f4f2ec; }
.seat-link { display: block; width: 100%; height: 100%; color: inherit; }
.seat-plate { position: absolute; inset: 0; display: block; background: transparent; transition: background 90ms linear, box-shadow 90ms linear; }
.seat-link:hover .seat-plate { background: rgba(244, 242, 236, 0.07); }
.seat-dash { opacity: 0.4; }
.seat-quote { opacity: 0.68; }

.stage { display: flex; flex-direction: column; }
.lines { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.lines p { margin: 0; }
.quote-name { display: block; min-height: 1em; font-size: 0.62em; line-height: 1; letter-spacing: 0.14em; text-transform: uppercase; color: rgba(30, 28, 26, 0.45); }

.seatrow { list-style: none; margin: 0; padding: 0; }
/* Three seats have no page yet. They stay in the row — the meeting is four people —
   but they are inert text, not links that would land a reader on a 404. */
.seatbtn[aria-disabled="true"] { opacity: 0.38; cursor: default; }
a.seatbtn:hover { background: #1e1c1a; border-color: #1e1c1a; color: #f4f2ec; }

.foot-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr)); gap: 20px clamp(24px, 3vw, 48px); }
.foot-col { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.foot-col h2 { margin: 0; font: 500 10px/1 'JetBrains Mono', monospace; letter-spacing: 0.22em; text-transform: uppercase; color: rgba(244, 242, 236, 0.38); }
.foot-col ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; font: 400 11.5px/1.4 'JetBrains Mono', monospace; }
.foot-col a { color: rgba(244, 242, 236, 0.74); padding: 2px 0; }
.foot-col a:hover { color: #0c7c78; }
.foot-base { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 24px clamp(24px, 3vw, 48px); border-top: 1px solid rgba(244, 242, 236, 0.14); padding-top: clamp(12px, 1.6vh, 16px); }
.legal { flex: 1 1 440px; font: 400 10.5px/1.55 'JetBrains Mono', monospace; color: rgba(244, 242, 236, 0.42); }
.seal {
  /* A <button> brings its own chrome and, less obviously, `text-align: center` —
     which shifts monospaced art off its own left edge. The art is authored column by
     column, so the alignment has to be stated. */
  background: none;
  border: 0;
  padding: 0;
  text-align: left;
  font: inherit;
}

/* ---- geometry, morph and motion, from the export's stylesheet ---- */

  html, body { margin: 0; padding: 0; background: #efe8da; -webkit-font-smoothing: antialiased; }
  /* The UA baseline this stylesheet has to own. Zeroing html and body alone left every <p>,
     heading and list carrying the browser's own 1em margins. Harmless wherever a flex or grid
     parent centres the box anyway — which is why it survived the rebuild unseen — and load
     bearing the moment one is positioned: .topic--bar resolved `top: 100%` against the header
     correctly and was then pushed 16px clear of it by a margin nobody wrote. Vertical spacing
     is declared here or it does not exist. */
  h1, h2, h3, h4, h5, h6, p, ul, ol, dl, dd, figure, blockquote, pre { margin: 0; }
  body { font-family: 'JetBrains Mono', ui-monospace, monospace; color: #1e1c1a; }
  img { image-rendering: pixelated; }
  .seat { -webkit-tap-highlight-color: transparent; }
  a { color: #1e1c1a; text-decoration: none; }
  a:hover { color: #0c7c78; }

  /* phase-0 geometry: 2x2 with 8px lines (single column under 768px) */
  .seat { position: absolute; overflow: hidden; z-index: 1; width: calc(50% - 4px); height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 8px) / 2); }
  .seat[data-seat="1"] { left: 0; top: 0; }
  .seat[data-seat="2"] { left: calc(50% + 4px); top: 0; }
  .seat[data-seat="3"] { left: 0; top: calc((100dvh - clamp(48px, 6.2vw, 56px) + 8px) / 2); }
  .seat[data-seat="4"] { left: calc(50% + 4px); top: calc((100dvh - clamp(48px, 6.2vw, 56px) + 8px) / 2); }
  .seat { contain: paint; }
  .seat:focus-visible { outline: 2px solid #0c7c78; outline-offset: -2px; z-index: 3; }
  @media (max-width: 767px) {
    .seat { left: 0; width: 100%; height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 24px) / 4); }
    .seat[data-seat="2"] { top: calc((100dvh - clamp(48px, 6.2vw, 56px) + 8px) / 4); }
    .seat[data-seat="3"] { top: calc((100dvh - clamp(48px, 6.2vw, 56px) + 8px) / 2); }
    .seat[data-seat="4"] { top: calc((100dvh - clamp(48px, 6.2vw, 56px) + 8px) * 0.75); }
  }

  /* phase-1 geometry: filmstrip slots, 4px lines.
     Two beats so seats never pass through each other: first they take their column
     (width + horizontal travel), then the whole row compresses and rises into the strip. */
  @keyframes seat1 {
    0% { left: 0; top: 0; width: calc(50% - 4px); height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 8px) / 2); }
    50% { left: 0; top: 0; width: calc(25% - 3px); height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 8px) / 2); }
    100% { left: 0; top: 0; width: calc(25% - 3px); height: 100%; }
  }
  @keyframes seat2 {
    0% { left: calc(50% + 4px); top: 0; width: calc(50% - 4px); height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 8px) / 2); }
    50% { left: calc(25% + 1px); top: 0; width: calc(25% - 3px); height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 8px) / 2); }
    100% { left: calc(25% + 1px); top: 0; width: calc(25% - 3px); height: 100%; }
  }
  @keyframes seat3 {
    0% { left: 0; top: calc((100dvh - clamp(48px, 6.2vw, 56px) + 8px) / 2); width: calc(50% - 4px); height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 8px) / 2); }
    50% { left: calc(50% + 2px); top: calc((100dvh - clamp(48px, 6.2vw, 56px) + 8px) / 2); width: calc(25% - 3px); height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 8px) / 2); }
    100% { left: calc(50% + 2px); top: 0; width: calc(25% - 3px); height: 100%; }
  }
  @keyframes seat4 {
    0% { left: calc(50% + 4px); top: calc((100dvh - clamp(48px, 6.2vw, 56px) + 8px) / 2); width: calc(50% - 4px); height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 8px) / 2); }
    50% { left: calc(75% + 3px); top: calc((100dvh - clamp(48px, 6.2vw, 56px) + 8px) / 2); width: calc(25% - 3px); height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 8px) / 2); }
    100% { left: calc(75% + 3px); top: 0; width: calc(25% - 3px); height: 100%; }
  }
  @keyframes seatBg {
    0% { height: calc(100dvh - clamp(48px, 6.2vw, 56px)); }
    50% { height: calc(100dvh - clamp(48px, 6.2vw, 56px)); }
    100% { height: 100%; }
  }
  @keyframes imgFocus { 0% { object-position: 50% 26%; } 50% { object-position: 50% 26%; } 100% { object-position: 50% 19%; } }
  @media (max-width: 767px) {
    @keyframes seat1 {
      0% { left: 0; top: 0; width: 100%; height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 24px) / 4); }
      50% { left: 0; top: 0; width: calc(25% - 3px); height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 24px) / 4); }
      100% { left: 0; top: 0; width: calc(25% - 3px); height: 100%; }
    }
    @keyframes seat2 {
      0% { left: 0; top: calc((100dvh - clamp(48px, 6.2vw, 56px) + 8px) / 4); width: 100%; height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 24px) / 4); }
      50% { left: calc(25% + 1px); top: calc((100dvh - clamp(48px, 6.2vw, 56px) + 8px) / 4); width: calc(25% - 3px); height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 24px) / 4); }
      100% { left: calc(25% + 1px); top: 0; width: calc(25% - 3px); height: 100%; }
    }
    @keyframes seat3 {
      0% { left: 0; top: calc((100dvh - clamp(48px, 6.2vw, 56px) + 8px) / 2); width: 100%; height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 24px) / 4); }
      50% { left: calc(50% + 2px); top: calc((100dvh - clamp(48px, 6.2vw, 56px) + 8px) / 2); width: calc(25% - 3px); height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 24px) / 4); }
      100% { left: calc(50% + 2px); top: 0; width: calc(25% - 3px); height: 100%; }
    }
    @keyframes seat4 {
      0% { left: 0; top: calc((100dvh - clamp(48px, 6.2vw, 56px) + 8px) * 0.75); width: 100%; height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 24px) / 4); }
      50% { left: calc(75% + 3px); top: calc((100dvh - clamp(48px, 6.2vw, 56px) + 8px) * 0.75); width: calc(25% - 3px); height: calc((100dvh - clamp(48px, 6.2vw, 56px) - 24px) / 4); }
      100% { left: calc(75% + 3px); top: 0; width: calc(25% - 3px); height: 100%; }
    }
  }
  @keyframes tagFull { 0% { opacity: 1; } 45% { opacity: 0; } 100% { opacity: 0; } }
  @keyframes tagShort { 0% { opacity: 0; } 52% { opacity: 0; } 88% { opacity: 1; } 100% { opacity: 1; } }
  @keyframes themeOut { 0% { opacity: 1; } 34% { opacity: 0; } 100% { opacity: 0; } }
  /* Identical to themeOut now that both variants open at full strength; kept as two names
     because the inline caption and the plate are assigned separately and one may yet need
     to move without the other. */
  @keyframes theme2Out { 0% { opacity: 1; } 34% { opacity: 0; } 100% { opacity: 0; } }
  .title { opacity: 1; transform: none; }
  @keyframes titleIn { 0% { opacity: 0; transform: translateY(12px); } 44% { opacity: 0; transform: translateY(12px); } 80% { opacity: 1; transform: translateY(0); } 100% { opacity: 1; transform: translateY(0); } }

  @supports (animation-timeline: scroll()) {
    .seat, .seats-bg, .seat-img, .seat-tag--full, .seat-tag--short, .topic--inline, .topic--bar {
      animation-duration: 1ms; animation-timing-function: linear; animation-fill-mode: both;
      animation-timeline: scroll(root block); animation-range: 0 52vh;
    }
    .seat[data-seat="1"] { animation-name: seat1; }
    .seat[data-seat="2"] { animation-name: seat2; }
    .seat[data-seat="3"] { animation-name: seat3; }
    .seat[data-seat="4"] { animation-name: seat4; }
    .seats-bg { animation-name: seatBg; }
    .seat-img { animation-name: imgFocus; }
    .seat-tag--full { animation-name: tagFull; }
    .seat-tag--short { animation-name: tagShort; }
    .topic--inline { animation-name: themeOut; }
    .topic--bar { animation-name: theme2Out; }
  }

  /* honest static fallback: no scroll-timeline support, reduced motion, or morph off */
  @supports not (animation-timeline: scroll()) {
    .seats { position: static; height: calc(100dvh - clamp(48px, 6.2vw, 56px)); }
    .call-spacer { display: none; }
  }
      /* static fallback: same shape as reduced-motion, used when the timeline is inert */
          @media (prefers-reduced-motion: reduce) {
    /* .topic--* is deliberately NOT in this list. The preference asks for no MOVEMENT, and
       themeOut/theme2Out animate opacity and nothing else — while being the only mechanism
       that takes the caption off the second screen. Freezing it here left "MEETING: CAN WE
       PROVE WHAT HAPPENED?" pinned under the header for the whole page, at full opacity:
       measured 1.00 at max scroll on both phone and desktop. */
    .seat, .seats-bg, .seat-img, .seat-tag--full, .seat-tag--short, .title { animation: none !important; transition: none !important; }
    .seats { position: static !important; height: calc(100dvh - clamp(48px, 6.2vw, 56px)) !important; }
    .call-spacer { display: none !important; }
    * { transition: none !important; }
  }

  /* the scene has no resting middle: native scroll always settles on expanded, collapsed, or the page end */
  /* completion is driven from the logic class (direction-aware), not by nearest-point snapping */
  /* The export disabled native snapping and drove the "settle on a screen" behaviour from
     JavaScript instead — a wheel/touch hijack that called preventDefault on every gesture.
     That hijack is gone: it fought the platform, broke keyboard and assistive scrolling, and
     the browser does the same job natively. `proximity` settles a nearly-finished scroll and
     leaves a deliberate one alone. Both fallbacks below still turn it off. */
  /* `mandatory`, not `proximity`: the scene has no resting middle — a scroll always finishes
     on a screen boundary. That is what the export's wheel hijack was for; the browser does it
     natively, and unlike the hijack it leaves keyboard, find-in-page and assistive scrolling
     alone. On short phones the footer is a third screen with its own snap point. */
  html { scroll-snap-type: y mandatory; }
  .snap-probe { position: absolute; left: 0; width: 1px; height: 1px; opacity: 0; pointer-events: none; scroll-snap-align: start; }
  /* active speaker: exactly one seat ringed, independent of visitor hover */
  .seat-speak { visibility: hidden; position: absolute; inset: 0; z-index: 2; opacity: 0; pointer-events: none; box-shadow: inset 0 0 0 2px #0c7c78; background: rgba(12, 124, 120, 0.14); transition: opacity 220ms linear; }
  [data-speaking="1"] .seat[data-seat="1"] .seat-speak,
  [data-speaking="2"] .seat[data-seat="2"] .seat-speak,
  [data-speaking="3"] .seat[data-seat="3"] .seat-speak,
  [data-speaking="4"] .seat[data-seat="4"] .seat-speak { visibility: visible; }
  /* first load: signal static until each portrait arrives */
  .seat-connecting { position: absolute; inset: 0; display: block; overflow: hidden; background: #16201f; transition: opacity 340ms linear; }
  .seat-connecting[data-ready="1"] { opacity: 0; pointer-events: none; }
  .seat-noise { position: absolute; inset: -18%; background-image: repeating-linear-gradient(0deg, rgba(244, 242, 236, 0.075) 0 1px, rgba(0, 0, 0, 0) 1px 3px), repeating-linear-gradient(90deg, rgba(244, 242, 236, 0.05) 0 1px, rgba(0, 0, 0, 0) 1px 2px); animation: noiseJitter 170ms steps(2, end) infinite; }
  @keyframes noiseJitter { 0% { transform: translate3d(0, 0, 0); } 25% { transform: translate3d(-2px, 1px, 0); } 50% { transform: translate3d(1px, -2px, 0); } 75% { transform: translate3d(2px, 2px, 0); } 100% { transform: translate3d(-1px, -1px, 0); } }
  .seat-band { position: absolute; left: 0; right: 0; height: 24%; background: linear-gradient(rgba(12, 124, 120, 0) 0%, rgba(12, 124, 120, 0.3) 46%, rgba(244, 242, 236, 0.14) 54%, rgba(12, 124, 120, 0) 100%); animation: bandSweep 2.2s linear infinite; }
  @keyframes bandSweep { from { top: -28%; } to { top: 108%; } }
  .seat-connlabel { opacity: 0.86; position: absolute; left: 12px; top: 12px; display: flex; align-items: center; gap: 5px; font: 400 9.5px/1 'JetBrains Mono', monospace; letter-spacing: 0.16em; text-transform: uppercase; color: rgba(244, 242, 236, 0.6); }
  .dots { animation: dotsBlink 1.05s steps(1, end) infinite; }
  @keyframes dotsBlink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0.18; } }
  @media (prefers-reduced-motion: reduce) { .seat-noise, .dots { animation: none !important; } .seat-band { display: none; } }

  /* call interface on the strip: who is speaking */
  .seat-level { position: absolute; top: 8px; right: 8px; z-index: 3; display: none; align-items: flex-end; gap: 2px; height: 12px; pointer-events: none; }
  .seat-level > span { width: 3px; height: 100%; background: #0c7c78; transform-origin: bottom; animation: levelBar 680ms ease-in-out infinite alternate; }
  .seat-level > span:nth-child(2) { animation-delay: 150ms; }
  .seat-level > span:nth-child(3) { animation-delay: 300ms; }
  @keyframes levelBar { from { transform: scaleY(0.26); } to { transform: scaleY(1); } }
  [data-speaking="1"] .seat[data-seat="1"] .seat-level,
  [data-speaking="2"] .seat[data-seat="2"] .seat-level,
  [data-speaking="3"] .seat[data-seat="3"] .seat-level,
  [data-speaking="4"] .seat[data-seat="4"] .seat-level { display: flex; }
  [data-speaking="1"] .seat[data-seat="1"] .seat-tag--short,
  [data-speaking="2"] .seat[data-seat="2"] .seat-tag--short,
  [data-speaking="3"] .seat[data-seat="3"] .seat-tag--short,
  [data-speaking="4"] .seat[data-seat="4"] .seat-tag--short { background: #0c7c78 !important; color: #f4f2ec !important; }
  @media (prefers-reduced-motion: reduce) { .seat-level > span { animation: none !important; transform: scaleY(0.62); } }

  /* mobile: the meeting topic is a second line under the header, gone on scroll */
  .topic--bar { display: none; }
  @media (max-width: 767px) {
    .topic--bar { display: flex; }
    header .topic--inline { display: none !important; }
    /* Dropping the inline topic leaves the bar's third grid column empty, and the column gap
       still sits between the links and the padding edge: the links ended 22px in while the
       logo started at 12px. Two columns, and the nav closes on the inset the logo opens at.
       Three rules used to aim at this and all three addressed `header > div:nth-child(3)`,
       written against the export's divs — the rebuild made those children a, p, nav, p, so
       the selector matched nothing. Measured: 0 elements, on every viewport. */
    .bar { grid-template-columns: auto minmax(0, 1fr); }
    .bar-links { justify-self: end; flex-wrap: nowrap; }
    .brand { min-width: 0; overflow: hidden; }
    .brand-name { overflow: hidden; text-overflow: ellipsis; }
  }
  /* Whether the topic is shown at all is decided here, in one place, and this clause has to
     come last: it is one class deep like the two rules above it, so anywhere earlier the
     media query simply wins and the rule is dead — which is what the first version of it was.
     The topic hangs off a sticky header and therefore rides the whole document; the only
     thing that ever took it off the second screen is the scroll-driven fade. Where no
     timeline exists to run that fade, the caption would sit over the stage for the length of
     the page, so it is not shown: the recording chrome belongs to the animated layer, and a
     browser that cannot run the morph gets the static grid without it. */
  @supports not (animation-timeline: scroll()) {
    .topic--inline, .topic--bar { display: none; }
  }
  .rec { animation: breathe 4.5s ease-in-out infinite; }
  @keyframes breathe { 0%, 100% { opacity: 0.34; transform: scale(0.82); } 45% { opacity: 1; transform: scale(1); } }
  @media (prefers-reduced-motion: reduce) { .rec { animation: none !important; } }
  @keyframes caretBlink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }
  .caret { animation: caretBlink 1s steps(1, end) infinite; }
  @media (prefers-reduced-motion: reduce) { .caret { animation: none !important; } }
  .stage { min-height: calc(100dvh - clamp(48px, 6.2vw, 56px) - clamp(70px, min(11vw, 26vh), 400px)); }
  @media (min-height: 700px) { .stage { height: calc(100dvh - clamp(48px, 6.2vw, 56px) - clamp(70px, min(11vw, 26vh), 400px)); } }
  /* mobile: two footer columns, otherwise screen 2 cannot hold one viewport */
  @media (max-width: 767px) {
    .stage > footer > div:first-child { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: 14px 18px !important; }
    .stage > footer a { font-size: 10.5px !important; }
    .stage > footer span { font-size: 9.5px !important; }
    .stage > footer > div:last-child { gap: 10px 18px !important; padding-top: 9px !important; }
    /* on a phone the footer sits on the header's side rail, not the wide content rail */
    .stage > footer { padding-top: 16px !important; padding-bottom: 10px !important; gap: 14px !important; padding-left: clamp(12px, 1.6vw, 20px) !important; padding-right: clamp(12px, 1.6vw, 20px) !important; }
    .seal pre { font-size: 3.6px !important; }
    .stage > div:first-child { padding-top: 18px !important; padding-bottom: 18px !important; }
    /* Three columns in a two-column grid leave the last one alone on its row with the other
       half empty. It takes the whole row instead, and its four links run down two columns —
       the export's arrangement, restored: the rules that carried it addressed
       `footer > div:first-child > div:nth-child(3)`, and the rebuild made these children
       sections, so nothing matched. Column flow, so the pairs read down and then across. */
    .foot-cols > .foot-col:last-child { grid-column: 1 / -1; }
    .foot-cols > .foot-col:last-child > ul {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      grid-template-rows: repeat(2, auto);
      grid-auto-flow: column;
      gap: 4px 18px;
    }
    .foot-cols > .foot-col:last-child > ul a { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  }
  /* short phones (SE, mini): the footer becomes its own screen — text keeps a whole one */
  @media (max-width: 767px) and (max-height: 829px) {
    .stage { height: auto !important; }
    .stage > div:first-child { box-sizing: border-box; min-height: calc(100dvh - clamp(48px, 6.2vw, 56px) - clamp(70px, min(11vw, 26vh), 400px)) !important; }
    .stage > footer { box-sizing: border-box; min-height: calc(100dvh - clamp(48px, 6.2vw, 56px) - clamp(70px, min(11vw, 26vh), 400px)); justify-content: flex-start !important; padding-top: clamp(22px, 4vh, 34px) !important; scroll-snap-align: start; scroll-margin-top: calc(clamp(48px, 6.2vw, 56px) + clamp(70px, min(11vw, 26vh), 400px)); }
  }
  @media (max-width: 767px) {
    .stage > footer > div:last-child { flex-wrap: nowrap !important; align-items: flex-start !important; }
  }
  .stage > footer { flex: 0 0 auto; }
  /* `.seatbtn:hover { color: #f4f2ec !important }` used to live here. It restated what
     `a.seatbtn:hover` above already says, and by dropping the `a` it also caught the three
     disabled spans: their background is not part of that rule, so hovering Corporate,
     Developer or Operator turned the label cream on a cream page and the button read as
     gone. An inactive control has no hover state — that is what makes it read as inactive. */
  /* the longest line needs a third line on a phone; wider screens fit it in two */
  @media (max-width: 767px) {
    .quote-text { min-height: calc(1.6em * 3) !important; }
    /* 30px clear between each rule and the content outside the pair */
    .title + .rule { margin-top: max(0px, 30px - clamp(14px, 2.2vh, 26px)); }
    .bridge { margin-top: max(0px, 30px - clamp(14px, 2.2vh, 26px)) !important; }
  }
  /* Short phones give the footer a screen of its own, so the text screen is the one that has
     room to spare there — the pair keeps its original 60px. This block has to FOLLOW the one
     above: identical specificity, so anywhere earlier it simply loses and reads as applied. */
  @media (max-width: 767px) and (max-height: 829px) {
    .title + .rule { margin-top: max(0px, 60px - clamp(14px, 2.2vh, 26px)); }
    .bridge { margin-top: max(0px, 60px - clamp(14px, 2.2vh, 26px)) !important; }
  }
  /* wide and tall displays: the second screen has room, so use it */
  @media (min-width: 1920px) {
    .title { font-size: clamp(64px, 3.5vw, 104px) !important; max-width: min(20ch, 1100px) !important; }
    .quote { font-size: clamp(21px, 1.15vw, 32px) !important; max-width: min(100%, 1100px) !important; }
    .bridge { font-size: clamp(14px, 0.72vw, 20px) !important; }
    .seatbtn { font-size: clamp(13px, 0.66vw, 18px) !important; height: calc(30px - 0.1em) !important; }
    .seatrow { max-width: 1100px !important; }
    .rule { width: min(100%, 1100px) !important; }
    .seat-tag--short { font-size: 13px !important; padding: 6px 11px !important; }
    .seat-tag--full { font-size: 15px !important; padding: 9px 14px !important; }
  }
  .seal pre { transition: transform 150ms steps(2, end); }
  /* pressed: the seal erases line by line, top down — and is whole again the moment you let go */
  .seal.is-pressed pre { animation: sealErase 320ms steps(11, end) forwards; }
  @keyframes sealErase { from { clip-path: inset(0 0 0 0); } to { clip-path: inset(100% 0 0 0); } }
  @media (prefers-reduced-motion: reduce) { .seal.is-pressed pre { animation: none !important; } }
  .seal:hover pre { transform: translateY(2px); }
  @media (prefers-reduced-motion: reduce) { .seal pre { transition: none !important; } .seal:hover pre { transform: none !important; } }
  @supports not (animation-timeline: scroll()) { html { scroll-snap-type: none; } }
  @media (prefers-reduced-motion: reduce) { html { scroll-snap-type: none !important; } }

/* the bar under the header carries a slightly smaller dot than the inline one */
.topic--bar .rec { width: 5px; height: 5px; flex: none; }

/* ---- hover states the export carried as a style-hover attribute ---- */
/* the brand mark dims slightly on hover */
.brand:hover { opacity: 0.72; }
/* hovering a seat darkens its name plate so the caption stays legible over the portrait */
.seat-link:hover .seat-tag--full { background: rgba(30, 28, 26, 0.97); }

/* a quote with a speaker is a quote worth showing */
.quote:has(.quote-name:not(:empty)) { opacity: 1; }

/* ---- the call UI belongs to the strip, not to the grid ----
   On the first screen the seats are half-screen portraits: a speaking ring and a level
   meter on them read as decoration, and the export hid the short name plate there for the
   same reason (@keyframes tagShort holds opacity 0 until 52% of the morph). The ring and
   the meter had no such gate, so they showed on the grid too. They get it now, from the
   same scroll timeline — two conditions must hold at once: someone is speaking (visibility
   / display, set by the speaking state) AND the strip has formed (opacity, driven by the
   morph). Neither alone puts anything on screen. */
@keyframes callUiIn { 0%, 52% { opacity: 0; } 100% { opacity: 1; } }

@supports (animation-timeline: scroll()) {
  .seat-speak, .seat-level {
    animation-name: callUiIn;
    animation-duration: 1ms;
    animation-timing-function: linear;
    animation-fill-mode: both;
    animation-timeline: scroll(root block);
    animation-range: 0 52vh;
  }
}
/* Without a scroll timeline there is no morph and therefore no grid-versus-strip
   distinction: the call UI simply shows whenever someone is speaking, as before. */
@supports not (animation-timeline: scroll()) {
  .seat-speak, .seat-level { opacity: 1; }
}

/* ---- the heading animates on ITS OWN position, not on the page's scroll offset ----
   It used to share the morph's `scroll(root block)` timeline. Two ways that showed:
   the heading is dark text, so any intermediate opacity reads as grey rather than as a
   fade; and returning to the page from a link (back out of /llms.txt, restored from the
   back/forward cache) leaves that timeline unsynchronised, so the heading could stay
   part-way — grey, or invisible altogether.
   `view()` is measured from the element's own box against the viewport, so it is correct
   at any scroll position, after any restore, at any window height. */
@supports (animation-timeline: view()) {
  .title {
    animation-name: titleIn;
    animation-duration: 1ms;
    animation-timing-function: linear;
    animation-fill-mode: both;
    animation-timeline: view();
    animation-range: entry 0% entry 60%;
  }
}
