/* porchhouse.ch — Giuliano Sulzberger */

/* Lulo Clean — Yellow Design Studio */
@font-face{
  font-family: "Lulo Clean";
  src: url("fonts/Lulo Clean Family/Yellow Design Studio - Lulo Clean One.otf") format("opentype");
  font-weight: 400;
  font-display: swap;
}
@font-face{
  font-family: "Lulo Clean";
  src: url("fonts/Lulo Clean Family/Yellow Design Studio - Lulo Clean One Bold.otf") format("opentype");
  font-weight: 700;
  font-display: swap;
}

:root{
  --yellow: rgb(245, 217, 32);
  --red: #e0483c;
  --ink: #1a1405;
  --body: 12px;
  --gutter: 3rem;
  --maxw: 1440px;
}

*{ box-sizing: border-box; }

html, body{ margin:0; padding:0; }

body{
  background:#2b2413;
  color: var(--yellow);
  font-family: "Lulo Clean", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 700;
  font-size: var(--body);
  line-height: 1.6;
  letter-spacing: .04em;
  -webkit-font-smoothing: antialiased;
}

/* ---------- background video ---------- */
.bg{
  position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none;
}
.bg iframe{
  position:absolute; top:50%; left:50%;
  /* source video is portrait 240x320 (3:4) — size the iframe to that
     ratio and scale it up so it always covers the viewport */
  width: 100vw; height: 133.34vw;
  min-width: 75vh; min-height: 100vh;
  transform: translate(-50%, -50%);
  border:0;
}
.vignette{
  position: fixed; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(ellipse 95% 90% at 28% 50%,
              rgba(10,8,2,.68) 0%, rgba(10,8,2,.42) 45%, rgba(10,8,2,.10) 80%);
}

/* ---------- heading row + studio button ----------
   The button sits on the same line as the name, right-aligned, sharing its
   baseline. On narrow screens it wraps underneath. */
.hero-row{
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem 2rem;
  flex-wrap: wrap;
  margin: 0 0 4.5rem;
}
.hero-row h1.line{ margin: 0; }

/* the record button — a round red dot in a ring, with the label beside it.
   Sits on the heading's baseline. The dot glows on hover, like arming a track. */
.rec-btn{
  display: inline-flex; align-items: center; gap: .65em;
  font: inherit; font-size: 9.5px; letter-spacing: .1em;
  line-height: 1;                 /* so the text box is just the cap-height,
                                     and the dot centres on the letters */
  color: var(--yellow);
  background: transparent;
  border: 0; padding: 0;
  cursor: pointer;
  opacity: .88;
  transition: opacity .3s ease;
}
/* Lulo caps sit a touch high in their box; nudge the text down to meet the dot */
.rec-txt{ position: relative; top: 1px; }
.rec-btn:hover{ opacity: 1; }
.rec-dot{
  position: relative;
  width: 18px; height: 18px; flex: none;
  border-radius: 50%;
  border: 1.5px solid var(--yellow);
  display: grid; place-items: center;
  transition: border-color .3s ease;
}
.rec-dot::after{
  content: "";
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--red);
  box-shadow: 0 0 0 0 rgba(224,72,60,.5);
  transition: transform .3s ease, box-shadow .3s ease;
}
.rec-btn:hover .rec-dot::after{
  transform: scale(1.12);
  box-shadow: 0 0 0 6px rgba(224,72,60,.18), 0 0 14px rgba(224,72,60,.55);
}
.rec-btn:active .rec-dot::after{ transform: scale(.9); }
.rec-txt{ white-space: nowrap; }

/* ---------- the scatter — prints tossed over the page ----------
   The backdrop only dims a little, so the site reads through underneath. */
.scatter{
  position: fixed; inset: 0; z-index: 40;
  background: rgba(6,5,2,.62);
  -webkit-backdrop-filter: blur(3px) saturate(.8);
          backdrop-filter: blur(3px) saturate(.8);
  animation: fadeIn .35s ease both;
}
.scatter[hidden]{ display: none; }
@keyframes fadeIn{ from{ opacity:0 } to{ opacity:1 } }
/* the layer itself scrolls; the stage grows to fit the grid */
.scatter{ overflow-y: auto; overflow-x: hidden; }
.scatter-stage{ position: relative; min-height: 100%; }

