/* ══════════════════════════════════════════════════════════════
   Shared styles for individual project pages.

   The .pj-wrap / .pj-grid / .pj-row-N / .pj-media rules below are a
   DELIBERATE numeric copy of #works / .wk / .wk-row-N / .wk-media on
   the home page — same clamp() widths/heights, same margins, same
   container padding. Keeping the numbers identical (not just visually
   similar) means the hero image on a project page occupies the exact
   same width/height/left as the card it was clicked from; only the
   vertical scroll position needs to be reconciled by project.js.
   If the home page's row numbers ever change, mirror them here.
   ══════════════════════════════════════════════════════════════ */

*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

/* Opts every project page into the native cross-document view
   transition (see index.html for the full rationale) — this is what
   finally closes the residual native-browser flash between the blind
   fully covering the outgoing page and the incoming page's first
   paint, since both sides of that gap are cross-faded instead of the
   browser showing its own blank frame.                              */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) {
    animation: none !important;
  }
}

:root {
  --bg:     oklch(0.985 0.002 75);
  --text:   oklch(0.14 0.020 255);
  --muted:  oklch(0.52 0.014 255);
  --border: rgba(0,0,0,0.085);
  --font:   'Manrope', sans-serif;
}

html { scroll-behavior: smooth; }
body { font-family: var(--font); background: var(--bg); color: var(--text); }

/* ─── NAV — verbatim from the home page's #nav rules. Project pages
   always end up with nav.className === 'light' (set by the copied
   updateNav() logic), so only the #nav.light branch ever paints, but
   every selector is copied as-is (including the #nav.dark / base
   dark-hero branch) rather than pre-collapsed, so a future change on
   the home page's nav can be diffed/ported here line for line.      ─── */
#nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  display: flex; justify-content: space-between; align-items: flex-start;
  padding: 26px 30px;
  line-height: 1.4;
}
.nav-name {
  font-size: 13px; font-weight: 600; letter-spacing: 0.02em;
  text-decoration: none; color: rgba(255,255,255,1);
  transition: color 0.38s;
}
#nav.light .nav-name { color: var(--text); }
#nav.dark  .nav-name { color: rgba(255,255,255,1); }

.nav-links { display: flex; gap: 15px; }
.nav-links a:last-child { margin-right: -1px; }
.nav-links a {
  font-size: 13px; font-weight: 400; text-decoration: none;
  color: rgba(255,255,255,1); letter-spacing: 0.01em;
  transition: color 0.2s;
}
.nav-links a:hover { color: white; }
#nav.light .nav-links a { color: var(--text); }
#nav.light .nav-links a:hover { color: var(--text); }
#nav.dark  .nav-links a { color: rgba(255,255,255,1); }
#nav.dark  .nav-links a:hover { color: white; }

/* magnet: nav links translate slightly toward the cursor */
#nav a {
  display: inline-block;
  transition: transform 0.55s cubic-bezier(0.22,1,0.36,1),
              color 0.34s ease;
}

/* ─── OUTER WRAP — mirrors #works (30px padding) ─── */
.pj-wrap { padding: 0 30px; }
main.proj { padding-top: 128px; }

/* ─── GRID — mirrors .wk (max-width 1280, centered) ─── */
.pj-grid {
  max-width: 1280px;
  margin: 0 auto;
}

/* ─── FOOTER NAV — in normal flow at the end of the page, same
   30px inset as .pj-wrap/.p-nav so it still lines up under the
   logo and Contact, just no longer pinned to the viewport ─── */
.p-foot {
  display: flex; justify-content: space-between; align-items: center;
  margin-top: 120px;
  padding-bottom: 26px;
}

.proj-back, .proj-next {
  font-size: 13px; font-weight: 400; letter-spacing: 0.01em;
  color: var(--text);
  text-decoration: none;
  transition: color 0.2s;
}
.proj-back::before { content: '← '; }
.proj-next::after { content: ' →'; }
.proj-back:hover, .proj-next:hover { color: var(--muted); }

