@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap');


:root{
  --bg:#080808;
  --panel:#0D0D0D;

  --fg:#EDEDED;
  --dim:#6E6E6E;

  --line:#242424;

  --white:#FFFFFF;

  --accent:#FFFFFF;
  --accent-dim:#555555;
}


*{
  margin:0;
  padding:0;
  box-sizing:border-box;
}


html{
  scroll-behavior:smooth;
}


body{
  background:var(--bg);

  color:var(--fg);

  font-family:
    'JetBrains Mono',
    ui-monospace,
    'SF Mono',
    Consolas,
    monospace;

  line-height:1.7;

  font-size:14px;

  overflow-x:hidden;
}


a{
  color:inherit;
}


::selection{
  background:var(--fg);
  color:var(--bg);
}


::-webkit-scrollbar{
  width:8px;
}


::-webkit-scrollbar-track{
  background:var(--bg);
}


::-webkit-scrollbar-thumb{
  background:var(--line);
}


/* =========================================
   BOOT SCREEN
========================================= */

#boot-screen{
  position:fixed;

  inset:0;

  z-index:10000;

  display:flex;

  align-items:center;
  justify-content:center;

  padding:24px;

  background:#080808;

  color:var(--fg);

  opacity:1;

  visibility:visible;

  transition:
    opacity .45s ease,
    visibility 0s linear .45s;
}


#boot-screen.boot-finished{
  opacity:0;

  visibility:hidden;

  pointer-events:none;
}


.boot-console{
  width:min(560px,100%);

  font-size:12px;

  letter-spacing:.02em;
}


.boot-logo{
  margin-bottom:22px;

  color:var(--white);

  opacity:0;

  animation:
    bootAppear .25s ease .05s forwards;
}


.boot-logo::before{
  content:"> ";

  color:var(--accent);
}


.boot-log{
  border-top:1px solid var(--line);

  border-bottom:1px solid var(--line);

  padding:10px 0;
}


.boot-log div{
  display:flex;

  justify-content:space-between;

  gap:20px;

  padding:4px 0;

  color:var(--dim);

  opacity:0;

  transform:translateX(-5px);

  animation:
    bootRow .28s ease forwards;
}


.boot-log div:nth-child(1){
  animation-delay:.15s;
}


.boot-log div:nth-child(2){
  animation-delay:.28s;
}


.boot-log div:nth-child(3){
  animation-delay:.41s;
}


.boot-log div:nth-child(4){
  animation-delay:.54s;
}


.boot-log div:nth-child(5){
  animation-delay:.67s;
}


.boot-log b{
  color:var(--accent);

  font-weight:500;
}


.boot-prompt{
  margin-top:18px;

  color:var(--white);

  opacity:0;

  animation:
    bootAppear .3s ease .9s forwards;
}


.boot-cursor{
  display:inline-block;

  width:7px;
  height:13px;

  margin-left:3px;

  vertical-align:-2px;

  background:var(--accent);

  animation:
    blink .8s step-end infinite;
}


@keyframes bootAppear{

  from{
    opacity:0;

    transform:
      translateY(4px);
  }

  to{
    opacity:1;

    transform:
      translateY(0);
  }

}


@keyframes bootRow{

  from{
    opacity:0;

    transform:
      translateX(-5px);
  }

  to{
    opacity:1;

    transform:
      translateX(0);
  }

}


/* =========================================
   WRAPPER
========================================= */

.wrap{
  max-width:720px;

  margin:0 auto;

  padding:60px 20px 40px;

  position:relative;

  z-index:2;
}


/* =========================================
   TERMINAL
========================================= */

.term{
  border:1px solid var(--line);

  background:var(--panel);

  box-shadow:
    0 40px 100px rgba(0,0,0,.6);
}


/* =========================================
   TERMINAL BAR
========================================= */

.term-bar{
  display:flex;

  align-items:center;

  gap:8px;

  padding:12px 14px;

  border-bottom:1px solid var(--line);
}


.dot{
  width:9px;
  height:9px;

  border-radius:50%;

  background:var(--line);

  border:1px solid #333;

  opacity:0;

  animation:
    dotPowerOn .3s ease forwards;
}


.dot:nth-child(1){
  animation-delay:.1s;
}


.dot:nth-child(2){
  animation-delay:.22s;
}


.dot:nth-child(3){
  animation-delay:.34s;
}


@keyframes dotPowerOn{

  from{
    opacity:0;

    transform:scale(.4);
  }

  to{
    opacity:1;

    transform:scale(1);
  }

}


