/* The LuvBugz — brand canon: white plush characters, red/blue heart accents, pastel sky.
   Colour rides real brand objects (characters, thumbnails) and the primary action only.
   No card frames, stripes, accent bars, glows, gradients or glass. */

:root{
  --ink:#14202b;
  --ink-soft:#4b5c6b;
  --sky:#00b4e0;          /* brand sky, from the original property */
  --sky-deep:#0079a8;
  --heart:#e03a5c;        /* Mrs LuvBug's heart */
  --rule:#dfe6ea;
  --page:#ffffff;
  --band:#f2f9fc;
  --sky-pale:#e8f6fb;     /* the scene's own sky, used as its loading ground */
  --max:1120px;
  --ease-out:cubic-bezier(0.22,1,0.36,1);
}

*{box-sizing:border-box}
/* The sticky header would otherwise cover whatever an in-page anchor lands on.
   The blog links straight to /songs/<slug>/#lyrics, so without this the Lyrics
   heading arrives underneath the bar and the page looks like it jumped to the
   wrong place. The nav wraps to two lines below 760px, hence the two values. */
html{-webkit-text-size-adjust:100%;scroll-padding-top:88px}
@media (max-width:760px){html{scroll-padding-top:124px}}
body{
  margin:0;
  /* Lets the full-bleed hero use 100vw without the scrollbar's width spilling
     out as a sideways scroll. It must be `clip`, not `hidden`: `hidden` makes
     this a scroll container and kills the sticky header. */
  overflow-x:clip;
  background:var(--page);
  color:var(--ink);
  /* Nunito carries Latin, Cyrillic and Vietnamese. It has NO glyphs for
     Devanagari, CJK, Thai, Korean or Arabic, so those locales fall through to a
     named system face rather than to whatever the browser picks. Listing them
     explicitly is what stops a Hindi or Japanese page rendering in a different
     weight and rhythm from the rest of the site. */
  font:400 17px/1.65 Nunito,"Segoe UI",system-ui,-apple-system,
    "Hiragino Sans","Yu Gothic UI","Noto Sans JP","Noto Sans SC","Noto Sans TC",
    "Apple SD Gothic Neo","Malgun Gothic","Noto Sans KR",
    "Noto Sans Devanagari","Nirmala UI",
    "Thonburi","Leelawadee UI","Noto Sans Thai",
    sans-serif;
}
img{max-width:100%;height:auto;display:block}
a{color:var(--sky-deep);text-decoration:underline;text-underline-offset:2px}
a:hover{color:var(--heart)}
h1,h2,h3{line-height:1.2;margin:0 0 .5em;font-weight:800;letter-spacing:-.01em}
h1{font-size:clamp(30px,4.4vw,46px);line-height:1.12}
h2{font-size:clamp(24px,3.2vw,36px);margin-top:1.6em;line-height:1.16}
section>h2:first-child{margin-top:0}
p{margin:0 0 1em}
.small{font-size:14px;color:var(--ink-soft)}
.lede{font-size:clamp(18px,2.1vw,21px);color:var(--ink-soft);max-width:62ch}
.skip{position:absolute;left:-9999px}
.skip:focus{left:8px;top:8px;background:#fff;padding:8px;z-index:9}

/* ---- nav: solid surface, no glass, no gradient ----
   Sticky so the way back is always one tap away on a long listing page. Solid
   fill rather than a blur, because glass over a moving scene is both a banned
   pattern here and unreadable against the bright sky. */
.nav{
  position:sticky;top:0;z-index:20;
  background:var(--page);
  border-bottom:1px solid var(--rule);
}
.navin{
  display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;
  max-width:var(--max);margin:0 auto;padding:14px 16px;
}
.brand{display:flex;align-items:center;gap:10px;font-weight:800;font-size:19px;
  color:var(--ink);text-decoration:none}
.brand img{border-radius:50%}
.nav nav{display:flex;gap:18px;flex-wrap:wrap}
.nav nav a{color:var(--ink);text-decoration:none;font-weight:600}
.nav nav a:hover{color:var(--heart)}

main{max-width:var(--max);margin:0 auto;padding:0 16px 72px}
section{margin:0}
main>section+section{margin-top:clamp(56px,8vw,104px)}
/* A page that ends on a full-bleed tinted band runs it straight into the footer.
   Leaving main's bottom padding there puts a thin white strip between two almost
   identical tints, which reads as a mistake rather than as breathing space. */
main:has(>.split:last-child){padding-bottom:0}
main:has(>.split:last-child)~.foot{margin-top:0}

/* ---- hero: the meadow is the page, not a picture sitting on it ----
   The old hero put the scene in a rounded box inside the text column, which is
   what made the page read as a document with an illustration in it. */
.hero{padding:0}
/* Sized to the viewport MINUS the scrollbar. A plain 100vw includes the bar and
   makes the whole page scroll sideways on desktop. */
/* The scene is shaped by ASPECT, not by a fixed height. A tall fixed window on
   a phone forces object-fit:cover to zoom until only two heads are left, which
   is what the first attempt did. Widening the box as the screen widens keeps
   the whole meadow in frame at every size. */
.heroscene{
  position:relative;left:50%;transform:translateX(-50%);
  width:100vw;
  aspect-ratio:3/2;max-height:70vh;
  /* `clip`, NOT `hidden`. `hidden` would make this a scroll container, and the
     view timeline below would then measure the art against THIS box - which
     never moves - freezing the parallax at a constant. */
  overflow:clip;
  /* The scene's own passage through the viewport is what drives the art. */
  view-timeline-name:--hero;
  background:var(--sky-pale);
}
/* ⛔ Do NOT widen these back into a cinematic band. Measured on the master:
   his antenna starts 5.6% down the image and her hearts 11.2%. A 2.4:1 band
   cropped 15.4% off the top, so both antennae were cut on a laptop - and the
   antennae are canon (STYLE_LOCK). The source is 16:9 with content hard against
   the top edge, so the frame has to stay near 16:9 or it eats the characters. */
@media (min-width:640px){.heroscene{aspect-ratio:16/9;max-height:74vh}}
@media (min-width:1100px){.heroscene{aspect-ratio:1.9/1;max-height:82vh}}
.heroscene picture{display:block;height:100%}
/* Taller than its frame so it has somewhere to travel. The overhang is 16% of
   the frame each way; the parallax moves 9% of the ART's height, which is 11.9%
   of the frame. Keep overhang > travel or the scene lifts off its own edge and
   shows the bare sky colour behind it.

   ⛔ This is the SINGLE-LAYER hero, reverted 2026-09-20. The two-layer version
   shipped a magenta rim on every edge, pink wings, and characters pasted on top
   of the grass instead of standing in it. The layered idea is sound; that matte
   was not. Do not re-enable layers without a matte Sam has approved at 1:1. */
.heroart{
  position:absolute;left:0;top:-3%;
  width:100%;height:106%;
  object-fit:cover;object-position:50% 46%;
  transform:translateY(var(--par,0%));
  /* ⚠️ The overhang is the parallax's travel budget AND a crop off the top of
     the artwork. It used to be 16% a side, which cut both antennae off. It is
     now 3%, which is why the travel below is small: the source simply has no
     spare sky above the characters to crop into. Gentle and complete beats
     dramatic and decapitated. Measured at 1440x900: his antenna lands 14px
     inside the top edge and their feet 6px inside the bottom, so the travel has
     to stay under ~1.5% or the parallax itself clips what the framing just
     saved. */
  --amp:1.5%;
}
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .heroart{
      animation:heroPar linear both;
      animation-timeline:--hero;
      /* `cover` so the scene responds from the very first pixel of scroll. An
         `exit` range looks better on paper - a top-of-page hero is already on
         screen, so cover spends some travel before the visitor arrives - but it
         leaves ~200px of scroll where nothing moves at all, which reads as
         broken. Continuous and slightly clipped beats correct and dead. */
      animation-range:cover 0% cover 100%;
    }
  }
}
@keyframes heroPar{
  from{transform:translateY(calc(var(--amp) * -1))}
  to  {transform:translateY(var(--amp))}
}
.herotext{padding-top:clamp(26px,3.6vw,48px)}

