/* ============================================================
   Yuwen Chang — personal site
   Layout follows the jchang.cc reference: one narrow centred
   column, hairline list rows, quiet type, floating dock.
   ============================================================ */

:root {
  --bg:            #E6EFFF;   /* per brief */
  --ink:           #0A0A0A;
  --ink-2:         #5A6472;   /* secondary — 5.2:1 on --bg */
  --rule:          rgba(16, 20, 26, 0.12);
  --rule-soft:     rgba(16, 20, 26, 0.07);
  --hover:         rgba(16, 30, 70, 0.045);
  --panel:         rgba(255, 255, 255, 0.55);
  --accent:        #10141A;   /* active chip / dock */
  --dim:           #6E7788;   /* sentence colour while a keyword is hovered */
  --live:          #17A673;

  --font:          "Geist", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --col:           744px;   /* the reference measure, widened 20% */
  --r:             12px;

  --t: 220ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

a { color: inherit; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip {
  position: absolute; left: 8px; top: -48px; z-index: 20;
  background: var(--ink); color: #fff; padding: 8px 14px;
  border-radius: 999px; font-size: 13px; text-decoration: none;
}
.skip:focus { top: 8px; }

/* ---------- shell ---------- */

.wrap {
  --pad: 96px;                 /* gutter sits outside the content cap */
  max-width: calc(var(--col) + var(--pad) * 2);
  margin: 0 auto;
  padding: 128px var(--pad);
}

/* the intro is fluid on small screens and stops growing at 600px.
   No percentage width: the cap does the work. */
.hero { max-width: 600px; }

/* ---------- site logo ---------- */

.mark-link {
  display: inline-block;
  transition: opacity var(--t);
}
.mark-link:hover { opacity: 0.62; }

.mark {
  display: block;
  width: auto;
  height: 42px;
  margin-bottom: 54px;
}

/* ---------- hero ---------- */

.hero p {
  margin: 16px 0 0;
  font-size: 24px;
  line-height: 32px;
  font-weight: 500;
  letter-spacing: -0.04px;
  color: var(--ink);          /* one colour — emphasis is revealed on hover */
}
.hero p:first-child { margin-top: 0; }

/* keyword: invisible at rest. Hovering any one of them dims the whole intro
   so every keyword, in both paragraphs, reads as the emphasised line. */
.kw {
  color: var(--ink);
  transition: color var(--t);
  cursor: default;
}

.kw-link {
  text-decoration: underline;
  text-decoration-color: #BFBFBF;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  cursor: pointer;
}
.kw-link:hover { text-decoration-color: var(--ink); }
.hero p { transition: color var(--t); }
.hero:has(.kw:hover) p { color: var(--dim); }

@supports not selector(:has(*)) {
  .hero:hover p { color: var(--dim); }
}

/* ---------- section blocks ---------- */

.block { margin-top: 64px; }

.block-title {
  margin: 0 0 12px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.005em;
}

.list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--rule-soft);
}

.list > li { border-bottom: 1px solid var(--rule-soft); }

/* ---------- experience rows ---------- */

.row {
  display: flex;
  text-decoration: none;
  color: inherit;
  align-items: center;
  gap: 14px;
  padding: 14px 12px;
  margin: 0 -12px;
  border-radius: 10px;
  transition: background var(--t), padding var(--t);
}
/* hover presses the row: it darkens and the contents move inward */
.exp-item:hover .row,
.row:focus-visible {
  background: var(--hover);
  padding: 17px 20px;
}

.logo img { width: 100%; height: 100%; object-fit: contain; display: block; }
.logo.has-img { background: transparent; border-color: transparent; }

.logo {
  flex: 0 0 auto;
  /* square, sized to the height of the two text lines beside it.
     Nudged 2px up: geometrically centred, it reads low against two lines. */
  margin-top: -2px;
  overflow: hidden;
  width: 44px;
  height: 44px;
  border-radius: 8px;
  display: grid; place-items: center;
  background: rgba(16, 20, 26, 0.08);
  border: 1px solid var(--rule-soft);
  font-size: 14px; font-weight: 600; color: var(--ink-2);
}

.org { font-weight: 500; }
.org-note {
  display: block;
  font-size: 12.5px;
  color: var(--ink-2);
  margin-top: 1px;
}

.pj-badge .live {
  display: inline-block;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--live); margin-right: 5px;
  vertical-align: middle;
}

.meta {
  margin-left: auto;
  flex: 0 0 auto;
  font-size: 12.5px;
  color: var(--ink-2);
  white-space: nowrap;
}
.meta .live {
  display: inline-block;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--live); margin-right: 6px;
  vertical-align: middle;
}

/* ---------- filter bar ---------- */

.filters { margin: 6px 0 22px; }

