/* MacaroniShark 3D Prints
   Colours are the five from Branding/MacaroniShark-Brand-Guide.pdf and nothing else.
   The guide's rules, enforced below: cream is the page, deep sea is the text,
   gold and coral are accents only, and no pale accent ever carries small text. */

:root {
  --sea:        #003746;  /* deep sea  */
  --teal:       #389EAA;  /* shark teal */
  --gold:       #F4BC40;  /* pasta gold */
  --cream:      #FFF9EB;  /* warm cream */
  --coral:      #FF856B;  /* coral */

  /* Derived only for shading inside the illustration and for hover states.
     Nothing here introduces a new hue. */
  --gold-deep:  #d99f24;
  --sea-soft:   #0a4a5c;
  --cream-warm: #fdf2d9;
  /* Same hue as --teal, dropped in value until cream body copy clears 4.5:1 on
     it. Nothing in the palette clears that bar on --teal itself, so the CTA
     section needs this step rather than a different colour. */
  --teal-deep:  #2b7c86;

  --display: "Baloo 2", "Trebuchet MS", system-ui, sans-serif;
  --body:    Figtree, "DejaVu Sans", system-ui, -apple-system, sans-serif;

  --wrap: 1140px;
  --gut: clamp(1rem, 4vw, 3rem);
  --radius: 22px;

  /* The palette is a fixed brand palette, not a themeable one. Declaring the
     scheme stops Android Chrome's auto-dark from re-tinting it. */
  color-scheme: light;
}

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

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

body {
  margin: 0;
  background: var(--cream);
  color: var(--sea);
  font-family: var(--body);
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.0625rem);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

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

a { color: inherit; }

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

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--sea);
  color: var(--cream);
  padding: 0.75rem 1.25rem;
  z-index: 99;
  border-radius: 0 0 12px 0;
}
.skip:focus { left: 0; }

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

/* ── Type ─────────────────────────────────────────────────── */

.h2 {
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(2rem, 1.3rem + 3vw, 3.25rem);
  line-height: 1.05;
  letter-spacing: -0.015em;
  margin: 0 0 0.6rem;
}
.h2--light { color: var(--cream); }

.sub {
  max-width: 46ch;
  margin: 0 0 2.75rem;
  font-size: 1.0625rem;
}
.sub--light { color: var(--cream-warm); }

.eyebrow {
  font-weight: 600;
  font-size: 0.8125rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sea);
  /* 0.62 measured 4.02:1 on cream - under AA for 13px. */
  opacity: 0.72;
  margin: 0 0 1.1rem;
}

.lede {
  max-width: 44ch;
  font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.1875rem);
  margin: 0 0 2rem;
}

/* ── Buttons and links ────────────────────────────────────── */

.btn {
  display: inline-block;
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.0625rem;
  text-decoration: none;
  padding: 0.85rem 1.75rem;
  border-radius: 999px;
  background: var(--sea);
  color: var(--cream);
  border: 3px solid var(--sea);
  transition: transform 0.15s ease, background-color 0.15s ease;
}
.btn:hover { background: var(--sea-soft); transform: translateY(-2px); }
.btn:active { transform: translateY(0); }

.btn--sm { padding: 0.5rem 1.15rem; font-size: 0.9375rem; }

/* Gold sits on deep sea only, where it has the contrast to carry a label. */
.btn--gold {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--sea);
}
.btn--gold:hover { background: var(--gold-deep); border-color: var(--gold-deep); }

.link-arrow {
  display: inline-flex;
  align-items: center;
  /* Tall enough to be a comfortable tap target without looking like a button. */
  min-height: 44px;
  font-family: var(--display);
  font-weight: 700;
  text-decoration: none;
  box-shadow: inset 0 -3px 0 var(--coral);
  white-space: nowrap;
}
.link-arrow::after { content: " \2192"; }
.link-arrow:hover { box-shadow: inset 0 -3px 0 var(--sea); }

/* ── Top bar ──────────────────────────────────────────────── */