.motion .rise{opacity:0;transform:translateY(10px);
  transition:opacity .5s ease,transform .5s var(--ease-out)}
.motion .rise.in{opacity:1;transform:none}

/* A child or anyone else who asks for less motion gets none of it. The hero
   rule is NOT scoped to .motion: the parallax is CSS-driven and would still
   run with the script blocked, so it has to be cancelled on its own terms. */
@media (prefers-reduced-motion:reduce){
  .heroart{animation:none;transform:none}
  .motion .rise{opacity:1;transform:none;transition:none}
}
.hero h1{max-width:17ch;font-size:clamp(36px,5.6vw,66px);line-height:1.06;
  letter-spacing:-.022em}
.hero .lede{max-width:52ch}
.actions{display:flex;gap:22px;align-items:center;flex-wrap:wrap;margin-top:30px}
.btn{
  display:inline-block;background:var(--sky);color:#fff;text-decoration:none;
  font-weight:800;padding:13px 26px;border-radius:999px;
  transition:background .15s ease;
}
.btn:hover{background:var(--sky-deep);color:#fff}

/* ---- listing grid: image + text on the page ground, no frame ---- */
.grid{list-style:none;margin:0;padding:0;display:grid;gap:26px 22px;
  grid-template-columns:repeat(auto-fill,minmax(210px,1fr))}
.item a{text-decoration:none;color:var(--ink);display:block}
.item img{border-radius:10px;width:100%;aspect-ratio:16/9;object-fit:cover;background:var(--band)}
.item .t{display:block;margin-top:9px;font-weight:700;line-height:1.35}
.item a:hover .t{color:var(--heart)}
.item .m{display:block;font-size:14px;color:var(--ink-soft);margin-top:2px}

/* ---- rows: hairline separation, no boxes ---- */
.rows{list-style:none;margin:0;padding:0}
.rows li{display:flex;justify-content:space-between;gap:16px;align-items:baseline;
  padding:13px 0;border-bottom:1px solid var(--rule)}
.rows a{font-weight:700;text-decoration:none;color:var(--ink)}
.rows a:hover{color:var(--heart)}
.rows .m{font-size:14px;color:var(--ink-soft);white-space:nowrap}
.plain{margin:0 0 1em;padding-left:1.15em;max-width:62ch}
.plain li{margin-bottom:.45em}

/* ---- song page ---- */
.crumb{font-size:14px;color:var(--ink-soft);margin:14px 0 10px}
.crumb a{color:var(--ink-soft)}
.embed{position:relative;padding-top:56.25%;margin:22px 0 10px;border-radius:12px;
  overflow:hidden;background:var(--band)}
.embed iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
.meta{font-size:14px;color:var(--ink-soft)}
.lyrics{max-width:62ch;margin-top:34px}
.verse p{margin:0 0 1.15em;line-height:1.85}
.prose{max-width:66ch}
.prose h2{margin-top:1.6em}

/* ---- FAQ: plain question/answer prose, no boxes ---- */
.faq{max-width:62ch;margin-top:38px}
.faq h3{font-size:18px;margin:1.5em 0 .35em}
.faq p{color:var(--ink-soft)}

/* ---- split: plain columns, hairline rules only ---- */
/* Full-bleed band. Below the hero the page was white all the way to the footer,
   so the brand appeared exactly once and the rest read as a plain document. A
   solid tint - not a gradient - gives the page a second ground. The horizontal
   padding re-centres the content on the same column as everything above it. */
.split{
  position:relative;left:50%;transform:translateX(-50%);
  width:100vw;
  background:var(--band);
  border-top:1px solid var(--rule);
  padding:clamp(44px,5.5vw,76px) max(16px,calc(50vw - var(--max)/2 + 16px));
  display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:40px;
}
.split h2{margin-top:0;font-size:22px}
.split p{max-width:40ch}

/* ---- footer ----
   Three bands, hairline-separated: the brand-and-links grid, a quiet language
   band, then the legal line. Footer links sit BELOW the body copy in size and
   weight on purpose. The old footer set them at 17px/600 - heavier than the
   prose above them - and four wrapping rows of that is what made the page read
   as cheap. A footer supports the page; it does not compete with it. */
.foot{border-top:1px solid var(--rule);background:var(--band);margin-top:56px}
.foot-main{
  max-width:var(--max);margin:0 auto;padding:56px 16px 44px;
  display:grid;grid-template-columns:1.6fr 1fr 1fr;gap:48px;
}
/* Same circle mask as the header mark, and for the same reason: the master
   artwork sits at 79% of the tile so the inscribed circle clips zero pixels.
   The full logo is shown in full. Never substitute a crop here. */
.foot-mark{display:inline-block;margin-bottom:18px}
.foot-mark img{border-radius:50%}
.foot-brand>p{margin:0 0 26px;max-width:44ch;font-size:15px;color:var(--ink-soft)}
.foot-h{margin:0 0 14px;font-size:14px;font-weight:700;color:var(--ink)}
.foot-col ul{list-style:none;margin:0;padding:0}
.foot-col li{margin-bottom:11px}
.foot-col a{
  color:var(--ink-soft);text-decoration:none;font-size:15px;font-weight:400}
.foot-col a:hover{color:var(--heart)}
/* Social marks. The 44px box is a TAP TARGET, not a drawn tile - no border, no
   background, no radius, because a bordered icon tile is a card frame and those
   are banned here. The negative margin pulls the first glyph back onto the same
   left edge as the text above it, which the 44px box would otherwise indent. */
.social-row{display:flex;gap:4px;flex-wrap:wrap;margin-left:-11px}
.social-row a{
  display:inline-flex;align-items:center;justify-content:center;
  width:44px;height:44px;
  color:var(--ink-soft);text-decoration:none;
  transition:color .15s var(--ease-out);
}
.social-row a:hover{color:var(--heart)}
.social-row svg{width:22px;height:22px;display:block;fill:currentColor}

/* Language band. 18 links are the least important thing in the footer, so they
   are the quietest thing in it - smaller and lighter than the columns above.
   The current language is dimmed, not highlighted: the visitor is looking for
   the one they can read, not the one they are already on. */
.foot .langs{
  max-width:var(--max);margin:0 auto;padding:24px 16px;
  border-top:1px solid var(--rule)}
.foot .langs span{
  display:block;margin-bottom:12px;font-size:14px;font-weight:700;color:var(--ink)}
.foot .langs a{
  display:inline-block;margin:0 18px 8px 0;
  color:var(--ink-soft);text-decoration:none;font-size:14px;font-weight:400}
.foot .langs a:hover{color:var(--heart)}
.foot .langs a[aria-current]{color:#93a2ad}

.foot .small{
  max-width:var(--max);margin:0 auto;padding:18px 16px 32px;
  border-top:1px solid var(--rule);font-size:13.5px}
.foot .small a{color:var(--ink-soft)}
.foot .small a:hover{color:var(--heart)}

@media (max-width:760px){
  .navin{padding:12px 16px}
  .nav nav{gap:14px;font-size:15px}
  /* A phone screen is narrow, so object-fit:cover has to zoom a 16:9 scene hard
     to fill it. Every percent of parallax overhang is cropped on top of that,
     which is what cut the tops of their heads off. Buy the crop back by giving
     the layers less to hide and less to travel. */
  .heroart{top:-3%;height:106%;--amp:1.5%}
  /* Brand across the top, then the two link columns side by side - stacking all
     three makes the footer taller than the page content on a phone. */
  .foot-main{grid-template-columns:1fr 1fr;gap:30px 24px;padding:40px 16px 34px}
  .foot-brand{grid-column:1/-1}
}
