/* ============================================================
   Portfolio_DS  .  index.css
   Layout for the two index pages: the homepage and the work index.

   Loaded after system.css. These pages run the full display scale:
   h1 to 84px, section rhythm to 104px, mono labels at 11.5px. The
   case studies run a tighter scale of their own, in case.css. Where
   a selector appears in both files the difference is deliberate.
   ============================================================ */

*{box-sizing:border-box}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--body);font-size:16px;line-height:1.6;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
}
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.001ms !important;transition-duration:.001ms !important}
}
h1,h2,h3,h4{font-family:var(--display);font-weight:600;letter-spacing:-.03em;margin:0;text-wrap:balance;line-height:1.04}
img{max-width:100%}
.mono{font-family:var(--mono);font-size:11.5px;letter-spacing:.06em;text-transform:uppercase;font-weight:500}
.rule{height:1px;background:var(--line);border:0;margin:0}
.navbar{display:flex;align-items:center;gap:16px;height:62px}
.brand{display:flex;align-items:baseline;gap:10px;font-family:var(--display);font-weight:600;letter-spacing:-.02em;font-size:16px}
.brand .sig{color:var(--ink-4);font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;font-weight:500}
nav.links{margin-left:auto;display:flex;gap:4px}
nav.links a{padding:7px 12px;border-radius:100px;color:var(--ink-3);font-size:13.5px;font-weight:500;transition:color .18s,background .18s}
nav.links a:hover{color:var(--ink);background:var(--paper-2)}
/* header.js marks the link for the section on screen */
nav.links a[aria-current]{color:var(--violet-ink);background:var(--violet-tint)}
nav.links ~ .toggle{margin-left:10px}
/* Below 720px the links fold into a sheet under the header, opened by Menu. Without
   header.js the button does nothing, so it only shows once the script has run. */
.menu-btn{
  display:none;margin-left:8px;align-items:center;gap:8px;border:1px solid var(--line);background:var(--raise);color:var(--ink);
  padding:7px 13px;border-radius:100px;cursor:pointer;font-family:var(--mono);font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;font-weight:500;transition:border-color .18s
}
.menu-btn:hover,.menu-btn[aria-expanded="true"]{border-color:var(--violet)}
@media(max-width:720px){
  nav.links{display:none}
  nav.links ~ .toggle{margin-left:auto}
  header.has-menu .menu-btn{display:inline-flex}
  header.menu-open nav.links{
    display:flex;flex-direction:column;gap:2px;position:absolute;left:0;right:0;top:100%;margin:0;
    padding:10px var(--pad) 16px;background:var(--paper);border-bottom:1px solid var(--line-2);box-shadow:var(--shadow)
  }
  header.menu-open nav.links a{padding:12px 14px;font-size:16px;border-radius:10px}
}
@media(max-width:420px){
  .brand .sig{display:none}
}
.hero{padding-block:clamp(52px,9vw,104px) 32px;position:relative;overflow:hidden}
.hero::before{
  content:"";position:absolute;inset:0;pointer-events:none;
  background-image:linear-gradient(90deg,var(--grid-line) 1px,transparent 1px);
  background-size:calc(100%/12) 100%;
  mask-image:linear-gradient(to bottom,rgba(0,0,0,.85),transparent 78%);
  -webkit-mask-image:linear-gradient(to bottom,rgba(0,0,0,.85),transparent 78%);
}
.hero .shell{position:relative}
.avail{
  display:inline-flex;align-items:center;gap:9px;background:var(--violet-tint);color:var(--violet-ink);
  padding:6px 13px 6px 11px;border-radius:100px;font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;font-weight:500
}
.pulse{position:relative;width:7px;height:7px;border-radius:50%;background:var(--lime);box-shadow:0 0 0 0 var(--lime)}
.pulse::after{content:"";position:absolute;inset:0;border-radius:50%;background:var(--lime);animation:ping 2.6s cubic-bezier(0,0,.2,1) infinite}
@keyframes ping{0%{transform:scale(1);opacity:.7}70%,100%{transform:scale(2.8);opacity:0}}
h1.head{margin-top:22px;font-size:clamp(40px,7.4vw,84px);font-weight:600;letter-spacing:-.045em;max-width:16ch}
h1.head .em{color:var(--violet)}
/* The hand-drawn mark under one word of each index headline: "clarity" on the
   homepage, "hard" on the work index. One system, one path per page. Each path is a
   single marker stroke drawn behind the glyphs, so a descender crosses over it, in a
   viewBox cut to its word's proportions so preserveAspectRatio none barely stretches
   it; the stroke width is in viewBox units, so it scales with the headline at every
   breakpoint. On load it draws left to right once the headline has nearly settled
   (.rise-2 lands at .8s): pathLength="1" lets the dash run from 1 to 0 whatever the
   path's real length. The shape lives in each page's markup, so the pages can differ;
   the weight, colour and timing live here, so they cannot. Lime: the hero's one accent
   under the headline. Under reduced motion it is simply there. */