.bar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 1.5rem;
  padding: 0.6rem var(--gut);
  background: color-mix(in srgb, var(--cream) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 2px solid color-mix(in srgb, var(--sea) 12%, transparent);
}

.bar__brand {
  display: flex;
  align-items: center;
  min-height: 44px;
  gap: 0.6rem;
  text-decoration: none;
  margin-right: auto;
}
.bar__fin { width: 44px; height: auto; }
.bar__name {
  font-family: var(--display);
  font-weight: 800;
  font-size: 1.15rem;
  line-height: 1;
  letter-spacing: -0.01em;
}
.bar__name em {
  display: block;
  font-style: normal;
  font-family: var(--body);
  font-weight: 600;
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  /* 0.6 measured 3.79:1 on cream - under AA for 11px. */
  opacity: 0.75;
  margin-top: 2px;
}

.bar__nav { display: flex; gap: 1.5rem; }
.bar__nav a {
  display: flex;
  align-items: center;
  /* iPads use this desktop bar and are touch devices, so it keeps the 44px
     target rather than the 43px that 0.5rem padding produced. */
  min-height: 44px;
  text-decoration: none;
  font-weight: 500;
  font-size: 0.9375rem;
  border-bottom: 2px solid transparent;
}
.bar__nav a:hover { border-bottom-color: var(--coral); }

/* On a phone the bar wraps to two rows and the sections become a scrollable
   strip of pills. A hamburger would hide three links behind a tap; this keeps
   them visible and thumb-sized, and it needs no JavaScript. */
@media (max-width: 860px) {
  .bar { flex-wrap: wrap; gap: 0.5rem 1rem; padding-bottom: 0; }
  .bar__brand { margin-right: auto; }

  .bar__nav {
    order: 3;
    width: 100%;
    /* Wrap rather than scroll. The three pills are wider than every phone
       viewport, so a scrolling strip left the last one sliced down the middle
       at all widths - which reads as a broken layout, not as "scroll me". */
    flex-wrap: wrap;
    gap: 0.5rem;
    padding-bottom: 0.6rem;
  }

  .bar__nav a {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 0 0.75rem;
    font-size: 0.875rem;
    border: 2px solid color-mix(in srgb, var(--sea) 18%, transparent);
    border-radius: 999px;
    white-space: nowrap;
  }
  .bar__nav a:hover { border-color: var(--coral); }
}

/* On a narrow phone the brand and the CTA stop fitting on one row together,
   which pushed the sticky bar to ~224px - nearly half a 568px screen. Shrink
   both so they share a row and the header stays out of the way. */
@media (max-width: 400px) {
  .bar { gap: 0.4rem 0.6rem; }
  .bar__fin { width: 34px; }
  .bar__name { font-size: 1rem; }
  .bar__name em { font-size: 0.625rem; letter-spacing: 0.12em; }
  .btn--sm { padding: 0.5rem 0.85rem; font-size: 0.875rem; }
  .bar__nav { gap: 0.4rem; }
  .bar__nav a { padding: 0 0.6rem; font-size: 0.8125rem; }
}

/* ── Hero ─────────────────────────────────────────────────── */

.hero { position: relative; padding-top: clamp(2.5rem, 5vw, 5rem); }

.hero__inner {
  max-width: var(--wrap);
  margin-inline: auto;
  padding: 0 var(--gut) clamp(5rem, 12vw, 9rem);
  display: grid;
  /* The headline is held on one line by non-breaking spaces, so it is always
     wider than an even split and spills into the next column. The copy side
     gets the larger share to absorb that. Two columns only above 1000px,
     because below it the spill lands on the mascot. */
  grid-template-columns: 1.5fr 1fr;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: center;
}

/* Grid tracks size to their widest unbreakable content by default, and the
   headline is held together with non-breaking spaces. Without this the track
   pushes past the viewport on a 320px phone. */
.hero__inner > * { min-width: 0; }