/* each print — square, borderless, straight: the same language as the album
   covers below. Rises into place; on hover it lifts a touch, like the covers. */
.print{
  position: absolute;
  left: 0; top: 0;
  width: var(--w, 260px);
  height: var(--h, var(--w, 260px));   /* heroes carry their own height; singles are square */
  overflow: hidden;
  background: #111;
  cursor: default;
  transform: translate(var(--x), calc(var(--y) + 14px));
  opacity: 0;
  transition: transform .55s cubic-bezier(.2,.8,.25,1), opacity .5s ease, filter .35s ease;
  will-change: transform, opacity;
  /* the covers' resting look */
  filter: grayscale(.35) contrast(1.05) brightness(.92);
}
.print.is-in{ opacity: 1; transform: translate(var(--x), var(--y)); }
.print:hover{ filter: none; }          /* colour comes up on hover — no zoom */
.print img, .print video{
  display: block; width: 100%; height: 100%;
  object-fit: cover;
}

.scatter-close{
  position: fixed; top: 1.4rem; right: 1.6rem; z-index: 50;
  font: inherit; font-size: 13px;
  color: var(--yellow);
  background: rgba(5,4,2,.5);
  border: 1px solid rgba(245,217,32,.4);
  border-radius: 999px;
  width: 42px; height: 42px;
  display: grid; place-items: center;
  cursor: pointer;
  opacity: .8;
  transition: opacity .25s ease, border-color .25s ease, transform .2s ease;
}
.scatter-close:hover{ opacity: 1; border-color: var(--yellow); }
.scatter-close:active{ transform: scale(.94); }

.scatter-hint{
  position: fixed; left: 50%; bottom: 1.4rem; z-index: 50;
  padding: .4rem .9rem; border-radius: 999px;
  background: rgba(5,4,2,.55);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  transform: translateX(-50%);
  margin: 0;
  font-size: 10px; letter-spacing: .12em;
  color: var(--yellow);
  opacity: .5;
  pointer-events: none;
  animation: hintFade 7s ease forwards;
}
@keyframes hintFade{ 0%,75%{ opacity:.5 } 100%{ opacity:0 } }

/* ---------- layout ---------- */
main{
  position: relative; z-index: 2;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 7rem var(--gutter) 6rem;
}

.block{ margin: 0 0 4.5rem; }
h1.line{ margin: 0 0 4.5rem; font-size: 17px; font-weight: 700; letter-spacing: .06em; }

.line{
  margin: 0;
  font-size: var(--body);
  line-height: 1.75;
}
/* red rule drawn as a background on the inner span so it stops at the last
   letter — text-decoration would also underline the trailing letter-spacing.
   box-decoration-break:clone gives every wrapped line its own rule. */
.line > span{
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  padding-bottom: 2.5px;
  background: linear-gradient(var(--red), var(--red)) 0 100% / calc(100% - .04em) 2px no-repeat;
}
h1.line > span{ background-size: calc(100% - .06em) 2px; }

/* ---------- the poem ----------
   No underlines — a plain, left-aligned stanza. */
.poem p{
  margin: 0;
  font-size: var(--body);
  line-height: 1.75;
  letter-spacing: .06em;
  opacity: .92;
}

/* ---------- say hi ----------
   label and icons on one line; no underline on the label — the icons
   pick up the site's red rule only on hover */
.sayhi{
  display: flex;
  align-items: center;
  gap: 1.1rem;
}
.sayhi-label{
  font-size: var(--body);
  letter-spacing: .06em;
  opacity: .92;
}
.social{ display:flex; align-items:center; gap:1rem; margin:0; }
.social a{
  color: var(--yellow);
  line-height:0;
  display:inline-block;
  padding-bottom: 4px;
  border-bottom: 2px solid transparent;
  opacity: .85;
  transition: border-color .25s ease, opacity .25s ease;
}
.social a:hover{ border-color: var(--red); opacity: 1; }
.social svg{ width:22px; height:22px; display:block; }