.dot.live{
  background:var(--accent);

  border-color:var(--accent-dim);

  opacity:0;

  animation:
    dotPowerOn .3s ease forwards,
    dotBreathe 2.4s
      ease-in-out .5s infinite;
}


.dot.live:nth-child(3){
  animation-delay:
    .34s,
    .8s;
}


@keyframes dotBreathe{

  0%,100%{
    box-shadow:
      0 0 0 0
      rgba(255,255,255,.35);
  }

  50%{
    box-shadow:
      0 0 5px 2px
      rgba(255,255,255,.35);
  }

}


.term-title{
  margin-left:10px;

  font-size:11px;

  color:var(--dim);

  letter-spacing:.05em;
}


/* =========================================
   TERMINAL BODY
========================================= */

.term-body{
  padding:36px 30px 40px;
}


/* =========================================
   HERO
========================================= */

header{
  margin-bottom:10px;
}


.boot-line{
  position:relative;

  color:var(--dim);

  font-size:12px;

  opacity:0;

  animation:
    fadeIn .4s ease forwards;
}


.boot-line::after{
  content:"";

  position:absolute;

  left:0;

  bottom:-2px;

  width:0;

  height:1px;

  background:var(--accent);

  opacity:.45;

  transition:
    width .45s ease;
}


.boot-line:hover::after{
  width:100%;
}


.boot-line .ok{
  color:var(--accent);
}


.boot-line:nth-child(1){
  animation-delay:.05s;
}


.boot-line:nth-child(2){
  animation-delay:.2s;
}


.boot-line:nth-child(3){
  animation-delay:.35s;
}


h1{
  position:relative;

  display:inline-block;

  margin-top:22px;

  font-size:
    clamp(30px,6vw,46px);

  font-weight:700;

  letter-spacing:-.01em;

  color:var(--white);

  opacity:0;

  animation:
    fadeIn .5s ease forwards;

  animation-delay:.55s;
}


h1::before{
  content:"> ";

  color:var(--accent);
}


h1::after{
  content:attr(data-text);

  position:absolute;

  inset:0;

  color:var(--accent);

  opacity:0;

  pointer-events:none;
}


h1:hover::after{
  opacity:.18;

  animation:
    miniGlitch .28s steps(2,end);
}


@keyframes miniGlitch{

  0%{
    transform:translate(0);

    clip-path:inset(0);
  }

  35%{
    transform:
      translate(2px,-1px);

    clip-path:
      inset(20% 0 55% 0);
  }

  70%{
    transform:
      translate(-2px,1px);

    clip-path:
      inset(60% 0 10% 0);
  }

  100%{
    transform:translate(0);

    clip-path:inset(0);
  }

}


.role-line{
  margin-top:10px;

  color:var(--dim);

  font-size:14px;

  opacity:0;

  animation:
    fadeIn .5s ease forwards;

  animation-delay:.75s;
}


.role-text{
  display:inline-block;

  overflow:hidden;

  white-space:nowrap;

  vertical-align:top;

  width:0;

  animation:
    typeRole .6s steps(9,end) forwards;

  animation-delay:1.15s;
}


@keyframes typeRole{

  from{
    width:0;
  }

  to{
    width:9ch;
  }

}


.cursor{
  display:inline-block;

  width:8px;
  height:15px;

  background:var(--accent);

  margin-left:4px;

  vertical-align:-3px;

  animation:
    blink 1s step-end infinite;
}


@keyframes fadeIn{

  from{
    opacity:0;

    transform:
      translateY(4px);
  }

  to{
    opacity:1;

    transform:
      translateY(0);
  }

}


@keyframes blink{

  50%{
    opacity:0;
  }

}


/* =========================================
   COMMAND BLOCKS
========================================= */

.cmd-block{
  position:relative;

  margin-top:44px;

  opacity:0;

  transform:
    translateY(14px);

  transition:
    opacity .6s ease,
    transform .6s
      cubic-bezier(.16,1,.3,1);
}


.cmd-block.in{
  opacity:1;

  transform:
    translateY(0);
}


.cmd-block::before{
  content:"";

  position:absolute;

  top:-22px;

  left:0;

  width:0;

  height:1px;

  background:var(--line);

  transition:
    width .8s
      cubic-bezier(.16,1,.3,1);
}


.cmd-block.in::before{
  width:100%;
}


.cmd{
  color:var(--dim);

  font-size:13px;

  margin-bottom:16px;
}


.cmd .sym{
  display:inline-block;

  color:var(--accent);

  transition:
    transform .2s ease,
    opacity .2s ease;
}


.cmd:hover .sym,
.cmd:active .sym{
  transform:
    translateX(3px);
}