.hero__title {
  font-family: var(--display);
  font-weight: 800;
  /* Lower bound so "Thoughtful gifts." still fits a 320px screen without
     breaking across the non-breaking space; upper bound so the same
     unbreakable line clears the mascot in the two-column layout. */
  font-size: clamp(2.25rem, 1.15rem + 5.4vw, 5rem);
  line-height: 0.95;
  letter-spacing: -0.03em;
  margin: 0 0 1.5rem;
}
.hero__title-alt { color: var(--teal); }

.hero__actions {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 3vw, 2rem);
  flex-wrap: wrap;
}

.hero__art { position: relative; }

.hero__shark {
  width: 100%;
  max-width: 520px;
  margin-inline: auto;
  filter: drop-shadow(0 18px 28px rgba(0, 55, 70, 0.14));
  animation: bob 7s ease-in-out infinite;
}

@keyframes bob {
  0%, 100% { transform: translateY(0) rotate(-1deg); }
  50%      { transform: translateY(-14px) rotate(1deg); }
}

/* Bubbles drifting up past the shark. */
.bubble {
  position: absolute;
  display: block;
  border-radius: 50%;
  border: 3px solid var(--teal);
  background: color-mix(in srgb, var(--teal) 12%, transparent);
}
.bubble--1 { top: 12%; left: 4%;    width: 26px; height: 26px; animation: drift 9s  ease-in-out infinite; }
.bubble--2 { top: 48%; left: -1%;   width: 16px; height: 16px; animation: drift 11s ease-in-out infinite -3s; }
.bubble--3 { top: 72%; left: 12%;   width: 11px; height: 11px; animation: drift 7s  ease-in-out infinite -1s; }
.bubble--4 { top: 22%; right: 1%;   width: 19px; height: 19px; animation: drift 8s  ease-in-out infinite -5s; }

@keyframes drift {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-22px); }
}

@media (prefers-reduced-motion: reduce) {
  .hero__shark, .bubble { animation: none; }
}

/* Tablets and small laptops: stack, so the headline has the full width and
   nothing lands on the mascot. The art stays large here, unlike on a phone. */
@media (max-width: 1000px) {
  .hero__inner { grid-template-columns: 1fr; }
  .hero__art { order: -1; max-width: min(320px, 44%); margin-inline: auto; }
}

@media (max-width: 760px) {
  .hero { padding-top: 1.5rem; }
  /* The wave is absolutely positioned at the bottom of the hero and is 110px
     tall at phone widths, so the hero needs at least that much padding or the
     dark crest paints straight through the Etsy button. */
  .hero__inner { grid-template-columns: 1fr; padding-bottom: clamp(8.5rem, 22vw, 10rem); }

  /* The mascot leads on mobile, but at 340px it filled a third of the screen
     and pushed the headline past the halfway mark and the Etsy button off the
     bottom of a 375x812 phone. Sized so the whole hero, eyebrow through
     button, lands on the first screen. */
  .hero__art {
    order: -1;
    max-width: min(210px, 58%);
    margin-inline: auto;
    margin-bottom: 0.5rem;
  }

  .hero__title { margin-bottom: 1rem; }
  .lede { margin-bottom: 1.5rem; }
  .bubble--2, .bubble--3 { display: none; }
}

/* A short phone - the iPhone SE 3 at 375x667 is the one that matters - has
   ~180px less height than the phones the hero was tuned against, and the Etsy
   button landed at 676px, sliced by the fold. Tighten the stack for height,
   not width: a 390x844 phone is unaffected. */
@media (max-width: 760px) and (max-height: 700px) {
  .hero { padding-top: 1rem; }
  .hero__art { max-width: min(165px, 46%); margin-bottom: 0.25rem; }
  .hero__title { margin-bottom: 0.75rem; }
  .lede { margin-bottom: 1.25rem; }
  .eyebrow { margin-bottom: 0.7rem; }
}

/* ── The wave into the deep ───────────────────────────────── */

/* The fill stretches to its box on purpose - it is an abstract shape, so an
   uneven scale costs it nothing. That freedom is only safe because no type
   rides on it any more; see the comment in index.html. */
