/* ==================================================================
   The Cafezinho — Goodness Coffee Roasters
   ------------------------------------------------------------------
   Built to the Agência Mosca identity (2023). Personality per the
   brand board: exclusive, serious, human, authority. Quiet and
   confident, never loud.

   Revision, 10 September: the navy is out at the client's request.
   The page now runs on the identity's brown, beige and off-white
   only, which is also the packaging's own colouring. The photographs
   are very dark, so the page is deliberately light-dominant: cream
   grounds carry the reading, and brown is spent on two bands only.
   ================================================================== */

:root {
  /* From the identity. COR 1, COR 3 and COR 4, unchanged.
     COR 2, the navy, is deliberately unused. */
  --marrom: #2B1810;
  --bege:   #CEB89B;
  --claro:  #EFEFEF;

  /* One derived tone. COR 4 is a cool grey, which goes lifeless next
     to a warm brown, so the main reading ground is the same value
     carried a few degrees toward the beige. */
  --creme:  #F5EFE6;

  --wrap: 1120px;
  --gutter: clamp(1.5rem, 5vw, 4.5rem);
  --banda: clamp(4.5rem, 12vh, 9rem);

  /* The rendered width of The Cafezinho lockup. It lives here because
     the hero's eyebrow is centred against it and the two must not be
     allowed to drift apart. */
  --lockup-w: clamp(260px, 34vw, 430px);
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.0625rem);
  line-height: 1.6;
  color: var(--marrom);
  background: var(--creme);
  -webkit-font-smoothing: antialiased;
}

img, svg { display: block; max-width: 100%; height: auto; }

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

.skip { position: absolute; left: -9999px; background: var(--marrom); color: var(--creme); padding: .75rem 1rem; z-index: 10; }
.skip:focus { left: 1rem; top: 1rem; }

:focus-visible { outline: 2px solid var(--marrom); outline-offset: 4px; }
.banda--marrom :focus-visible { outline-color: var(--bege); }

/* ------------------------------------------------------------------
   Bands. Brown, beige, off-white and the warm cream. Nothing else.
   ------------------------------------------------------------------ */

.banda { padding-block: var(--banda); }

.banda--marrom { background: var(--marrom); color: var(--creme); }
.banda--creme  { background: var(--creme);  color: var(--marrom); }
.banda--claro  { background: var(--claro);  color: var(--marrom); }
.banda--bege   { background: var(--bege);   color: var(--marrom); }

main { background: var(--creme); }

/* Small letterspaced label, echoing "Coffee Roasters" in the lockup. */
.olho {
  margin: 0 0 1.25rem;
  font-family: "Instrument Serif", Georgia, serif;
  font-size: clamp(.9375rem, .9rem + .2vw, 1.0625rem);
  letter-spacing: 0.32em;
  text-transform: uppercase;
  opacity: 0.72;
}

/* ------------------------------------------------------------------
   The Cafezinho lockup
   ------------------------------------------------------------------
   Their product wordmark, rebuilt in type. The only artwork that
   exists for it is printed on a curved, glossy, dark bag, so cutting
   it out of a photograph was never going to give a clean mark.

   Playfair Display is the closest freely licensed match to the caps
   on the packaging; the arced line is a formal script, as printed.
   Both are subset in the <head> to just these characters.

   textLength pins the width of CAFEZINHO, so the composition holds
   its proportions even in the moment before the webfont arrives, or
   permanently if it never does.
   ------------------------------------------------------------------ */

.hero__marca { margin: 0 0 clamp(1.75rem, 4vh, 2.5rem); }

.lockup {
  width: var(--lockup-w);
  height: auto;
  overflow: visible;
}

.lockup__arc {
  font-family: "Petit Formal Script", "Snell Roundhand", cursive;
  font-size: 30px;
  fill: currentColor;
  opacity: .78;
}

.lockup__the {
  font-family: "Playfair Display", Georgia, serif;
  font-style: italic;
  font-size: 74px;
  fill: currentColor;
}