.cmd .arg{
  color:var(--white);
}


.out{
  padding-left:0;
}


.out p{
  color:#C8C8C8;

  font-size:14px;

  max-width:64ch;

  font-weight:400;
}


.cmd-block.in .out p{
  animation:
    textSettle .7s ease both;
}


@keyframes textSettle{

  from{
    opacity:.25;

    transform:
      translateX(-4px);
  }

  to{
    opacity:1;

    transform:
      translateX(0);
  }

}


/* =========================================
   VIDEO
========================================= */

.photo-row{
  display:flex;

  gap:24px;

  align-items:flex-start;

  flex-wrap:wrap;
}


.photo-frame{
  position:relative;

  width:180px;
  height:220px;

  flex-shrink:0;

  background:#111;

  border:1px solid var(--line);

  overflow:hidden;

  isolation:isolate;
}


.photo-frame video{
  width:100%;
  height:100%;

  object-fit:cover;

  display:block;

  filter:
    contrast(1.2)
    brightness(.85);

  transition:
    filter .5s ease,
    transform .6s
      cubic-bezier(.16,1,.3,1);
}

.photo-frame video.is-loading{
  filter:
    contrast(1.2)
    brightness(.6)
    blur(14px);
}


.photo-frame:hover video,
.photo-frame:active video{
  filter:
    grayscale(.2)
    contrast(1.15)
    brightness(.90);

  transform:
    scale(1.05);
}


.photo-frame:hover,
.photo-frame:active{
  border-color:var(--accent-dim);
}


/* =========================================
   VIDEO SPINNER
========================================= */

.video-spinner{
  position:absolute;

  inset:0;

  z-index:20;

  display:flex;

  flex-direction:column;

  align-items:center;

  justify-content:center;

  gap:9px;

  pointer-events:none;

  background:
    rgba(0,0,0,.30);

  opacity:1;

  visibility:visible;

  transition:
    opacity .35s ease,
    visibility .35s ease;
}


.video-spinner.loaded{
  opacity:0;

  visibility:hidden;
}


.spinner-ring{
  width:30px;

  height:30px;

  border-radius:50%;

  border:
    2px solid
    rgba(255,255,255,.15);

  border-top-color:
    rgba(255,255,255,.95);

  animation:
    spinnerRotate .7s linear infinite;

  will-change:transform;
}


.spinner-text{
  color:#999;

  font-size:8px;

  letter-spacing:.16em;

  text-transform:uppercase;

  animation:
    loadingPulse 1.2s ease-in-out infinite;
}


@keyframes spinnerRotate{

  from{
    transform:rotate(0deg);
  }

  to{
    transform:rotate(360deg);
  }

}


@keyframes loadingPulse{

  0%,100%{
    opacity:.35;
  }

  50%{
    opacity:1;
  }

}


/* =========================================
   VIDEO FALLBACK
========================================= */

.photo-fallback{
  position:absolute;

  inset:0;

  z-index:15;

  display:none;

  align-items:center;

  justify-content:center;

  text-align:center;

  padding:20px;

  color:#777;

  font-size:9px;

  letter-spacing:.08em;

  background:#0b0b0b;
}


.photo-fallback.visible{
  display:flex;
}


/* =========================================
   VIDEO TAG
========================================= */

.photo-frame .tag{
  position:absolute;

  bottom:6px;
  left:6px;

  z-index:25;

  font-size:9px;

  letter-spacing:.1em;

  text-transform:uppercase;

  color:var(--dim);

  background:
    rgba(0,0,0,.6);

  padding:2px 5px;

  transition:
    color .25s ease,
    background .25s ease;
}


.photo-frame:hover .tag{
  color:var(--white);

  background:
    rgba(0,0,0,.78);
}


/* =========================================
   VIDEO SCAN
========================================= */

.photo-frame::after{
  content:"";

  position:absolute;

  left:0;

  top:-25%;

  width:100%;

  height:22%;

  pointer-events:none;

  z-index:30;

  background:
    linear-gradient(
      to bottom,
      transparent,
      rgba(255,255,255,.09),
      transparent
    );

  opacity:.55;

  animation:
    videoScan 3.4s
    linear infinite;
}


.photo-frame:hover::after{
  opacity:1;

  animation-duration:1.7s;
}


@keyframes videoScan{

  from{
    transform:
      translateY(0);
  }

  to{
    transform:
      translateY(575%);
  }

}


/* =========================================
   VIDEO META
========================================= */

.photo-meta{
  font-size:12px;

  color:var(--dim);

  padding-top:4px;
}