.wave {
  position: absolute;
  inset: auto 0 0 0;
  height: clamp(110px, 14vw, 190px);
  pointer-events: none;
}
.wave__fill { position: absolute; inset: 0; width: 100%; height: 100%; }
.wave__fill path { fill: var(--sea); }

/* ── What we print ────────────────────────────────────────── */

.deep {
  background: var(--sea);
  color: var(--cream);
  /* The wave's trough lands just above this, so the heading needs more than
     the ~16px the old 1rem floor left it. */
  padding: clamp(2rem, 4vw, 3.5rem) 0 clamp(3rem, 6vw, 5rem);
}

.cards {
  list-style: none;
  margin: 0;
  padding: 0;
  /* Flex, not grid. The card count comes from listings.json and will change,
     and grid's auto-fit leaves a short last row orphaned against the left edge
     - 2 + 1 with a hole at 820px. flex-wrap centres that last row under the one
     above. (auto-fit with a capped track would centre too, but it then packs
     max-width tracks instead of sharing the row, dropping desktop to 2 up.) */
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(1rem, 2.5vw, 1.75rem);
}

.cards > li { display: flex; flex: 1 1 258px; max-width: 380px; }

.card {
  display: flex;
  flex-direction: column;
  width: 100%;
  background: var(--cream);
  color: var(--sea);
  border-radius: var(--radius);
  padding: 1.75rem 1.6rem 1.9rem;
  border-bottom: 10px solid var(--teal);
  overflow: hidden;
}

/* A listing card is the link to its Etsy listing, so the whole card is the
   target rather than a small "view" link tucked in a corner. */
