/* Haepari — built on QD (Qualle Design) principles: flat bodies with light on the rim,
   monochrome type, colour only for what you press, "picked" is one clear drop, blur only on
   floating things. The palette below is a proposal (dark only for now). */

:root {
  color-scheme: dark;
  --bg: #05060a;
  --surface: #0d0f15;
  --surface-2: #13161e;
  --line: rgba(255, 255, 255, 0.075);
  --line-strong: rgba(255, 255, 255, 0.14);
  --text: #f2f3f6;
  --text-2: #a7acb9;
  --text-3: #737a89;
  --accent: #5fd6ee;
  --accent-on: #03141a;
  --accent-hover: #7fe0f3;
  --rim-a: rgba(255, 255, 255, 0.3);
  --rim-b: rgba(255, 255, 255, 0.04);
  --rim-c: rgba(255, 255, 255, 0.14);
  --glass: rgba(16, 18, 24, 0.62);
  --glass-thick: rgba(14, 16, 22, 0.86);
  --r-sm: 12px;
  --r-md: 16px;
  --r-lg: 22px;
  --r-pill: 999px;
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --spring: linear(0, 0.02 1.2%, 0.09 3.2%, 0.36 8.4%, 0.68 14.2%, 0.89 19.4%, 1.01 24.4%, 1.055 28.6%, 1.064 32%, 1.052 36.2%, 1.018 44.8%, 0.998 53.6%, 0.993 60%, 0.998 72%, 1);
  --font: 'Pretendard Variable', Pretendard, -apple-system, BlinkMacSystemFont, 'Apple SD Gothic Neo', 'Segoe UI', system-ui, sans-serif;
  --mono: 'JetBrains Mono', 'SF Mono', ui-monospace, Consolas, monospace;
  --pad: clamp(20px, 5vw, 64px);
  --wide: 1240px;
  /* Every chapter's content starts on the same line: the wide column, or the page padding. */
  --edge: max(var(--pad), calc((100% - var(--wide)) / 2));
}

* { box-sizing: border-box; }
html { background: var(--bg); scroll-behavior: smooth; }
/* No background on body: the scene canvas sits behind it (z-index -1) and would be covered. */
body {
  margin: 0;
  font-family: var(--font);
  color: var(--text);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  word-break: keep-all;
  overflow-wrap: break-word;
}
a { color: inherit; }
img { display: block; max-width: 100%; }
button { font: inherit; color: inherit; }

/* Language: both are in the markup, one is shown. */
html[data-lang='en'] .ko { display: none; }
html[data-lang='ko'] .en { display: none; }

.skip {
  position: fixed;
  z-index: 30;
  left: 16px;
  top: -60px;
  padding: 10px 16px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  text-decoration: none;
}
.skip:focus { top: 16px; }

/* ---------------------------------------------------------------- rim light (QD 2) */
.drop::before {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(135deg, var(--rim-a), var(--rim-b) 40%, var(--rim-b) 60%, var(--rim-c));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
}

/* ---------------------------------------------------------------- the drop (QD 3)
   One clear drop says "picked" / "you are here". Its two edges travel separately: the leading
   edge gets there first and the trailing one follows, so it stretches and catches up. */
.drop {
  position: absolute;
  z-index: 0;
  top: 3px;
  bottom: 3px;
  left: var(--l, 0px);
  right: var(--r, 0px);
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.07);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06), inset 0 0 6px rgba(255, 255, 255, 0.05), 0 1px 4px rgba(0, 0, 0, 0.35);
  opacity: 0;
  pointer-events: none;
  transition:
    left 380ms var(--spring) var(--dl, 0ms),
    right 380ms var(--spring) var(--dr, 0ms),
    opacity 200ms var(--ease);
}
.drop[data-on='true'] { opacity: 1; }
.drop[data-still='true'] { transition: opacity 200ms var(--ease); }

/* Segmented control: what is picked wears the drop. */
.seg {
  position: relative;
  display: flex;
  padding: 3px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.05);
}
.seg button {
  position: relative;
  z-index: 1;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-3);
  background: transparent;
  border: 0;
  border-radius: var(--r-pill);
  padding: 5px 12px;
  cursor: pointer;
  transition: color 0.2s var(--ease), transform 0.35s var(--spring);
}
.seg button[aria-pressed='true'], .seg button[aria-selected='true'] {
  color: var(--text);
  text-shadow: 0 0 0 var(--text);
}
.seg button:active { transform: scale(0.96); }
.seg .drop { top: 3px; bottom: 3px; }