.photo-meta div{
  display:flex;

  gap:10px;

  padding:4px 0;

  border-bottom:
    1px dashed var(--line);

  opacity:0;

  transform:
    translateX(-6px);

  transition:
    opacity .45s ease,
    transform .45s ease;
}


.cmd-block.in .photo-meta div:nth-child(1){
  opacity:1;

  transform:none;

  transition-delay:.1s;
}


.cmd-block.in .photo-meta div:nth-child(2){
  opacity:1;

  transform:none;

  transition-delay:.22s;
}


.cmd-block.in .photo-meta div:nth-child(3){
  opacity:1;

  transform:none;

  transition-delay:.34s;
}


.cmd-block.in .photo-meta div:nth-child(4){
  opacity:1;

  transform:none;

  transition-delay:.46s;
}


.photo-meta span:first-child{
  width:90px;

  color:#555;
}


.photo-meta .status-ok{
  color:var(--accent);

  display:inline-block;

  transition:
    color .25s ease;
}


.photo-meta .status-ok.loading{
  animation:
    statusPulse
    1.2s
    ease-in-out
    infinite;
}


@keyframes statusPulse{

  0%,100%{
    opacity:1;
  }

  50%{
    opacity:.4;
  }

}


/* =========================================
   PROJECTS
========================================= */

.work-list{
  border-top:
    1px solid var(--line);
}


.work{
  position:relative;

  display:flex;

  justify-content:space-between;

  align-items:center;

  padding:16px 0;

  border-bottom:
    1px solid var(--line);

  text-decoration:none;

  opacity:0;

  transform:
    translateY(10px);

  transition:
    padding-left .3s
      cubic-bezier(.16,1,.3,1),
    background .3s,
    opacity .5s ease,
    transform .5s
      cubic-bezier(.16,1,.3,1);
}


.cmd-block.in .work{
  opacity:1;

  transform:
    translateY(0);
}


.cmd-block.in .work:nth-child(1){
  transition-delay:.05s;
}


.cmd-block.in .work:nth-child(2){
  transition-delay:.16s;
}


.cmd-block.in .work:nth-child(3){
  transition-delay:.27s;
}


.cmd-block.in .work:nth-child(4){
  transition-delay:.38s;
}


.work::before{
  content:"";

  position:absolute;

  left:0;

  top:0;

  bottom:0;

  width:2px;

  background:var(--accent);

  transform:
    scaleY(0);

  transform-origin:center;

  transition:
    transform .25s ease;
}


.work:hover::before{
  transform:
    scaleY(1);
}


.work:active::before{
  transform:
    scaleY(1);
}


.work:hover,
.work:active{
  padding-left:10px;

  background:
    rgba(255,255,255,.03);

  border-color:
    var(--accent-dim);

  transform:
    translateY(-1px);
}


.work:active{
  transform:
    translateY(-1px)
    scale(.985);
}


.work:hover .work-name,
.work:active .work-name{
  color:var(--white);
}


.work:hover .work-name .idx,
.work:active .work-name .idx{
  color:var(--accent);
}


.work:hover .arrow,
.work:active .arrow{
  opacity:1;

  transform:
    translateX(0);
}


.work-name{
  font-size:14px;

  color:#CFCFCF;

  transition:
    color .3s;
}


.work-name .idx{
  color:var(--dim);

  margin-right:10px;

  transition:
    color .3s;
}


.work-meta{
  display:flex;

  align-items:center;

  gap:16px;

  font-size:12px;

  color:var(--dim);
}


.arrow{
  color:var(--accent);

  opacity:.55;

  transform:
    translateX(0);

  transition:
    opacity .3s,
    transform .3s;

  animation:
    arrowNudge 1.8s
    ease-in-out infinite;
}


.work:hover .arrow{
  opacity:1;

  animation-play-state:paused;
}


@keyframes arrowNudge{

  0%,100%{
    transform:
      translateX(0);
  }

  50%{
    transform:
      translateX(4px);
  }

}


/* =========================================
   SKILLS
========================================= */

.skill-row{
  margin-bottom:14px;
}


.skill-label{
  display:flex;

  justify-content:space-between;

  font-size:12px;

  color:var(--dim);

  margin-bottom:6px;
}


.skill-label .v{
  color:#999;
}


.bar{
  height:4px;

  background:var(--line);

  position:relative;

  overflow:hidden;
}


.bar-fill{
  position:relative;

  height:100%;

  width:0%;

  overflow:hidden;

  background:
    repeating-linear-gradient(
      to right,
      var(--accent) 0 2px,
      transparent 2px 4px
    );

  transition:
    width 1.2s
      cubic-bezier(.16,1,.3,1);
}


