/* ==========================================================================
   bimon.net - base layer
   Reset, document defaults, accessibility primitives, layout, chrome.
   Load order: fonts.css -> tokens.css -> base.css -> components.css
   ========================================================================== */

/* ---------- cross-document view transitions ----------
   Progressive enhancement: browsers without support simply navigate. Browsers
   with it get a cross-fade between pages for free, no JS and no SPA. */
@view-transition { navigation: auto; }

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 1rem);
  /* clip, not hidden: hidden on <body> propagates to the viewport and stops
     clipping the body's own children, which is how stray horizontal overflow
     survives. clip contains it without creating a scroll container. */
  overflow-x: clip;
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  background-color: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  line-height: var(--leading-body);
  font-weight: 400;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: "kern" 1, "liga" 1, "calt" 1;
  min-height: 100vh;
  min-height: 100svh;
  overflow-x: clip;
  max-width: 100%;
  transition: background-color var(--dur-3) var(--ease-in-out),
              color var(--dur-3) var(--ease-in-out);
}

img, svg, video, canvas { display: block; max-width: 100%; }
img { height: auto; }
input, button, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
ul, ol { list-style: none; padding: 0; }

::selection { background: var(--selection); color: var(--ink); }

/* ---------- focus ----------
   Visible for keyboard users, invisible for mouse users. Never removed. */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--r-1);
}

/* ---------- accessibility helpers ---------- */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.skip-link {
  position: fixed;
  top: var(--s-2xs);
  left: var(--s-2xs);
  z-index: var(--z-overlay);
  padding: var(--s-xs) var(--s-s);
  background: var(--ink);
  color: var(--bg);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  border-radius: var(--r-2);
  transform: translateY(-160%);
  transition: transform var(--dur-2) var(--ease-swift);
}
.skip-link:focus-visible { transform: translateY(0); }

/* ---------- typography ---------- */
h1, h2, h3, h4 {
  font-weight: 400;
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
}
p { text-wrap: pretty; }

.display {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-display);
}
.display--xl { font-size: var(--step-5); }
.display--l  { font-size: var(--step-4); }
.display--m  { font-size: var(--step-3); }

/* Serif italic used as an inline accent inside a sans headline.
   This is the site's signature typographic move: the eye lands on the
   italic word, so the sentence carries a hierarchy without extra weight. */
.accent-serif {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.06em;
  letter-spacing: -0.01em;
}
.accent-ink { color: var(--accent); }

.mono {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  font-weight: 500;
  color: var(--ink-dim);
}
.mono--plain { text-transform: none; letter-spacing: 0.02em; }

.lede {
  font-size: var(--step-1);
  line-height: 1.5;
  color: var(--ink-2);
  max-width: var(--measure-narrow);
  letter-spacing: -0.005em;
}
.prose-fade { color: var(--ink-dim); }

/* ---------- links ----------
   Underline drawn on a scaleX transform so it grows from the left instead of
   fading in - the same trick used across design-engineering portfolios. */
.link {
  color: inherit;
  text-decoration: none;
  position: relative;
  padding-bottom: 0.12em;
}
.link::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-3) var(--ease-out-quint);
}
.link:hover::after, .link:focus-visible::after { transform: scaleX(1); }
.link--static::after { transform: scaleX(1); opacity: .3; transition: opacity var(--dur-2) var(--ease-swift); }
.link--static:hover::after { opacity: 1; }

.link-quiet { color: var(--ink-dim); text-decoration: none; transition: color var(--dur-2) var(--ease-swift); }
.link-quiet:hover { color: var(--ink); }