/* ---------------------------------------------------------------- buttons */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  padding: 0 20px;
  border-radius: var(--r-pill);
  font-size: 15px;
  font-weight: 650;
  text-decoration: none;
  color: var(--text);
  background: rgba(255, 255, 255, 0.07);
  box-shadow: inset 0 0 0 1px var(--line-strong);
  transition: background-color 0.2s var(--ease), transform 0.35s var(--spring);
}
.btn:hover { background: rgba(255, 255, 255, 0.12); }
.btn:active { transform: scale(0.96); }
.btn-accent {
  color: var(--accent-on);
  background: var(--accent);
  box-shadow: inset 0 1px 0.5px rgba(255, 255, 255, 0.45);
}
.btn-accent:hover { background: var(--accent-hover); }
.btn:focus-visible, .seg button:focus-visible, .entry:focus-visible, .text-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}
.text-link {
  color: var(--accent);
  font-weight: 650;
  text-decoration: none;
}
.text-link:hover { text-decoration: underline; text-underline-offset: 3px; }
.text-link.small { font-size: 13px; }

/* ---------------------------------------------------------------- the scene
   One canvas behind the whole page (scene.js). It is sized to the large viewport (100lvh), so a
   phone's address bar sliding away does not resize it and restart the water. */
canvas.gl {
  position: fixed;
  z-index: -1;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  height: 100lvh;
  display: block;
  pointer-events: none;
}

/* ---------------------------------------------------------------- chapters
   Each chapter names the scene it wants (data-scene); the one under the middle of the screen
   decides. Text sits straight on the water; the product chapters put theirs on thick glass. */
.ch { position: relative; }
.ch-hero {
  height: 100vh;
  height: 100svh;
  min-height: 600px;
  touch-action: pan-y;
}
.hero-copy {
  position: absolute;
  left: var(--edge);
  right: var(--edge);
  bottom: clamp(88px, 14vh, 140px);
  max-width: 760px;
  pointer-events: none;
}
.hero-copy .entries { pointer-events: auto; }
.eyebrow {
  margin: 0 0 10px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.12em;
  color: var(--text-2);
}
h1 {
  margin: 0;
  white-space: nowrap;
  font-size: clamp(52px, 9.2vw, 132px);
  line-height: 0.92;
  font-weight: 780;
  letter-spacing: -0.02em;
}
.lede {
  margin: 20px 0 28px;
  max-width: 560px;
  font-size: clamp(17px, 1.6vw, 20px);
  color: var(--text-2);
  text-wrap: balance;
}
.ch-hero .lang {
  position: absolute;
  z-index: 2;
  top: max(18px, env(safe-area-inset-top));
  right: var(--edge);
  --lg-bevel: 12px;
  --lg-fill: rgba(5, 8, 18, 0.2);
  text-shadow: 0 0 10px var(--lg-halo);
}

/* The hero's ways in: each one is a slab of glass that takes you to its chapter. */
.entries { display: flex; flex-wrap: wrap; gap: 10px; }
.entry {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-rows: auto auto;
  column-gap: 18px;
  align-items: center;
  min-width: 200px;
  padding: 12px 16px 12px 20px;
  border-radius: var(--r-lg);
  text-decoration: none;
  text-shadow: 0 0 10px var(--lg-halo);
  --lg-bevel: 14px;
  --lg-fill: rgba(5, 8, 18, 0.22);
  transition: transform 0.35s var(--spring);
}
.entry-name { font-size: 17px; font-weight: 720; letter-spacing: -0.01em; }
.entry-sub { grid-row: 2; font-size: 12.5px; color: var(--text-2); }
.entry-arrow {
  grid-row: 1 / 3;
  grid-column: 2;
  width: 16px;
  height: 16px;
  color: var(--text-2);
  transition: transform 0.35s var(--spring), color 0.2s var(--ease);
}
.entry:hover .entry-arrow { transform: translateY(3px); color: var(--text); }
.entry:active { transform: scale(0.97); }

