/* ccshan · design-system components (Figma「ccshan / Design System」874:2)
 * Loaded after components.css (legacy page blocks) so these win where both apply.
 * Interaction states: hover only on pointer devices, :active = Pressed, [aria-current] = Active.
 */

/* ---------- Layout ---------- */
:root{
  --gutter-min:var(--layout-margin-tablet);
  --section-pad:var(--space-128);
  --section-pad-tight:var(--space-48);
  --header-h:76px;                                  /* Figma 导航 / 主导航: 1440×76 */
}
@media (max-width:1199px){:root{--section-pad:var(--space-96);--section-pad-tight:var(--space-32)}}
@media (max-width:767px){:root{--gutter-min:var(--layout-margin-mobile);--section-pad:var(--space-64);--section-pad-tight:var(--space-32);--header-h:56px}}
/* 1440 → 180 exactly; narrower desktops keep the 1080 column centred with ≥48 gutters */
.l-gutter{padding-inline:max(var(--gutter-min), calc((100% - var(--layout-content)) / 2))}
.l-gutter-wide{padding-inline:max(var(--gutter-min), calc((100% - var(--layout-content-wide)) / 2))}
@media (max-width:1199px){.l-gutter,.l-gutter-wide{padding-inline:var(--gutter-min)}}
.l-section{padding-block:var(--section-pad)}
.l-section--subtle{background:var(--color-bg-subtle)}
.l-section--inverse{background:var(--color-bg-inverse);color:var(--color-text-on-inverse)}
.l-section--follows-same{padding-top:var(--section-pad-tight)}
.l-measure{max-width:var(--layout-measure)}
.l-stack{display:flex;flex-direction:column;gap:var(--space-24)}

/* ---------- Typography (ccshan/* text styles; tablet −1 step for Display/H1, mobile −2) ---------- */
.t-display{font:var(--type-display);letter-spacing:-.01em;margin:0}
.t-h1{font:var(--type-h1);letter-spacing:-.01em;margin:0}
.t-h2{font:var(--type-h2);margin:0}
.t-h3{font:var(--type-h3);margin:0}
.t-h4{font:var(--type-h4);margin:0}
.t-eyebrow{font:var(--type-eyebrow);color:var(--color-text-secondary);margin:0}
.t-lead{font:var(--type-body-lead);margin:0}
.t-body-l{font:var(--type-body-large);margin:0}
.t-body{font:var(--type-body);margin:0}
.t-caption{font:var(--type-caption);color:var(--color-text-secondary);margin:0}
.t-secondary{color:var(--color-text-secondary)}
@media (max-width:1199px){
  .t-display{font:var(--type-h1)}
  .t-h1{font:var(--type-h2)}
}
@media (max-width:767px){
  .t-display{font:var(--type-h2)}
  .t-h1,.t-h2{font:var(--type-h3)}
  .t-h3{font:var(--type-h4)}
  .t-lead{font:var(--type-body-large)}
}

/* ---------- Header / Nav ---------- */
.site-header{position:sticky;top:0;z-index:50;background:rgba(255,255,255,.92);-webkit-backdrop-filter:saturate(180%) blur(12px);backdrop-filter:saturate(180%) blur(12px);border-bottom:1px solid rgba(0,0,0,.04)}
.site-header__inner{height:var(--header-h);display:flex;align-items:center;justify-content:space-between;gap:var(--space-24)}
.logo{font:var(--type-h4);letter-spacing:-.02em;color:var(--color-text-primary)}
.logo .shan{color:var(--color-text-brand)}
.site-nav{display:flex;align-items:center;gap:var(--space-32)}
.nav-link{position:relative;display:inline-flex;flex-direction:column;align-items:center;gap:var(--space-4);padding:8px 0 6px;font:var(--type-body);color:var(--color-text-primary);transition:opacity var(--motion-duration-fast) var(--ease-standard)}
.nav-link::before{content:"";position:absolute;inset:-6px -10px}            /* ≥44px hit area */
.nav-link::after{content:"";width:100%;height:2px;border-radius:1px;background:currentColor;transform:scaleX(0);transition:transform var(--motion-duration-base) var(--ease-emphasized)}
.nav-link[aria-current]{font-weight:500}
.nav-link[aria-current]::after{transform:scaleX(1)}
@media (hover:hover){.nav-link:not([aria-current]):hover{opacity:.72}}
.nav-link:active{opacity:.72;transition-duration:var(--motion-duration-instant)}

