/* ============================================================
   SITE — the shared system
   One stylesheet, every page. Sections:
     1. Frame & ruled grid
     2. Type roles
     3. Shared components: nav, metadata, image and video plates, footer
     4. Page modules: landing grid, case study, info
     5. Placeholders (template-only — see README)
     6. Motion
     7. Responsive
   ============================================================ */

*,*::before,*::after{box-sizing:border-box}
html{color-scheme:only light;background:var(--surface-page);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
body{
  margin:0;
  padding:var(--frame-gap);
  background:var(--surface-page);
  color:var(--text-primary);
  font:var(--type-body);
  text-wrap:pretty;
}
::selection{background:var(--selection-bg);color:var(--selection-fg)}
a{color:var(--text-link);text-decoration:none;transition:var(--transition-control)}
a:hover{color:var(--text-link-hover)}
h1,h2,h3,p,dl,ul,figure{margin:0}
:focus-visible{outline:none;box-shadow:var(--shadow-focus)}

/* ------------------------------------------------------------
   1. FRAME & RULED GRID
   The sheet owns the top + left rule; every cell owns right + bottom.
   Adjacent cells share one 1px line — never give a cell four borders.
   ------------------------------------------------------------ */
:root{
  --rule:var(--border-subtle);
  --frame-gap:clamp(16px,2.4vw,40px);   /* page padding around the sheet */
  --cell-pad:clamp(28px,3.2vw,56px);    /* uniform inset inside every cell */
  --pad-roomy:clamp(56px,7vw,120px);    /* vertical padding on statement rows */
  --pad-mid:clamp(40px,4.5vw,72px);     /* vertical padding on title / prev-next rows */
}
.sheet{border-top:1px solid var(--rule);border-left:1px solid var(--rule)}
.row{display:grid;grid-template-columns:repeat(12,minmax(0,1fr))}
.cell{border-right:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:var(--cell-pad);min-width:0}
.cell.flush{padding:0}                     /* edge-to-edge image cells */
.cell.blank{padding:0}                     /* no content, carries the rules: closes a half-filled row (odd card count) */
/* Four row formats, used everywhere — no other spans on the site:
     FULL     c12                one cell (statements, titles, section heads, full-width images)
     HALVES   c6 + c6            work cards, gallery pairs, prev / next
     THIRDS   c4 + c4 + c4       nav, footer, case-study meta cells
     SPLIT    c4 + c8            label or portrait left, content right (info rows, case-study info, focus list)
   Inside a FULL cell, .split gives the same 4/8 proportion without a divider (focus list, info lists). */
.c4{grid-column:span 4}.c6{grid-column:span 6}.c8{grid-column:span 8}.c12{grid-column:span 12}
.row[data-theme="inverse"]{background:var(--surface-inverse);color:var(--text-inverse)}

/* Full-bleed: case-study galleries may break the frame. Text never does. */
.bleed{margin-inline:calc(-1 * var(--frame-gap) - 1px);width:calc(100% + 2 * var(--frame-gap) + 1px)}

/* Screen-reader-only text */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* Layout helpers used inside cells */
.stack{display:flex;flex-direction:column;gap:var(--space-6)}
.stack>.label{margin-bottom:calc(-1 * var(--space-3))}
.between{display:flex;flex-direction:column;justify-content:space-between;gap:var(--space-8);height:100%}
.row.roomy>.cell{padding-block:var(--pad-roomy)}
.row.mid>.cell{padding-block:var(--pad-mid)}

/* ------------------------------------------------------------
   2. TYPE ROLES — display serif, body sans, mono
   Instrument Serif 400 (its only weight) for headers and display text; Inter 400/500 for body, meta values and links;
   IBM Plex Mono, uppercase, ≤12px for labels and micro-copy.
   ------------------------------------------------------------ */
.display{font:var(--weight-regular) clamp(38px,4.6vw,76px)/1.05 var(--font-display);letter-spacing:var(--tracking-display)}
.title{font:var(--weight-regular) clamp(32px,3.4vw,56px)/1.08 var(--font-display);letter-spacing:var(--tracking-display)}
.title-sm{font:var(--weight-regular) clamp(22px,1.7vw,26px)/1.2 var(--font-display);letter-spacing:-0.005em}
.lede{font:var(--weight-regular) clamp(20px,1.7vw,28px)/1.35 var(--font-display);letter-spacing:-0.005em}
.body p{font:var(--type-body);color:var(--text-secondary);max-width:60ch;margin:0 0 var(--space-6)}
.body p:last-child{margin-bottom:0}
.mono{font:var(--type-meta);letter-spacing:var(--tracking-label);text-transform:uppercase;color:var(--text-muted)}
.label{font:var(--weight-medium) var(--text-2xs)/1.6 var(--font-mono);letter-spacing:var(--tracking-eyebrow);text-transform:uppercase;color:var(--text-muted)}

/* ------------------------------------------------------------
   3. SHARED COMPONENTS
   ------------------------------------------------------------ */

/* Nav row — scrolls with the page (not sticky) */
.row.nav{background:var(--surface-page)}
.nav .cell{display:flex;align-items:center;padding-block:var(--space-5)}
.brand{display:inline-flex;align-items:center;gap:var(--space-4);color:inherit}
.brand-mark{display:block;width:64px;height:64px;object-fit:contain;flex:none}
.brand-word{display:flex;flex-direction:column;gap:2px;font:var(--weight-medium) var(--text-2xs)/1.3 var(--font-mono);letter-spacing:var(--tracking-label);text-transform:uppercase;color:var(--text-primary)}
.brand-word small{font-size:inherit;color:var(--text-muted)}
.navlink{font:var(--type-label);letter-spacing:var(--tracking-label);text-transform:uppercase;color:var(--text-secondary);transition:color var(--dur-fast) ease}
.navlink:hover{color:var(--text-primary)}
.navlink[aria-current="page"]{color:var(--ox-600)}

/* Metadata block — the signature motif. Two columns: mono key, sans value. */
.meta{display:grid;grid-template-columns:max-content minmax(0,1fr);column-gap:var(--space-6);row-gap:var(--space-3)}
.meta dt{font:var(--weight-medium) var(--text-2xs)/1.6 var(--font-mono);letter-spacing:var(--tracking-eyebrow);text-transform:uppercase;color:var(--text-muted)}
.meta dd{margin:0;font:var(--weight-regular) var(--text-base)/1.5 var(--font-sans);color:var(--text-primary)}

/* Pill button — kept as a utility (currently unused; the cursor label is the only pill on the site). */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:var(--space-3);
  font:var(--weight-medium) var(--text-xs)/1 var(--font-mono);letter-spacing:var(--tracking-label);text-transform:uppercase;
  padding:12px 22px;border-radius:var(--radius-pill);border:1px solid var(--border-strong);
  color:var(--text-primary);background:transparent;cursor:pointer;transition:var(--transition-control);
}
.btn:hover{background:var(--text-primary);color:var(--text-inverse)}
.btn:active{transform:translateY(1px)}