.lockup__nome {
  font-family: "Playfair Display", Georgia, serif;
  font-weight: 500;
  font-size: 92px;
  fill: currentColor;
}

/* ------------------------------- Hero ------------------------------ */

.hero { padding-block: clamp(3rem, 7vh, 5rem) clamp(3rem, 8vh, 5.5rem); }

.hero__grid { display: grid; gap: clamp(2.5rem, 6vh, 4rem); }

.hero__inner { text-align: center; }

.hero__marca { display: flex; justify-content: center; }

.hero__lede {
  margin: clamp(1.5rem, 3.5vh, 2.25rem) auto 0;
  max-width: 26ch;
  font-family: "Instrument Serif", Georgia, serif;
  font-size: clamp(1.375rem, 1rem + 1.4vw, 2.125rem);
  line-height: 1.24;
  text-wrap: balance;
}

.hero__en {
  margin: 1.25rem auto 0;
  max-width: 44ch;
  font-size: .9375rem;
  line-height: 1.55;
  opacity: 0.7;
  font-style: italic;
  text-wrap: pretty;
}

.hero__foto { margin: 0; }

.hero__foto img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  object-position: 50% 45%;
}

@media (min-width: 54rem) {
  /* The hero escapes the reading column so the photograph can run to
     the viewport edge. The text keeps the page's own left margin, so
     it still lines up with every band below it. */
  .hero .wrap {
    max-width: none;
    padding-inline: 0;
  }

  .hero__grid {
    grid-template-columns: 1fr minmax(320px, 46%);
    align-items: center;
    gap: clamp(2.5rem, 5vw, 5rem);
  }

  /* The whole hero column is a centred composition — eyebrow, lockup,
     tagline and English line all on one axis — which is also exactly
     how it stacks on a phone, so the two read as the same design at
     any width.

     It keeps the page's left margin as padding and centres inside the
     space that leaves, between that margin and the photograph. The
     lockup needs no special handling: its artwork carries even padding
     inside its viewBox, so its box centre is its glyph centre. */
  .hero__inner {
    text-align: center;
    padding-inline-start: max(
      var(--gutter),
      calc((100vw - var(--wrap)) / 2 + var(--gutter))
    );
  }

  .hero__foto img {
    aspect-ratio: auto;
    height: min(78vh, 620px);
  }
}

/* ---------------------------- Atributos ---------------------------- */

.atributos { padding-block: clamp(2.5rem, 6vh, 4rem); }

.atributos__lista {
  margin: 0; padding: 0; list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: clamp(1rem, 3vw, 2.5rem);
  text-align: center;
  font-family: "Instrument Serif", Georgia, serif;
  font-size: clamp(1.125rem, 1rem + .9vw, 1.75rem);
}

/* The four-pointed star is the identity's own decorative element, so
   it is the separator. Nothing invented. */
.atributos__estrela {
  width: 15px; height: 15px; flex: none;
  background: var(--marrom);
  clip-path: polygon(50% 0%, 60% 40%, 100% 50%, 60% 60%, 50% 100%, 40% 60%, 0% 50%, 40% 40%);
}

@media (max-width: 34rem) {
  .atributos__estrela { display: none; }
  .atributos__lista { flex-direction: column; gap: .6rem; }
}

/* ------------------------------ Sabor ------------------------------ */

.sabor { position: relative; overflow: hidden; }
.sabor .wrap { position: relative; z-index: 1; }

.sabor__texto {
  margin: 0;
  max-width: 24ch;
  font-family: "Instrument Serif", Georgia, serif;
  font-size: clamp(1.75rem, 1rem + 3.6vw, 4rem);
  line-height: 1.1;
  letter-spacing: -0.015em;
  color: var(--bege);
  text-wrap: balance;
}

/* ----------------------------- Produto ----------------------------- */

.produto__grid {
  display: grid;
  gap: clamp(2.5rem, 6vw, 5rem);
  align-items: center;
}

/* Grid children default to min-width:auto, which lets a wide image
   push the track past the viewport instead of shrinking. */
