/* TERALIS
   Ground is a grainy grey, not black. Ink is Soft Oat from the moodboard. */

:root{
  --ground:#1E211F;
  --oat:#F0EDE5;

  --ink:var(--oat);
  --ink-72:rgba(240,237,229,.72);
  --ink-48:rgba(240,237,229,.48);
  --ink-30:rgba(240,237,229,.30);
  --ink-16:rgba(240,237,229,.16);
  --ink-09:rgba(240,237,229,.09);

  --display:'Anybody','Helvetica Neue',Arial,sans-serif;
  --mono:'Martian Mono',ui-monospace,'SF Mono',Menlo,monospace;

  --gut:clamp(22px,5vw,80px);
  --ease:cubic-bezier(.2,.7,.2,1);
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0; background:var(--ground); color:var(--ink);
  font-family:var(--mono); font-size:14px; line-height:1.6;
  -webkit-font-smoothing:antialiased;
}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
a{color:inherit;text-decoration:none}

/* ---------------- shared: terrain ---------------- */
.terrain{
  position:absolute; left:0; right:0; bottom:0; height:64%; margin:0; z-index:0;
  font-family:var(--mono); font-size:12px; line-height:1.02;
  white-space:pre; overflow:hidden; color:var(--ink); opacity:.92;
  -webkit-mask-image:linear-gradient(to bottom,transparent 0%,rgba(0,0,0,.3) 20%,#000 48%,#000 100%);
  mask-image:linear-gradient(to bottom,transparent 0%,rgba(0,0,0,.3) 20%,#000 48%,#000 100%);
  user-select:none; pointer-events:none;
}

/* ---------------- landing ---------------- */
.landing{
  position:relative; min-height:100vh; min-height:100svh; overflow:hidden;
  display:flex; flex-direction:column; justify-content:flex-start;
  padding:15vh var(--gut) 6vh;
}
.landing__veil{position:absolute; left:0; right:0; bottom:0; height:64%; z-index:1;
  pointer-events:none;
  background:linear-gradient(to bottom,var(--ground) 0%,transparent 34%,transparent 100%)}
.landing__inner{position:relative; z-index:2}

.wordmark{margin:0; line-height:.8}
.wordmark__canvas{display:block; width:100%; height:auto}

.lede{
  font-family:var(--display); font-variation-settings:'wdth' 100,'wght' 400;
  font-size:clamp(1rem,1.9vw,1.35rem); line-height:1.45;
  color:var(--ink-72); max-width:42ch; margin:1.8rem 0 0;
}

.enter{
  display:inline-flex; align-items:center; gap:.9rem; margin-top:2.8rem;
  font-size:.72rem; letter-spacing:.18em; text-transform:uppercase;
  padding:.85rem 1.5rem; border:1px solid var(--ink-30);
  transition:border-color .2s var(--ease),background .2s var(--ease),gap .2s var(--ease);
}
.enter:hover{border-color:var(--ink); background:var(--ink-09); gap:1.4rem}
.enter__arrow{transition:transform .2s var(--ease)}
.enter:hover .enter__arrow{transform:translateX(3px)}

/* ---------------- interior pages ---------------- */
.hero{
  position:relative; height:46vh; height:46svh; min-height:300px; max-height:520px;
  overflow:hidden;
}
.hero__veil{position:absolute; inset:0; z-index:1; pointer-events:none;
  background:linear-gradient(to bottom,var(--ground) 0%,transparent 42%,transparent 100%)}
.hero .terrain{height:78%;
  -webkit-mask-image:linear-gradient(to bottom,transparent 0%,#000 40%,#000 100%);
  mask-image:linear-gradient(to bottom,transparent 0%,#000 40%,#000 100%)}
.wrap{padding:0 var(--gut); max-width:1400px; margin:0 auto}

/* ---------------- about ---------------- */
.top{
  position:fixed; top:0; left:0; right:0; z-index:20;
  display:flex; align-items:center; justify-content:space-between; gap:2rem;
  padding:1.4rem var(--gut);
  font-size:.66rem; letter-spacing:.16em; text-transform:uppercase;
  background:linear-gradient(to bottom,var(--ground) 40%,transparent);
}
.top__mark{font-family:var(--display); font-variation-settings:'wdth' 100,'wght' 800;
  letter-spacing:-.01em; font-size:1rem; text-transform:none}
.nav{display:flex; gap:1.6rem}
.nav a{color:var(--ink-30); transition:color .18s var(--ease)}
.nav a:hover{color:var(--ink-72)}
.nav a[aria-current="true"]{color:var(--ink)}


.sec{padding:5rem 0 6rem}
.sec__h{
  font-family:var(--display); font-variation-settings:'wdth' 100,'wght' 800;
  font-size:clamp(2rem,5.5vw,3.6rem); line-height:1; letter-spacing:-.035em;
  text-transform:none; color:var(--ink); margin:0 0 3rem; font-weight:800;
}

/* lead */
.sec--lead{padding-top:1rem}
.lead__h{
  font-family:var(--display); font-variation-settings:'wdth' 100,'wght' 800;
  font-size:clamp(2.4rem,7vw,5.6rem); line-height:1; letter-spacing:-.035em;
  margin:0 0 2.4rem; max-width:14ch;
}
.lead__body{max-width:62ch}
.lead__body p{margin:0 0 1.4rem; color:var(--ink-72); font-size:.88rem; line-height:2}
.lead__body p:last-child{margin-bottom:0; color:var(--ink-48)}

/* portfolio */
.port{list-style:none; margin:0; padding:0;
  display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:1px;
  background:var(--ink-16); border:1px solid var(--ink-16)}
.port__i{background:var(--ground)}
.port__i a{
  /* flex, not grid, so the url pins to the bottom of every card no matter how
     many lines the note runs to */
  display:flex; flex-direction:column; gap:.5rem;
  padding:2.2rem 1.8rem 1.8rem; height:100%;
  transition:background .2s var(--ease);
}
.port__i a:hover{background:var(--ink-09)}
.port__ico{display:block; width:54px; color:var(--ink-48); margin-bottom:1.4rem;
  transition:color .2s var(--ease)}
.port__ico svg{display:block; width:100%; height:auto}
.port__i a:hover .port__ico{color:var(--ink)}
.port__name{font-family:var(--display); font-variation-settings:'wdth' 100,'wght' 800;
  font-size:1.5rem; letter-spacing:-.02em; line-height:1}
.port__note{color:var(--ink-72); font-size:.74rem; letter-spacing:.02em}
.port__url{color:var(--ink-30); font-size:.62rem; letter-spacing:.08em; margin-top:auto;
  padding-top:1.4rem; transition:color .2s var(--ease)}
.port__i a:hover .port__url{color:var(--ink-72)}

/* team */
.team{list-style:none; margin:0; padding:0;
  display:grid; grid-template-columns:repeat(auto-fit,minmax(290px,1fr)); gap:1px;
  background:var(--ink-16); border:1px solid var(--ink-16)}
.mem{background:var(--ground); min-width:0}
.mem__btn{
  appearance:none; background:none; border:0; font:inherit; color:inherit;
  cursor:pointer; width:100%; text-align:left;
  display:grid; grid-template-columns:auto 1fr auto; align-items:center;
  column-gap:1.3rem; padding:1.7rem 1.6rem;
  transition:background .18s var(--ease);
}
.mem__btn:hover{background:var(--ink-09)}
.mem__ico{width:62px; color:var(--ink-48); transition:color .18s var(--ease)}
.mem__ico svg{display:block; width:100%; height:auto}
.mem__btn:hover .mem__ico{color:var(--ink)}
.mem__txt{min-width:0}
.mem__name{font-family:var(--display); font-variation-settings:'wdth' 100,'wght' 800;
  font-size:1.35rem; letter-spacing:-.02em; line-height:1.15; display:block}
.mem__role{font-size:.64rem; letter-spacing:.16em; text-transform:uppercase;
  color:var(--ink-48); display:block; margin-top:.25rem}
.mem__more{font-size:.6rem; letter-spacing:.14em; text-transform:uppercase;
  color:var(--ink-30); transition:color .18s var(--ease)}
.mem__btn:hover .mem__more{color:var(--ink-72)}

/* profile overview */
.profile{
  border:1px solid var(--ink-30); background:var(--ground); color:var(--ink);
  padding:2.4rem; max-width:min(640px,92vw); width:100%;
  max-height:min(84vh,760px); overflow-y:auto; overscroll-behavior:contain;
  font-family:var(--mono); position:relative;
}
.profile::backdrop{background:rgba(12,14,13,.82)}
.profile__x{
  position:sticky; float:right; top:0; margin:-.6rem -.6rem 0 0; appearance:none; background:none;
  border:0; font:inherit; color:var(--ink-48); cursor:pointer;
  font-size:.6rem; letter-spacing:.16em; text-transform:uppercase; padding:.5rem;
  transition:color .15s var(--ease);
}
.profile__x:hover{color:var(--ink)}
.profile__head{display:flex; align-items:center; gap:1.4rem; margin-bottom:1.6rem}
.profile__ico{width:64px; flex:none; color:var(--ink-72)}
.profile__ico svg{display:block; width:100%; height:auto}
.profile__name{font-family:var(--display); font-variation-settings:'wdth' 100,'wght' 800;
  font-size:1.7rem; letter-spacing:-.02em; margin:0; line-height:1.1}
.profile__role{font-size:.64rem; letter-spacing:.16em; text-transform:uppercase;
  color:var(--ink-48); margin:.35rem 0 0}
.profile__bio{margin:0 0 1.2rem; color:var(--ink-72); font-size:.8rem; line-height:1.95}
.profile__stat{margin:0 0 1.4rem; font-size:.62rem; letter-spacing:.14em;
  text-transform:uppercase; color:var(--ink-48)}
.repos{list-style:none; margin:0 0 1.6rem; padding:0;
  border-top:1px solid var(--ink-16)}
.repos li{border-bottom:1px solid var(--ink-16)}
.repos a{display:grid; grid-template-columns:1fr auto; gap:.2rem 1rem; padding:.85rem 0;
  align-items:baseline; transition:opacity .15s var(--ease)}
.repos a:hover{opacity:.65}
.repo__n{font-family:var(--display); font-variation-settings:'wdth' 100,'wght' 700;
  font-size:.98rem; letter-spacing:-.01em}
.repo__m{font-size:.6rem; letter-spacing:.12em; text-transform:uppercase;
  color:var(--ink-30); white-space:nowrap}
.repo__d{grid-column:1 / -1; font-size:.72rem; color:var(--ink-48); line-height:1.6}
.profile__links{margin:0; display:flex; gap:1.4rem; flex-wrap:wrap}
.profile__links a{font-size:.68rem; letter-spacing:.1em; color:var(--ink-72);
  border-bottom:1px solid var(--ink-30); padding-bottom:2px;
  transition:color .15s var(--ease),border-color .15s var(--ease)}
.profile__links a:hover{color:var(--ink); border-color:var(--ink)}
@media (max-width:620px){
  .profile{padding:1.8rem 1.3rem}
  .profile__head{gap:1rem}
  .profile__ico{width:52px}
}

/* blog */
.blog__empty{margin:0; color:var(--ink-48); font-size:.82rem; letter-spacing:.02em}

/* end */
.end{
  margin-top:2rem; display:flex; align-items:baseline; justify-content:space-between; flex-wrap:wrap;
  gap:1rem; border-top:1px solid var(--ink-16); padding:2.4rem 0 4rem;
}
.end__mail{font-family:var(--display); font-variation-settings:'wdth' 100,'wght' 600;
  font-size:clamp(1.05rem,2.4vw,1.6rem); letter-spacing:-.015em;
  border-bottom:1px solid var(--ink-30); transition:border-color .15s var(--ease)}
.end__mail:hover{border-color:var(--ink)}
.end__note{font-size:.62rem; letter-spacing:.14em; color:var(--ink-30)}

/* ---------------- grain ---------------- */
.grain{position:fixed; inset:0; z-index:40; pointer-events:none;
  opacity:.12; mix-blend-mode:overlay; width:100%; height:100%}

/* ---------------- reveals ---------------- */
[data-reveal]{opacity:0; transform:translateY(16px);
  transition:opacity .5s var(--ease),transform .5s var(--ease)}
[data-reveal].is-in{opacity:1; transform:none}

/* ================================================================
   SMALL SCREENS
   The rules above are the desktop composition and stay as they are.
   Everything below narrows it; nothing here applies at 1440.
   ================================================================ */

/* Grid and flex children default to min-width:auto, so a long url or a wide
   mono word can push its track past the viewport. Costs nothing, and it is the
   usual cause of a stray horizontal scrollbar. */
.port__i,.port__i a,.mem,.end{min-width:0}
.port__url,.port__note,.end__mail,.end__note{overflow-wrap:anywhere}

/* The reveal used to fade the whole <li>, which let the grid's hairline colour
   show through as a pale block until the card arrived. Obvious once the grid is
   a single column and each card is a full-width slab. Fading the <a> instead
   keeps the card's own ground painted the whole time; the resting state is
   identical. */
.port__i[data-reveal]{opacity:1; transform:none; transition:none}
.port__i[data-reveal] > a{
  opacity:0; transform:translateY(16px);
  transition:opacity .5s var(--ease),transform .5s var(--ease),background .2s var(--ease);
}
.port__i[data-reveal].is-in > a{opacity:1; transform:none}

/* Blog and Team are short enough that on a tall phone the footer lands in the
   middle of the screen with a third of a viewport of empty ground under it.
   The header, grain and page-transition curtain are all fixed, so the only flex
   children here are the hero band and the column. */
@media (max-width:1000px){
  .page-interior{min-height:100vh; min-height:100svh; display:flex; flex-direction:column}
  .page-interior > .hero{flex:0 0 auto}
  .page-interior > .wrap{flex:1 0 auto; display:flex; flex-direction:column}
  .page-interior > .wrap > .end{margin-top:auto}
}

/* ---------------- phones (portrait) ---------------- */
@media (max-width:620px){
  /* header: four items plus the wordmark on one line, so the nav loses some
     tracking rather than wrapping */
  .top{gap:1rem; padding:1.1rem var(--gut)}
  .nav{gap:1.1rem; font-size:.6rem; letter-spacing:.08em}

  /* landing: the wordmark scales with the column, so the work here is where the
     text block sits. At 80% the mask reaches full strength at a fixed 58% of the
     viewport whatever the phone's height, and the padding centres the block in
     the sky above that line instead of pinning it to a fraction of the screen —
     otherwise a 932px phone gets a third of a screen of nothing under the button. */
  .landing{padding:max(4rem,calc(29vh - 6.75rem)) var(--gut) 7vh}
  .landing .terrain{font-size:10px; height:80%}
  .landing__veil{height:80%}
  .lede{margin-top:1.5rem; line-height:1.4}
  .enter{margin-top:2.1rem}

  /* hero: 46svh is nearly half a phone screen for a band that is mostly sky.
     Shorter band, and the terrain fills more of it so the range is not a sliver. */
  .hero{height:38vh; height:38svh; min-height:248px; max-height:340px}
  .hero .terrain{font-size:10px; height:88%}

  /* The row count always rounds up, so the block of glyphs is up to one line
     taller than its box. Bottom-aligning it puts that spare line under the top
     of the mask, where it is transparent, instead of slicing the near ridge. */
  .terrain{display:grid; align-content:end}

  .sec{padding:3.2rem 0 4rem}
  .sec--lead{padding-top:1.6rem}
  .sec__h{margin-bottom:2rem}
  .lead__h{margin-bottom:1.8rem}

  /* Martian Mono runs about 0.7em per character, so 14px only fits ~33 columns
     in a phone measure and the copy reads chopped. 12.5px gets it to ~38 and
     the leading comes in to match. */
  .lead__body p{font-size:.78rem; line-height:1.95; margin-bottom:1.25rem}

  .port__i a{padding:1.8rem 1.4rem 1.5rem}
  .port__ico{width:46px; margin-bottom:1.1rem}
  .port__name{font-size:1.35rem}
  .port__note{font-size:.72rem}
  .port__url{padding-top:1.2rem}

  .team{gap:1.8rem}
  .mem{column-gap:1.1rem}
  .mem__ico{width:58px}
  .mem__name{font-size:1.3rem}

  .blog__empty{font-size:.76rem}
  .end{padding:2rem 0 3rem}
}

/* Below ~360px the nav needs the room more than it needs the tracking. The gap
   is the last thing to give, because it is what keeps the hit areas apart. */
@media (max-width:360px){
  .nav{gap:clamp(1rem,5.1vw,1.35rem); font-size:.55rem; letter-spacing:.04em}
}

/* ---------------- phones (landscape) ----------------
   A 46svh band plus a 15vh top padding swallows a 393px-tall viewport whole,
   and on the landing the copy ends up sitting on the mountains. Everything
   vertical gets pulled in, and the wordmark is capped so it stops driving the
   height of the whole composition. */
@media (orientation:landscape) and (max-height:560px){
  .top{padding:.85rem var(--gut)}

  .landing{padding:8vh var(--gut) 5vh}
  .landing .terrain{font-size:10px; height:56%}
  .landing__veil{height:56%}
  .wordmark{max-width:min(480px,58vw)}
  .lede{margin-top:1rem; font-size:clamp(.92rem,1.5vw,1.15rem); max-width:46ch}
  .enter{margin-top:1.4rem}

  .hero{height:52vh; height:52svh; min-height:186px; max-height:230px}
  .hero .terrain{font-size:9px; height:97%}
  .terrain{display:grid; align-content:end}

  .sec{padding:2.4rem 0 3.4rem}
  .sec--lead{padding-top:1.2rem}
  .sec__h{margin-bottom:1.6rem; font-size:clamp(1.9rem,4.4vw,3rem)}
  .lead__h{margin-bottom:1.5rem; font-size:clamp(2rem,5vw,3.4rem)}
  .end{padding:2rem 0 3rem}
}

/* ---------------- touch ----------------
   The nav and the wordmark are set small on purpose. Padding plus a matching
   negative margin grows the hit area to 44px without moving anything. */
@media (hover:none){
  .nav a{display:block; padding:.95rem .45rem; margin:-.95rem -.45rem}
  .top__mark{padding-block:.58rem; margin-block:-.58rem}
  .end__mail{position:relative}
  .end__mail::after{content:''; position:absolute; inset:-.6rem -.5rem}
  /* :hover latches after a tap and sticks until you tap something else, which
     leaves a card lit up after you come back from the site it opened. Hover is
     off here and the same values are moved onto :active, so a press still reads
     without anything new being introduced. */
  .enter:hover{border-color:var(--ink-30); background:none; gap:.9rem}
  .enter:hover .enter__arrow{transform:none}
  .enter:active{border-color:var(--ink); background:var(--ink-09)}
  .port__i a:hover{background:none}
  .port__i a:hover .port__ico{color:var(--ink-48)}
  .port__i a:hover .port__url{color:var(--ink-30)}
  .port__i a:active{background:var(--ink-09)}
  .port__i a:active .port__ico{color:var(--ink)}
  .port__i a:active .port__url{color:var(--ink-72)}
  .nav a:hover{color:var(--ink-30)}
  .nav a[aria-current="true"]:hover{color:var(--ink)}
  .nav a:active{color:var(--ink-72)}
  .top__mark:active,.end__mail:active{opacity:.62}
  .end__mail:hover{border-color:var(--ink-30)}
}
/* Four nav items and the wordmark on a 320px line leaves no slack, so the hit
   areas go right up against each other rather than shrinking further. */
@media (hover:none) and (max-width:360px){
  .nav a{padding-inline:.5rem; margin-inline:-.5rem}
}

@media (prefers-reduced-motion:reduce){
  *{animation:none!important}
  [data-reveal]{opacity:1; transform:none; transition:none}
  .port__i[data-reveal] > a{opacity:1; transform:none; transition:none}
}