.hero-meta {
  position: absolute;
  left: var(--edge);
  right: var(--edge);
  bottom: 28px;
  font-size: 12px;
  color: var(--text-3);
}
html[data-gl='off'] .hint { display: none; }
.hint-touch { display: none; }
@media (pointer: coarse) {
  .hint-fine { display: none; }
  .hint-touch { display: inline; }
}

/* Plain text over the water. */
.ch-text {
  display: grid;
  align-items: center;
  min-height: 90vh;
  min-height: 90svh;
  padding: clamp(80px, 12vh, 140px) var(--pad);
}
.ch-body { width: min(var(--wide), 100%); margin: 0 auto; }
.ch-text h2, .ch-text .prose { text-shadow: 0 0 18px var(--lg-halo), 0 0 3px var(--lg-halo); }
.ch-text .prose { font-size: clamp(18px, 1.7vw, 22px); max-width: 680px; }

/* Product chapters: the board or the network fills the screen, the words sit on thick glass. On a
   tall enough screen the card holds still for half a screen while the scene plays behind it. */
.ch-product { min-height: 100vh; min-height: 100svh; padding-inline: var(--pad); }
.stick {
  display: grid;
  grid-template-columns: minmax(0, 520px) minmax(0, 1fr);
  align-items: center;
  gap: clamp(24px, 4vw, 64px);
  width: min(var(--wide), 100%);
  margin: 0 auto;
  padding-block: clamp(72px, 10vh, 120px);
}
@media (min-width: 861px) and (min-height: 700px) {
  .ch-product { min-height: 150vh; min-height: 150svh; }
  .stick { position: sticky; top: 0; height: 100vh; height: 100svh; padding-block: 0; }
}
/* Clear glass: the scene dims itself behind the card (scene.js, "hush"), so the words read without
   tinting or frosting the glass, and what passes under the rim stays bright enough to see it bend. */
.card {
  position: relative;
  padding: clamp(24px, 2.6vw, 34px);
  border-radius: 28px;
  color: var(--text-2);
  text-shadow: 0 0 14px var(--lg-halo), 0 0 2px var(--lg-halo);
  --lg-bevel: 20px;
  --lg-fill: rgba(5, 8, 18, 0.1);
}
.card p { margin: 0 0 12px; }
.card .meta { margin: 0 0 6px; }
.product-name {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 14px;
  margin: 0 0 16px;
  font-size: clamp(40px, 4.6vw, 60px);
  line-height: 1;
  color: var(--text);
}
.product-sub {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--text-2);
}
.product-name .logo { height: clamp(30px, 3.2vw, 40px); align-self: center; }
.product-name .ko-name { font-size: 0.62em; font-weight: 720; letter-spacing: -0.02em; }
.shot {
  position: relative;
  margin: 0;
  padding: 12px;
  border-radius: var(--r-lg);
  --lg-bevel: 14px;
  --lg-fill: transparent;
}
.shot img { width: 100%; height: auto; aspect-ratio: 2 / 1; object-fit: cover; object-position: top; border-radius: 12px; }
.facts { margin: 18px 0 0; display: grid; border-top: 1px solid var(--line-strong); }
.facts div { display: flex; justify-content: space-between; gap: 16px; padding: 10px 0; border-bottom: 1px solid var(--line); font-size: 14px; }
.facts dt { color: var(--text-3); }
.facts dd { margin: 0; color: var(--text); font-weight: 560; text-align: right; }

/* The last word: one line over the water. */
.ch-contact {
  display: grid;
  align-items: center;
  min-height: 70vh;
  min-height: 70svh;
  padding: 0 var(--edge);
}
.contact-line {
  margin: 0;
  white-space: nowrap;
  font-size: clamp(20px, 3.4vw, 44px);
  font-weight: 700;
  letter-spacing: -0.01em;
  text-shadow: 0 0 18px var(--lg-halo), 0 0 3px var(--lg-halo);
}
.contact-label { font-weight: 600; letter-spacing: 0.12em; color: var(--text-2); }
.contact-line a { text-decoration: none; transition: color 0.2s var(--ease); }
.contact-line a:hover { color: var(--accent); }
.contact-line a:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 6px; }