/* Image plate — square corners, media fills the frame.
   Colour behaviour lives with the context, not here:
   · Card plates (see 4. PAGE MODULES): greyscale at rest, colour + 1.03 scale on hover — unchanged.
   · Non-card plates (case-study gallery, portrait): greyscale at rest, colour when their .row / .bleed
     is armed with .drawn by site.js — rules below. Because .draw is only ever added by site.js (and
     never under prefers-reduced-motion), reduced-motion users and no-JS browsers get full colour,
     no transition, automatically.
   · Video plates are never greyscale. */
.plate{display:block;position:relative;width:100%;overflow:hidden;background:var(--surface-sunken)}
.plate img,.plate video{display:block;width:100%;height:100%;object-fit:cover;position:absolute;inset:0}
.plate-link{display:block;color:inherit}
.plate-link:hover img{filter:grayscale(0);transform:scale(1.03)}
.plate-fig figcaption{font:var(--type-meta);letter-spacing:var(--tracking-label);text-transform:uppercase;color:var(--text-muted);padding:var(--space-4) var(--cell-pad)}

/* Non-card plates: greyscale until the row draws in, then colour over the reveal duration */
.row.draw>.cell:not(.card) .plate img,
.bleed.draw .plate img{filter:grayscale(1);transition:filter var(--dur-reveal) var(--ease-entrance)}
.row.drawn>.cell:not(.card) .plate img,
.bleed.drawn .plate img{filter:grayscale(0)}

/* ------------------------------------------------------------
   4. PAGE MODULES
   ------------------------------------------------------------ */

/* Info: inset portrait — portrait proportion, compact, inside the padded cell */
.portrait{width:min(260px,100%)}

/* Case study: intro block — title + meta/info held to about two-thirds of the viewport */
.case-intro{display:flex;flex-direction:column;min-height:calc(66vh - var(--frame-gap) - 118px)}   /* 118px ≈ nav row height */
.case-intro>.row:last-child{flex:1}
@media (max-width:760px){.case-intro{min-height:0}}