.ink-mark{position:relative;white-space:nowrap}
.ink-line{
  position:absolute;left:-.05em;bottom:-.17em;width:calc(100% + .1em);height:.4em;
  z-index:-1;overflow:visible;pointer-events:none
}
.ink-line path{
  fill:none;stroke:var(--lime);stroke-width:13;stroke-linecap:round;stroke-linejoin:round;opacity:.92;
  stroke-dasharray:1;stroke-dashoffset:1;animation:ink-draw .85s cubic-bezier(.5,.05,.25,1) .45s both
}
@keyframes ink-draw{to{stroke-dashoffset:0}}
@media(prefers-reduced-motion:reduce){
  .ink-line path{animation:none;stroke-dashoffset:0}
}
.lede{margin-top:24px;font-size:clamp(16.5px,1.55vw,19px);line-height:1.62;color:var(--ink-2);max-width:56ch}
.lede b{color:var(--ink);font-weight:600}
.cta{margin-top:32px;display:flex;flex-wrap:wrap;gap:10px;align-items:center}
.btn{
  display:inline-flex;align-items:center;gap:9px;padding:12px 20px;border-radius:100px;font-size:14px;font-weight:600;
  border:1px solid transparent;cursor:pointer;transition:transform .16s ease,box-shadow .2s,background .2s,border-color .2s,color .2s
}
.btn:active{transform:translateY(1px)}
.btn-1{background:var(--btn);color:var(--on-btn);box-shadow:var(--shadow)}
.btn-1:hover{background:var(--violet);color:var(--on-violet)}
.btn-2{border-color:var(--line);color:var(--ink);background:var(--raise)}
.btn-2:hover{border-color:var(--violet);color:var(--violet-ink)}
/* Book a call, on the contact band. Violet rather than .btn-1, whose --btn turns lime in
   the dark theme: the band already spends its one lime on the email underline. */
.btn-book{background:var(--violet);color:var(--on-violet);box-shadow:var(--shadow)}
.btn-book:hover{background:var(--violet-ink)}
.btn .arw{transition:transform .18s ease}
.btn:hover .arw{transform:translateX(3px)}
.facts{
  margin-top:clamp(44px,6vw,72px);display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  border-top:1px solid var(--line);padding-top:22px;gap:22px
}
@media(max-width:760px){
  .facts{grid-template-columns:repeat(2,minmax(0,1fr));gap:26px 22px}
}
.fact dt{font-family:var(--mono);font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-4);font-weight:500}
.fact dd{margin:7px 0 0;font-family:var(--display);font-size:clamp(26px,3.2vw,34px);font-weight:600;letter-spacing:-.035em;line-height:1;font-variant-numeric:tabular-nums}
.fact:nth-child(2) dd{color:var(--violet)}
.fact dd.sm{font-size:clamp(19px,2.1vw,23px);letter-spacing:-.025em}
.fact small{display:block;margin-top:6px;font-size:12.5px;color:var(--ink-3);letter-spacing:0;line-height:1.45;font-family:var(--body);font-weight:400}
section{padding-block:clamp(56px,7.5vw,104px)}
.sec-head{display:flex;align-items:baseline;gap:14px;margin-bottom:clamp(30px,4vw,46px);flex-wrap:wrap}
.sec-head .mono{color:var(--ink-4)}
.sec-head .mono::before{content:"";display:inline-block;width:22px;height:1px;background:var(--violet);vertical-align:middle;margin-right:11px;transform:translateY(-1px)}
.sec-head h2{font-size:clamp(25px,3.1vw,36px);letter-spacing:-.038em}
.sec-head .aside{margin-left:auto;font-size:13.5px;color:var(--ink-3);max-width:34ch}
/* Selected work is the one title long enough to fill the row on its own, which pushed
   its aside onto a line of its own. Capped, it runs over two lines and the aside comes
   back up beside it, baseline aligned to the first. Scoped rather than set on every
   sec-head h2: About's title is 477px against this 480px, close enough that a global
   cap would wrap it too on a machine where the font renders a hair wider. */
