/* ============================================================
   lovehails.com
   palette : black, white and grey
   type    : gabarito (display) / figtree (body) / dm mono (meta)
   motif   : correspondence. stamps, perforations, an envelope.
   ============================================================ */

:root{
  /* black, white, grey. a truly neutral ramp (r=g=b), so it never reads warm or cool
     against the greyscaled photography. */
  --char:   #3C3C3C;   /* darkest grey  : the case band, meta text */
  --slate:  #606060;   /* mid grey      : borders, focus, hover */
  /* the ornaments (✿ markers, the footer mark) sat at ~2.5:1 when this was a
     green, which colour carried and grey does not. darkened until they read on
     both the light ground and the black footer. */
  --ash:    #888888;   /* light-mid     : small ornaments */
  --silver: #D6D6D6;   /* pale grey     : knockout text on the dark bands */
  /* the highlight behind "outlast" needs its own value: at --silver it barely
     separated from the paper, where the green it replaced read instantly. */
  --mark:   #C8C8C8;   /* the marker block */
  --wash:   #E9E9E9;   /* lightest fill : tints and flat panels */

  /* ground + ink */
  --paper:  #F2F2F2;
  --card:   #FCFCFC;
  --ink:    #161616;
  --ink-60: color-mix(in srgb, var(--ink) 60%, transparent);

  --f-display: 'Gabarito', ui-sans-serif, system-ui, sans-serif;
  --f-body:    'Figtree', ui-sans-serif, system-ui, sans-serif;
  --f-mono:    'DM Mono', ui-monospace, 'Cascadia Mono', monospace;
  --f-kao:     'Segoe UI Symbol','Segoe UI Historic','Yu Gothic UI','Meiryo',
               'Hiragino Sans','Noto Sans Symbols 2','Apple Color Emoji',sans-serif;

  --wrap: 1140px;
  --r:    22px;

  /* the colour that "bites into" perforated + scalloped edges.
     re-declared per section so the cutouts match their background. */
  --bleed: var(--paper);
}

*,*::before,*::after{ box-sizing:border-box; }

html{ scroll-behavior:smooth; }
@media (prefers-reduced-motion:reduce){ html{ scroll-behavior:auto; } }

body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--f-body);
  font-size:clamp(1rem,.96rem + .2vw,1.075rem);
  line-height:1.62;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}

img{ max-width:100%; display:block; }

a{ color:inherit; }

.wrap{
  width:100%;
  max-width:var(--wrap);
  margin-inline:auto;
  padding-inline:clamp(20px,5vw,40px);
}

.skip{
  position:absolute; left:-9999px; top:0; z-index:100;
  background:var(--ink); color:var(--paper);
  padding:12px 18px; border-radius:0 0 14px 0;
  font-family:var(--f-mono); font-size:.85rem;
}
.skip:focus{ left:0; }

:focus-visible{
  outline:3px solid var(--slate);
  outline-offset:3px;
  border-radius:6px;
}

/* the palette is black and white, the photographs are not: they keep whatever
   colour they came with. the objects are nearly colourless anyway (median
   saturation 0.000 on every one but the canon), so they sit in the greys
   without being forced there. */

/* the objects are cut out to transparent pngs by images/src/cutout.py, so
   nothing blends. that is what lets a sticker overlap the portrait without
   darkening the photo underneath it. */

/* photographs fill their frame rather than sitting inside it like the art does */
.portrait img.photo{
  width:100%; height:100%;
  object-fit:cover;
  object-position:50% 42%;
}

.kao{
  font-family:var(--f-kao);
  font-style:normal;
  letter-spacing:.02em;
}

/* ─────────────────────────── type ─────────────────────────── */

h1,h2,h3{
  font-family:var(--f-display);
  font-weight:800;
  letter-spacing:-.03em;
  line-height:.98;
  margin:0;
  text-wrap:balance;
}

h1{
  font-size:clamp(2.65rem,7.4vw,5.15rem);
  font-weight:900;
  letter-spacing:-.042em;
  line-height:.93;
}

