/* Birthday Party SG - shared styles.
   Rules used identically by more than one page live here.
   Page-specific rules and every media query stay in their page. */

* { margin:0; padding:0; box-sizing:border-box; }
:root {
  --purple:#7530B5;
  --pink:#F03070;
  --teal:#14B0C0;
  /* Text-only shades (2026-08-14). The brand colours above are UNCHANGED - they
     stay correct for the header rule, backgrounds and large display type. But as
     SMALL TEXT on the cream/soft backgrounds they fail WCAG AA:
       --teal #14B0C0 -> 2.56:1 on cream, 2.30:1 on soft
       --pink #F03070 -> 3.83:1 on cream
     These darker shades read as the same hues at 10-13px and pass:
       --teal-text #0A6E78 -> 5.84:1 on cream, 5.24:1 on soft
       --pink-text #C4185A -> 5.66:1 on cream, 5.08:1 on soft
     (#D6215D was tried first: 4.85 on cream but only 4.35 on the SOFT
      background, so it failed on half the site. Test both backgrounds.)
     Use --teal/--pink for brand and backgrounds; these two for small text. */
  --teal-text:#0A6E78;
  --pink-text:#C4185A;
  --orange:#F07010;
  --gold:#F0B010;
  --navy:#241F54;
  /* Warm shell (31 Jul): the whole site adopts the story page's paper/cream
     palette so every page feels like one thing. Cards stay white on top. */
  --bg:#FFFCF7;
  --soft:#F6EFE6;
  --line:#E9DCCC;
}
body {
  font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  background:var(--bg);
  color:var(--navy);
  line-height:1.6;
  font-optical-sizing:auto;
  -webkit-font-smoothing:antialiased;
}
.container { max-width:1020px; margin:0 auto; padding:0 20px; }
/* ===== HEADER & NAV ===== */
/* Translucent material header — content scrolls underneath (Apple: materials & depth) */
header {
  background:rgba(255,252,247,.72);
  backdrop-filter:blur(20px) saturate(180%);
  -webkit-backdrop-filter:blur(20px) saturate(180%);
  padding:3px 0;
  border-bottom:4px solid var(--teal);
  display:flex; align-items:center; justify-content:space-between;
}
.logo-img { height:125px; width:auto; max-width:none; display:block; }
/* Desktop bar is locked to 68px. The logo is taller than that and hangs past
   the bar rather than being shrunk to fit — anchored to the top so it can only
   overflow downwards, never off the top of the window. Phones keep their own
   taller two-row header, so this is desktop-only. */
@media (min-width:769px){
  header{ height:68px; box-sizing:border-box; padding:0; }
  header > .container{ height:100%; }
  header > .container > a:first-child{ align-self:flex-start; margin-top:2px; }
}
nav a {
  display:inline-block; font-weight:700; font-size:16px; text-decoration:none;
  color:var(--navy); margin-left:14px;
  transition:color .2s, transform .1s ease-out;
}
nav a:hover { color:var(--pink-text); }
nav a:active { transform:scale(.96); }
nav a.active { color:var(--pink-text); border-bottom:3px solid var(--pink); padding-bottom:2px; }
.hero h1 .hl-pink { color:var(--pink-text); }
/* 19px, not 17px: white on --pink measures 3.92:1, which fails WCAG AA's 4.5:1
   for normal text. At >=18.66px bold the button counts as LARGE text, where the
   bar is 3:1 and 3.92:1 passes. Keeps the brand pink. Do not reduce below 19px.
   (Eisen ruled the font bump over darkening the pink, 2026-08-14.) */