/* ---------- platform switch ---------- */
.switch{
  display:flex; align-items:center; gap:.35rem;
  margin: 2.5rem 0 1.2rem;
  flex-wrap: wrap;
}
.switch-label{
  font-size:10px; letter-spacing:.14em; text-transform: uppercase;
  opacity:.45; margin-right:.5rem;
  line-height: 1;
  position: relative; top: 1px;      /* Lulo caps sit high; nudge to the pills' optical centre */
}

.switch .plat{
  padding: .34rem .62rem !important;
  display: inline-flex; align-items: center; justify-content: center;
}
.switch .plat .logo{ width: 15px; height: 15px; display: block; }

.switch button{
  font: inherit;
  font-size: 10.5px;
  letter-spacing: .04em;
  padding: .28rem .7rem;
  border: 1px solid rgba(245,217,32,.35);
  border-radius: 999px;
  background: transparent;
  color: var(--yellow);
  opacity: .7;
  cursor: pointer;
  white-space: nowrap;
  line-height: 1.4;
  transition: background .3s ease, color .3s ease, opacity .3s ease,
              border-color .3s ease, transform .2s ease;
}
.switch button:hover{ opacity: 1; border-color: rgba(245,217,32,.75); }
.switch button:active{ transform: scale(.96); }

/* ---------- mini player ----------
   A fixed bar at the bottom: art, play/pause, title/artist, a thin progress
   line. Appears on the first cover click and stays while you browse. */
.np{
  position: fixed; left: 50%; bottom: 1.1rem; z-index: 30;
  transform: translateX(-50%);
  display: flex; align-items: center; gap: .85rem;
  width: min(92vw, 560px);
  padding: .55rem .9rem .55rem .55rem;
  background: rgba(14,11,3,.82);
  border: 1px solid rgba(245,217,32,.28);
  border-radius: 999px;
  color: var(--yellow);
  -webkit-backdrop-filter: blur(10px) saturate(.9);
          backdrop-filter: blur(10px) saturate(.9);
  box-shadow: 0 14px 40px rgba(0,0,0,.55);
  animation: npIn .35s cubic-bezier(.2,.8,.25,1) both;
}
.np[hidden]{ display: none; }
@keyframes npIn{ from{ opacity:0; transform: translate(-50%, 12px) } to{ opacity:1; transform: translate(-50%, 0) } }

.np-art{
  width: 40px; height: 40px; flex: none;
  border-radius: 50%;
  object-fit: cover;
  background: #111;
  animation: npSpin 9s linear infinite;      /* a record, turning */
}
.np.is-paused .np-art{ animation-play-state: paused; }
@keyframes npSpin{ to{ transform: rotate(360deg) } }

.np-toggle{
  flex: none;
  width: 34px; height: 34px;
  border-radius: 50%;
  border: 1px solid rgba(245,217,32,.4);
  background: transparent;
  color: var(--yellow);
  display: grid; place-items: center;
  cursor: pointer;
  transition: background .25s ease, color .25s ease;
}
.np-toggle:hover{ background: var(--yellow); color: var(--ink); }
.np-ico{ width: 16px; height: 16px; }
.np-ico-play{ display: none; }
.np.is-paused .np-ico-play{ display: block; }
.np.is-paused .np-ico-pause{ display: none; }