.hl{
  position:relative;
  z-index:0;
  white-space:nowrap;
}
.hl::before{
  content:"";
  position:absolute;
  z-index:-1;
  left:-.12em; right:-.12em;
  top:.14em; bottom:.06em;
  background:var(--mark);
  border-radius:.42em;
  transform:rotate(-1.2deg);
}

.eyebrow{
  font-family:var(--f-mono);
  font-size:.78rem;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--char);
  margin:0 0 .7rem;
  display:flex;
  align-items:center;
  gap:.6em;
}

.lede{
  font-size:clamp(1.02rem,.98rem + .34vw,1.2rem);
  max-width:34em;
  color:color-mix(in srgb,var(--ink) 82%,transparent);
}

/* ─────────────────────────── nav ─────────────────────────── */

.nav{
  position:sticky; top:0; z-index:50;
  background:color-mix(in srgb,var(--paper) 86%,transparent);
  backdrop-filter:blur(10px);
  border-bottom:1px solid color-mix(in srgb,var(--slate) 22%,transparent);
}
.nav__in{
  max-width:var(--wrap);
  margin-inline:auto;
  padding:11px clamp(20px,5vw,40px);
  display:flex; align-items:center; justify-content:space-between; gap:16px;
}

.brand{
  display:inline-flex; align-items:center; gap:10px;
  text-decoration:none;
  font-family:var(--f-display);
  font-weight:900;
  font-size:1.32rem;
  letter-spacing:-.035em;
}
.brand__mark{
  width:34px; height:34px; flex:none;
  border-radius:50%;
  background:var(--wash);
  display:grid; place-items:center;
  overflow:hidden;
}
.brand__mark img{ width:88%; height:88%; object-fit:contain; }
.brand__star{ color:var(--slate); }

.nav__links{ display:flex; align-items:center; gap:8px; }

.pill{
  font-family:var(--f-body);
  font-weight:600;
  font-size:.9rem;
  text-decoration:none;
  padding:8px 16px;
  border-radius:999px;
  border:1.5px solid color-mix(in srgb,var(--ink) 22%,transparent);
  transition:background .18s ease, color .18s ease, border-color .18s ease;
  white-space:nowrap;
}
.pill:hover{ background:var(--wash); border-color:var(--slate); }
.pill--solid{
  background:var(--ink);
  color:var(--paper);
  border-color:var(--ink);
}
.pill--solid:hover{ background:var(--slate); border-color:var(--slate); color:var(--paper); }

@media (max-width:720px){
  .nav__links .pill:not(.pill--solid){ display:none; }
}

/* ────────────────────────── buttons ────────────────────────── */

.btn{
  display:inline-flex; align-items:center; justify-content:center;
  font-family:var(--f-body);
  font-weight:700;
  font-size:.98rem;
  text-decoration:none;
  padding:14px 26px;
  border-radius:999px;
  border:2px solid var(--ink);
  background:var(--ink);
  color:var(--paper);
  cursor:pointer;
  transition:transform .16s ease, background .18s ease, box-shadow .18s ease;
}
.btn:hover{
  background:var(--slate); border-color:var(--slate);
  transform:translateY(-2px);
  box-shadow:0 8px 0 -2px color-mix(in srgb,var(--char) 34%,transparent);
}
.btn:active{ transform:translateY(0); }

.btn--ghost{
  background:transparent;
  color:var(--ink);
}
.btn--ghost:hover{
  background:var(--wash); border-color:var(--ink); color:var(--ink);
}

/* ─────────────────────────── hero ─────────────────────────── */

.hero{ padding:clamp(48px,8vw,92px) 0 clamp(40px,6vw,64px); }

.hero__grid{
  display:grid;
  grid-template-columns:1.08fr .92fr;
  gap:clamp(28px,5vw,60px);
  align-items:center;
}

.presence{
  display:inline-flex; align-items:center; gap:.55em;
  font-family:var(--f-mono);
  font-size:.82rem;
  letter-spacing:.02em;
  background:var(--card);
  border:1.5px solid color-mix(in srgb,var(--slate) 40%,transparent);
  border-radius:999px;
  padding:7px 15px 7px 12px;
  margin:0 0 clamp(18px,2.6vw,26px);
}
.presence a{ color:var(--char); font-weight:500; }