/* Case study: stacked key/value meta beside the project-info statement */
.kv-stack{display:flex;flex-direction:column;gap:var(--space-5)}
.kv .label{margin-bottom:var(--space-2)}
.kv-val{font:var(--type-body);color:var(--text-primary)}
.info{font:var(--weight-regular) clamp(21px,1.9vw,30px)/1.3 var(--font-display);letter-spacing:-0.01em;color:var(--text-primary);max-width:40ch;text-wrap:pretty}
.bio{gap:var(--space-5)}
.bio .info{max-width:44ch}

/* Case study: prev / next */
.pn{display:flex;flex-direction:column;gap:var(--space-3);color:var(--text-primary)}
.pn-title{font:var(--weight-regular) clamp(24px,2.2vw,34px)/1.15 var(--font-display);letter-spacing:-0.01em;transition:color var(--dur-fast) ease}
.pn:hover .pn-title{color:var(--text-brand)}
.pn.next{text-align:right;align-items:flex-end}
/* A row with only a Next link (no Previous yet): the cell moves to the right half so "Next →" is always right-aligned */
.row>.cell:only-child:has(>.pn.next){grid-column:7/span 6}

/* Info: contact links, experience rows, client list */
.arrows{display:flex;flex-direction:column;gap:var(--space-5);align-items:flex-start}
.arrows a{font:var(--weight-regular) var(--text-lg)/1.3 var(--font-sans);color:var(--text-primary);border-bottom:1px solid var(--ox-300);padding-bottom:2px;transition:color var(--dur-fast) ease,border-color var(--dur-fast) ease}
.arrows a:hover{color:var(--text-brand);border-bottom-color:var(--ox-600)}
/* Entries — hairline rows inside a .split (Experience, Education). Year / Role → Company on a 4/8 line. */
.entries{list-style:none;padding:0;display:flex;flex-direction:column}
.entry{display:grid;grid-template-columns:1fr 2fr;column-gap:var(--space-8);align-items:baseline;padding:var(--space-4) 0;border-bottom:1px solid var(--rule)}
.entry:first-child{padding-top:0}
.yr{font:var(--weight-regular) var(--text-2xs)/1.7 var(--font-mono);letter-spacing:var(--tracking-eyebrow);text-transform:uppercase;color:var(--text-muted)}
.what{font:var(--type-body);color:var(--text-primary)}
.what .co{color:var(--text-secondary)}
.list{list-style:none;padding:0;font:var(--type-body);color:var(--text-secondary)}
.list li{padding:3px 0}

/* Landing: hero statement — one paragraph, text only.
   .messy: the word's letters start scattered (inline transforms set by site.js) and drift home. */
.messy{display:inline-block;color:var(--ox-600)}
.messy-letter{display:inline-block;transition:transform 1800ms cubic-bezier(.3,.7,.2,1)}

/* Landing: hero statement — one paragraph, text only */
.statement{font:var(--weight-regular) clamp(30px,3.2vw,52px)/1.15 var(--font-display);letter-spacing:-0.01em;color:var(--text-primary);max-width:40ch;text-wrap:pretty}

/* Landing: section heads (label left, mono count right) */
.sec-head{display:flex;justify-content:space-between;align-items:baseline;gap:var(--space-6);flex-wrap:wrap}

/* Landing: text link with arrow (VIEW ALL PROJECTS →) */
.link-arrow{display:inline-flex;align-items:center;gap:var(--space-3);font:var(--type-label);letter-spacing:var(--tracking-label);text-transform:uppercase;color:var(--text-primary);transition:color var(--dur-fast) ease}
.link-arrow:hover{color:var(--text-brand)}

/* Landing: areas of focus — label left, three-column ruled list right, inside one cell */
.split{display:grid;grid-template-columns:1fr 2fr;column-gap:var(--space-8)}   /* the SPLIT proportion without a divider */
.focus{list-style:none;padding:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));column-gap:var(--space-8);row-gap:var(--space-7)}
.focus li{padding-bottom:var(--space-3);border-bottom:1px solid var(--rule);font:var(--weight-regular) clamp(20px,1.6vw,26px)/1.2 var(--font-display);letter-spacing:-0.005em;color:var(--text-primary)}

/* Work card (landing + projects index) — the whole cell is the link.
   Hover: image saturates; the cursor pill reads the project title (data-cursor-label, see site.js).
   Touch devices have no cursor, so .card-name shows the title as the first line of the box. */