/* Cards ease in once as they arrive (ui.js). Its own opacity is fine for a lens (glass.js). */
.reveal { opacity: 0; transform: translateY(18px); transition: opacity 500ms var(--ease), transform 700ms var(--spring); }
.reveal[data-in='true'] { opacity: 1; transform: none; }
.shot.reveal { transition-delay: 120ms; }

/* Without the scene, each chapter keeps a still background of its own. */
html[data-gl='off'] .ch[data-scene='water'] { background: radial-gradient(120% 80% at 75% 30%, rgba(0, 150, 200, 0.22), transparent 60%), var(--bg); }
html[data-gl='off'] .ch[data-scene='gridpi'],
html[data-gl='off'] .ch[data-scene='beellim'] {
  background-color: var(--surface);
  background-image: radial-gradient(rgba(255, 255, 255, 0.08) 1px, transparent 1.5px);
  background-size: 24px 24px;
}
.kicker {
  margin: 0 0 10px;
  font-size: 13px;
  font-weight: 650;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-3);
}
h2 {
  margin: 0 0 32px;
  font-size: clamp(32px, 4.2vw, 52px);
  line-height: 1.08;
  font-weight: 760;
  letter-spacing: -0.035em;
}
h3 {
  margin: 4px 0 10px;
  font-size: 22px;
  line-height: 1.25;
  font-weight: 720;
  letter-spacing: -0.015em;
  display: flex;
  align-items: center;
  gap: 10px;
}
.meta {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-3);
}
.muted { color: var(--text-3); font-size: 14px; }
.prose { font-size: 18px; color: var(--text-2); margin: 0 0 24px; max-width: 720px; }
.link-row { margin: 22px 0 0; }
.logo { height: 22px; width: auto; opacity: 0.95; }
html[data-lang='en'] .ko-name { display: none; }

/* ---------------------------------------------------------------- footer */
.foot {
  width: min(var(--wide), calc(100% - 2 * var(--pad)));
  margin: 0 auto;
  padding: 24px 0 40px;
  display: flex;
  justify-content: space-between;
  gap: 16px;
  font-size: 13px;
  color: var(--text-3);
  border-top: 1px solid var(--line-strong);
  text-shadow: 0 0 10px var(--lg-halo);
}

/* ---------------------------------------------------------------- liquid glass (QD 4-6)
   .glass is a lens host: glass.js puts an SVG lens inside its backdrop-filter (Chromium), so the
   clear bevel bends whatever passes under the edge and only the middle frosts. Where the lens
   cannot run, the blur below stands in. On top of either:
   - ::after   a soft-edged tint in the middle so text on the glass reads (never on the bevel);
   - ::before  the lit rim, bright where it faces the one light (--la, set by glass.js), with a
               weaker internal reflection on the far side;
   - shadows   light caught across the bevel on the lit side, the glass's own shade on the other,
               so it reads as a thick slab rather than a pane with a border.
   Ported from the dddddd.dev hub (server-hub chrome.css .lg), dark values. */