.card--link {
  text-decoration: none;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.card--link:hover {
  transform: translateY(-4px);
  box-shadow: 0 14px 28px rgba(0, 20, 26, 0.28);
}

.card__photo {
  width: calc(100% + 3.2rem);
  margin: -1.75rem -1.6rem 1.25rem;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.card__cue {
  margin-top: auto;
  padding-top: 1.1rem;
  font-family: var(--display);
  font-weight: 700;
  font-size: 0.9375rem;
}
.card__cue::after { content: " \2192"; }
.card--gold  { border-bottom-color: var(--gold); }
.card--coral { border-bottom-color: var(--coral); }
.card--teal  { border-bottom-color: var(--teal); }

.card__title {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.5rem;
  line-height: 1.1;
  margin: 0 0 0.4rem;
}
.card p { margin: 0; }

.prints__more { margin: clamp(1.75rem, 4vw, 2.5rem) 0 0; }

/* The coral underline has enough contrast on deep sea; the text needs to be
   cream rather than inherit, or it stays deep-sea-on-deep-sea. */
.link-arrow--light { color: var(--cream); }
.link-arrow--light:hover { box-shadow: inset 0 -3px 0 var(--cream); }

/* ── Inventory ────────────────────────────────────────────── */

.stock { padding: clamp(2.5rem, 6vw, 4rem) 0 clamp(4rem, 8vw, 6rem); }

/* .card is cream, which reads as a card on the home page's deep-sea band but
   disappears on a cream page - only the accent border survived. Warm cream
   separates it from the background without introducing a colour. */
.stock .card { background: var(--cream-warm); }

/* A short page otherwise leaves the footer floating mid-screen with cream
   below it. Push it to the bottom without forcing a scrollbar. */
.stock-page { min-height: 100vh; display: flex; flex-direction: column; }
.stock-page main { flex: 1 0 auto; }
.stock-page .foot { flex-shrink: 0; }

/* ── Who we are ───────────────────────────────────────────── */

.us { padding: clamp(4.5rem, 9vw, 7rem) 0; }

.us__grid {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}
.us__grid p { max-width: 52ch; }
.us__grid p:last-of-type { margin-bottom: 2rem; }

.us__art {
  margin: 0;
  background: var(--cream-warm);
  border-radius: var(--radius);
  padding: clamp(1.5rem, 4vw, 2.75rem);
}

@media (max-width: 760px) {
  .us__grid { grid-template-columns: 1fr; }
  .us__art { order: -1; }
}

/* ── How it's made ────────────────────────────────────────── */

.how {
  background: var(--gold);
  padding: clamp(4.5rem, 9vw, 7rem) 0;
}

.steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: clamp(1.5rem, 3vw, 2.5rem);
}

/* Four steps only ever divide as 4, 2x2 or 1. auto-fit alone gave a 3+1 split
   between 620 and 1010px, which orphans step 04 under a numbered sequence. */
@media (min-width: 620px) and (max-width: 1010px) {
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.step {
  border-top: 4px solid var(--sea);
  padding-top: 1.1rem;
}
.step__n {
  display: block;
  font-family: var(--display);
  font-weight: 800;
  font-size: 2.5rem;
  line-height: 1;
  color: var(--sea);
  /* 0.55 measured 2.89:1 on gold, under even the 3:1 large-text floor. */
  opacity: 0.7;
  margin-bottom: 0.4rem;
}
.step__title {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.375rem;
  margin: 0 0 0.3rem;
}
.step p { margin: 0; }

/* ── Shop CTA ─────────────────────────────────────────────── */

.shop {
  background: var(--teal-deep);
  padding: clamp(4rem, 8vw, 6rem) 0;
}
.shop__inner {
  display: grid;
  grid-template-columns: 240px 1fr;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: center;
}
/* Not mirrored: the brand guide requires the mascot keep its single eye and
   left-facing smile, so the artwork is never flipped to face the copy. */
.shop__shark { width: 100%; }
.shop .sub--light { color: var(--cream); }

@media (max-width: 760px) {
  .shop__inner { grid-template-columns: 1fr; text-align: center; }
  .shop__shark { max-width: 190px; margin-inline: auto; }
  .shop .sub { margin-inline: auto; }
}

/* ── Contact ──────────────────────────────────────────────── */

.contact { padding: clamp(4rem, 8vw, 6rem) 0; }

.routes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(1rem, 2.5vw, 1.75rem);
}
/* Unlike .cards, the card here IS the <li> - there is no inner wrapper, so
   selectors must target the li directly. A descendant selector matches nothing. */
.route {
  display: flex;
  flex-direction: column;
  flex: 1 1 300px;
  max-width: 460px;
  background: var(--cream-warm);
  border-radius: var(--radius);
  padding: 1.75rem 1.6rem 1.9rem;
  border-bottom: 10px solid var(--teal);
}
/* Two routes, two accents: teal for buyers, gold for business. */
.routes > .route:last-child { border-bottom-color: var(--gold); }

.route__title {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.375rem;
  line-height: 1.1;
  margin: 0 0 0.4rem;
}
.route p { margin: 0 0 1.5rem; }
/* Push the buttons to a common baseline so two cards of unequal copy still
   line their actions up. */
.route .btn { margin-top: auto; align-self: flex-start; }

/* The second route is the quieter one: same shape, less shout. */
.btn--ghost {
  background: transparent;
  color: var(--sea);
  border-color: var(--sea);
}
.btn--ghost:hover { background: var(--sea); color: var(--cream); }

/* ── Footer ───────────────────────────────────────────────── */

.foot {
  background: var(--sea);
  color: var(--cream-warm);
  padding: clamp(2.5rem, 5vw, 3.5rem) 0;
}
.foot__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
}
.foot__brand {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  color: var(--cream);
}
.foot__brand img { width: 56px; }
.foot__brand .bar__name { font-size: 1.35rem; }
.foot__legal { margin: 0; font-size: 0.875rem; opacity: 0.8; }
.foot__year::before { content: "· "; }

/* ── 404 ──────────────────────────────────────────────────── */

.lost {
  min-height: 70vh;
  display: grid;
  place-items: center;
  text-align: center;
  padding: 3rem var(--gut);
}
.lost img { width: 220px; margin: 0 auto 1.5rem; }
/* No inline styles anywhere, so the CSP needs no style-src 'unsafe-inline'. */
.lost__sub { margin-inline: auto; }
.lost .btn { margin-top: 1.5rem; }