.dot{
  width:9px; height:9px; flex:none;
  border-radius:50%;
  background:var(--ink);
  box-shadow:0 0 0 0 color-mix(in srgb,var(--ink) 75%,transparent);
  animation:pulse 2.4s ease-out infinite;
}
@keyframes pulse{
  0%   { box-shadow:0 0 0 0 color-mix(in srgb,var(--ink) 70%,transparent); }
  70%  { box-shadow:0 0 0 9px transparent; }
  100% { box-shadow:0 0 0 0 transparent; }
}

.hero__actions{
  display:flex; flex-wrap:wrap; gap:12px;
  margin-top:clamp(22px,3vw,30px);
}

.lede{ margin:clamp(18px,2.6vw,26px) 0 0; }

.hero__kao{
  font-size:1.4rem;
  color:var(--slate);
  margin:22px 0 0;
}

/* the plain credentials, kept typographic rather than blown up into stat tiles */
.facts{
  list-style:none;
  margin:clamp(18px,2.4vw,24px) 0 0;
  padding:0;
  display:flex; flex-wrap:wrap; align-items:center;
  gap:.5em 1em;
  font-family:var(--f-mono);
  font-size:.79rem;
  letter-spacing:.03em;
  color:var(--char);
}
.facts li{ display:inline-flex; align-items:center; gap:1em; }
.facts li:not(:last-child)::after{
  content:"✿";
  color:var(--ash);
  font-size:.9em;
}
.facts b{ font-weight:500; color:var(--ink); }

/* art */
.hero__art{ position:relative; justify-self:center; width:min(100%,420px); }

.portrait{
  aspect-ratio:1;
  border-radius:50%;
  background:var(--wash);
  display:grid; place-items:center;
  overflow:hidden;
  position:relative;
}
.portrait::after{
  content:"";
  position:absolute; inset:0;
  border-radius:50%;
  border:2px solid color-mix(in srgb,var(--slate) 45%,transparent);
}
.portrait img{ width:82%; height:82%; object-fit:contain; }
.portrait.is-empty::before{
  content:"ฅ՞•ﻌ•՞ฅ";
  font-family:var(--f-kao);
  font-size:2rem;
  color:var(--slate);
}

.sticker{
  position:absolute;
  width:27%;
  filter:drop-shadow(0 4px 10px rgb(22 22 22 / .16));
}
.sticker--star{ top:-5%; right:-4%; transform:rotate(11deg); }
.sticker--cat{ bottom:-4%; left:-7%; width:25%; transform:rotate(-9deg); }

@media (max-width:860px){
  .hero__grid{ grid-template-columns:1fr; }
  .hero__art{ order:-1; width:min(100%,258px); }
}

/* ────────────────────────── ticker ────────────────────────── */

.ticker{
  background:var(--ink);
  color:var(--paper);
  overflow:hidden;
  padding:13px 0;
  border-block:2px solid var(--ink);
}
.ticker__track{
  display:flex;
  width:max-content;
  animation:slide 42s linear infinite;
}
.ticker__set{
  display:inline-flex; align-items:center; gap:.65em;
  padding-right:.65em;
  font-family:var(--f-mono);
  font-size:.84rem;
  letter-spacing:.06em;
  white-space:nowrap;
}
.ticker__set b{ font-weight:500; color:var(--silver); }
.ticker__set i{ font-style:normal; color:var(--slate); }
@keyframes slide{ to{ transform:translateX(-50%); } }

/* ────────────────────────── sections ────────────────────────── */

.sec{ padding:clamp(56px,9vw,110px) 0; }

.sec__head{ margin-bottom:clamp(30px,4.5vw,52px); }
.sec__head h2{ font-size:clamp(2.05rem,5.2vw,3.4rem); }

/* ─────────────────── the work : postage stamps ─────────────────── */

.work{ --bleed:var(--paper); }

.stamps{
  list-style:none; margin:0; padding:0;
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(255px,1fr));
  gap:clamp(28px,4vw,44px);
}