.menu-toggle{display:none;width:44px;height:44px;margin-right:-10px;align-items:center;justify-content:center;border:0;background:none;color:var(--color-text-primary);cursor:pointer;-webkit-tap-highlight-color:transparent}
.menu-toggle svg{width:18px;height:12px;display:block}
.menu-toggle:active{opacity:.72}
@media (max-width:767px){
  .js .site-nav{display:none}
  .js .menu-toggle{display:inline-flex}
  .site-nav{gap:var(--space-16)}                                          /* no-JS fallback: links stay inline */
}

/* Case chapter nav shares the header's column until its P3 redesign */
.case-subnav{padding-inline:max(var(--gutter-min), calc((100% - var(--layout-content)) / 2))}
@media (max-width:1199px){.case-subnav{padding-inline:var(--gutter-min)}}

/* ---------- Mobile menu (Menu / Mobile · overlay, spring-gentle) ---------- */
.site-menu{position:fixed;inset:0;z-index:100;display:flex;flex-direction:column;gap:var(--space-32);padding:0 var(--layout-margin-mobile) var(--space-48);background:var(--color-bg-default);
  transform:translate3d(0,-100%,0);visibility:hidden;
  transition:transform var(--motion-duration-base) var(--ease-standard),visibility 0s linear var(--motion-duration-base)}
.site-menu.is-open{transform:none;visibility:visible;transition:transform var(--motion-duration-spring-gentle) var(--ease-spring-gentle),visibility 0s}
.site-menu:focus{outline:none}
.site-menu__bar{height:56px;display:flex;align-items:center;justify-content:space-between}
.site-menu__close{width:44px;height:44px;margin-right:-10px;display:inline-flex;align-items:center;justify-content:center;border:0;background:none;color:var(--color-text-primary);cursor:pointer}
.site-menu__close svg{width:18px;height:18px}
.site-menu__links{display:flex;flex-direction:column;gap:var(--space-24);margin:0;padding:0;list-style:none}
.site-menu__link{display:inline-block;font:var(--type-h3);color:var(--color-text-primary);opacity:0;transform:translate3d(0,-8px,0);transition:opacity var(--motion-duration-fast) var(--ease-standard),transform var(--motion-duration-base) var(--ease-emphasized)}
.site-menu__link[aria-current]{color:var(--color-text-secondary)}
.site-menu.is-open .site-menu__link{opacity:1;transform:none;transition-delay:calc(var(--motion-duration-instant) + var(--i,0) * var(--motion-stagger-step) / 2)}
.site-menu__cta{margin-top:auto}
.site-menu__cta .btn{width:100%;justify-content:center}
html.menu-open{overflow:hidden}

/* ---------- Button & Link (Button: Primary / Secondary / Link / Link Inverse × Default / Hover / Pressed) ---------- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--space-8);min-height:44px;padding:12px 24px;border:0;border-radius:var(--radius-full);font:var(--type-label-link);cursor:pointer;-webkit-tap-highlight-color:transparent;
  transition:background-color var(--motion-duration-fast) var(--ease-standard),box-shadow var(--motion-duration-fast) var(--ease-standard),opacity var(--motion-duration-fast) var(--ease-standard)}
.btn--primary{background:var(--color-action-primary);color:var(--color-text-on-inverse)}
.btn--secondary{background:transparent;color:var(--color-text-primary);box-shadow:inset 0 0 0 1px var(--color-text-primary)}
@media (hover:hover){
  .btn--primary:hover{background:color-mix(in srgb,var(--color-action-primary) 85%,transparent)}
  .btn--secondary:hover{background:var(--color-bg-subtle)}
}
.btn:active{opacity:.72;transition-duration:var(--motion-duration-instant)}

/* inline (not flex) so the arrow, an atomic inline-block, is left out of the underline */
.link{position:relative;display:inline;font:var(--type-label-link);color:var(--color-text-primary);
  text-decoration:underline;text-decoration-color:transparent;text-underline-offset:4px;text-decoration-thickness:1px;
  transition:color var(--motion-duration-fast) var(--ease-standard),text-decoration-color var(--motion-duration-fast) var(--ease-standard),opacity var(--motion-duration-fast) var(--ease-standard)}