.sec-head.split h2{max-width:480px}
@media(max-width:760px){
  .sec-head .aside{margin-left:0}
}
.practice{background:var(--paper-2);border-block:1px solid var(--line-2)}
.cols{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(24px,3vw,44px)}
@media(max-width:820px){
  .cols{grid-template-columns:1fr;gap:30px}
}
.col h3{font-size:19px;letter-spacing:-.025em;margin-bottom:9px}
.col .n{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;color:var(--violet);font-weight:500;display:block;margin-bottom:13px}
.col p{font-size:14.5px;line-height:1.62;color:var(--ink-3);max-width:40ch}
.col ul{margin-top:14px;display:flex;flex-wrap:wrap;gap:6px}
.col li{
  font-family:var(--mono);font-size:10.5px;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-3);
  border:1px solid var(--line);padding:4px 9px;border-radius:100px;background:var(--paper)
}
/* Two columns, not three. The rail used to be a 104px gutter beside the copy; it
   now sits above it, which gives the summary and the problem/approach/outcome list
   the full column width and lets the role read on one line. The media column
   carries the project cover above its figure. Ratio 1 : .66 matches the 599 / 393
   split in the design at a 1072 content width. */
.proj{
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.66fr);gap:clamp(24px,5.5vw,80px);
  padding-block:clamp(34px,4.4vw,54px);border-top:1px solid var(--line);align-items:start
}
.proj:first-of-type{border-top:0;padding-top:0}
@media(max-width:960px){
  .proj{grid-template-columns:1fr;gap:28px}
}
/* copy column: rail, then body */
.proj-main{display:flex;flex-direction:column;gap:clamp(24px,3.4vw,48px);min-width:0}
.rail .yr{font-family:var(--mono);font-size:13px;font-weight:500;letter-spacing:.02em;color:var(--ink);font-variant-numeric:tabular-nums}
.rail .rl{margin-top:6px;font-family:var(--mono);font-size:10.5px;letter-spacing:.07em;text-transform:uppercase;color:var(--ink-4);line-height:1.5}
/* media column: cover over figure */
.proj-media{display:flex;flex-direction:column;gap:24px;min-width:0}
/* A cover rests in grey and comes up to full colour as it passes the middle of the
   viewport, then falls back to grey on the way out. --cover-gray is written per
   element by assets/js/covers.js: 1 is grey, 0 is full colour. The
   default of 1 is what a reader with no JavaScript gets, which is the resting state
   rather than a broken one.

   The desaturation sits on the frame and --photo-filter on the image inside it,
   deliberately. --photo-filter is `none` in light mode, and `filter:none grayscale(1)`
   is invalid, so composing them in one declaration drops the whole thing and no cover
   is ever grey. Two elements, two filters, and the browser composes them. */
.proj-cover{
  display:block;position:relative;aspect-ratio:16/9;overflow:hidden;border-radius:10px;
  border:1px solid var(--line);background:var(--paper-2);line-height:0;
  filter:grayscale(var(--cover-gray,1));
  /* its own layer, so the per-frame grey from covers.js is applied on the GPU rather
     than repainting the cover under the header's blur (see site.html's .brief-row .cover) */
  will-change:filter,transform;
  transition:transform .32s cubic-bezier(.2,.7,.2,1),box-shadow .32s cubic-bezier(.2,.7,.2,1),border-color .18s
}
.proj-cover img{
  display:block;width:100%;height:100%;object-fit:cover;filter:var(--photo-filter);
  transition:transform .42s cubic-bezier(.2,.7,.2,1)
}

/* The cover is a second, redundant route to the project. The row already carries
   .case-link, so this one is hidden from assistive tech and taken out of the tab
   order: keyboard and screen reader users reach the same page through the text link,
   and nobody hears the destination announced twice per row. The image is alt="" for
   the same reason, which is what the homepage covers do inside their row link.

   The motion is depth only. Colour on these covers belongs to the scroll position,
   so hover must not fight it: the frame lifts, the image pushes in behind the clip,
   and the arrow arrives. Pressing takes the lift back off, so the click resolves
   downward instead of just stopping. */