/* one line, scrolled sideways. Fades hint at what is off-screen. */
.chips {
  display: flex;
  flex-wrap: nowrap;
  gap: 8px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  padding: 2px 0;
  scrollbar-width: none;
  -ms-overflow-style: none;
  cursor: grab;
  -webkit-mask-image: var(--chips-fade, none);
  mask-image: var(--chips-fade, none);
}
.chips::-webkit-scrollbar { display: none; }
.chips.is-dragging { cursor: grabbing; scroll-snap-type: none; }
.chips[data-scroll="start"] { --chips-fade: linear-gradient(90deg, #000 0, #000 85%, transparent 100%); }
.chips[data-scroll="middle"] { --chips-fade: linear-gradient(90deg, transparent 0, #000 6%, #000 85%, transparent 100%); }
.chips[data-scroll="end"] { --chips-fade: linear-gradient(90deg, transparent 0, #000 8%, #000 100%); }

.chip {
  flex: 0 0 auto;
  scroll-snap-align: start;
  appearance: none;
  font: inherit;
  font-size: 13px;
  line-height: 1;
  padding: 10px 16px;
  border-radius: 999px;
  border: 1px solid var(--rule);
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--t), color var(--t), border-color var(--t);
}
.chip:hover { background: var(--hover); color: var(--ink); }
.chip[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* ---------- project rows ---------- */

.list--projects > li { transition: opacity var(--t); }
.list--projects > li[hidden] { display: none; }

.pj {
  display: block;
  /* full column width plus the negative-margin gutters */
  width: calc(100% + 24px);
  margin: 0 -12px;
  padding: 0;
  border: 0;
  background: transparent;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  border-radius: var(--r);
  transition: background var(--t);
}

.pj-head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 19px 12px;
  border-radius: var(--r);
  transition: background var(--t), padding var(--t);
}

.pj-main { flex: 1 1 auto; min-width: 0; }

/* card anatomy (BUILD_SPEC_v3 §5): eyebrow, headline, subline.
   The company never sits inline with the headline. */
.pj-eyebrow {
  display: flex;
  align-items: baseline;
  gap: 7px;
  margin-bottom: 5px;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--ink-2);
}

.pj-co-name {
  font-weight: 600;
  color: #64748B;
}

.pj-domain { min-width: 0; }
.pj-domain::before { content: "\00b7"; margin-right: 7px; color: var(--rule); }

.pj-badge {
  margin-left: auto;
  flex: 0 0 auto;
  white-space: nowrap;
  font-size: 12.5px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.pj-title {
  display: block;
  font-size: 16px;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: -0.005em;
}

.pj-impact {
  display: block;
  margin-top: 7px;
  font-size: 14px;
  line-height: 1.55;
  color: var(--ink);
}

.pj-impact-label {
  font-size: 14px;
  line-height: 1;
  color: #9AA3B2;
  margin-right: 8px;
}

.pj-impact strong { font-weight: 600; }

/* the tap affordance: no hover on touch, so the row has to say it opens */
.pj-caret {
  display: block;
  flex: 0 0 auto;
  margin-top: 6px;
  width: 12px; height: 12px;
  color: var(--ink-2);
  transition: transform var(--t);
}

.pj-co { color: var(--ink-2); font-weight: 400; }
/* expanded state — hover on pointer devices, click/focus everywhere */
.pj-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--t);
}
.pj-panel > * { overflow: hidden; }
.pj[aria-expanded="true"] .pj-caret { transform: rotate(180deg); }

/* no press effect on project rows: the row stays put, only the tint changes */
.pj:hover .pj-head,
.pj:focus-visible .pj-head { background: var(--hover); }

.pj[aria-expanded="true"] { background: var(--panel); }
.pj[aria-expanded="true"] .pj-panel { grid-template-rows: 1fr; }

.pj-body { display: block; }
.pj-desc { display: block; }

.pj-body {
  padding: 17px 12px 18px;
  border-top: 1px solid var(--rule-soft);
  opacity: 0;
  transform: translateY(-3px);
  transition: opacity var(--t), transform var(--t);
}
.pj[aria-expanded="true"] .pj-body { opacity: 1; transform: none; }

.sec { display: block; margin-top: 24px; }
.sec:first-of-type { margin-top: 0; }

.sec-label {
  display: block;
  margin-bottom: 5px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #6B7280;
}

.sec-body, .sec-item {
  display: block;
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-2);
}

.sec-list { display: block; }
.sec-item { margin-bottom: 7px; }
.sec-item:last-child { margin-bottom: 0; }
.sec-item strong { color: var(--ink); font-weight: 600; }

.pj-outcome {
  display: block;
  margin: 0 0 12px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink);
}

.pj-desc {
  margin: 0 0 8px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-2);
}

.pj-going {
  display: block;
  margin: 0 0 12px;
  font-size: 13px;
  font-style: italic;
  line-height: 1.6;
  color: var(--ink-2);
}