.link::before{content:"";position:absolute;inset:-10px -8px}               /* ≥44px hit area */
.link .arrow{display:inline-block;margin-left:var(--space-4);transition:transform var(--motion-duration-base) var(--ease-emphasized)}
.link--inverse{color:var(--color-text-on-inverse)}
@media (hover:hover){
  .link:hover{color:var(--color-text-brand);text-decoration-color:currentColor}
  .link:hover .arrow{transform:translate3d(2px,0,0)}
  .link--inverse:hover{color:var(--color-text-on-inverse-muted)}
}
.link:active{opacity:.72;transition-duration:var(--motion-duration-instant)}

/* ---------- Card (Project / Experience / Article × Default / Hover) ---------- */
.card-cover{position:relative;overflow:hidden;border-radius:var(--radius-md);background:var(--color-bg-subtle);isolation:isolate}
.card-cover img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transition:transform var(--motion-duration-slow) var(--ease-emphasized)}

.project-card{position:relative;display:flex;flex-direction:column;gap:var(--space-16)}
.project-card .card-cover{aspect-ratio:344/480}
.project-card__title{font:var(--type-h3);margin:0}
.project-card__meta{font:var(--type-body-large);color:var(--color-text-secondary);margin:0}

/* Project tile (作品页项目行): subtle panel, cover on top, text inset 24 */
.project-tile{position:relative;display:flex;flex-direction:column;gap:var(--space-16);padding-bottom:28px;border-radius:var(--radius-md);overflow:hidden;background:var(--color-bg-subtle);transition:box-shadow var(--motion-duration-slow) var(--ease-emphasized)}
.project-tile .card-cover{aspect-ratio:528/345}
.project-tile > :not(.card-cover){margin-inline:var(--space-24)}
.project-tile__title{font:var(--type-h3);margin:0}
.project-tile__meta{font:var(--type-body);color:var(--color-text-secondary);margin:0}
.project-tile > .link{align-self:center}                    /* Figma 作品页: 「查看项目 →」居中，标题与说明左对齐 */

/* Experience card — values from 首页「经历 / 核心经历」: white on subtle, no resting shadow */
.experience-card{position:relative;display:flex;flex-direction:column;gap:var(--space-16);padding:var(--space-32);border-radius:var(--radius-md);background:var(--color-surface-card);transition:box-shadow var(--motion-duration-slow) var(--ease-emphasized)}
.experience-card__title{font:var(--type-h3);margin:0}
.experience-card__meta{font:var(--type-body);color:var(--color-text-secondary);margin:0}
.experience-card__desc{font:var(--type-body-large);margin:0;flex:1}

.article-card{position:relative;display:flex;align-items:center;gap:var(--space-48);overflow:hidden;border-radius:var(--radius-md);background:var(--color-bg-subtle);transition:box-shadow var(--motion-duration-slow) var(--ease-emphasized)}
.article-card .card-cover{flex:0 0 420px;height:260px;border-radius:0}
.article-card__body{display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-12);padding:var(--space-24) var(--space-24) var(--space-24) 0}
.article-card__kicker{font:var(--type-label-strong);color:var(--color-text-secondary);margin:0}
.article-card__title{font:var(--type-h3);margin:0}
@media (max-width:1199px){
  .article-card{gap:var(--space-32)}
  .article-card .card-cover{flex-basis:280px}
}
@media (max-width:767px){
  .experience-card__title,.project-card__title,.project-tile__title,.article-card__title{font:var(--type-h4)}
  .project-card__meta,.experience-card__desc{font:var(--type-body)}
  .article-card{flex-direction:column;align-items:stretch;gap:var(--space-16)}
  .article-card .card-cover{flex-basis:auto;height:200px}
  .article-card__body{padding:0 var(--space-24) var(--space-24)}
}

/* Whole card is the hit area: the title link stretches over the card (one tab stop, readable name). */
.card-hit::after{content:"";position:absolute;inset:0;z-index:1;border-radius:var(--radius-md)}
.card-hit:focus-visible{outline:none}
.card-hit:focus-visible::after{outline:2px solid var(--color-text-primary);outline-offset:4px}
@media (hover:hover){
  .project-card:hover .card-cover img,.project-tile:hover .card-cover img,.article-card:hover .card-cover img{transform:scale(1.04)}
  .experience-card:hover,.article-card:hover,.project-tile:hover{box-shadow:var(--shadow-md)}
  :is(.project-card,.project-tile,.experience-card,.article-card):hover .link{color:var(--color-text-brand);text-decoration-color:currentColor}
  :is(.project-card,.project-tile,.experience-card,.article-card):hover .link .arrow{transform:translate3d(2px,0,0)}
}