/* ---------- layout ---------- */
.container {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container--narrow { max-width: 900px; }

.section { padding-block: clamp(3.5rem, 8vh, 6.5rem); }
.section--tight { padding-block: clamp(2.5rem, 5vh, 4rem); }
.section + .section { border-top: 1px solid var(--line); }

/* Section header: a mono index + label on the left, optional aside right.
   Repeating this exact strip down every page is what makes the site read as
   one designed system rather than a pile of pages. */
.section__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-m);
  padding-bottom: var(--s-m);
  margin-bottom: var(--s-l);
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
}
.section__label { display: flex; align-items: baseline; gap: var(--s-xs); }
.section__index { color: var(--ink-dim); font-variant-numeric: tabular-nums; }
.section__title {
  font-family: var(--font-display);
  font-size: var(--step-2);
  letter-spacing: var(--tracking-display);
  line-height: 1.1;
}
.section__aside { margin-left: auto; }

.rule { border: 0; border-top: 1px solid var(--line); }

/* ---------- header ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: saturate(1.6) blur(14px);
  -webkit-backdrop-filter: saturate(1.6) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-3) var(--ease-in-out),
              background-color var(--dur-3) var(--ease-in-out);
}
/* Hairline only appears once the page has scrolled - a header that is
   invisible at rest keeps the hero feeling unboxed. */
.site-header[data-scrolled="true"] { border-bottom-color: var(--line); }

.header__inner {
  display: flex;
  align-items: center;
  gap: var(--s-m);
  min-height: var(--header-h);
}

.wordmark {
  font-family: var(--font-display);
  font-size: var(--step-1);
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
  display: inline-flex;
  align-items: baseline;
  gap: 0.12em;
  margin-right: auto;
  white-space: nowrap;
}
.wordmark__mark {
  display: inline-block;
  width: 0.5em; height: 0.5em;
  background: var(--accent);
  border-radius: var(--r-full);
  transform: translateY(-0.08em);
  transition: transform var(--dur-3) var(--ease-out-quint);
}
.wordmark:hover .wordmark__mark { transform: translateY(-0.08em) scale(1.35); }

.nav { display: flex; align-items: center; gap: clamp(0.75rem, 2vw, 1.5rem); }
.nav__link {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  color: var(--ink-dim);
  text-decoration: none;
  position: relative;
  padding-block: 0.5rem;
  transition: color var(--dur-2) var(--ease-swift);
  white-space: nowrap;
}
.nav__link:hover { color: var(--ink); }
.nav__link[aria-current="page"] { color: var(--ink); }
.nav__link[aria-current="page"]::before {
  content: "";
  position: absolute;
  left: -0.62em; top: 50%;
  width: 0.3em; height: 0.3em;
  margin-top: -0.15em;
  background: var(--accent);
  border-radius: var(--r-full);
}

.header__tools { display: flex; align-items: center; gap: var(--s-2xs); }

/* Small square icon buttons: 44px touch target, hairline border that only
   resolves on hover. */
.icon-btn {
  width: 2.25rem; height: 2.25rem;
  display: grid; place-items: center;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--ink-dim);
  transition: color var(--dur-2) var(--ease-swift),
              border-color var(--dur-2) var(--ease-swift),
              background-color var(--dur-2) var(--ease-swift);
}
.icon-btn:hover { color: var(--ink); border-color: var(--line-strong); background: var(--bg-elev); }
.icon-btn svg { width: 1rem; height: 1rem; }
[data-theme="light"] .icon-btn .icon-moon { display: none; }
[data-theme="dark"] .icon-btn .icon-sun { display: none; }

.lang-toggle {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  overflow: hidden;
  height: 2.25rem;
}
.lang-toggle button {
  padding-inline: 0.6rem;
  height: 100%;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.04em;
  color: var(--ink-dim);
  transition: color var(--dur-2) var(--ease-swift), background-color var(--dur-2) var(--ease-swift);
}
.lang-toggle button:hover { color: var(--ink); }
.lang-toggle button[aria-pressed="true"] { color: var(--bg); background: var(--ink); }