.np-meta{
  display: flex; flex-direction: column; gap: .15rem;
  min-width: 0; flex: 1;
  font-size: 10.5px; letter-spacing: .06em; line-height: 1.2;
}
.np-title, .np-artist{ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.np-artist{ opacity: .6; font-size: 9.5px; }

.np-hint{
  flex: none;
  font-size: 8.5px; letter-spacing: .08em;
  opacity: .5;
  max-width: 150px; text-align: right; line-height: 1.3;
}

/* progress: no track line — the fill alone, growing from the left, reads as progress */
.np-bar{
  position: absolute; left: 1.2rem; right: 1.2rem; bottom: 4px;
  height: 1px; background: transparent;
  overflow: hidden;
}
.np-fill{ height: 100%; width: 0; background: var(--yellow); transition: width .25s linear; }

@media (max-width: 700px){
  .np{ width: 94vw; gap: .6rem; padding: .45rem .7rem .45rem .45rem; bottom: .8rem; }
  .np-hint{ display: none; }        /* no room; the tap itself teaches it */
  .np-art{ width: 34px; height: 34px; }
}

/* ---------- gallery ---------- */
.grid{
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  column-gap: 1.1rem;
  row-gap: .6rem;   /* caption already adds vertical space below each cover */
  margin-bottom: 2rem;
}

.tile{
  position: relative;
  cursor: pointer;
  border: 0; padding: 0; margin: 0;
  background: none;
  display: block;
  text-align: left;
  filter: grayscale(.35) contrast(1.05) brightness(.92);
  transition: filter .4s ease;
}
/* only the artwork clips — so the zoom stays inside, but the caption is free */
.tile .art{
  display: block;
  overflow: hidden;
}
.tile img{
  width: 100%; display:block; aspect-ratio: 1/1; object-fit: cover;
  transition: transform .5s cubic-bezier(.2,.8,.3,1);
}
/* the caption always occupies its two lines, so the grid never shifts
   and one row's text can't overlap the next */
.tile .cap{
  display: block;
  opacity: 0;
  margin-top: .5rem;
  min-height: 2.6em;
  font-size: 10.5px;
  line-height: 1.3;
  letter-spacing: .05em;
  color: var(--yellow);
  transition: opacity .3s ease;
}
.tile:hover, .tile.is-playing{ filter: none; }
.tile:hover img, .tile.is-playing img{ transform: scale(1.04); }
.tile:hover .cap, .tile.is-playing .cap{ opacity: 1; }
/* the one that's playing wears a thin yellow rule under its cover */
.tile.is-playing .art{ box-shadow: 0 3px 0 0 var(--yellow); }
.tile:focus-visible{ outline: 2px solid var(--yellow); outline-offset: 3px; }

/* ---------- worked with ---------- */
.worked{ margin: 2.6rem 0 1rem; }

.worked-label{
  margin: 0 0 .7rem;
  font-size: 12px;
  letter-spacing: .08em;
  opacity: .55;
}

/* always fully visible — no collapsing */
.worked-list{
  max-width: 1100px;
  font-size: 12px;
  line-height: 1.9;
  letter-spacing: .05em;
}


/* ---------- scroll-in reveal ----------
   Only hidden when JS has run (html.js), so a broken script never leaves
   content invisible. Elements get .is-in from an IntersectionObserver. */
html.js .reveal{
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 1.5s ease, transform 1.5s cubic-bezier(.2,.8,.25,1);
  will-change: opacity, transform;
}
html.js .reveal.is-in{
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* ---------- mobile ---------- */
@media (max-width: 700px){
  :root{ --gutter: 1.5rem; }
  main{ padding-top: 4.5rem; }
  .grid{ grid-template-columns: repeat(2, 1fr); gap: .8rem; }
  /* mobile: the label is long, so it takes its own line; the three
     platform toggles + the speaker sit together on the line below */
  .switch{ gap: 6px; }
  .switch-label{ flex-basis: 100%; font-size: 9px; margin: 0 0 2px; }
  .switch button{ font-size: 9px; padding: 4px 7px; }
  /* label may wrap: pin the dot to the centre of the FIRST line
     (line box 1.4 × 9.5px ≈ 13.3px, dot 18px → lift by ~2.5px) */
  .rec-txt{ white-space: normal; text-align: left; line-height: 1.4; top: 0; }
  .rec-btn{ align-items: flex-start; }
  .rec-dot{ margin-top: -2.5px; flex: none; }
}

@media (prefers-reduced-motion: reduce){
  *{ transition-duration: .01ms !important; animation-duration: .01ms !important; }
}