:root {
  --la: -36deg;
  --lg-tint: rgba(10, 14, 30, 0.06);
  --lg-fill: rgba(5, 8, 18, 0.32);
  --lg-fill-over: rgba(5, 8, 18, 0.62);
  --lg-spec: rgba(236, 252, 255, 0.95);
  --lg-spec-far: rgba(160, 225, 255, 0.55);
  --lg-glow: rgba(150, 225, 255, 0.3);
  --lg-shade: rgba(0, 0, 0, 0.55);
  --lg-shadow: 0 16px 34px -16px rgba(0, 0, 0, 0.9), 0 2px 8px -2px rgba(0, 0, 0, 0.55);
  --lg-halo: rgba(3, 5, 12, 0.7);
}
.glass {
  --lg-bevel: 16px;
  isolation: isolate;
  background: var(--lg-tint);
  -webkit-backdrop-filter: blur(14px) saturate(170%);
  backdrop-filter: blur(14px) saturate(170%);
  box-shadow: inset 0 10px 16px -10px var(--lg-glow), inset 0 -8px 14px -9px var(--lg-shade), var(--lg-shadow);
}
@supports (width: calc(sin(1deg) * 1px)) {
  .glass {
    box-shadow:
      inset calc(sin(var(--la)) * -10px) calc(cos(var(--la)) * 10px) 14px -8px var(--lg-glow),
      inset calc(sin(var(--la)) * 9px) calc(cos(var(--la)) * -9px) 14px -8px var(--lg-shade),
      var(--lg-shadow);
  }
}
.glass::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  padding: 1.4px;
  pointer-events: none;
  /* Two glints on opposite corners (the light on the front edge, its reflection off the back),
     next to nothing along the sides: a lit edge, not a border. */
  background: linear-gradient(calc(var(--la) + 180deg),
    var(--lg-spec) 0%, color-mix(in srgb, var(--lg-spec) 30%, transparent) 16%, transparent 34%,
    transparent 70%, color-mix(in srgb, var(--lg-spec-far) 30%, transparent) 86%, var(--lg-spec-far) 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
}
.glass::after {
  content: '';
  position: absolute;
  z-index: -1;
  inset: calc(var(--lg-bevel) * 0.55);
  border-radius: inherit;
  background: var(--lg-fill);
  filter: blur(calc(var(--lg-bevel) * 0.45));
  pointer-events: none;
}
.btn.btn-glass {
  --lg-bevel: 12px;
  --lg-fill: rgba(5, 8, 18, 0.2);
  background: var(--lg-tint);
  text-shadow: 0 0 10px var(--lg-halo);
}
.btn.btn-glass:hover { background: rgba(255, 255, 255, 0.08); }
/* Bevel sizes per part (after .glass, which sets the default). */
.entry.glass { --lg-bevel: 14px; }
.card.glass { --lg-bevel: 20px; }
/* Where the lens cannot run (Safari, Firefox) the big plates keep only a light blur, so they still read
   as clear glass and not a dark pane; the scene behind already dims for the words. */
.card.glass, .shot.glass { -webkit-backdrop-filter: blur(4px) saturate(150%); backdrop-filter: blur(4px) saturate(150%); }
.shot.glass, .lang.glass { --lg-bevel: 12px; }
.entry.glass:hover { background: rgba(255, 255, 255, 0.06); }
@supports (width: calc(sin(1deg) * 1px)) {
  .btn.btn-glass.glass {
    box-shadow:
      inset calc(sin(var(--la)) * -8px) calc(cos(var(--la)) * 8px) 12px -7px var(--lg-glow),
      inset calc(sin(var(--la)) * 7px) calc(cos(var(--la)) * -7px) 12px -7px var(--lg-shade),
      var(--lg-shadow);
  }
}

/* ---------------------------------------------------------------- phone (QD 14) */
@media (max-width: 860px) {
  .hero-copy { top: clamp(96px, 16vh, 140px); bottom: auto; }
  .entries { flex-direction: column; align-items: stretch; max-width: 420px; }
  .entry { min-width: 0; }
  /* A stretch of scene alone above and below the card, so the board and the network get the whole
     screen for a moment before the words come. */
  .stick { grid-template-columns: 1fr; padding-block: 38svh 30svh; }
  .ch-text { min-height: 80svh; }
  .foot { flex-direction: column; }
}
@media (max-width: 860px) and (max-height: 760px) {
  .hero-copy { top: 72px; }
  .lede { margin: 14px 0 18px; }
}

/* ---------------------------------------------------------------- settings (QD 15) */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .btn, .seg button, .entry, .entry-arrow, .drop, .reveal { transition: none !important; }
  .hint { visibility: hidden; } /* the water is a still frame here: nothing to stir or tilt */
}
/* Less see-through, still glass: a firmer tint in the middle, the lens stays and the scene dims more
   behind the cards (scene.js). A solid pane here turned every glass part into a black slab, and Windows
   reports this setting whenever "Transparency effects" is off (owner saw it as broken, 2026-10-10). */
@media (prefers-reduced-transparency: reduce) {
  .glass { --lg-fill: rgba(5, 8, 18, 0.5); }
  .card.glass { --lg-fill: rgba(5, 8, 18, 0.4); }
}
@media (forced-colors: active) {
  canvas.gl { display: none !important; }
  .glass::before, .glass::after { display: none; }
  .glass { border: 1px solid CanvasText; }
}