.stamp-item{ display:flex; flex-direction:column; gap:18px; }

.stamp{
  position:relative;
  background:var(--card);
  padding:16px 16px 20px;
  display:flex; flex-direction:column; gap:12px;
  transition:transform .22s ease;
}
.stamp-item:hover .stamp{ transform:translateY(-5px) rotate(-.7deg); }

/* perforations: circles painted in the section's own background colour,
   biting into all four edges. no masks, so it holds up everywhere. */
.stamp::after{
  content:"";
  position:absolute; inset:0;
  pointer-events:none;
  background:
    radial-gradient(circle 5.5px at 50% 0,   var(--bleed) 97%, transparent 100%) 0 0    /18px 11px round no-repeat,
    radial-gradient(circle 5.5px at 50% 100%,var(--bleed) 97%, transparent 100%) 0 100% /18px 11px round no-repeat,
    radial-gradient(circle 5.5px at 0 50%,   var(--bleed) 97%, transparent 100%) 0 0    /11px 18px no-repeat round,
    radial-gradient(circle 5.5px at 100% 50%,var(--bleed) 97%, transparent 100%) 100% 0 /11px 18px no-repeat round;
}

.stamp__rail{
  display:flex; align-items:baseline; justify-content:space-between; gap:10px;
  font-family:var(--f-mono);
  font-size:.66rem;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--char);
}
.stamp__denom{
  font-family:var(--f-display);
  font-weight:900;
  font-size:1.28rem;
  letter-spacing:-.03em;
  text-transform:lowercase;
  color:var(--ink);
  line-height:1;
}

.stamp__art{
  position:relative;
  aspect-ratio:1;
  background:var(--wash);
  overflow:hidden;
  border-radius:4px;
}
/* absolutely positioned so the percentages resolve against a definite box.
   a percentage HEIGHT on an in-flow child of an aspect-ratio parent does not
   resolve, which let these overflow their frames. */
.stamp__art img{
  position:absolute;
  top:var(--fit); left:var(--fit);
  width:calc(100% - 2 * var(--fit));
  height:calc(100% - 2 * var(--fit));
  object-fit:contain;
  filter:saturate(.92) contrast(1.04);
}
/* per-image inset, tuned so the three subjects carry equal optical weight
   despite very different aspect ratios */
.stamp__art{ --fit:14%; }
.stamp__art--bunny{   --fit:13%; }
.stamp__art--camera{  --fit:11%; }
.stamp__art--boombox{ --fit:7%;  }
.stamp__art--money{   --fit:12%; }
.stamp__art--record{  --fit:9%;  }

.stamp__title{
  font-size:1.22rem;
  font-weight:800;
  line-height:1.08;
}

.stamp__note{
  margin:0;
  font-size:.945rem;
  color:color-mix(in srgb,var(--ink) 78%,transparent);
}
.stamp__note a{
  display:inline-block;
  margin-top:.35em;
  font-family:var(--f-mono);
  font-size:.82rem;
  color:var(--char);
  text-underline-offset:3px;
}

/* postmark, only on the live one */
.postmark{
  position:absolute;
  top:40%; right:6%;
  width:96px; height:96px;
  display:grid; place-content:center; gap:2px;
  border:2px solid color-mix(in srgb,var(--char) 62%,transparent);
  border-radius:50%;
  transform:rotate(-14deg);
  color:color-mix(in srgb,var(--char) 72%,transparent);
  font-family:var(--f-mono);
  font-size:.6rem;
  letter-spacing:.13em;
  text-transform:uppercase;
  text-align:center;
  pointer-events:none;
}
.postmark::before,
.postmark::after{
  content:"";
  position:absolute; left:9%; right:9%;
  border-top:1.5px solid color-mix(in srgb,var(--char) 40%,transparent);
}
.postmark::before{ top:31%; }
.postmark::after{ bottom:31%; }

/* ───────────── the case : scalloped cloud + three columns ─────────────
   moss rather than sage: cream body copy on sage is only ~4:1, which
   fails for text at this size. moss takes it to ~6.5:1.               */