.produto__grid > * { min-width: 0; }

@media (min-width: 50rem) {
  .produto__grid { grid-template-columns: 1.1fr 1fr; }
}

.produto__linha {
  margin: 0 0 1rem;
  max-width: 26ch;
  font-family: "Instrument Serif", Georgia, serif;
  font-size: clamp(1.5rem, 1rem + 1.8vw, 2.5rem);
  line-height: 1.18;
  text-wrap: balance;
}

.produto__en {
  margin: 0;
  max-width: 34ch;
  font-size: .9375rem;
  font-style: italic;
  opacity: 0.6;
  text-wrap: pretty;
}

/* Square corners and no frame: the identity has no rounding anywhere
   and the photographs are dark enough to hold their own edge. */
.foto { margin: 0; }

.foto img {
  width: 100%;
  aspect-ratio: 642 / 963;
  object-fit: cover;
}

@media (min-width: 50rem) {
  /* Pull the photograph toward the page edge so the band reads as an
     editorial spread rather than a centred card. */
  .produto .wrap { padding-inline-start: 0; }
}

/* ----------------------------- Galeria ----------------------------- */

.galeria { padding-block: clamp(3rem, 8vh, 6rem); }

.galeria__grid {
  display: grid;
  gap: clamp(1rem, 2.5vw, 1.75rem);
}

.galeria__grid > * { min-width: 0; }

.galeria__larga img { aspect-ratio: 642 / 428; }
.galeria__alta  img { aspect-ratio: 642 / 963; }

@media (min-width: 46rem) {
  /* 2.25 : 1 is not a taste decision, it is the two photographs' own
     aspect ratios (1.5 landscape, 0.667 portrait) reduced to a common
     height. At these tracks both fill the row edge to edge with no
     crop at all, so the wordmark on the bag stays whole. */
  .galeria__grid { grid-template-columns: 2.25fr 1fr; align-items: stretch; }

  /* The portrait keeps its intrinsic ratio and so sets the row height.
     The landscape then stretches to fill that height — and because the
     tracks are in the same 2.25 : 1 proportion, the height it is asked
     for is exactly the height its own ratio would have produced. Both
     stretching and cropping are therefore no-ops. */
  .galeria__alta  img { aspect-ratio: 642 / 963; height: auto; }
  .galeria__larga figure, .galeria__larga { height: 100%; }
  .galeria__larga img { height: 100%; aspect-ratio: auto; object-fit: cover; }
}

/* ----------------------------- Contato ----------------------------- */

.contato { position: relative; overflow: hidden; }
.contato .wrap { text-align: center; position: relative; z-index: 1; }

.contato__nome {
  margin: 0 0 2.25rem;
  font-family: "Instrument Serif", Georgia, serif;
  font-size: clamp(1.75rem, 1rem + 2.4vw, 3rem);
  line-height: 1.15;
  color: var(--bege);
}

.contato__links { margin: 0; padding: 0; list-style: none; }
.contato__links li { margin-bottom: .75rem; }

/* Ghost interaction only. An institutional page should not have
   anything on it that pretends to be a buy button. */