.proj-cover:hover{transform:translateY(-3px);box-shadow:var(--shadow);border-color:var(--violet)}
.proj-cover:hover img{transform:scale(1.04)}
.proj-cover:active{transform:translateY(0) scale(.995);transition-duration:.09s}
.proj-cover:active img{transform:scale(1.02);transition-duration:.09s}
.proj-go{
  position:absolute;right:12px;bottom:12px;width:34px;height:34px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  /* --ink-3 at 32% alpha, which is the #6b687852 asked for, derived from the token
     rather than written as a literal so it still themes: in dark --ink-3 is a
     lighter grey and the veil follows it. */
  background:color-mix(in srgb,var(--ink-3) 32%,transparent);color:var(--on-violet);
  opacity:0;transform:translate(6px,6px) scale(.9);
  transition:opacity .28s cubic-bezier(.2,.7,.2,1),transform .28s cubic-bezier(.2,.7,.2,1)
}
.proj-go svg{width:15px;height:15px;display:block}
.proj-cover:hover .proj-go{opacity:1;transform:none}
.proj-cover:active .proj-go{transform:scale(.94)}
/* A hover only affordance is never the only affordance: on touch the arrow stays put
   so the cover still reads as something you can press. */
@media(hover:none){
  .proj-go{opacity:1;transform:none}
  .proj-cover:hover{transform:none;box-shadow:none;border-color:var(--line)}
  .proj-cover:hover img{transform:none}
}
@media(prefers-reduced-motion:reduce){
  .proj-cover,.proj-cover img,.proj-go{transition-duration:.01ms}
  .proj-cover:hover,.proj-cover:active{transform:none}
  .proj-cover:hover img,.proj-cover:active img{transform:none}
}
.body h3{font-size:clamp(23px,2.7vw,31px);letter-spacing:-.035em;display:flex;align-items:center;gap:11px;flex-wrap:wrap}
.dom{
  font-family:var(--mono);font-size:10px;letter-spacing:.09em;text-transform:uppercase;font-weight:500;
  color:var(--violet-ink);background:var(--violet-tint);padding:4px 9px;border-radius:100px;transform:translateY(-1px)
}
.body .sum{margin-top:12px;font-size:15.5px;line-height:1.65;color:var(--ink-2);max-width:50ch}
.pao{margin-top:22px;display:grid;gap:11px}
.pao div{display:grid;grid-template-columns:78px minmax(0,1fr);gap:14px;align-items:baseline}
@media(max-width:520px){
  .pao div{grid-template-columns:1fr;gap:3px}
}
.pao dt{font-family:var(--mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-4);font-weight:500;padding-top:3px}
.pao dd{margin:0;font-size:14.5px;line-height:1.6;color:var(--ink-3)}
.pao dd strong{color:var(--ink);font-weight:600}
.pao div:last-child dt{color:var(--lime-ink)}
/* The link sits well clear of the outcome line: 64px at full width, against 22px
   before. On Tino that lands the copy and the media column on the same baseline,
   which is what the design shows. It is a fixed offset rather than a push to the
   bottom of the row on purpose: bottom alignment opens a void on the rows whose
   figure is taller than their copy, Taxmaro worst of all. */
