/* =====================================================
   The Local Lab — base
   Art direction: the bench and the batch sheet. This is a working R&D room, so the
   page is built like the paper that comes out of it — specimen stock, hairline rules,
   a faint graph grid, monospaced numbers, one acid highlight for the thing you are
   meant to look at, and one vermilion for the thing you are meant to press.
   Vietnamese-ness is carried by the content, the ingredient data and the tool
   drawings, not by ornament.
   ===================================================== */

:root {
  /* ---- brand hues: fixed, because they are used as fills ---- */
  --graphite:   #14161A;   /* the ink everything is printed in */
  --graphite-2: #2A2E36;
  --steel:      #5C6068;   /* the quiet column: captions, units, secondary data */
  --paper:      #F4F1EA;   /* specimen stock */
  --paper-2:    #E9E5DA;   /* the darker sheet, for banded sections */
  --card:       #FFFFFF;   /* a clean sheet laid on top */
  --signal:     #D8FF3E;   /* the acid marker — a fill you put ink ON, never text in */
  --signal-dim: #B8E22A;
  --vermilion:  #C22C12;   /* the one accent: actions, live data, the hot cell */
  --vermilion-deep: #9A2009;
  --vermilion-on-dark: #FF7A52;
  --pass:       #17694F;   /* a result that cleared the bench */
  --pass-on-dark: #4FD6A4;
  --amber:      #A8690A;   /* a result still running */
  --nav:        #1F3F63;   /* the brand navy, kept for the logo and one data hue */

  /* ---- semantic roles: these are what the theme swap moves ---- */
  --bg:          var(--paper);
  --bg-alt:      var(--paper-2);
  --surface:     var(--card);
  --text:        var(--graphite);
  --muted:       var(--steel);
  --text-soft:   #3A3E46;
  --line:        rgba(20, 22, 26, .14);
  --line-strong: rgba(20, 22, 26, .38);
  --grid:        rgba(20, 22, 26, .05);
  --accent:      var(--vermilion);
  --accent-2:    var(--nav);
  --accent-on-dark: var(--vermilion-on-dark);
  --accent-hover: var(--vermilion-deep);
  --gold-ink:    #7A4E06;      /* amber darkened to a text weight — #A8690A is only 3.97:1 on paper */
  --on-accent:   #FFF6F2;     /* text sitting on a vermilion or navy fill */
  --on-signal:   #1A2000;     /* text sitting on the acid highlight */
  --edge:        var(--line-strong);   /* the drawn line around a sheet */
  --edge-fill:   var(--graphite);      /* the solid rule under a header */
  --shadow:      0 1px 2px rgba(20, 22, 26, .05);
  --shadow-lift: 0 10px 26px -18px rgba(20, 22, 26, .5);
  --shadow-hard: 0 1px 0 var(--line-strong);

  /* ---- type ---- */
  --display: "Be Vietnam Pro", system-ui, -apple-system, sans-serif;
  --body:    "Be Vietnam Pro", system-ui, -apple-system, sans-serif;
  /* every number, unit, code and label. Vietnamese words never go in here — the
     mono faces that ship with the OS do not all carry the full diacritic set. */
  --mono:    ui-monospace, "Cascadia Mono", "Segoe UI Mono", "SF Mono", Menlo, Consolas, monospace;
  --script:  "Pacifico", "Be Vietnam Pro", cursive;   /* the marker note, used twice */
  --fs-body: clamp(1rem, .25vw + .95rem, 1.0625rem);
  --step--2: clamp(.69rem, .1vw + .67rem, .76rem);
  --step--1: clamp(.81rem, .16vw + .78rem, .9rem);
  --step-0:  clamp(1rem, .3vw + .93rem, 1.075rem);
  --step-1:  clamp(1.25rem, .7vw + 1.06rem, 1.7rem);
  --step-2:  clamp(1.6rem, 1.4vw + 1.16rem, 2.5rem);
  --step-3:  clamp(2.1rem, 3vw + 1.2rem, 3.9rem);
  --step-4:  clamp(2.8rem, 6.5vw + .6rem, 6.4rem);
  --step-5:  clamp(3.6rem, 12vw - 1rem, 11rem);

  /* ---- space & shape ---- */
  --gutter: clamp(18px, 5vw, 76px);
  --maxw: 1320px;
  --head-h: 74px;
  /* the pinned title card of each chapter. Shorter than a screenful on purpose: the
     next chapter peeks under it before sticking, which reads as a sheet turning over
     rather than nine blank viewports to scroll through. */
  --chapter-h: clamp(440px, 76svh, 680px);
  --r-sm: 2px;
  --r-md: 3px;
  --r-lg: 4px;
  --r-pill: 2px;          /* nothing is round any more; a form field is a box */
  --hair: 1px;
  --ease: cubic-bezier(.22, .61, .36, 1);
  --ease-back: cubic-bezier(.34, 1.56, .64, 1);
  --z-head: 80;
  --z-narrator: 90;
  --z-fab: 100;
  --z-panel: 120;
  --z-toast: 140;
}