.contato__links a {
  color: var(--bege);
  overflow-wrap: anywhere;
  text-decoration: none;
  background-image: linear-gradient(var(--bege), var(--bege));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 1px;
  padding-bottom: 0.22em;
  transition: background-size 260ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.contato__links a:hover,
.contato__links a:focus-visible {
  background-size: 100% 2px;
}

/* ------------------------------ Rodapé ----------------------------- */

.rodape {
  padding-block: clamp(2.5rem, 6vh, 4rem);
  border-top: 1px solid rgba(206, 184, 155, 0.18);
}

.rodape__grid {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem 2rem;
}

.rodape__marca img { width: clamp(180px, 22vw, 260px); }

.rodape__copy {
  margin: 0;
  font-size: .8125rem;
  opacity: .6;
}

@media (max-width: 34rem) {
  .rodape__grid { flex-direction: column; align-items: flex-start; gap: 1.75rem; }
}

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

/* ==================================================================
   Motion
   ------------------------------------------------------------------
   The brand board reads exclusive, serious and authority, so movement
   here is slow, short and only ever in one direction. No bounce, no
   spring, nothing that draws attention to itself. If motion is not
   wanted, or JavaScript never runs, everything is simply visible.
   ================================================================== */

@media (prefers-reduced-motion: no-preference) {

  /* Hero entrance. Runs on load, staggered by --d, in reading order:
     the label, the mark, then the copy. */
  [data-rise] {
    animation: rise 900ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
    animation-delay: var(--d, 0ms);
  }

  /* Scroll reveals only hide themselves once the observer is running,
     so a failed script leaves the page readable rather than blank. */
  .js-reveal [data-reveal] {
    opacity: 0;
    transform: translateY(14px);
    transition:
      opacity 700ms cubic-bezier(0.22, 0.61, 0.36, 1) var(--d, 0ms),
      transform 700ms cubic-bezier(0.22, 0.61, 0.36, 1) var(--d, 0ms);
  }

  .js-reveal [data-reveal].is-in {
    opacity: 1;
    transform: none;
  }

  /* The four-pointed star is the identity's own element, so it is the
     one thing allowed a flourish: it turns a quarter turn as the row
     arrives and settles. */
  .js-reveal .atributos__lista .atributos__estrela {
    transform: rotate(-90deg) scale(0.6);
    opacity: 0;
    transition: transform 900ms cubic-bezier(0.22, 0.61, 0.36, 1) 220ms,
                opacity 600ms ease 220ms;
  }

  .js-reveal .atributos__lista.is-in .atributos__estrela {
    transform: none;
    opacity: 1;
  }
}

@keyframes rise {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}

/* ------------------------------------------------------------------
   Texture
   ------------------------------------------------------------------
   Their own roasted beans, cut from the top-down photograph, knocked
   well back so the two brown bands have depth instead of being flat.
   Texture, not a second photograph.
   ------------------------------------------------------------------ */

.sabor__midia,
.contato__textura {
  position: absolute;
  inset: 0;
  background: url("/assets/beans-texture.jpg") center / cover no-repeat;
  opacity: 0.22;
  /* Luminosity keeps the beans inside the brown rather than tinting
     it toward a muddy grey. */
  mix-blend-mode: luminosity;
  pointer-events: none;
}

/* ------------------------------------------------------------------
   The pouring loop
   ------------------------------------------------------------------
   `o sabor` is the one band that gets movement. Its background is the
   video's own first frame, so the band is fully dressed before — and
   without — any video at all. The <video> is then laid over that same
   frame by script, and only where it is worth the bytes. See the
   loader in index.html for the conditions.

   4.25s, 285KB, silent, and crossfaded end-to-start so the loop has
   no visible cut. Sits at the same opacity and luminosity blend as
   the still texture it replaces, under the same gradient, so it reads
   as texture rather than as a video playing behind the words.
   ------------------------------------------------------------------ */

.sabor__midia { background-image: url("/assets/beans-pour-poster.jpg"); }

.sabor__midia video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* Fades up once the first frame is actually decoded, so a slow
     connection never shows a black rectangle over the poster. */
  opacity: 0;
  transition: opacity 700ms ease;
}

.sabor__midia video.is-playing { opacity: 1; }

/* Settle the texture into the band so it still meets its neighbours
   on a clean edge. */
.sabor__midia::after,
.contato__textura::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to bottom,
    var(--marrom) 0%,
    rgba(43, 24, 16, 0.58) 38%,
    rgba(43, 24, 16, 0.78) 100%
  );
}

/* The photographs lift very slightly on hover. Enough to feel alive,
   not enough to read as a control you can click. */
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .hero__foto img,
  .foto img {
    transition: transform 900ms cubic-bezier(0.22, 0.61, 0.36, 1);
  }
  .hero__foto:hover img,
  .foto:hover img { transform: scale(1.018); }

  .hero__foto, .foto { overflow: hidden; }
}