.skill-row:nth-child(1) .bar-fill{
  transition-delay:0s;
}


.skill-row:nth-child(2) .bar-fill{
  transition-delay:.15s;
}


.skill-row:nth-child(3) .bar-fill{
  transition-delay:.3s;
}


.skill-row:nth-child(4) .bar-fill{
  transition-delay:.45s;
}


.bar-fill::after{
  content:"";

  position:absolute;

  top:0;
  bottom:0;

  width:32px;

  left:-40px;

  background:
    rgba(255,255,255,.35);

  filter:
    blur(3px);
}


.skill-row:hover .bar-fill::after{
  animation:
    barSweep .65s ease;
}


@keyframes barSweep{

  from{
    left:-40px;
  }

  to{
    left:110%;
  }

}


/* =========================================
   CONTACT
========================================= */

.links{
  display:flex;
  flex-direction: column;

  gap:0;

  flex-wrap:wrap;

  border-top:
    1px solid var(--line);

  margin-top:4px;
}


.links a{
  position:relative;

  overflow:hidden;

  flex:1 1 auto;

  min-width:140px;

  text-align:center;

  font-size:12px;

  color:var(--dim);

  text-decoration:none;

  padding:16px 10px;

  border-right:
    1px solid var(--line);

  border-bottom:
    1px solid var(--line);

  transition:
    color .25s,
    background .25s,
    transform .15s ease;
}


.links a::after{
  content:"";

  position:absolute;

  left:-100%;

  bottom:0;

  width:100%;

  height:1px;

  background:var(--accent);

  transition:
    left .35s
      cubic-bezier(.16,1,.3,1);

  animation:
    linkSweep 3.5s
    ease-in-out infinite;
}


.links a:nth-child(2)::after{
  animation-delay:.4s;
}


.links a:nth-child(3)::after{
  animation-delay:.8s;
}


.links a:hover::after{
  left:0;

  animation-play-state:paused;
}


@keyframes linkSweep{

  0%,70%,100%{
    left:-100%;
  }

  85%{
    left:0;
  }

}


.links a:last-child{
  border-right:none;
}


.links a:hover,
.links a:active{
  color:var(--accent);

  background:
    rgba(255,255,255,.04);
}


.links a:active{
  transform:
    scale(.97);
}


/* =========================================
   TAP RIPPLE
========================================= */

.work,
.links a{
  overflow:hidden;
}


.tap-ripple{
  position:absolute;

  border-radius:50%;

  background:
    rgba(255,255,255,.12);

  pointer-events:none;

  transform:scale(0);

  animation:
    tapRipple .55s ease-out;
}


@keyframes tapRipple{

  from{
    transform:scale(0);

    opacity:1;
  }

  to{
    transform:scale(1.4);

    opacity:0;
  }

}


/* =========================================
   FOOTER
========================================= */

.term-footer{
  border-top:
    1px solid var(--line);

  padding:16px 30px;

  font-size:11px;

  color:var(--dim);

  display:flex;

  justify-content:space-between;
}


.term-footer .exit-ok{
  color:var(--accent);

  animation:
    footerBlink 4s
    ease-in-out
    infinite;
}


@keyframes footerBlink{

  0%,92%,100%{
    opacity:1;
  }

  94%,97%{
    opacity:.35;
  }

}


footer{
  text-align:center;

  padding:30px 0 10px;

  color:#444;

  font-size:11px;
}


/* =========================================
   SCROLL PROGRESS
========================================= */

#scroll-progress{
  position:fixed;

  top:0;
  left:0;

  height:1px;

  width:100%;

  z-index:10001;

  background:var(--accent);

  opacity:.55;

  pointer-events:none;

  transform-origin:left;

  transform:scaleX(0);
}


/* =========================================
   MOBILE
========================================= */

@media (max-width:600px){

  .wrap{
    padding:30px 12px;
  }


  .term-body{
    padding:26px 18px 30px;
  }


  .photo-row{
    flex-direction:column;

    align-items:center;
  }


  .photo-meta{
    width:100%;

    max-width:220px;
  }


  .links a{
    min-width:50%;
  }

}


/* =========================================
   REDUCED MOTION
========================================= */

@media (prefers-reduced-motion:reduce){

  #boot-screen{
    display:none !important;
  }


  *{
    animation:none !important;

    transition:none !important;
  }


  .boot-line,
  h1,
  .role-line,
  .cmd-block{
    opacity:1;

    transform:none;
  }


  .term{
    animation:none !important;
  }


  .spinner-ring{
    animation:none !important;
  }


  #scroll-progress{
    display:none !important;
  }

}