.tags { margin-top: 24px; display: flex; flex-wrap: wrap; gap: 6px; }
.tag {
  font-size: 12px;
  line-height: 1;
  padding: 6px 9px;
  border-radius: 999px;
  border: 1px solid var(--rule);
  color: var(--ink-2);
  background: rgba(255, 255, 255, 0.5);
  white-space: nowrap;
}

.empty { font-size: 14px; color: var(--ink-2); padding: 18px 0; }

/* ---------- about ---------- */

.photo {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--r);
  margin: 22px 0 0;
}

.prose strong { font-weight: 600; color: var(--ink); }

.inline-link {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: #BFBFBF;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.inline-link:hover { text-decoration-color: var(--ink); }

/* same specification as the two paragraphs above it */
.outside {
  margin: 22px 0 0;
  font-size: 15px;
  line-height: 1.62;
  color: var(--ink-2);
}
.outside strong { font-weight: 600; color: var(--ink); }

.photo-caption {
  margin: 10px 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: #9AA3B2;
}

.prose p {
  margin: 0 0 22px;
  font-size: 15px;
  line-height: 1.62;
  color: var(--ink-2);
}
.prose p:last-child { margin-bottom: 0; }

/* ---------- contact ---------- */

.contact { font-size: 15px; }
.contact .status {
  margin: 0 0 16px;
  font-size: 14px;
  font-style: italic;
  color: var(--ink-2);
}
.actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-bottom: 4px; }

.btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 11px 18px;
  border-radius: 999px;
  border: 1px solid var(--rule);
  background: rgba(255, 255, 255, 0.55);
  font-size: 14px;
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--t), border-color var(--t);
}
.contact .btn, .contact .btn:hover { text-decoration: none; }
.btn:hover { background: #fff; border-color: rgba(16, 20, 26, 0.22); }

/* location is context, not an action, so it sits in the heading and never
   wears a pill */
.here {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: 9px;
  font-size: 12.5px;
  font-weight: 400;
  color: var(--ink-2);
}
.here::before { content: "\00b7"; margin-right: 3px; color: var(--rule); }
/* the egg: grey like the text until hovered, then the team's own colour */
.glyph {
  width: 14px;
  height: 14px;
  vertical-align: -2px;
  margin: 0 1px 0 3px;
  color: #9AA3B2;
  transition: color var(--t), transform var(--t);
}
.glyph--knicks:hover { color: #F58426; transform: rotate(-12deg); }
.glyph--liberty:hover { color: #3FB89A; transform: translateY(-1px); }

/* footer icons, all rendered at one size */
.ico {
  flex: 0 0 auto;
  width: 18px; height: 18px;
  border-radius: 50%;
  object-fit: contain;
}
.contact a { text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.contact a:hover { text-decoration-color: var(--ink-2); }
.contact .quiet { color: var(--ink-2); }
.contact .note {
  margin: 22px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-2);
}

.contact .colophon {
  margin-top: 8px;
  font-size: 12.5px;
  color: var(--ink-2);
}

/* ---------- floating dock ---------- */

.dock {
  position: fixed;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 5px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.78);
  border: 1px solid var(--rule-soft);
  backdrop-filter: saturate(160%) blur(12px);
  -webkit-backdrop-filter: saturate(160%) blur(12px);
  z-index: 10;
}

/* icons only; the name appears on hover, like the team glyphs */
.dock-item {
  position: relative;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 999px;
  color: #64748B;
  text-decoration: none;
  transition: background var(--t), color var(--t);
}
.dock-item svg { width: 19px; height: 19px; }

/* the mark doubles as "back to top", since the page has no sticky header */
.dock-home img {
  width: 20px;
  height: 20px;
  object-fit: contain;
  transition: opacity var(--t);
}
.dock-home:hover img { opacity: 0.65; }

.dock-sep {
  width: 1px;
  height: 20px;
  margin: 0 5px;
  background: var(--rule);
}
.dock-item:hover { background: var(--hover); color: var(--ink); }

.dock-item::after {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 9px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  padding: 5px 9px;
  border-radius: 7px;
  background: var(--ink);
  color: #fff;
  font-size: 11.5px;
  line-height: 1;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t), transform var(--t);
}
.dock-item:hover::after,
.dock-item:focus-visible::after { opacity: 1; transform: translateX(-50%); }

:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* ---------- responsive ---------- */

@media (max-width: 640px) {
  .wrap { --pad: 24px; padding: 64px var(--pad) 112px; }
  .hero p { font-size: 22px; line-height: 30px; }
  .pj-head { gap: 10px; }
  .photo { height: 170px; }
}

@media (hover: none) {
  /* Opening is a press on every device now, so the old hover overrides are
     gone: they only fought the aria-expanded rules. Touch keeps a tighter
     head, and no hover tint (it would stick after a tap). */
  .pj-head { align-items: flex-start; gap: 10px; }
  .pj:hover .pj-head { background: transparent; }
  .exp-item:hover .row { background: transparent; padding: 14px 12px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 1ms !important; scroll-behavior: auto; }
}