.proj-title {
  font-size: clamp(32px, 4.4vw, 58px);
  font-weight: 800; letter-spacing: -0.02em; line-height: 1.06;
  color: var(--text);
  padding: 0 clamp(0px, 50vw - 490px, 180px) 0 clamp(80px, 9vw, 130px);
  margin-bottom: 56px;
}

/* ─── ARTICLE ─ figure floats in at the top, all copy (the old
   lead sentence + the long-form body) flows as ONE continuous text
   that starts alongside the figure and wraps below it once the
   image's height is cleared. Left/right insets reuse the exact
   margin values the home page uses to align .wk-row-1/3/5 (left)
   and .wk-row-2/4 (right) images — NOT the same number on both
   sides: the left inset mirrors .wk-row-1/3/5's margin-left, the
   right inset mirrors .wk-row-2/4's margin-right, so the grid's own
   edges coincide exactly with wherever those images actually sit,
   instead of a generic symmetric padding that only approximated it.  ─── */
.pj-article {
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 clamp(0px, 50vw - 490px, 180px) 0 clamp(80px, 9vw, 130px);
}
.pj-article::after { content: ''; display: table; clear: both; }

.pj-media {
  overflow: hidden;
  /* Values below aren't derived by eyeballing a number — floated
     images sitting in wrapped text only get shoved to the next line
     in whole line-height steps, so the RENDERED gap above/below jumps
     in ~25px increments rather than tracking the margin smoothly (the
     side gap has no such quirk: horizontal space next to a float is
     exact). These specific top/bottom numbers were solved by measuring
     the actual rendered gap px-by-px so all three edges land within
     ~2px of the fixed 32px side gap — don't "round" them without
     re-measuring, nearby values can jump a full text line larger/
     smaller. */
  margin: 26px 0 8px;
}
.pj-media image-slot { display: block; width: 100%; height: 100%; }
/* Outer edge (away from the text column) sits flush with the
   paragraph's own edge — no margin there. The three edges that
   actually touch text (top, bottom, inner side) share the same 32px. */
.pj-media-l { float: left;  margin-left: 0;  margin-right: 32px; }
.pj-media-r { float: right; margin-right: 0; margin-left: 32px; }

/* per-project figure sizes — mirror the home page's row-N media */
.pj-media-1 { width: clamp(250px, 27vw, 370px); height: clamp(305px, 34vw, 460px); } /* portrait */
.pj-media-2 { width: 400px; height: 400px; } /* square — same short side as the About photo */
.pj-media-3 { width: clamp(360px, 38vw, 500px); height: clamp(240px, 25.3vw, 333px); } /* landscape 3:2 */
.pj-media-4 { width: 400px; height: 400px; } /* square — same short side as the About photo */
.pj-media-5 { width: clamp(242px, 26.19vw, 358px); height: clamp(296px, 32.98vw, 446px); } /* portrait 3:4 */

.pj-article p {
  font-size: 14px;
  font-weight: 300;
  line-height: 1.8;
  color: var(--muted);
  text-wrap: pretty;
  text-align: justify;
  margin: 0;
}
/* A gap only appears between two paragraphs that sit directly next to
   each other (i.e. a deliberate blank line left while editing) — a
   paragraph split only because a floated image sits between it and
   the next one does NOT get this gap, so the text still reads as one
   continuous flow around the figure. */
.pj-article p + p { margin-top: 1.3em; }

/* Images added from the in-page editor — a floated <span> (not a
   <div>) so it stays valid, wrappable phrasing content sitting right
   inside the paragraph at the caret: text before AND after the caret
   keeps flowing in the same paragraph around the float, instead of a
   block sibling forcing the paragraph to end early at that point. */
.pj-media img { display: block; width: 100%; height: 100%; object-fit: cover; }
.pj-media-portrait  { width: clamp(250px, 27vw, 370px); height: clamp(305px, 34vw, 460px); }
.pj-media-landscape { width: clamp(360px, 38vw, 500px); height: clamp(240px, 25.3vw, 333px); }
.pj-media-square    { width: 400px; height: 400px; }

/* Fallback for a stray non-<p> block a browser's contenteditable might
   still produce on Enter (defaultParagraphSeparator in edit-mode.js
   should prevent this, but keep the article's own typography as the
   floor either way, instead of the browser's generic default). */