/* ---------- language switching ----------
   Both languages are rendered into the HTML at build time; the toggle only
   flips a data attribute. No fetch, no flash, and each language keeps its own
   correct lang attribute for screen readers and hyphenation. */
[data-lang="en"] [data-lang-zh],
[data-lang="zh"] [data-lang-en] { display: none !important; }

/* ---------- footer ---------- */
.site-footer {
  border-top: 1px solid var(--line);
  padding-block: var(--s-xl) var(--s-l);
  margin-top: var(--s-2xl);
}
.footer__cta {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-4);
  line-height: 1.02;
  letter-spacing: var(--tracking-display);
  color: var(--ink);
  text-decoration: none;
  margin-bottom: var(--s-l);
}
.footer__cta .arrow {
  display: inline-block;
  transition: transform var(--dur-3) var(--ease-out-quint);
}
.footer__cta:hover .arrow { transform: translate(0.18em, -0.18em); }
.footer__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--s-m) var(--s-l);
  padding-top: var(--s-m);
  border-top: 1px solid var(--line);
}
.footer__col { display: flex; flex-direction: column; gap: 0.45rem; align-items: flex-start; }
.footer__col .mono { margin-bottom: 0.2rem; }
.footer__social { display: flex; flex-wrap: wrap; gap: 0.35rem 1rem; }
.footer__bottom {
  display: flex;
  justify-content: space-between;
  gap: var(--s-s);
  flex-wrap: wrap;
  margin-top: var(--s-l);
  padding-top: var(--s-s);
  border-top: 1px solid var(--line);
  color: var(--ink-dim);
}

/* ---------- decorative layers ---------- */

/* Film grain: a static SVG turbulence tile at ~4% opacity. It kills the
   flatness of large solid fields without adding an image request. */
.grain {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  pointer-events: none;
  opacity: var(--grain-opacity);
  mix-blend-mode: multiply;
  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='.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
[data-theme="dark"] .grain { mix-blend-mode: screen; }

/* Layout guides: the designer's own grid, made visible. Off by default,
   toggled with the "Grid" button in the footer or the G key. */
.guides {
  position: fixed;
  inset: 0;
  z-index: var(--z-guides);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-3) var(--ease-in-out);
}
[data-guides="on"] .guides { opacity: 1; }
.guides__inner {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
  height: 100%;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(0.5rem, 1.6vw, 1.5rem);
}
.guides__col { background: color-mix(in srgb, var(--accent) 5%, transparent); }
.guides__baseline {
  position: absolute;
  inset: 0;
  background-image: linear-gradient(to bottom, var(--line) 1px, transparent 1px);
  background-size: 100% 8px;
  opacity: .5;
}

/* ---------- reveal on scroll ----------
   Elements start 14px low and slightly transparent, then settle. Small
   distance, long duration: content feels placed rather than thrown in. */
[data-reveal] {
  opacity: 0;
  transform: translate3d(0, 14px, 0);
  transition: opacity var(--dur-4) var(--ease-out-quint),
              transform var(--dur-4) var(--ease-out-quint);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}
[data-reveal].is-in { opacity: 1; transform: none; }

/* Image variant: the frame opens with a wipe instead of a fade. Used on
   case-study figures, where a fade would read as "loading" rather than
   "presenting". */
[data-reveal="clip"] {
  opacity: 1;
  transform: none;
  clip-path: inset(0 0 100% 0);
  transition: clip-path var(--dur-5) var(--ease-out-quint);
}
[data-reveal="clip"].is-in { clip-path: inset(0 0 0 0); }

/* Without JS nothing must stay invisible. */
.no-js [data-reveal] { opacity: 1; transform: none; clip-path: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  [data-reveal] { opacity: 1 !important; transform: none !important; clip-path: none !important; }
}

/* ---------- print ---------- */
@media print {
  .site-header, .site-footer, .grain, .guides, .work-preview { display: none !important; }
  body { background: #fff; color: #000; }
  a { text-decoration: underline; }
}