.card{display:flex;flex-direction:column;color:var(--text-primary);height:100%}
.card .plate{border-bottom:1px solid var(--rule);transition:background-color var(--dur-slow) var(--ease-out)}
.card .plate img{filter:grayscale(1);transition:filter var(--dur-slow) var(--ease-out),transform var(--dur-slow) var(--ease-out)}
.card-info{padding:var(--cell-pad);display:flex;flex-direction:column;gap:var(--space-2)}
.card-name{display:none;font:var(--weight-regular) clamp(22px,1.7vw,26px)/1.2 var(--font-display);letter-spacing:-0.005em;color:var(--text-primary);margin-bottom:var(--space-2)}
.card-client{color:var(--text-primary);font-weight:var(--weight-medium)}   /* ink, medium — the darker line */
.card-focus{color:var(--text-muted)}
.meta-lines{padding:0}
.card:hover .plate img{filter:grayscale(0);transform:scale(1.03)}
.card:hover .ph-img{background-color:#E2E2E2}   /* template only: shows the hover on placeholder plates */
@media (hover:none){.card-name{display:block}}

/* Footer — shared on every page: three ruled cells, then a sign-off row (© left, logomark right) */
.foot-grid .label{margin-bottom:var(--space-4)}
.foot-line{font:var(--type-body);color:var(--text-primary)}
.foot-line a{color:var(--text-primary);border-bottom:1px solid var(--ox-300);padding-bottom:2px;transition:color var(--dur-fast) ease,border-color var(--dur-fast) ease}
.foot-line a:hover{color:var(--text-brand);border-bottom-color:var(--ox-600)}
.foot-links{display:flex;flex-direction:column;gap:var(--space-3);align-items:flex-start}
.foot-links a{font:var(--type-body);color:var(--text-primary);border-bottom:1px solid var(--ox-300);line-height:1.3;padding-bottom:2px;transition:color var(--dur-fast) ease,border-color var(--dur-fast) ease}
.foot-links a:hover{color:var(--text-brand);border-bottom-color:var(--ox-600)}
.copyright{font:var(--type-meta);letter-spacing:var(--tracking-label);text-transform:uppercase;color:var(--text-muted)}
.signoff{display:flex;justify-content:space-between;align-items:center;gap:var(--space-8)}
.signoff-mark{display:block;width:64px;height:auto}

/* Cursor — an oxblood dot that follows the pointer. Over an element with data-copy it
   stretches into a pill that reads "Copy"; after a click it reads "Copied".
   Enabled per page with <body class="has-cursor">; only on fine-pointer devices (see site.js). */
.cursor-on,.cursor-on a,.cursor-on button{cursor:none}
.cursor{position:fixed;left:0;top:0;z-index:9999;pointer-events:none;opacity:0;transition:opacity var(--dur-fast) ease;will-change:transform}
.cursor.is-visible{opacity:1}
.cursor-dot{
  display:flex;align-items:center;justify-content:center;
  width:18px;height:18px;border-radius:var(--radius-pill);background:var(--ox-600);
  transform:translate(-50%,-50%);
  transition:width var(--dur-base) var(--ease-out),height var(--dur-base) var(--ease-out);
}
.cursor-label{font:var(--weight-medium) 10px/1 var(--font-mono);letter-spacing:var(--tracking-label);text-transform:uppercase;color:var(--cream);opacity:0;transition:opacity var(--dur-fast) ease;white-space:nowrap;padding:0 12px}
.cursor.is-label .cursor-dot{width:auto;height:28px;min-width:64px}
.cursor.is-label .cursor-label{opacity:1;transition-delay:80ms}

/* ------------------------------------------------------------
   5. PLACEHOLDERS — template only.
   .ph      bracketed text slot; tinted so it cannot be missed. Remove the span when real copy lands.
   .ph-img  image slot; replace the whole <span class="plate ph-img"> with <span class="plate"><img …></span>.
   Grep for "ph" before launch: nothing with this class may ship.
   ------------------------------------------------------------ */
.ph{background:var(--ox-100);color:var(--ox-700);padding:0 .15em;margin:0 -.15em;-webkit-box-decoration-break:clone;box-decoration-break:clone}
.row[data-theme="inverse"] .ph{background:rgba(200,140,143,.22);color:var(--ox-200)}
.ph-img{
  display:flex;align-items:center;justify-content:center;
  background-color:var(--paper-200);
  background-image:
    linear-gradient(to top right,transparent calc(50% - .5px),#D6D6D6 calc(50% - .5px),#D6D6D6 calc(50% + .5px),transparent calc(50% + .5px)),
    linear-gradient(to bottom right,transparent calc(50% - .5px),#D6D6D6 calc(50% - .5px),#D6D6D6 calc(50% + .5px),transparent calc(50% + .5px));
}
.row[data-theme="inverse"] .ph-img{background-color:var(--ink-800)}
.ph-tag{font:var(--weight-medium) var(--text-2xs)/1 var(--font-mono);letter-spacing:var(--tracking-eyebrow);text-transform:uppercase;color:var(--ink-500);background:var(--paper-200);padding:6px 10px;border:1px solid #D6D6D6}

/* ------------------------------------------------------------
   6. MOTION — one gesture: 28px rise + fade, 720ms, 70ms sibling stagger
   Class toggle on opacity/transform only. Stagger via --delay on the element.
   ------------------------------------------------------------ */
@media (prefers-reduced-motion:reduce){
  *{animation-duration:.01ms!important;transition-duration:.01ms!important}
}

/* ------------------------------------------------------------
   6b. SIGNATURE MOTION — the grid draws itself.
   site.js adds .draw to every .row (and .bleed) and arms it with .drawn when it
   enters the viewport: each cell's bottom rule draws left→right, its right rule
   top→bottom a beat later, and the cell's content fades in once it is ruled.
   Cells stagger left to right (--ci is the cell index, set by site.js).
   Skipped entirely for reduced-motion users (the class is never added).
   ------------------------------------------------------------ */
.row.draw>.cell{border-right-color:transparent;border-bottom-color:transparent;position:relative}
.row.draw>.cell::after{content:"";position:absolute;left:0;right:-1px;bottom:-1px;height:1px;background:var(--rule);transform:scaleX(0);transform-origin:left;transition:transform 800ms var(--ease-entrance);transition-delay:calc(var(--ci,0)*90ms);pointer-events:none}
.row.draw>.cell::before{content:"";position:absolute;top:0;bottom:-1px;right:-1px;width:1px;background:var(--rule);transform:scaleY(0);transform-origin:top;transition:transform 700ms var(--ease-entrance);transition-delay:calc(var(--ci,0)*90ms + 200ms);pointer-events:none;z-index:1}
.row.draw>.cell>*{opacity:0;transition:opacity 700ms ease;transition-delay:calc(var(--ci,0)*90ms + 380ms)}
.row.drawn>.cell::after,.row.drawn>.cell::before{transform:none}
.row.drawn>.cell>*{opacity:1}
.bleed.draw>*{opacity:0;transition:opacity 800ms ease}
.bleed.drawn>*{opacity:1}

/* ------------------------------------------------------------
   7. RESPONSIVE
   ≤1080px: project cells go 2-up. ≤760px: two-column grid, most cells full width, work cards one per row; nav keeps 3 across.
   ------------------------------------------------------------ */
@media (max-width:1080px){
  .c4.card{grid-column:span 6}
}
@media (max-width:760px){
  .row{grid-template-columns:repeat(2,minmax(0,1fr))}
  .cell,.c4,.c6,.c8,.c12{grid-column:span 2}
  .nav .cell{grid-column:span 1}
  .nav .cell:first-child{grid-column:span 2}
  .entry{grid-template-columns:1fr;row-gap:var(--space-1)}
  .row.roomy>.cell{padding-block:clamp(40px,10vw,64px)}
  .row>.cell:only-child:has(>.pn.next){grid-column:span 2}   /* lone Next cell: full width once cells stack */
  /* Work cards: one per row on phones — full width and flush, same rhythm as every other stacked cell.
     Touch has no hover, so site.js toggles .in-view as a card scrolls through the viewport: the image
     saturates on the hover curve (filter var(--dur-slow) var(--ease-out)) and greys again on leaving. */
  .cell.card{grid-column:span 2}
  .cell.blank{display:none}   /* cards are one per row here, so the last card already closes the grid */
  .card.in-view .plate img{filter:grayscale(0)}
  .split{grid-template-columns:1fr;row-gap:var(--space-6)}
  .focus{grid-template-columns:1fr;row-gap:var(--space-5)}
  .row>.cell.tight{padding-block:var(--cell-pad)}   /* label-only cell: no extra height when stacked */
}
/* Phones + reduced motion: no scroll-to-colour, so cards show colour at rest (site.js skips them) */
@media (max-width:760px) and (prefers-reduced-motion:reduce){.card .plate img{filter:grayscale(0)}}