.case-link{
  display:inline-flex;align-items:center;gap:8px;margin-top:clamp(22px,4vw,64px);
  align-self:flex-start;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.09em;text-transform:uppercase;font-weight:500;color:var(--violet-ink);
  border-bottom:1px solid var(--line);padding-bottom:5px;transition:border-color .18s,color .18s
}
.case-link:hover{border-color:var(--violet);color:var(--violet)}
.case-link .arw{transition:transform .18s ease}
.case-link:hover .arw{transform:translateX(3px)}
.fig{background:var(--raise);border:1px solid var(--line);border-radius:14px;padding:16px;box-shadow:var(--shadow);position:relative;overflow:hidden}
.fig-cap{font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-4);margin-bottom:13px;display:flex;justify-content:space-between;gap:8px}
.fig-cap b{color:var(--violet-ink);font-weight:500}
.mtx{display:grid;grid-template-columns:62px repeat(4,1fr);gap:5px}
.mtx span{font-family:var(--mono);font-size:8.5px;letter-spacing:.04em;color:var(--ink-4);text-transform:uppercase;display:flex;align-items:center;line-height:1.2}
.cell{height:22px;border-radius:4px;background:var(--line-2);border:1px solid var(--line)}
.cell.on{background:var(--violet);border-color:var(--violet)}
.cell.part{background:var(--violet-tint);border-color:var(--violet)}
.cell.flag{background:var(--lime);border-color:var(--lime)}
.q{display:grid;gap:7px}
.q-row{display:grid;grid-template-columns:3px 1fr auto;gap:10px;align-items:center;background:var(--paper-2);border-radius:7px;padding:8px 10px}
.q-row i{display:block;height:100%;min-height:20px;border-radius:3px;background:var(--ink-4)}
.q-row.crit i{background:var(--lime)}
.q-row.crit{background:var(--lime-tint)}
.q-row.urg i{background:var(--violet)}
.bar{height:5px;border-radius:3px;background:var(--line);position:relative;overflow:hidden}
.bar em{position:absolute;inset:0 auto 0 0;background:var(--ink-4);border-radius:3px}
.q-row.crit .bar em{background:var(--lime-ink)}
.q-row.urg .bar em{background:var(--violet)}
.q-row .t{font-family:var(--mono);font-size:9px;color:var(--ink-3);letter-spacing:.04em;font-variant-numeric:tabular-nums}
.q-lbl{font-family:var(--mono);font-size:9px;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-3);margin-bottom:5px;display:block}
.tl{display:grid;gap:6px}
.tl-hdr{display:grid;grid-template-columns:52px repeat(8,1fr);gap:2px;font-family:var(--mono);font-size:8px;color:var(--ink-4);letter-spacing:.02em}
.tl-row{display:grid;grid-template-columns:52px repeat(8,1fr);gap:2px;align-items:center}
.tl-row span{font-family:var(--mono);font-size:8.5px;color:var(--ink-3);letter-spacing:.03em}
.slot{height:19px;border-radius:3px;background:var(--line-2);border:1px solid var(--line)}
.slot.bk{background:var(--violet);border-color:var(--violet)}
.slot.hold{background:var(--violet-tint);border-color:var(--violet)}
.slot.free{background:var(--lime-tint);border-color:var(--lime)}
.tbl{display:grid;gap:0}
.tr{
  display:grid;grid-template-columns:1fr 58px 46px;gap:10px;align-items:center;padding:8px 2px;border-bottom:1px solid var(--line-2);
  font-family:var(--mono);font-size:9.5px;color:var(--ink-3);letter-spacing:.03em;font-variant-numeric:tabular-nums
}
.tr:last-child{border-bottom:0}
.tr.h{color:var(--ink-4);font-size:8.5px;letter-spacing:.09em;text-transform:uppercase;border-bottom:1px solid var(--line)}
.tr .amt{text-align:right;color:var(--ink)}
.st{font-size:8px;letter-spacing:.06em;text-transform:uppercase;padding:3px 6px;border-radius:100px;text-align:center;font-weight:500}
.st.ok{background:var(--violet-tint);color:var(--violet-ink)}
.st.hold{background:var(--lime);color:var(--on-lime)}
.totl{
  display:flex;justify-content:space-between;margin-top:11px;padding-top:10px;border-top:1px solid var(--line);
  font-family:var(--mono);font-size:9.5px;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-4)
}
.totl b{color:var(--ink);font-size:12px;font-variant-numeric:tabular-nums;letter-spacing:-.01em}

.quote-sec{background:var(--quote-bg);color:var(--quote-fg);border-block:1px solid var(--quote-border)}

/* Voices. Three testimonials sharing one band: the quotes are stacked in a
   single grid cell so the section is as tall as the longest one and nothing
   reflows when you switch, and the faces double as the control. Lime lands on
   one highlighted phrase and nothing else here, so .qmark stays out of this
   section: the quote marks would be the second lime in the viewport. */
.vhead{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:clamp(22px,3vw,34px)}
.vhead .mono{color:var(--quote-mute)}
.vcount{color:var(--quote-mute);font-variant-numeric:tabular-nums}
.vcount b{color:var(--quote-fg);font-weight:500}
.vstack{display:grid}
.vq{
  grid-area:1/1;margin:0;font-family:var(--display);font-size:clamp(18px,2vw,25px);line-height:1.34;
  letter-spacing:-.025em;font-weight:500;max-width:58ch;color:var(--quote-fg);
  opacity:0;translate:0 14px;filter:blur(5px);visibility:hidden;
  transition:opacity .5s ease,translate .5s ease,filter .5s ease,visibility .5s
}
/* visibility, not just opacity: an inactive quote has to leave the accessibility
   tree, or a screen reader reads all three one after another. Transitioning it
   keeps the fade, because visibility flips to visible at the start of the run in
   and holds until the end of the run out. */
