/* ============================================================
   BASE / RESET
   ============================================================ */

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

html {
  scroll-behavior: smooth;
  /* Constant page background — covers the overscroll-bounce area too,
     so nothing but this shows around floating elements like the hero
     mat, in every section, not just wherever a section sets its own. */
  background: var(--color-bg);
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-ink);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, p, dl, dd, dt, ul {
  margin: 0;
  padding: 0;
}

/* Every headline on the site is Instrument Serif, which only ships a
   400 weight (see the Google Fonts link in each page's head). Headings
   inherit bold from the browser's own stylesheet, so without this the
   browser synthesises the bold by smearing the 400 outlines — that
   greasy, too-heavy look is exactly what reads as "wrong typography",
   and it shows up worst on the italics, where the fake weight fights
   the real italic shapes. Setting 400 here means no heading can pick
   up a faux weight by accident, now or on a page added later. */
h1, h2, h3 {
  font-weight: 400;
}

ul { list-style: none; }

a {
  color: inherit;
  text-decoration: none;
}

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

section {
  padding: var(--space-7) var(--gutter);
  max-width: var(--content-max);
  margin: 0 auto;
}

/* Respect reduced motion preference site-wide */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
}

/* ============================================================
   MESSAGE BUBBLE — shared component (Figma: Component/Receiver)

   The one chat-bubble component for the whole site (about's two
   quote bubbles, goodbye's message stack, and any future one) — no
   section gets its own copy of these properties. Width hugs the
   text (fit-content) up to a 359px cap — a short message like "Bye!!"
   stays narrow instead of stretching to fill a fixed box, and only
   text that would naturally exceed 359px wraps and takes the full
   width. Only the wrapping container decides where a bubble sits
   (absolute-positioned, flexed, whatever) — never its own dimensions.
   max-width is min(359px, 100%), not a bare 359px: on a narrow phone
   the container itself (already inset by the page's own side margin)
   can be less than 359px wide, and without the 100% ceiling the
   bubble would push past that margin instead of respecting it. */
.message-bubble {
  display: flex;
  flex-direction: column;
  gap: 16px;
  width: fit-content;
  max-width: min(359px, 100%);
  height: auto;
  padding: 8px 12px;
  font-family: var(--font-chat);
  font-weight: 400;
  font-size: 15px;
  line-height: 1.4;
  text-wrap: pretty;
  /* iMessage-style pop-in (main.js adds .is-visible via
     IntersectionObserver the first time each bubble scrolls into
     view) — starts scaled down from its own tail corner, like it's
     growing out of where the message "arrived" from. Site-wide rule
     per Clara, not just these two sections. */
  opacity: 0;
  transform: scale(0.3);
  transform-origin: bottom left;
}

.message-bubble.is-visible {
  animation: message-bubble-pop 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

@keyframes message-bubble-pop {
  from { opacity: 0; transform: scale(0.3); }
  to { opacity: 1; transform: scale(1); }
}

/* Both bubbles state their own text colour, and neither inherits it.
   A received bubble is always light grey, so its text is always ink,
   no matter what the surrounding section sets — this is not a
   preference, it's the only thing keeping the message readable. It
   used to inherit, which was fine on the home page (it picked up the
   body's ink) and broke on a project page, where the panel sets
   `color: var(--folder-accent)` and two projects' accents are white:
   white text on a #E9E9E9 bubble. The sent bubble is the mirror of
   the same rule — always white, because its blue is always blue. */
.message-bubble--received {
  background: var(--color-bubble-received);
  color: var(--color-ink);
  border-radius: var(--radius-md) var(--radius-md) var(--radius-md) 0;
}

.message-bubble--sent {
  background: var(--color-bubble-sent);
  border-radius: var(--radius-md) var(--radius-md) 0 var(--radius-md);
  color: #fff;
  /* Tail (and so the pop's growth point) is bottom-RIGHT for sent
     bubbles, mirroring received's bottom-left. */
  transform-origin: bottom right;
}

@media (max-width: 640px) {
  .message-bubble {
    padding: 5px 9px;
    font-size: 12px;
  }
}

/* Visually hidden but available to screen readers / SEO — used where
   copy is baked into a vector image for exact visual fidelity. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---------- Spanish: no widows ----------
   The English is placed line by line against the design, so its
   copy is set with `text-wrap: wrap` and the breaks fall where the
   design's do. The Spanish is longer and was never measured, so a
   lone word was closing paragraphs all over it (Clara). `pretty`
   lets the browser rebalance the last lines. Spanish only, so no
   English break moves. The weight of html[lang] plus :is() is what
   lets this win over each page's own `wrap`. */
html[lang="es"] :is(p, li, .message-bubble, .project-header__title, .project-header__description) {
  text-wrap: pretty;
}