/* After hours: the same bench under a desk lamp. Only the roles move — the brand
   hues above stay put because they double as fills, and every text colour goes
   through a role token instead. */
[data-theme="night"] {
  --bg:          #0E1014;
  --bg-alt:      #13161B;
  --surface:     #181C22;
  --text:        #E8EAEF;
  --muted:       #99A1AE;
  --text-soft:   #C3C9D3;
  --line:        rgba(232, 234, 239, .13);
  --line-strong: rgba(232, 234, 239, .34);
  --grid:        rgba(232, 234, 239, .045);
  --accent:      var(--vermilion-on-dark);
  --accent-2:    #7FB2E8;
  --accent-hover: #FF9470;
  --gold-ink:    #F0C24B;
  --on-accent:   #1A0C06;
  --on-signal:   #1A2000;
  --edge:        var(--line-strong);
  --edge-fill:   var(--line-strong);
  --shadow:      0 1px 2px rgba(0, 0, 0, .4);
  --shadow-lift: 0 14px 30px -20px rgba(0, 0, 0, .85);
  --shadow-hard: 0 1px 0 var(--line-strong);
  --pass:        var(--pass-on-dark);
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box }
* { margin: 0; padding: 0 }
/* Component rules set display on these elements, so the attribute alone would not hide them. */
[hidden] { display: none !important }

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--head-h) + 18px);
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--body);
  font-size: var(--fs-body);
  line-height: 1.66;
  color: var(--text);
  background: var(--bg);
  /* the graph grid a bench sheet is printed on */
  background-image:
    linear-gradient(to right, var(--grid) var(--hair), transparent var(--hair)),
    linear-gradient(to bottom, var(--grid) var(--hair), transparent var(--hair));
  background-size: 34px 34px;
  overflow-x: hidden;
  transition: background-color .55s var(--ease), color .55s var(--ease);
}

img, svg, video { display: block; max-width: 100% }
img { height: auto }
button, input, select, textarea { font: inherit; color: inherit }
button { background: none; border: 0; cursor: pointer }
ul[role="list"], ol[role="list"] { list-style: none }
::selection { background: var(--signal); color: var(--on-signal) }

/* ---------- photo guarding ----------
   A deterrent, not a lock: the browser still has the bytes. What this stops is the
   drag-to-desktop and the right-click-save almost everyone actually tries. */
img, .bleed-img {
  -webkit-user-drag: none;
  user-select: none;
  -webkit-touch-callout: none;
}

a {
  color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: .22em;
  transition: color .25s var(--ease);
}
a:hover { color: color-mix(in srgb, var(--accent) 70%, var(--text)) }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 0;
}

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

.skip {
  position: fixed; top: 10px; left: 10px; z-index: 200;
  transform: translateY(-160%); transition: transform .3s var(--ease);
  background: var(--graphite); color: var(--paper); padding: .7rem 1.1rem; border-radius: var(--r-sm);
  font: 700 var(--step--2)/1 var(--mono); letter-spacing: .12em; text-transform: uppercase;
  text-decoration: none;
}
.skip:focus { transform: none }

.ico { width: 22px; height: 22px; fill: currentColor; flex: none }
.ico.sm { width: 16px; height: 16px }

/* ---------- typography ---------- */
h1, h2, h3, h4 { font-family: var(--display); line-height: 1.02; font-weight: 800; letter-spacing: -.03em }

.display {
  font-family: var(--display);
  font-weight: 800;
  font-size: var(--step-4);
  line-height: .92;
  letter-spacing: -.04em;
  text-transform: uppercase;
}
.display.sm { font-size: var(--step-3) }
.display.xs { font-size: var(--step-1); text-transform: none; letter-spacing: -.02em }
.display .line { display: block }
.display .accent { color: var(--accent) }
.display .ink { color: var(--text) }