.vq.is-on{opacity:1;translate:0;filter:none;visibility:visible}
.vq .hl{color:var(--lime)}
.vrow{display:flex;align-items:center;gap:clamp(16px,2.4vw,26px);margin-top:clamp(28px,4vw,44px)}
.vfaces{display:flex;flex:none}
/* The desaturation sits on the button and --photo-filter on the image inside it,
   rather than both on one filter list. --photo-filter is `none` in light mode,
   and `filter:none grayscale(1)` is invalid, so composing them in one
   declaration drops it and every face stays in colour. Two elements, two
   filters, and the browser composes them. */
.vface{
  width:44px;height:44px;padding:0;border:0;border-radius:50%;overflow:hidden;cursor:pointer;
  background:var(--quote-bg);box-shadow:0 0 0 2px var(--quote-bg);
  filter:grayscale(1);transition:scale .3s ease,box-shadow .3s ease,filter .3s ease
}
.vface + .vface{margin-left:-8px}
.vface img{display:block;width:100%;height:100%;object-fit:cover;border-radius:50%;filter:var(--photo-filter)}
.vface:hover,.vface:focus-visible{filter:none}
.vface.is-on{z-index:1;scale:1.12;filter:none;box-shadow:0 0 0 2px var(--quote-bg),0 0 0 4px var(--violet)}
.vsep{flex:none;width:1px;height:34px;background:var(--quote-mute);opacity:.4}
.vwho{display:grid;flex:1 1 auto;min-width:0}
.vname{
  grid-area:1/1;margin:0;align-self:center;
  opacity:0;translate:-8px 0;visibility:hidden;
  transition:opacity .4s ease,translate .4s ease,visibility .4s
}
.vname.is-on{opacity:1;translate:0;visibility:visible}
@media(max-width:620px){
  .vrow{flex-wrap:wrap;gap:16px}
  .vsep{display:none}
  .vwho{flex-basis:100%}
}
@media(prefers-reduced-motion:reduce){
  .vq,.vname,.vface{transition-duration:.01ms}
}
.about{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr);gap:clamp(28px,5vw,72px)}
@media(max-width:860px){
  .about{grid-template-columns:1fr;gap:34px}
}
.about p{font-size:clamp(16px,1.5vw,18px);line-height:1.68;color:var(--ink-2);max-width:52ch}
.about p + p{margin-top:17px}
.about p b{color:var(--ink);font-weight:600}
.side{border-left:1px solid var(--line);padding-left:clamp(20px,2.4vw,32px)}
.side dl{display:grid;gap:19px;margin:0}
.side dt{font-family:var(--mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-4);font-weight:500}
.side dd{margin:5px 0 0;font-size:14.5px;color:var(--ink-2);line-height:1.55}
@media(max-width:860px){
  .side{border-left:0;border-top:1px solid var(--line);padding-left:0;padding-top:28px}
}
.contact{border-top:1px solid var(--line)}
.contact h2{font-size:clamp(32px,6vw,64px);letter-spacing:-.045em;max-width:20ch}
.contact h2 .em{color:var(--violet)}
.mailrow{margin-top:30px;display:flex;flex-wrap:wrap;gap:12px;align-items:center}
.mail{
  font-family:var(--mono);font-size:clamp(13px,1.6vw,16px);letter-spacing:.01em;color:var(--ink);
  border-bottom:2px solid var(--lime);padding-bottom:2px;transition:color .18s
}
.mail:hover{color:var(--violet)}
footer{border-top:1px solid var(--line);padding-block:26px 34px}
.foot{
  display:flex;flex-wrap:wrap;gap:14px 26px;align-items:center;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.08em;text-transform:uppercase;color:var(--ink-4)
}
.foot a{color:var(--ink-3);transition:color .18s}
.foot a:hover{color:var(--violet)}
.foot .sp{margin-left:auto}
@media(max-width:640px){
  .foot .sp{margin-left:0}
}
@media (prefers-reduced-motion: no-preference){
  .rise{animation:rise .7s cubic-bezier(.2,.7,.2,1) both}
  .rise-1{animation-delay:.04s}
  .rise-2{animation-delay:.1s}
  .rise-3{animation-delay:.16s}
  .rise-4{animation-delay:.22s}
  @keyframes rise{from{opacity:.55;transform:translateY(9px)}to{opacity:1;transform:none}}
}
