/* ============================================================
   ZENITH LABS — Advanced layer
   Peptide chain · specimen stage · atmosphere · instrument chrome
   ============================================================ */

/* ============================================================
   1. PEPTIDE CHAIN
   Monochrome + Swiss red only. Colouring by full physicochemical
   class would read as confetti and break the identity; class is
   carried by stroke/fill weight instead of by hue.
   ============================================================ */

#spec-chain { min-width: 0; width: 100%; }
.pep { display: block; width: 100%; height: auto; }

.pep__bb {
  stroke: var(--rule);
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.pep__term { fill: var(--fg-lo); }

.pep__n circle {
  stroke-width: 1.3;
  fill: var(--bg);
  stroke: var(--rule);
  vector-effect: non-scaling-stroke;
}
.pep__n text { fill: var(--fg-mid); }

.pep__n--polar  circle { stroke: var(--fg-lo); }
.pep__n--basic  circle { stroke: var(--red); }
.pep__n--basic  text   { fill: var(--red); }
.pep__n--acidic circle { stroke: var(--red); fill: var(--red-wash); }
.pep__n--acidic text   { fill: var(--red); }
.pep__n--metal  circle { fill: var(--red); stroke: var(--red); }
.pep__n--metal  text   { fill: #fff; }
.pep__n--special circle { fill: var(--fg); stroke: var(--fg); }
.pep__n--special text   { fill: var(--bg); }

/* Draw-on is driven by the Web Animations API in main.js, not by a class.
   Deliberate: a CSS class reveal here fails INVISIBLE if the cascade or the
   frame timing goes wrong, and invisible content is the worst failure mode
   available. The default state below is fully visible; JS only animates
   *into* it with fill:"backwards". No JS, no animation, still readable. */

@media (prefers-reduced-motion: reduce) {
  .pep__bb { stroke-dashoffset: 0 !important; }
}

/* ============================================================
   2. SPECIMEN STAGE
   Replaces the card grid. One specimen presented at scale, with a
   selector rail — a lab manifest, not a storefront shelf.
   ============================================================ */

.specimen {
  display: grid;
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: clamp(28px, 5vw, 80px);
  align-items: center;
}
@media (max-width: 980px) { .specimen { grid-template-columns: 1fr; gap: var(--s-6); } }

/* --- vial stage --- */
.specimen__stage {
  position: relative;
  display: grid;
  place-items: center;
  min-height: clamp(340px, 52vh, 560px);
  border: 1px solid var(--rule);
  border-radius: var(--r-2);
  overflow: hidden;
  background:
    radial-gradient(80% 60% at 50% 42%,
      color-mix(in srgb, var(--fg) 5%, transparent), transparent 70%);
}

/* Calibration grid behind the specimen */
.specimen__stage::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(color-mix(in srgb, var(--fg) 7%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in srgb, var(--fg) 7%, transparent) 1px, transparent 1px);
  background-size: 48px 48px;
  mask-image: radial-gradient(70% 60% at 50% 50%, #000 30%, transparent 78%);
  -webkit-mask-image: radial-gradient(70% 60% at 50% 50%, #000 30%, transparent 78%);
  pointer-events: none;
}

.specimen__vial {
  position: relative;
  z-index: 1;
  height: clamp(260px, 42vh, 440px);
  width: auto;
  filter: drop-shadow(0 30px 54px rgba(0, 0, 0, 0.42));
  transition: opacity 340ms var(--e-out), transform 520ms var(--e-swiss);
}
.specimen.is-swapping .specimen__vial { opacity: 0; transform: translateY(14px) scale(0.97); }

/* Corner registration marks — calibrated-instrument cue */
.reg {
  position: absolute;
  width: 13px; height: 13px;
  border: 1px solid var(--red);
  opacity: 0.55;
  pointer-events: none;
}
.reg--tl { top: 12px; left: 12px;  border-right: 0; border-bottom: 0; }
.reg--tr { top: 12px; right: 12px; border-left: 0;  border-bottom: 0; }
.reg--bl { bottom: 12px; left: 12px;  border-right: 0; border-top: 0; }
.reg--br { bottom: 12px; right: 12px; border-left: 0;  border-top: 0; }

.specimen__readout {
  position: absolute;
  left: 14px; bottom: 12px;
  z-index: 2;
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.14em;
  color: var(--fg-lo);
  text-transform: uppercase;
}

/* --- detail panel --- */
.specimen__panel { display: flex; flex-direction: column; gap: var(--s-5); min-width: 0; }

.specimen__name {
  font-family: var(--ff-body);
  font-weight: 600;
  font-size: clamp(2.4rem, 5.6vw, 4.4rem);
  line-height: 0.94;
  letter-spacing: -0.045em;
  transition: opacity 300ms var(--e-out), transform 420ms var(--e-swiss);
}
.specimen.is-swapping .specimen__name { opacity: 0; transform: translateY(10px); }

.specimen__sub {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-3) var(--s-5);
}
.specimen__strength {
  color: var(--red);
  font-size: var(--fs-lead);
  font-weight: 500;
  letter-spacing: 0.02em;
}

.specimen__chain {
  min-width: 0;
  padding: var(--s-5) 0;
  border-block: 1px solid var(--rule);
  transition: opacity 300ms var(--e-out);
}
.specimen.is-swapping .specimen__chain { opacity: 0; }

.specimen__chainhead {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s-4);
  margin-bottom: var(--s-4);
}

.specimen__buy {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  flex-wrap: wrap;
}
.specimen__price {
  font-size: clamp(1.5rem, 2.4vw, 2rem);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.specimen__price small {
  display: block;
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  font-weight: 400;
  letter-spacing: 0.12em;
  color: var(--fg-lo);
  text-transform: uppercase;
}

/* --- selector rail --- */
.rail {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 0;
  margin-top: clamp(32px, 5vw, 56px);
  border-top: 1px solid var(--rule);
}
@media (max-width: 760px) {
  .rail { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.rail__b {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 5px;
  padding: var(--s-5) var(--s-4) var(--s-5) 0;
  text-align: left;
  border-right: 1px solid var(--rule);
  color: var(--fg-lo);
  transition: color var(--t-base) var(--e-inout);
}
.rail__b:last-child { border-right: 0; }
@media (max-width: 760px) {
  .rail__b { border-bottom: 1px solid var(--rule); padding-right: var(--s-4); }
  .rail__b:nth-child(2n) { border-right: 0; }
}

.rail__b::before {
  content: "";
  position: absolute;
  top: -1px; left: 0; right: 0;
  height: 1px;
  background: var(--red);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--t-slow) var(--e-out);
}
.rail__b[aria-selected="true"]::before { transform: scaleX(1); }
.rail__b:hover { color: var(--fg-mid); }
.rail__b[aria-selected="true"] { color: var(--fg); }

.rail__n {
  font-size: var(--fs-lead);
  font-weight: 500;
  letter-spacing: -0.02em;
}
.rail__m {
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* ============================================================
   3. ATMOSPHERE
   The build read flat. Grain + volumetric glow give surfaces
   material without costing a repaint.
   ============================================================ */

/* Film grain — one tiled feTurbulence data URI, fixed so it never
   scrolls (scrolling grain reads as a texture, static reads as film). */
.grain {
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: 0.032;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  mix-blend-mode: overlay;
}
@media (prefers-reduced-motion: reduce) { .grain { opacity: 0.022; } }

/* Volumetric glow — a soft red bloom anchored to a section corner */
.glow {
  position: absolute;
  pointer-events: none;
  z-index: 0;
  border-radius: 50%;
  filter: blur(72px);
  opacity: 0.5;
}
.glow--red  { background: radial-gradient(circle, rgba(200,16,46,0.30), transparent 68%); }
.glow--cool { background: radial-gradient(circle, rgba(120,150,190,0.16), transparent 68%); }

/* ============================================================
   4. INSTRUMENT CHROME
   A consistent system, not scattered decoration: every dark
   section can carry a crosshair rule and an axis readout.
   ============================================================ */

.chrome-grid {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(90deg, color-mix(in srgb, var(--fg) 6%, transparent) 1px, transparent 1px);
  background-size: calc(100% / 12) 100%;
  mask-image: linear-gradient(180deg, transparent, #000 18%, #000 82%, transparent);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 18%, #000 82%, transparent);
}

.axis-label {
  position: absolute;
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--fg-lo);
  opacity: 0.7;
  pointer-events: none;
  z-index: 1;
}

/* Section index number — oversized, sits in the margin */
.sec-no {
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.2em;
  color: var(--red);
}

/* ============================================================
   5. PINNED HERO SEQUENCE
   The media column stages through specimen -> annotated -> sequence
   while the copy and CTAs stay on screen the whole time. Pinning
   the CTA out of view to win a motion moment would be a bad trade.
   ============================================================ */

.hero-track {
  --pin-vh: 3.2;
  height: calc(var(--pin-vh) * 100vh);
  position: relative;
}
.hero-track > .hero {
  position: sticky;
  top: 0;
  height: 100vh;
  min-height: 0;
  display: grid;
  align-items: center;
  overflow: hidden;
}

.hero__media { position: relative; }

.hero__layer {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  will-change: opacity, transform;
}

/* Stage 1 — the specimen */
.hero__layer--vial {
  opacity: var(--l1-o, 1);
  transform: translate3d(0, var(--l1-y, 0px), 0) scale(var(--l1-s, 1));
}

/* Stage 2 — instrument annotation */
.hero__layer--annot { opacity: var(--l2-o, 0); pointer-events: none; }
.hero__note {
  position: absolute;
  top: var(--y);
  left: 50%;
  display: flex;
  align-items: center;
  gap: 10px;
  transform: translate(6%, -50%);
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--tx-mid-d);
  white-space: nowrap;
}
.hero__note i {
  display: block;
  width: calc(46px * var(--l2-o, 0));
  height: 1px;
  background: var(--red);
  flex: none;
}
.hero__note--r { left: auto; right: 50%; flex-direction: row-reverse; transform: translate(-6%, -50%); }

/* Stage 3 — the sequence assembles */
.hero__layer--chain {
  opacity: var(--l3-o, 0);
  transform: translate3d(0, var(--l3-y, 20px), 0);
  padding-inline: 4%;
}
.hero__layer--chain .pep { max-width: 100%; }

.hero__stagelabel {
  position: absolute;
  left: 50%; bottom: 2px;
  transform: translateX(-50%);
  color: var(--tx-lo-d);
  white-space: nowrap;
}

/* Stage progress dots */
.hero__prog {
  position: absolute;
  right: calc(var(--gutter) * 0.6);
  top: 50%;
  transform: translateY(-50%);
  z-index: var(--z-content);
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.hero__prog i {
  display: block;
  width: 2px; height: 26px;
  background: var(--tx-lo-d);
  opacity: 0.3;
  transition: opacity var(--t-base) var(--e-inout), background var(--t-base) var(--e-inout);
}
.hero__prog i.on { opacity: 1; background: var(--red); }

/* No pin on small screens or with reduced motion: a 3-viewport scroll
   hijack on a phone is hostile, and the sequence is decoration. */
@media (max-width: 940px), (prefers-reduced-motion: reduce) {
  .hero-track { height: auto; }
  .hero-track > .hero { position: relative; height: auto; min-height: min(100svh, 900px); }
  .hero__layer--annot, .hero__layer--chain, .hero__prog { display: none; }
  .hero__layer--vial { opacity: 1 !important; transform: none !important; }
  .hero__stagelabel { display: none; }
}

/* ============================================================
   6. PHOTOGRAPHIC PLATES
   Brand photography sits BEHIND content, always under a scrim
   sized to keep body text at >= 4.5:1. A photo that costs
   legibility is a photo that costs conversion.
   ============================================================ */

.plate {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.plate img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--pos, 50% 50%);
  opacity: var(--op, 1);
}

/* Scrim variants — pick by where the text sits */
.plate::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--scrim,
    linear-gradient(90deg, rgba(15,17,20,0.96) 0%, rgba(15,17,20,0.82) 38%,
                           rgba(15,17,20,0.42) 68%, rgba(15,17,20,0.30) 100%));
}
.plate--center::after {
  background: radial-gradient(70% 60% at 50% 50%, rgba(15,17,20,0.55), rgba(15,17,20,0.93) 78%);
}
.plate--bottom::after {
  background: linear-gradient(180deg, rgba(15,17,20,0.55) 0%, rgba(15,17,20,0.20) 34%,
                                      rgba(15,17,20,0.88) 82%, rgba(15,17,20,0.97) 100%);
}

/* Section carrying a plate must raise its own content */
.has-plate { position: relative; overflow: hidden; }
.has-plate > .shell { position: relative; z-index: var(--z-content); }

/* Editorial: full-bleed peak, text held in the dark left third */
.editorial--photo {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: clamp(32px, 6vw, 88px);
  align-items: center;
  min-height: clamp(520px, 74vh, 780px);
}
@media (max-width: 900px) {
  .editorial--photo { grid-template-columns: 1fr; min-height: 0; }
}

/* Contained plate — a framed image inside a light section */
.plate-inline {
  position: relative;
  margin-top: clamp(40px, 6vw, 72px);
  border: 1px solid var(--rule);
  border-radius: var(--r-2);
  overflow: hidden;
  aspect-ratio: 21 / 8;
  background: var(--ink);
}
.plate-inline img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
.plate-inline__cap {
  position: absolute;
  left: var(--s-5); bottom: var(--s-4);
  z-index: 2;
  color: var(--tx-mid-d);
}
.plate-inline::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 40%, rgba(15,17,20,0.85) 100%);
  pointer-events: none;
}
@media (max-width: 700px) { .plate-inline { aspect-ratio: 4 / 3; } }

/* Hero horizon — a whisper of range behind the particle field */
.hero__horizon {
  position: absolute;
  inset: auto 0 0 0;
  height: 62%;
  z-index: 0;
  pointer-events: none;
  opacity: 0.30;
  mask-image: linear-gradient(180deg, transparent, #000 55%, #000 100%);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 55%, #000 100%);
}
.hero__horizon img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 62%; }
