/* Self-hosted variable fonts — no third-party requests, so nothing leaves the
   visitor's browser just to render type. Subset to latin + latin-ext. */
@font-face{
  font-family:'Geist';
  src:url('../font/geist-var.woff2') format('woff2-variations'),
      url('../font/geist-var.woff2') format('woff2');
  font-weight:100 900;
  font-style:normal;
  font-display:swap;
}
@font-face{
  font-family:'Sometype Mono';
  src:url('../font/sometype-mono-var.woff2') format('woff2-variations'),
      url('../font/sometype-mono-var.woff2') format('woff2');
  font-weight:400 700;
  font-style:normal;
  font-display:swap;
}

/* Portfolio Site — styles carried over from the design prototype.
   Everything that was an inline `style-hover` attribute in the prototype
   lives here as a real :hover rule (.hv1 … .hv6). */

@keyframes pageIn{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
@keyframes fbSpin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}
@keyframes caretBlink{0%,49%{opacity:1}50%,100%{opacity:0}}

html,body{margin:0;padding:0;background:#FCFBF8;}
*{box-sizing:border-box;}
a{color:inherit;text-decoration:none;}
a:hover{color:inherit;}
::selection{background:#D6E8A4;color:#1B2610;}

/* Nav chrome flips between light and dark as it crosses [data-nav="dark"]
   bands; the prototype recomputed these per render, here they are variables
   the router writes to. */
:root{
  --nav-ink:#1F2C13;
  --nav-item-ink:#1F2C13;
  --nav-bg:rgba(29,41,20,0.055);
  --nav-border:rgba(29,41,20,0.1);
  --nav-shade:rgba(255,255,255,0.34);
  --pill-work-bg:transparent;
  --pill-playground-bg:transparent;
  --pill-about-bg:transparent;
}

/* Hover states.
   !important is required, not lazy: the design sets background, color and
   border inline on these elements, and an inline declaration outranks any
   selector. Without it the nav pills and card hovers never fire. */
.hv1:hover,
a:hover .hv1 { background:#D8EF9A!important;color:#1F2C13!important;border-color:#D8EF9A!important; }
.hv2:hover,
a:hover .hv2 { transform:translateY(-4px)!important;border-color:#5C6B3C!important;background:#F7F9EF!important; }
.hv3:hover,
a:hover .hv3 { transform:scale(1.06)!important; }
.hv4:hover,
a:hover .hv4 { box-shadow:inset 0 -9px 0 #D8EF9A!important; }
.hv5:hover,
a:hover .hv5 { box-shadow:inset 0 -10px 0 #D8EF9A!important; }
.hv6:hover,
a:hover .hv6 { box-shadow:inset 0 -12px 0 #D8EF9A!important; }

/* responsive rules from the prototype */
@media (max-width:1080px){[data-heroframe][data-extra]{display:none}}
@media (max-width:900px){[data-footer] [style*="grid-template-columns:repeat(3,1fr)"]{grid-template-columns:1fr 1fr!important;row-gap:40px!important}}
@media (max-width:900px){[data-page="work"] [data-reveal-group]{grid-template-columns:1fr!important}[data-page="work"] [data-reveal-group]>div{padding-top:0!important}}
/* three featured cards in <=812px of gutter-less width get too narrow */
@media (max-width:900px){[data-page="home"] [data-reveal-group]{grid-template-columns:1fr!important;gap:18px!important}}
@media (max-width:820px){[data-hero]{flex-direction:column!important;align-items:flex-start!important;gap:34px!important}[data-heroframes]{order:2;align-self:stretch;justify-content:flex-start}[data-heroframes]>div{margin-top:0!important}[data-heroframe]{width:clamp(78px,17vw,132px)!important}}

/* The custom cursor replaces the system one, but only where there is a real
   pointer. Phone-width viewports are excluded too: pointer media queries are
   unreliable in embedded webviews, and a stuck cursor label reads as a bug. */
@media (hover:none),(pointer:coarse),(max-width:768px){
  #app,#app *{cursor:auto!important}
  [data-ref="cur"]{display:none!important}
}

/* ==========================================================================
   Burger menu
   The design ships a desktop pill nav; below 860px it collapses to a burger
   that opens a full-screen overlay.
   ========================================================================== */

.burger{
  display:none;
  position:relative;
  width:44px;height:44px;
  margin:-9px -10px 0 0;
  padding:0;
  border:0;background:none;
  pointer-events:auto;
  cursor:pointer;
  -webkit-tap-highlight-color:transparent;
}
.burger span{
  position:absolute;left:11px;
  width:22px;height:1.6px;border-radius:2px;
  background:var(--nav-ink);
  transition:transform 320ms cubic-bezier(.2,.8,.25,1),opacity 200ms ease,background 500ms ease;
}
.burger span:nth-child(1){top:19px}
.burger span:nth-child(2){top:25px}
.menu-open .burger span:nth-child(1){transform:translateY(3px) rotate(45deg)}
.menu-open .burger span:nth-child(2){transform:translateY(-3px) rotate(-45deg)}
.menu-open .burger span{background:#1F2C13}

.menu{
  position:fixed;inset:0;z-index:55;
  display:flex;flex-direction:column;justify-content:center;
  gap:44px;
  padding:120px 24px 44px;
  background:#FCFBF8;
  opacity:0;
  transform:translateY(-8px);
  transition:opacity 300ms ease,transform 380ms cubic-bezier(.2,.8,.25,1);
  overflow-y:auto;
  -webkit-overflow-scrolling:touch;
}
.menu-open .menu{opacity:1;transform:none}
/* A class-based display beats the UA rule for [hidden]; without this the
   overlay stays in the layout, covering the page and forcing overflow. */
.menu[hidden]{display:none}

/* The case-study rail dropdown trigger is a phone-only control; the mobile
   block below re-shows it. */
.rail-trigger{display:none}
.menu-open,.menu-open body{overflow:hidden}

.menu-links{display:flex;flex-direction:column;gap:6px}
.menu-links a{
  font-family:'Geist',sans-serif;
  font-size:clamp(34px,10vw,52px);
  line-height:1.18;
  letter-spacing:-0.01em;
  color:#161C10;
  padding:6px 0;
}
.menu-links a:active{color:#5C6B3C}

.menu-foot{
  display:flex;gap:22px;
  padding-top:26px;
  border-top:1px solid #E6E3D9;
  font-family:'Sometype Mono',monospace;
  font-size:11.5px;letter-spacing:0.14em;text-transform:uppercase;
  color:#605C53;
}

@media (max-width:860px){
  .burger{display:block;margin-left:auto}
  /* Hide the whole right-hand column, not just its contents: an empty flex
     child still takes part in space-between and pushes the burger inward. */
  #app > [data-entry] > div{display:none!important}
}

/* ==========================================================================
   Mobile
   Keyed off the u-* utility classes added to the markup. Inline styles still
   win the cascade, so these need !important — but classes (unlike
   [style*="…"] selectors) survive the browser re-serialising a style
   attribute when JS touches an element.
   ========================================================================== */

@media (max-width:768px){

  /* --- gutters ----------------------------------------------------------- */
  .u-pad{padding-left:22px!important;padding-right:22px!important}
  #app > [data-entry]{padding:20px 22px!important}
  .u-worktop{padding-top:112px!important}
  .u-footlinks{padding-top:34px!important}
  .u-footbase{padding-top:64px!important;padding-bottom:26px!important}

  /* --- type scale -------------------------------------------------------- */
  .u-lead{font-size:clamp(23px,5.9vw,30px)!important}
  .u-h2{font-size:23px!important}
  .u-body{font-size:16px!important}

  /* --- home hero --------------------------------------------------------- */
  .u-homehero{height:78vh!important;min-height:500px!important}
  .u-herobody{padding:96px 22px 34px!important}
  [data-ref="heroH1"]{
    font-size:clamp(27px,7.4vw,40px)!important;
    width:auto!important;
    margin-top:0!important;
  }

  /* --- home hero: static texture ----------------------------------------- */
  /* The layered canvas composites three offset copies; at phone width the
     seams between them become visible, so use the source texture directly. */
  [data-page="home"] [data-ref="cnv"]{display:none!important}
  .u-homehero{
    background:
      linear-gradient(180deg,rgba(38,52,22,0.34) 0%,rgba(38,52,22,0.08) 34%,rgba(38,52,22,0) 60%),
      url('../img/dapple-wall.png') center/cover no-repeat,
      #B9CE78!important;
  }

  /* --- case-study hero bands --------------------------------------------- */
  .u-band{height:300px!important;border-radius:0 0 14px 14px!important}

  /* --- one column: featured, work grid, and any side-by-side pair --------- */
  [data-page="home"] [data-reveal-group],
  [data-page="work"] [data-reveal-group],
  .u-stack{
    grid-template-columns:1fr!important;
    gap:16px!important;
  }
  [data-page="work"] [data-reveal-group] a{margin-bottom:44px!important}
  .u-meta{grid-template-columns:1fr!important;gap:10px!important;padding:22px 0!important}
  .u-marker{gap:12px!important}
  .u-callout{padding:24px!important}
  .u-gap112{gap:72px!important}

  /* --- case study: the section rail becomes a dropdown -------------------- */
  .u-raillayout{flex-direction:column!important;gap:0!important;padding-top:0!important}
  /* Sticks to the very top and reserves the nav's height as padding, so the
     opaque background covers everything scrolling underneath — the chip strip
     left a gap where text showed through. */
  .u-rail{
    position:sticky!important;
    top:0!important;
    width:100%!important;
    flex-direction:row!important;
    align-items:center;
    justify-content:space-between;
    gap:12px!important;
    z-index:40;
    padding:64px 0 12px!important;
    margin-bottom:22px!important;
    background:#FCFBF8;
    box-shadow:0 12px 14px -12px rgba(29,41,20,0.16);
  }
  .u-rail > a{margin-left:-8px!important;padding:6px 8px!important}
  .rail-trigger{
    display:inline-flex;align-items:center;gap:9px;
    padding:9px 14px;
    border:1px solid #DFDBD1;border-radius:99px;
    background:#FCFBF8;color:#161C10;
    font-family:'Sometype Mono',monospace;
    font-size:10.5px;letter-spacing:0.14em;
    cursor:pointer;
    -webkit-tap-highlight-color:transparent;
  }
  .rail-trigger svg{transition:transform 240ms cubic-bezier(.2,.8,.25,1)}
  .rail-open .rail-trigger svg{transform:rotate(180deg)}
  [data-rail-wrap]{
    position:absolute;top:100%;right:0;
    min-width:212px;
    display:none!important;
    flex-direction:column!important;
    gap:2px;
    padding:8px;
    background:#FCFBF8;
    border:1px solid #E6E3D9;border-radius:12px;
    box-shadow:0 20px 34px -20px rgba(29,41,20,0.34);
  }
  .rail-open [data-rail-wrap]{display:flex!important}
  [data-rail-wrap] [data-rail]{padding:9px 10px!important;border-radius:8px}
  [data-rail-wrap] [data-tick]{display:none!important}
  [data-sec]{scroll-margin-top:132px!important}

  /* --- about: experience timeline, spine hard left ----------------------- */
  [data-exp]{grid-template-columns:22px 1fr!important;column-gap:18px!important;margin-bottom:52px!important}
  [data-exp] > div:nth-child(1){grid-column:2!important;justify-content:flex-start!important}
  [data-exp] > div:nth-child(2){grid-column:1!important}
  [data-exp-card]{max-width:none!important}
  [data-exp-list] [style*="left:50%"],
  [data-exp-list] [style*="left: 50%"]{left:13px!important}

  /* --- about: photos move above the text and fill the width -------------- */
  [data-hero]{flex-direction:column!important;gap:34px!important}
  [data-heroframes]{
    order:-1!important;                 /* the design puts them below at 820px */
    width:100%!important;
    flex:0 0 auto!important;
    align-items:stretch!important;
    gap:10px!important;
  }
  [data-heroframes] > div{
    flex:1 1 0;min-width:0;
    margin:0!important;                 /* the columns carry offsets for the desktop stagger */
    gap:10px!important;
  }
  [data-heroframe]{
    position:relative!important;
    width:100%!important;
    margin:0!important;
    transform:none!important;           /* the tilt overlaps once they fill */
    aspect-ratio:3/4!important;         /* four different ratios left a ragged grid */
  }
  [data-heroframe] img{width:100%!important;height:100%!important;object-fit:cover!important}

  img,video{max-width:100%}
}

@media (max-width:400px){
  .u-pad{padding-left:18px!important;padding-right:18px!important}
  #app > [data-entry]{padding:18px 18px!important}
}

/* ==========================================================================
   Work grid order on one column
   The grid is two <div> columns, so stacking them plays column 1 in full
   before column 2 — which buried BMW and Vaelo under EasyBrew. Dissolving the
   wrappers with display:contents makes every card a direct grid item, then
   `order` restores the reading order the desktop layout implies.
   (revealSetup() detects display:contents and animates the cards instead.)
   ========================================================================== */
@media (max-width:900px){
  [data-page="work"] [data-reveal-group] > div{display:contents!important}
  [data-page="work"] [data-reveal-group] a[href="#anchor"]  {order:1}
  [data-page="work"] [data-reveal-group] a[href="#bmw"]     {order:2}
  [data-page="work"] [data-reveal-group] a[href="#orbis"]   {order:3}
  [data-page="work"] [data-reveal-group] a[href="#vaelo"]   {order:4}
  [data-page="work"] [data-reveal-group] a[href="#easybrew"]{order:5}
  [data-page="work"] [data-reveal-group] a[href="#apl"]     {order:6}
  [data-page="work"] [data-reveal-group] a[href="#schleasy"]{order:7}
}
