  /* ---------- hero (Apple / OpenAI monolithic typography) ----------
     Single font family throughout (Geist, the open-source font closest to
     Söhne / SF Pro Display). One weight on the headline, one color emphasis
     on the brand line — no italic, no serif, no mixed families. Confidence
     comes from size + tracking + whitespace, not from style switching. */
  .hero-headline {
    font-family: 'Geist', 'Noto Sans SC', sans-serif;
    font-weight: 600;
    letter-spacing: -4px;
    /* 1.0 is too tight for CJK glyphs (which already render tall inside the
       em-box) — adjacent lines visually touch. 1.18 gives each line clear
       breathing room without making the headline feel airy. */
    line-height: 1.18;
    color: #0e0e10;
    font-feature-settings: "ss01", "cv11";
  }
  /* Per-word hover — each word lifts and tints brand-blue. Static state
     is identical to before; only the cursor target changes.
     Note: accent word now shares the same element as .word (combined into
     <span class="hero-accent word">), so selectors must scope by :not. */
  .hero-headline .word {
    display: inline-block;
    transition:
      transform 260ms cubic-bezier(0.2, 0.8, 0.2, 1),
      color 180ms ease,
      filter 220ms ease;
    will-change: transform;
  }
  /* All words lift on hover */
  .hero-headline .word:hover {
    transform: translateY(-3px);
  }
  /* Non-accent words tint to brand violet (matches the new accent gradient's
     top stop, so hover and accent share one color identity). */
  .hero-headline .word:not(.hero-accent):hover {
    color: #0a87f7;
  }
  /* Accent words already use a transparent-with-gradient text fill —
     overriding color would kill the gradient. Boost saturation instead. */
  .hero-headline .word.hero-accent:hover {
    filter: saturate(1.4) brightness(0.95);
  }
  /* Hero accent — same family as the headline, color shift + a single notch
     of weight contrast (500 vs the headline's 600). Subtle enough that the
     line still reads as one unit, distinct enough to give the brand line
     its own breath. Stripe / Notion use the same trick. */
  .hero-accent {
    font-family: inherit;
    font-style: normal;
    font-weight: 500;
    letter-spacing: inherit;
    /* Deep-azure→sky axis — the logo's own blue range (primary fill →
       light wave), pushed deep enough at the top stop that the accent
       word still pops against the pale sky of the hero illustration. */
    background: linear-gradient(180deg, #0a6ce8 0%, #38b6f8 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
  /* Hero headline stack — all rotating taglines live in the same grid
     cell so the container auto-sizes to the tallest one and the page
     below never reflows when the active tagline changes. */
  .hero-headline-stack {
    display: grid;
    grid-template-columns: 1fr;
  }
  .hero-line {
    grid-area: 1 / 1;
    opacity: 0;
    transform: translateY(14px);
    transition: opacity 620ms ease,
                transform 620ms cubic-bezier(0.2, 0.8, 0.2, 1);
    pointer-events: none;
  }
  .hero-line.is-active {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }
  .btn-primary {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: #0e0e10;
    color: #ffffff;
    border-radius: 999px;
    padding: 12px 22px;
    font-family: 'Geist', sans-serif;
    font-size: 14px;
    font-weight: 500;
    line-height: 1;
    border: 1px solid #0e0e10;
    transition: transform 140ms ease, box-shadow 140ms ease, background 140ms ease;
  }
  .btn-primary:hover { background: #1a1a1d; transform: translateY(-1px); box-shadow: 0 8px 20px -8px rgba(14,14,16,0.4); }
  /* Secondary pill — same geometry as .btn-primary so the two read as a
     visual pair when placed side-by-side in the hero CTA row. Inverted
     fill (white surface, hairline black border) marks it as the second
     action. Hover deepens the border + lifts, no fill change, keeping
     .btn-primary as the unmistakable primary. */
  .btn-secondary {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: #ffffff;
    color: #0e0e10;
    border-radius: 999px;
    padding: 12px 22px;
    font-family: 'Geist', sans-serif;
    font-size: 14px;
    font-weight: 500;
    line-height: 1;
    border: 1px solid rgba(14,14,16,0.18);
    transition: transform 140ms ease, box-shadow 140ms ease, border-color 140ms ease;
    text-decoration: none;
  }
  .btn-secondary:hover {
    border-color: #0e0e10;
    transform: translateY(-1px);
    box-shadow: 0 8px 20px -10px rgba(14,14,16,0.25);
  }
  .btn-secondary-arrow {
    opacity: 0.7;
    transition: transform 180ms cubic-bezier(0.2, 0.8, 0.2, 1), opacity 180ms ease;
  }
  .btn-secondary:hover .btn-secondary-arrow {
    transform: translateX(3px);
    opacity: 1;
  }
  /* 品牌蓝填充变体 — 沿用 .btn-secondary 的几何与响应式。hero CTA 行里
     给首个动作（岛上机会）做主次区分：一蓝两白，视觉焦点唯一，同时让
     首屏多一块呼应 logo 的品牌蓝。 */
  .btn-secondary.is-brand {
    background: #0a87f7; color: #ffffff; border-color: #0a87f7;
  }
  .btn-secondary.is-brand:hover {
    background: #0969da; border-color: #0969da; color: #ffffff;
  }
  .btn-secondary.is-brand .btn-secondary-arrow { opacity: 0.85; }
  /* External-link variant — when the pill is an <a> (e.g. the GitHub
     SKILL.md CTA), nudge the arrow up-and-right so the motion matches the
     diagonal ↗ glyph direction instead of fighting it. */
  a.btn-secondary:hover .btn-secondary-arrow {
    transform: translate(3px, -3px);
  }
  .btn-ghost {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: rgba(255,255,255,0.7);
    color: #0e0e10;
    border-radius: 999px;
    padding: 12px 22px;
    font-family: 'Geist', sans-serif;
    font-size: 14px;
    font-weight: 500;
    line-height: 1;
    border: 1px solid rgba(14,14,16,0.18);
    transition: background 140ms ease, border-color 140ms ease;
  }
  .btn-ghost:hover { background: rgba(255,255,255,0.95); border-color: rgba(14,14,16,0.3); }

  /* ---------- illustrated upper-page shell (hero + marquee) ----------
     hero-shell wraps the hero copy and the company marquee so the painted
     island scene reads as one continuous upper canvas. The previous
     pink/violet gradient + grain treatment was replaced with a full-bleed
     illustration (assets/bg-day.png / bg-night.png per theme) after repeated
     feedback that the gradient look read as "AI-generated template". */
  .hero-shell {
    position: relative;
    /* No overflow:hidden — it would clip .hero-bg-glow's -80px top bleed
       (the old floating-card era needed the clip for cards pushed past the
       right edge; nothing overflows anymore). The bleed must actually
       paint behind the now-transparent nav, else the nav band shows the
       bare body background instead of sky. */
    isolation: isolate;
  }
  /* Day scene — lighthouse island on the right, open sky on the left where
     the headline sits. `cover` keeps the horizon stable across viewport
     widths; the 72% horizontal anchor only matters on narrow viewports
     (where cover crops horizontally) and keeps the lighthouse in frame on
     mobile instead of showing open sea. The -80px top bleed paints the sky
     behind the transparent sticky nav so the canvas starts at the very top
     of the page. The image ships as q82 JPEG (~280KB vs 3.6MB for the PNG
     master in the same dir). */
  .hero-bg-glow {
    position: absolute;
    inset: -80px 0 0 0;
    pointer-events: none;
    z-index: 0;
    background: url("/assets/bg-day.png") 72% center / cover no-repeat;
  }
  .hero-shell > *:not(.hero-bg-glow) { position: relative; z-index: 1; }

  /* Hero copy column — the old two-column grid (copy | floating cards) is
     now a single column: the illustration itself carries the right side.
     max-width matches the old 1.15fr column (~640px at the 7xl rail) so the
     headline wraps identically.

     min-height is viewport-height driven so the hero fills most of the
     fold (an earlier 16:9-tracking formula minimized vertical crop but
     left the hero shorter than wanted). Derivation: the shell adds ~142px
     of chrome around this column (section paddings + the marquee strip)
     and sits below the 69px nav, so copy = 100vh − 69 − 142 − ~40px peek
     of the next section ≈ 100vh − 250px.
       · When this makes the bg paint box taller than the image's 16:9,
         `cover` switches to height-driven scaling and crops horizontally
         instead — absorbed by the 72% anchor (left sky trimmed, the
         lighthouse island stays in frame).
       · 520px floor protects small windows; 880px ceiling keeps very
         tall/portrait monitors from getting an absurdly deep hero. */
  .hero-copy {
    max-width: 640px;
  }
  @media (min-width: 1024px) {
    .hero-copy {
      min-height: clamp(520px, calc(100vh - 250px), 880px);
    }
  }

  /* ---------- social-proof marquee ("Opportunities from:") ----------
     Infinite-loop horizontal scroller. The track contains the company list
     duplicated end-to-end; animating translateX from 0 to -50% creates the
     illusion of an endless ribbon. Edge gradient mask softens the in/out. */
  .marquee {
    position: relative;
    overflow: hidden;
    -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 8%, #000 92%, transparent 100%);
    mask-image:         linear-gradient(90deg, transparent 0%, #000 8%, #000 92%, transparent 100%);
  }
  .marquee-track {
    display: flex;
    gap: 28px;
    align-items: center;
    width: max-content;
    /* Duration is measured in JS from rendered track width so the logo strip
       keeps one constant px/s speed as brands, fonts, or images settle. */
    animation: marqueeScroll var(--marquee-duration, 90s) linear infinite;
    will-change: transform;
  }
  @keyframes marqueeScroll {
    0%   { transform: translateX(0); }
    100% { transform: translateX(-50%); }
  }
  .marquee-label {
    font-family: 'Geist', 'Noto Sans SC', sans-serif;
    font-size: 11.5px;
    font-weight: 500;
    color: #94949c;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    flex-shrink: 0;
  }
  .marquee-item {
    font-family: 'Geist', 'Noto Sans SC', sans-serif;
    font-size: 14px;
    font-weight: 500;
    color: #38383d;
    letter-spacing: -0.2px;
    white-space: nowrap;
    opacity: 0.85;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    /* Translucent pill — the strip floats directly on the hero's water
       since the hairline was dropped, and bare text items lost contrast
       against the bright sea. Plain alpha fill, deliberately NO
       backdrop-filter: the track animates ~160 of these continuously and
       per-item blur would jank the marquee. */
    background: rgba(255, 255, 255, 0.55);
    border: 1px solid rgba(255, 255, 255, 0.5);
    border-radius: 999px;
    padding: 6px 13px;
    transition: opacity 200ms ease, color 200ms ease;
  }
  .marquee-item:hover { opacity: 1; color: #0e0e10; }
  /* Cursor + subtle lift on the hover-able (non-stealth) marquee items.
     Signals "this is a link to filter the feed" without screaming. */
  .marquee-item.is-clickable { cursor: pointer; }
  .marquee-item.is-clickable:hover .marquee-logo { transform: translateY(-1px); }
  .marquee-logo {
    transition: transform 180ms cubic-bezier(0.2, 0.8, 0.2, 1);
  }
  .marquee-logo {
    width: 20px;
    height: 20px;
    object-fit: contain;
    flex-shrink: 0;
    border-radius: 4px;
  }
  /* Stealth Startup now renders with a fixed LinkedIn-style placeholder
     logo (assets/brands/stealth.png) so it visually matches other brand
     entries — no special styling needed. */