.pj-article div:not(.pj-media) {
  font-size: 14px;
  font-weight: 300;
  line-height: 1.8;
  color: var(--muted);
  text-align: justify;
}
.pj-article h2 {
  clear: both;
  font-size: clamp(21px, 2.1vw, 27px);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.25;
  color: var(--text);
  margin: 12px 0 20px;
}
.pj-article ul {
  list-style: none;
  margin: 0 0 28px;
}
.pj-article li {
  position: relative;
  padding-left: 22px;
  font-size: 16px;
  font-weight: 300;
  line-height: 1.7;
  color: var(--muted);
  margin-bottom: 12px;
}
.pj-article li::before {
  content: '';
  position: absolute;
  left: 0; top: 0.62em;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--border);
}
.pj-article li strong {
  color: var(--text);
  font-weight: 600;
}
.pj-article blockquote {
  border-left: 2px solid var(--border);
  padding-left: 24px;
  font-size: 19px;
  font-weight: 400;
  font-style: italic;
  line-height: 1.6;
  color: var(--text);
  margin: 0 0 28px;
}
.pj-article .pj-caption {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--muted);
  opacity: 0.75;
}

@media (max-width: 860px) {
  .pj-article { padding: 0 30px; }
  .pj-media-l, .pj-media-r { float: none; width: 100% !important; max-width: 420px; margin: 0 0 28px; }
}

/* ─── CURSOR — verbatim from the home page's #cursor rules. ─── */
#cursor {
  position: fixed; top: 0; left: 0; z-index: 1200;
  width: 20px; height: 20px; border-radius: 50%;
  transform: translate(-50%,-50%) scale(0.5);
  border: none;
  background: rgba(255,255,255,0.28);
  box-shadow:
    0 0 14px rgba(255,255,255,0.22),
    0 2px 8px  rgba(0,0,0,0.18);
  pointer-events: none;
  opacity: 0;
  filter: blur(7px);
  transition:
    opacity      0.16s ease-out,
    transform    0.46s cubic-bezier(0.34,1.56,0.64,1),
    filter       0.30s ease,
    border-radius 0.40s cubic-bezier(0.22,1,0.36,1),
    background 0.35s ease, box-shadow 0.35s ease;
  will-change: left, top, transform, filter;
}
#cursor.link-mode {
  border-radius: 9px;
  border: 1px solid rgba(255,255,255,0.28);
  background: rgba(255,255,255,0.11);
  box-shadow:
    0 0 0 1px rgba(255,255,255,0.06),
    0 6px 18px rgba(0,0,0,0.22),
    inset 0 0 10px rgba(255,255,255,0.04);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
#cursor.on-light.link-mode {
  border: 1px solid rgba(18,22,28,0.18);
  background: rgba(18,22,28,0.07);
  box-shadow:
    0 0 0 1px rgba(0,0,0,0.05),
    0 6px 18px rgba(0,0,0,0.10),
    inset 0 0 10px rgba(0,0,0,0.03);
}
#cursor.show {
  opacity: 1;
  filter: blur(0);
  transform: translate(-50%,-50%) scale(1);
}
#cursor.on-light {
  background: rgba(18,22,28,0.26);
  box-shadow:
    0 0 14px rgba(0,0,0,0.18),
    0 2px 8px  rgba(0,0,0,0.20);
}
@media (hover: none), (pointer: coarse) { #cursor { display: none; } }

/* ─── SCROLL REVEAL — identical timing/easing to the home page's
   .reveal-content: fades + rises + unblurs once, staggered.     ─── */
.reveal-content {
  opacity: 0;
  transform: translateY(40px);
  filter: blur(5px);
  transition:
    opacity   0.8s ease                           var(--rd, 0s),
    transform 0.8s cubic-bezier(0.22, 1, 0.36, 1) var(--rd, 0s),
    filter    0.8s ease                           var(--rd, 0s);
  will-change: opacity, transform, filter;
}
.reveal-content.revealed {
  opacity: 1;
  transform: translateY(0);
  filter: blur(0);
}
@media (prefers-reduced-motion: reduce) {
  .reveal-content { opacity: 1; transform: none; filter: none; transition: none; }
}