/* Pressed (all pointers): the whole card dims to 72%, 100ms — same as Button / Link Pressed */
:is(.project-card,.project-tile,.experience-card,.article-card):has(.card-hit:active){opacity:.72;transition:opacity var(--motion-duration-instant) var(--ease-standard)}

/* ---------- Tag ---------- */
.tag{display:inline-flex;align-items:center;padding:4px 12px;border-radius:var(--radius-full);font:var(--type-caption)}
.tag--neutral{background:var(--color-bg-subtle);color:var(--color-text-secondary)}
.tag--inverse{background:var(--color-bg-inverse);color:var(--color-text-on-inverse)}
.tag--brand{box-shadow:inset 0 0 0 1px var(--color-brand-accent);color:var(--color-text-brand)}

/* ---------- Carousel Hint ---------- */
.carousel-hint{display:flex;align-items:center;justify-content:space-between;gap:var(--space-16);margin-top:var(--space-16)}
.carousel-hint__label{font:var(--type-caption);color:var(--color-text-secondary);font-variant-numeric:tabular-nums}
.carousel-hint__buttons{display:flex;gap:var(--space-8)}
.carousel-hint__btn{width:40px;height:40px;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:var(--radius-full);background:none;color:var(--color-text-primary);box-shadow:inset 0 0 0 1px var(--color-border-default);cursor:pointer;
  transition:background-color var(--motion-duration-fast) var(--ease-standard),opacity var(--motion-duration-fast) var(--ease-standard)}
.carousel-hint__btn svg{width:20px;height:20px}
.carousel-hint__btn:disabled{opacity:.32;cursor:default}
@media (hover:hover){.carousel-hint__btn:not(:disabled):hover{background:var(--color-bg-subtle)}}
.carousel-hint__btn:not(:disabled):active{opacity:.72}
@media (max-width:767px){.carousel-hint__buttons{display:none}}

/* ---------- Footer (contact CTA) ---------- */
/* Build note under every page (was in legacy components.css) */
.site-footer{padding:40px;text-align:center;font-size:13px;color:var(--muted)}
.page-footer{display:flex;flex-direction:column;align-items:center;gap:var(--space-24);text-align:center;background:var(--color-bg-subtle)}
.page-footer__title{font:var(--type-h2);margin:0}
.page-footer__intent{font:var(--type-body-large);margin:0}
@media (max-width:767px){.page-footer__title{font:var(--type-h3)}}

/* ---------- Focus ---------- */
:where(.btn,.link,.nav-link,.menu-toggle,.site-menu__close,.carousel-hint__btn,.site-menu__link,.logo):focus-visible{outline:2px solid var(--color-text-primary);outline-offset:3px;border-radius:4px}
.btn:focus-visible{border-radius:var(--radius-full)}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion:reduce){
  .site-menu,.site-menu.is-open{transform:none;opacity:0;transition:opacity var(--motion-duration-fast) linear,visibility 0s linear var(--motion-duration-fast)}
  .site-menu.is-open{opacity:1;transition:opacity var(--motion-duration-fast) linear,visibility 0s}
  .site-menu__link{transform:none;transition:opacity var(--motion-duration-fast) linear}
  .site-menu.is-open .site-menu__link{transition-delay:0s}
  .nav-link::after,.link .arrow,.card-cover img{transition:none}
  .project-card:hover .card-cover img,.article-card:hover .card-cover img,.link:hover .arrow{transform:none}
}

/* ======================================================================
   Page composition (P2) — section heads, grids, hero, motion hooks
   ====================================================================== */
.head-stack{display:flex;flex-direction:column;align-items:center;text-align:center;gap:var(--space-24)}
.head-stack > *{max-width:100%}
.head-stack > :is(.grid-3,.grid-2,.list-stack){align-self:stretch;text-align:left}
.t-eyebrow--label{font:var(--type-label-strong)}
.gap-24{gap:var(--space-24)} .gap-32{gap:var(--space-32)} .gap-48{gap:var(--space-48)}
.mt-48{margin-top:var(--space-48)}
.w-measure{max-width:var(--layout-measure)}
.w-lead{max-width:850px}