.case{
  --bleed:var(--char);
  background:var(--char);
  color:var(--paper);
  padding:clamp(56px,8vw,104px) 0;
}

.case__grid{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(272px,100%),1fr));
  gap:clamp(26px,3.6vw,44px);
  margin-top:clamp(38px,5vw,64px);
}

.case__col h3{
  font-size:1.16rem;
  font-weight:800;
  line-height:1.14;
  padding-top:16px;
  border-top:2px solid color-mix(in srgb,var(--silver) 45%,transparent);
  margin-bottom:.62rem;
  color:var(--wash);
}
.case__col p{
  margin:0;
  font-size:.955rem;
  color:color-mix(in srgb,var(--paper) 88%,transparent);
}

.cloud{
  position:relative;
  background:var(--card);
  /* the band sets cream text, so the cloud must reclaim ink for its own copy */
  color:var(--ink);
  padding:clamp(34px,5vw,60px) clamp(30px,5vw,66px);
  max-width:830px;
  margin-inline:auto;
}
/* same gesture as the perforations, scaled up into scallops.
   `round` rather than `repeat`: the panel is never an exact multiple of the
   34px tile, so repeating left a clipped part-scallop at the end of every edge,
   which is what made the cut-out look uneven. round nudges the tile so a whole
   number fits the edge exactly. */
.cloud::after{
  content:"";
  position:absolute; inset:0;
  pointer-events:none;
  background:
    radial-gradient(circle 17px at 50% 0,   var(--bleed) 97%, transparent 100%) 0 0    /34px 34px round no-repeat,
    radial-gradient(circle 17px at 50% 100%,var(--bleed) 97%, transparent 100%) 0 100% /34px 34px round no-repeat,
    radial-gradient(circle 17px at 0 50%,   var(--bleed) 97%, transparent 100%) 0 0    /34px 34px no-repeat round,
    radial-gradient(circle 17px at 100% 50%,var(--bleed) 97%, transparent 100%) 100% 0 /34px 34px no-repeat round;
}
.cloud p{
  margin:0;
  position:relative; z-index:1;
  font-family:var(--f-display);
  font-weight:700;
  font-size:clamp(1.32rem,3.1vw,2.06rem);
  line-height:1.22;
  letter-spacing:-.025em;
  text-align:center;
  text-wrap:balance;
}

/* ───────────────────── what i handle ───────────────────── */

.handle{ background:var(--wash); }

.cards{
  list-style:none; margin:0; padding:0;
  display:grid;
  /* 360px min lands these as a clean 2x2 instead of orphaning the fourth */
  grid-template-columns:repeat(auto-fit,minmax(min(360px,100%),1fr));
  gap:clamp(16px,2.4vw,22px);
}

.card{
  background:var(--card);
  border-radius:var(--r);
  padding:clamp(24px,3vw,32px);
  border:2px solid transparent;
  transition:border-color .2s ease, transform .2s ease;
}
.card:hover{ border-color:var(--slate); transform:translateY(-3px); }

.card__num{
  display:block;
  font-size:1.35rem;
  line-height:1;
  color:var(--ash);
  margin-bottom:14px;
}
.card h3{
  font-size:1.2rem;
  font-weight:800;
  margin-bottom:.5rem;
}
.card p{
  margin:0;
  font-size:.945rem;
  color:color-mix(in srgb,var(--ink) 78%,transparent);
}

/* ──────────────────── contact : the envelope ──────────────────── */

.contact{ padding-bottom:clamp(64px,9vw,120px); }

.envelope{
  --bleed:var(--card);
  position:relative;
  background:var(--card);
  border:2px solid var(--ink);
  border-radius:var(--r);
  padding:clamp(34px,5vw,58px);
  /* the flap gets its own band up top so nothing overlaps the copy */
  padding-top:clamp(148px,23vw,246px);
  max-width:820px;
  margin-inline:auto;
  overflow:hidden;
}
/* the band the stamp is affixed to. it used to be two hairline creases folding
   like a back flap; it is now a photograph, so the creases would only fight it.
   the rule underneath is what still terminates the band cleanly. */