/* the Vietnamese chapter name — the loudest thing on the screen */
.vi-title {
  font-family: var(--display);
  font-weight: 800;
  font-size: var(--step-4);
  line-height: .9;
  letter-spacing: -.04em;
  color: var(--text);
  /* ế and Ả stack two marks above the cap, and a .9 line box is shorter than the glyph,
     so the tone marks overflow into whatever sits above — this is their headroom */
  padding-top: .22em;
}
.en-title {
  font-family: var(--mono);
  font-weight: 400;
  font-size: var(--step--2);
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--accent);
}

.script { font-family: var(--script); font-weight: 400; font-size: var(--step-2); color: var(--accent); line-height: 1.1 }

/* a mono label with a dotted leader is the basic unit of this whole design */
.kicker {
  font-family: var(--mono);
  font-size: var(--step--2);
  font-weight: 400;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--accent);
}

.eyebrow {
  display: inline-flex; align-items: center; gap: .5rem;
  font-family: var(--mono); font-size: var(--step--2); letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted);
}

.lede, .sec-lede { font-size: var(--step-0); color: var(--muted); max-width: 62ch }
.fine { font-size: var(--step--1); color: var(--muted) }
.muted { color: var(--muted) }
.note-card {
  font-size: var(--step--1); color: var(--text-soft); line-height: 1.6;
  border-left: 2px solid var(--accent); padding-left: .9rem; max-width: 36ch;
}
.note-card::before {
  content: "Field note"; display: block; margin-bottom: .3rem;
  font: 400 var(--step--2)/1 var(--mono); letter-spacing: .18em; text-transform: uppercase; color: var(--accent);
}

/* ---------- layout primitives ---------- */
.wrap { max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter) }
.band { padding-block: clamp(64px, 9vw, 140px); position: relative }
/* ink band: a fixed dark island, so its text roles are pinned and the night swap
   cannot turn light-on-ink into light-on-light. */
.band-ink {
  --text: #E8EAEF; --muted: #99A1AE; --text-soft: #C3C9D3;
  --accent: var(--vermilion-on-dark); --accent-2: #7FB2E8;
  /* the coral this island prints with is light, so the text sitting on it has to be dark
     even at midday — otherwise a primary button on ink is cream-on-cream */
  --on-accent: #1A0C06; --accent-hover: #FF9470;
  --line: rgba(232, 234, 239, .13); --line-strong: rgba(232, 234, 239, .34);
  --edge: var(--line-strong); --gold-ink: #F0C24B;
  background: #12161C; color: var(--text);
}

/* the ruler that separates two chapters — the tick strip printed down the side of
   a measuring cylinder, laid flat */
.checker {
  height: 16px;
  background-image:
    repeating-linear-gradient(90deg, var(--line-strong) 0 1px, transparent 1px 8px),
    repeating-linear-gradient(90deg, var(--accent) 0 1px, transparent 1px 40px);
  background-size: 100% 7px, 100% 16px;
  background-position: 0 9px, 0 0;
  background-repeat: no-repeat;
  border-top: var(--hair) solid var(--line);
}

/* ---------- motion ---------- */
/* reveal on scroll. --d is set per element by armReveals(): siblings in one container
   rise in sequence, which is what makes a grid feel like it is being filled in. */
.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .6s var(--ease), transform .6s var(--ease);
  transition-delay: var(--d, 0ms);
}
.reveal.in { opacity: 1; transform: none }

/* the rail and the street outside the hero read their progress off the scroll timeline,
   not off a listener, so they stay pinned to the finger */
@supports (animation-timeline: scroll()) {
  .rail-fill { animation: rail-grow linear both; animation-timeline: scroll(root); transform-origin: top }
  /* the street outside the hero slides slower than the reader, so the morning light
     is still moving when the first chapter pins */
  .hero-photo { animation: hero-drift linear both; animation-timeline: scroll(root); animation-range: 0 90svh }
}
@keyframes rail-grow { from { transform: scaleY(0) } to { transform: scaleY(1) } }
@keyframes hero-drift { to { transform: translateY(9%) scale(1.05) } }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
    animation-name: none !important;
    transition-duration: .001ms !important;
    transition-delay: 0ms !important;
  }
  .reveal { opacity: 1; transform: none }
}