.grid-3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--layout-gutter)}
.grid-2{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-32) var(--layout-gutter)}
.list-stack{display:flex;flex-direction:column;gap:var(--space-32)}
@media (max-width:1199px){
  .grid-3{grid-template-columns:repeat(2,minmax(0,1fr));row-gap:var(--space-48)}
  .grid-2{grid-template-columns:1fr}
}
@media (max-width:767px){.grid-3{grid-template-columns:1fr}}

/* Hero: full-bleed image keeps Figma's 1440×719 proportion; parallax runs on the compositor where supported */
.hero-media{overflow:hidden;aspect-ratio:1440/719;background:var(--color-bg-inverse)}
.hero-media img{width:100%;height:100%;object-fit:cover}
@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){
    .hero-media img{animation:hero-parallax linear both;animation-timeline:view();animation-range:cover 0% cover 100%}
  }
}
@keyframes hero-parallax{from{transform:translate3d(0,-12px,0) scale(1.05)}to{transform:translate3d(0,12px,0) scale(1.05)}}

/* Hero intro: eyebrow → title → lead → CTA, 700ms emphasized, 80ms apart; first visit of the session only */
@keyframes rise{from{opacity:0;transform:translate3d(0,24px,0)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:no-preference){
  html:not(.intro-seen) .hero-intro > *{animation:rise var(--motion-duration-reveal) var(--ease-emphasized) both}
  html:not(.intro-seen) .hero-intro > :nth-child(1){animation-delay:calc(var(--motion-duration-instant) + 0 * var(--motion-stagger-step))}
  html:not(.intro-seen) .hero-intro > :nth-child(2){animation-delay:calc(var(--motion-duration-instant) + 1 * var(--motion-stagger-step))}
  html:not(.intro-seen) .hero-intro > :nth-child(3){animation-delay:calc(var(--motion-duration-instant) + 2 * var(--motion-stagger-step))}
  html:not(.intro-seen) .hero-intro > :nth-child(4){animation-delay:calc(var(--motion-duration-instant) + 3 * var(--motion-stagger-step))}
  /* the hero image / video poster is the LCP element: it is visible from the first frame and only settles in scale
     (an opacity fade from 0 would hold LCP until the fade ends). `scale` composes with the parallax transform. */
  html:not(.intro-seen) .hero-intro-media > :is(img,video){animation:media-settle calc(var(--motion-duration-reveal) * 2) var(--ease-emphasized) both}
}
@keyframes media-settle{from{scale:1.04}}
/* same element also runs the scroll-driven parallax: list both so neither replaces the other */
@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){
    html:not(.intro-seen) :is(.hero-media,.case-cover).hero-intro-media > img{
      animation:media-settle calc(var(--motion-duration-reveal) * 2) var(--ease-emphasized) both,hero-parallax linear both;
      animation-timeline:auto,view();animation-range:normal,cover 0% cover 100%}
  }
}
@keyframes fade-in{from{opacity:0}to{opacity:1}}

/* Scroll reveal (js/reveal.js): fade + 28px rise, 700ms emphasized, once; groups stagger 80ms.
   Animations (not transitions) so components keep their own hover transitions. */
@keyframes reveal-rise{from{opacity:0;transform:translate3d(0,28px,0)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:no-preference){
  .js [data-reveal]:not(.is-in),.js [data-reveal-group]:not(.is-in) > *{opacity:0}
  .js [data-reveal].is-in,.js [data-reveal-group].is-in > *{animation:reveal-rise var(--motion-duration-reveal) var(--ease-emphasized) both;animation-delay:calc(var(--reveal-i,0) * var(--motion-stagger-step))}
}
.work-list{padding-bottom:var(--section-pad)}
.pb-30{padding-bottom:30px}                          /* 首页思考条目: last item sits 30 above the footer */

/* Line breaking: balanced headings (no orphan characters), pretty paragraphs */
:is(.t-display,.t-h1,.t-h2,.t-h3,.t-h4,.page-footer__title,[class*="__title"]){text-wrap:balance}
:is(.t-lead,.t-body-l,.t-body,[class*="__desc"],[class*="__meta"]){text-wrap:pretty}
.br-tablet{display:none}
@media (min-width:768px) and (max-width:1199px){.br-tablet{display:inline}}