.envelope::before{
  content:"";
  position:absolute;
  top:0; left:0; right:0;
  height:clamp(126px,20vw,216px);
  pointer-events:none;
  background:url("images/banner.jpg") 50% 46% / cover no-repeat, var(--wash);
  border-bottom:2px solid var(--ink);
}
.envelope > *{ position:relative; z-index:1; }

/* an actual postage stamp, so it needs no drawn frame: it carries its own
   perforated edge. just affixed, slightly crooked, the way a real one is. */
.envelope__stamp{
  position:absolute;
  top:clamp(16px,2.4vw,26px);
  right:clamp(20px,3vw,34px);
  z-index:2;
  width:clamp(72px,9vw,92px);
  transform:rotate(4deg);
  filter:drop-shadow(0 5px 12px rgb(22 22 22 / .22));
}

.envelope__h{
  font-size:clamp(2.1rem,5.4vw,3.5rem);
  margin-bottom:.55rem;
}
.envelope__body{
  max-width:46ch;
  margin:0 0 clamp(24px,3vw,32px);
  color:color-mix(in srgb,var(--ink) 82%,transparent);
}

.addr{
  display:flex; align-items:center; gap:14px; flex-wrap:wrap;
  padding:18px 0;
  border-top:2px dashed color-mix(in srgb,var(--slate) 45%,transparent);
  border-bottom:2px dashed color-mix(in srgb,var(--slate) 45%,transparent);
  margin-bottom:clamp(24px,3vw,30px);
}
.addr__label{
  font-family:var(--f-mono);
  font-size:.7rem;
  letter-spacing:.18em;
  text-transform:uppercase;
  color:var(--char);
  border:1.5px solid color-mix(in srgb,var(--slate) 45%,transparent);
  border-radius:6px;
  padding:3px 9px;
  flex:none;
}
.addr__mail{
  font-family:var(--f-display);
  font-weight:800;
  font-size:clamp(1.2rem,3.6vw,1.95rem);
  letter-spacing:-.035em;
  text-decoration:none;
  border-bottom:3px solid var(--silver);
  word-break:break-word;
  transition:border-color .18s ease;
}
.addr__mail:hover{ border-color:var(--slate); }

.envelope__actions{ display:flex; flex-wrap:wrap; gap:12px; }

.envelope__kao{
  margin:24px 0 0;
  font-size:1.25rem;
  color:var(--slate);
}

/* ─────────────────────────── footer ─────────────────────────── */

.foot{
  background:var(--ink);
  color:var(--paper);
  padding:clamp(44px,6vw,70px) 0 clamp(34px,4vw,48px);
}
.foot__in{ text-align:center; }

/* drawn, not photographed, so no artwork is used twice on the page */
.foot__mark{
  width:34px; height:34px;
  display:block;
  margin:0 auto 20px;
  color:var(--ash);
}
.foot__name{
  font-family:var(--f-display);
  font-weight:900;
  font-size:clamp(1.6rem,4vw,2.3rem);
  letter-spacing:-.035em;
  margin:0 0 .3rem;
}
.foot__meta{
  margin:0 0 1.1rem;
  font-family:var(--f-mono);
  font-size:.82rem;
  letter-spacing:.06em;
  color:var(--silver);
}
.foot__mail a{
  font-family:var(--f-mono);
  font-size:.9rem;
  color:var(--paper);
  text-underline-offset:4px;
}
.foot__mail{ margin:0; }

/* ────────────────────────── motion ────────────────────────── */

/* gated on .js so the page still renders with scripting off */
.js .reveal{
  opacity:0;
  transform:translateY(18px);
  transition:opacity .62s cubic-bezier(.22,.68,.3,1) calc(var(--d,0) * 90ms),
             transform .62s cubic-bezier(.22,.68,.3,1) calc(var(--d,0) * 90ms);
}
.js .reveal.is-in{ opacity:1; transform:none; }

@media (prefers-reduced-motion:reduce){
  .js .reveal{ opacity:1; transform:none; transition:none; }
  .ticker__track{ animation:none; }
  .dot{ animation:none; }
  .btn:hover,.card:hover,.stamp-item:hover .stamp{ transform:none; }
}