.cta-primary {
  display:inline-block; background:var(--pink); color:#fff;
  padding:16px 42px; border-radius:10px; font-size:19px; font-weight:800;
  text-decoration:none;
  /* Spring-like ease-out: fast start, gentle settle (Apple: response) */
  transition:transform .3s cubic-bezier(.175,.885,.32,1.1), box-shadow .3s cubic-bezier(.175,.885,.32,1.1);
  box-shadow:0 4px 14px rgba(240,48,112,.35);
}
.cta-primary:hover { transform:translateY(-2px); box-shadow:0 6px 18px rgba(240,48,112,.45); }
.cta-primary:active { transform:translateY(0) scale(.97); transition-duration:.1s; box-shadow:0 2px 8px rgba(240,48,112,.3); }
/* ===== SECTION BASICS ===== */
.section { padding:56px 0; }
.section-title { font-size:26px; font-weight:900; text-align:center; margin-bottom:8px; color:var(--navy); letter-spacing:-0.015em; line-height:1.15; }
.section-sub { text-align:center; color:#4A4666; font-size:15px; margin-bottom:40px; }
.tick { color:var(--teal-text); font-weight:900; }
.why {
  display:flex; gap:12px; background:#fff; border:2px solid var(--line);
  border-radius:12px; padding:18px;
}
.why .wi { font-size:20px; font-weight:900; color:var(--teal-text); flex-shrink:0; }
.why .wt { font-size:13.5px; color:#3E3A5C; line-height:1.6; }
.why .wt strong { display:block; color:var(--navy); font-size:14.5px; margin-bottom:3px; }
/* ===== BOOKING INFO ===== */
.book-info {
  max-width:760px; margin:0 auto; background:var(--soft);
  border-radius:12px; padding:24px 28px; font-size:14px; color:#3E3A5C; line-height:2;
}
.book-info strong { color:var(--navy); }
/* ===== BANNERS ===== */
/* Sizes are fluid, not fixed: these banners sit inside a .snap-page that is
   pinned to 100svh and now clips overflow, so they must shrink on a phone
   rather than run past the panel. */
/* The label rides the top border as a centred pill, the same treatment as the
   Best Value badge on a package card, rather than sitting off to the side. */
.banner {
  position:relative;
  max-width:760px; margin:clamp(24px,3.5vh,32px) auto clamp(16px,2.4vh,24px); background:var(--soft);
  border-radius:12px; border:2px solid var(--line);
  padding:clamp(19px,2.6vh,25px) clamp(15px,4vw,24px) clamp(12px,1.9vh,18px); text-align:center;
}
.banner:last-of-type { margin-bottom:0; }
.banner .b-label {
  position:absolute; top:-13px; left:50%; transform:translateX(-50%);
  /* navy label, not white: white on --orange was 2.99:1 at 10.5px. Navy on the
     SAME brand orange is 5.03:1 - passes without dulling the palette. */
  background:var(--orange); color:var(--navy); padding:4px 14px; border-radius:20px;
  font-size:clamp(10.5px,2.7vw,12px); font-weight:800; letter-spacing:.5px;
  text-transform:uppercase; white-space:nowrap; margin:0;
}
.banner p { font-size:clamp(12px,3.4vw,14.5px); line-height:1.62; color:#3E3A5C; margin:0 0 3px; }
.banner p:last-child { margin-bottom:0; }
.banner .b-lead { font-weight:800; color:var(--navy); }
.banner .b-aside { font-size:clamp(10.5px,2.9vw,13px); color:#6B6688; font-style:italic; }
/* 13 Sep 2026: the travel surcharge grew from two venues to five, and one run-on
   sentence became a wall of text on a phone. The venues are now chips — scannable
   at a glance, wrapping to as many rows as the screen needs, with the price above
   them and the reassurance below. */
.banner .b-venues {
  list-style:none; margin:7px auto 7px; padding:0; max-width:560px;
  display:flex; flex-wrap:wrap; justify-content:center; gap:6px 7px;
}
.banner .b-venues li {
  background:rgba(255,255,255,.72); border:1px solid rgba(18,40,75,.12);
  border-radius:20px; padding:4px 11px; color:#3E3A5C; line-height:1.35;
  font-size:clamp(11px,3vw,13.5px); font-weight:600; white-space:nowrap;
}
.banner .b-venues li:last-child { white-space:normal; }
.fine-print {
  max-width:760px; margin:clamp(9px,1.5vh,14px) auto 0; text-align:center;
  font-size:clamp(11px,3vw,13.5px); color:#6B6688; line-height:1.55;
}
.banner.b-transparency .b-label { background:var(--teal); color:var(--navy); }   /* navy not white: white was 2.62:1, navy is 5.72:1 */
/* ===== PARENT QUOTES ===== */
.quote-grid {
  display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
  gap:18px; max-width:920px; margin:0 auto;
}
.quote {
  background:#fff; border:2px solid var(--line); border-radius:14px;
  padding:22px 22px 18px; text-align:left;
}
.quote blockquote { font-size:15px; line-height:1.75; color:#3E3A5C; font-style:italic; }
.quote figcaption { margin-top:12px; font-size:12.5px; font-weight:800; color:var(--purple); }
.quote-note { text-align:center; font-size:12.5px; color:#8A87A5; margin-top:18px; }
@media (max-width:768px){
  .quotes-sec .fam-title{ margin-bottom:10px; }
  /* One column, and min-width:0 — inside home's flex-column screens a grid
     refuses to shrink below its min-content width and drags the whole page
     into horizontal scroll. */
  .quote-grid{ gap:10px; grid-template-columns:1fr; min-width:0; width:100%; }
  .quotes-sec > .container{ padding-left:20px; padding-right:20px; }
  .quote{ padding:14px 16px 12px; border-radius:12px; }
  .quote blockquote{ font-size:clamp(12px,1.8dvh,14.5px); line-height:1.6; }
  .quote figcaption{ margin-top:8px; font-size:11px; }
  .quote-note{ font-size:11px; margin-top:10px; }
}
/* ===== PROGRESS RAIL (all widths) =====
   The rail is built by JS from whichever elements actually snap. Visible on
   all widths now, matching the story page. Desktop: right:22px, 10px dots.
   Mobile: right:10px, 8px dots. */
.rail{ position:fixed; right:22px; top:50%; transform:translateY(-50%); z-index:55;
       display:flex; flex-direction:column; gap:12px; }
.rail button{ width:10px; height:10px; padding:0; border-radius:50%; border:0; cursor:pointer;
              background:#DACFC2; transition:background .3s, transform .3s; }
.rail button.now{ background:var(--pink); transform:scale(1.45); }
/* ===== PANEL REVEAL (mobile only) =====
   Fade and slide up as sections enter. Desktop shows content immediately. */
@media (max-width:768px){
  .rail{ right:10px; gap:9px; }
  .rail button{ width:8px; height:8px; }
  .rv{ opacity:0; transform:translateY(12px); transition:opacity .55s ease, transform .55s ease; }
  .rv.on{ opacity:1; transform:none; }
}
@media (prefers-reduced-motion:reduce){
  .rv{ opacity:1 !important; transform:none !important; transition:none !important; }
  .rail button{ transition:none; }
  .cta-primary, .pack, .pack a, .f-cta, nav a { transition:opacity .2s ease !important; transform:none !important; }
  .cta-primary:hover, .pack:hover { transform:none !important; }
  .carousel { scroll-behavior:auto; }
  .carousel img:hover { transform:none; }
}
/* Frostier surfaces when the user prefers less transparency */
@media (prefers-reduced-transparency:reduce){
  header { background:var(--bg); backdrop-filter:none; -webkit-backdrop-filter:none; }
}
@media (prefers-contrast:more){
  header { background:var(--bg); backdrop-filter:none; -webkit-backdrop-filter:none; border-bottom-color:var(--navy); }
  .pack, .quote, .why { border-color:var(--navy); }
}
/* ===== FOOTER ===== */
footer { background:var(--navy); color:#fff; text-align:center; padding:clamp(60px,15vh,120px) 0; margin-top:56px; display:flex; align-items:center; justify-content:center; min-height:400px; }
footer h3 { font-size:22px; font-weight:900; margin-bottom:18px; }
.f-cta {
  display:inline-block; background:var(--pink); color:#fff; padding:14px 36px;
  border-radius:10px; font-weight:800; font-size:19px; text-decoration:none; margin-bottom:22px;
  transition:background .2s, transform .1s ease-out;
}
.f-cta:hover { background:#D6215D; }
.f-cta:active { transform:scale(.97); }
.f-links { margin:6px 0 16px; }
.f-links a { color:var(--gold); text-decoration:none; font-weight:700; font-size:80px; margin:0 12px; }
.f-links a:hover { text-decoration:underline; }
@media (max-width:640px) {
  .f-links a { font-size:120px; margin:0 8px; }
}
/* ===== PACKAGES ===== */
.packages { background:var(--soft); }
.usual-price { font-size:13.5px; color:#8A87A5; margin-bottom:6px; }
.usual-price s { text-decoration-thickness:1.5px; }
.save-badge { display:inline-block; background:var(--gold); color:var(--navy); font-size:12.5px; font-weight:800; padding:3px 10px; border-radius:999px; margin-bottom:12px; }
.pack {
  background:#fff; border:2px solid var(--line); border-radius:14px;
  padding:18px 16px 16px; text-align:center; position:relative;
  transition:border-color .25s, box-shadow .25s, transform .3s cubic-bezier(.175,.885,.32,1.1);
  display:flex; flex-direction:column;
}
.pack:hover { border-color:var(--purple); box-shadow:0 8px 22px rgba(117,48,181,.14); transform:translateY(-3px); }
.pack.star { border-color:var(--pink-text); box-shadow:0 8px 22px rgba(240,48,112,.14); }
.pack-badge {
  position:absolute; top:-13px; left:50%; transform:translateX(-50%);
  /* navy label, not white: white on --orange was 2.99:1 at 10.5px. Navy on the
     SAME brand orange is 5.03:1 - passes without dulling the palette. */
  background:var(--orange); color:var(--navy); padding:4px 14px; border-radius:20px;
  font-size:12px; font-weight:800; text-transform:uppercase; letter-spacing:.5px; white-space:nowrap;
}
.pack h3 { font-size:18px; font-weight:900; color:var(--purple); margin:4px 0 2px; }
.pack.star h3 { color:var(--pink-text); }
.pack .price { font-size:38px; font-weight:900; color:var(--navy); margin-bottom:6px; }
.pack .list {
  text-align:left; background:var(--soft); border-radius:10px; padding:10px 14px;
  font-size:13px; color:#3E3A5C; line-height:1.5; margin:12px 0 14px; flex-grow:1;
}
.pack a {
  display:block; background:var(--purple); color:#fff; padding:10px 12px;
  border-radius:8px; font-weight:800; font-size:13px; text-decoration:none;
  transition:background .2s, transform .1s ease-out;
}
.pack a:hover { background:#5F2596; }
.pack a:active { transform:scale(.97); }
/* #D6215D not var(--pink): white on --pink is 3.92:1 and these buttons render
   ~11px inside a tight card, so the >=18.66px large-text escape is unavailable.
   #D6215D is the palette's own pink-hover shade and measures 4.96:1 — passes AA
   at any size, and reads as the same pink. (Eisen, 2026-08-14) */
.pack.star a { background:#D6215D; }
.pack.star a:hover { background:#D6215D; }
.badge-wrap { text-align:center; }
.fam-title { font-size:24px; font-weight:900; text-align:center; margin-bottom:8px; color:var(--navy); }
.fam-sub { text-align:center; color:#4A4666; font-size:14.5px; margin-bottom:34px; }
/* ===== GALLERY CAROUSEL ===== */
.gallery-section { background:var(--bg); padding:clamp(40px,8vh,80px) 0; }
.gallery-title { font-size:clamp(24px,6vw,32px); font-weight:900; text-align:center; margin-bottom:clamp(30px,5vh,50px); color:var(--navy); }
.gallery-carousel { display:grid; gap:clamp(40px,6vh,60px); }
/* Arrows sit outside the strip on desktop and overlap it on a phone. Shared by
   Home and Gallery, both of which run the looping carousel script. */
.carousel-wrapper{ position:relative; display:flex; align-items:center; gap:16px; }
.carousel-arrow{
  position:absolute; top:50%; transform:translateY(-50%);
  background:var(--purple); color:#fff; border:none;
  width:44px; height:44px; border-radius:50%; font-size:28px; cursor:pointer;
  display:flex; align-items:center; justify-content:center; z-index:10;
  transition:background .2s;
}
.carousel-arrow:hover{ background:var(--pink); }
.carousel-arrow[hidden]{ display:none; }
.carousel-arrow-left{ left:-60px; }
.carousel-arrow-right{ right:-60px; }
@media (max-width:768px){
  .carousel-arrow{ width:36px; height:36px; font-size:22px; }
  .carousel-arrow-left{ left:8px; }
  .carousel-arrow-right{ right:8px; }
}
/* Momentum scrolling with snap points — flick lands on a photo boundary */
.carousel { display:flex; gap:16px; overflow-x:auto; scroll-behavior:smooth; padding:8px 0;
  -webkit-overflow-scrolling:touch; scroll-snap-type:x proximity; overscroll-behavior-x:contain; }
/* Each photo takes exactly the width its flex basis asks for. A flex item
   otherwise keeps min-width:auto — for an image that is its intrinsic width at
   the row's height — so widths varied with aspect ratio and changed again as
   lazy images arrived. The loop measures one set of photos to know how far to
   shift, so geometry moving underneath it made the wrap land wrong. */
.carousel img { min-width:0; }
.carousel img { scroll-snap-align:start; }
.carousel::-webkit-scrollbar { height:6px; }
.carousel::-webkit-scrollbar-track { background:var(--line); border-radius:3px; }
.carousel::-webkit-scrollbar-thumb { background:var(--teal); border-radius:3px; }
.carousel::-webkit-scrollbar-thumb:hover { background:var(--purple); }
/* Show exactly 3 photos: flex-basis = 1/3 of carousel width, height maintained with object-fit */
.carousel img { flex:0 0 calc((100% - 32px) / 3); height:clamp(220px,35vw,340px); object-fit:cover; border-radius:12px; display:block; transition:transform .2s, box-shadow .2s; cursor:grab; }
.carousel img:active { cursor:grabbing; }
.carousel img:hover { transform:scale(1.05); box-shadow:0 8px 20px rgba(0,0,0,.15); }
@media (max-width:768px) {
  .carousel-label { font-size:16px; }
}

/* ===== A11Y UTILITIES (2026-08-14) =====
   .sr-only hides text from sight but keeps it for screen readers and search
   engines. .skip-link is visually hidden until focused, then appears - it lets
   a keyboard user jump the six nav links that otherwise precede content on
   every page. */
.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; }
.skip-link{ position:absolute; left:-9999px; top:0; z-index:100;
            background:var(--navy); color:#fff; padding:10px 18px;
            border-radius:0 0 8px 0; font-weight:800; font-size:15px; text-decoration:none; }
.skip-link:focus{ left:0; }

/* ===== TAP TARGETS (2026-08-15) =====
   WCAG 2.2 asks for 24x24px minimum. Two controls were under it and neither can
   simply be made bigger without wrecking a tight layout:
     - nav links rendered 16px tall (the header width budget, see the standard)
     - rail dots are 8x8 by design; enlarging them would clutter the screen edge
   Both get an INVISIBLE hit area via ::after instead. The dot and the label look
   exactly the same; the finger target is 24px+. position:relative on the parent
   is what anchors it. */
nav a{ position:relative; }
nav a::after{ content:''; position:absolute; left:0; right:0; top:50%;
              transform:translateY(-50%); height:26px; }
.rail button{ position:relative; }
.rail button::after{ content:''; position:absolute; top:50%; left:50%;
                     transform:translate(-50%,-50%); width:26px; height:26px; }
