:root{
    --cream: #faf3e6;
    --sage: #a8c3a0;
    --sage-dark: #6f8f68;
    --sun: #f6c453;
    --sun-dark: #d99a2b;
    --clay: #e08e6d;
    --ink: #3c3430;
    --paper: #fffaf1;
    --line: #ecdfc7;
    --drop-accent: #ff6b6b;
    --drop-glow: #ff9e7d;
  }

  *{box-sizing:border-box; margin:0; padding:0;}

  /* Every <img> carries width/height attributes so the browser reserves space
     before the file arrives (no layout shift). Those attributes would otherwise
     pin the rendered height, so height:auto hands sizing back to the CSS width
     and the intrinsic aspect ratio. Rules that set both dimensions explicitly
     (.cart-item-icon img, .qv-include-icon img) still win on specificity. */
  img{ max-width:100%; height:auto; }

  html{
    scrollbar-width:none; /* Firefox */
    -ms-overflow-style:none; /* old Edge/IE */
  }
  html::-webkit-scrollbar{ display:none; width:0; height:0; } /* Chrome/Safari */

  body{
    background:var(--cream);
    color:var(--ink);
    font-family:'Nunito', sans-serif;
    line-height:1.6;
    scrollbar-width:none;
    -ms-overflow-style:none;
  }
  body::-webkit-scrollbar{ display:none; width:0; height:0; }

  /* ---------- NAV ---------- */
  .top-stack{ position:sticky; top:0; z-index:100; }
  .nav{
    display:flex; align-items:center; justify-content:space-between;
    padding:14px 24px;
    background:rgba(250,243,230,0.92);
    backdrop-filter:blur(10px);
    border-bottom:1px solid var(--line);
    transition: box-shadow 0.25s ease;
  }
  .top-stack.scrolled .nav{ box-shadow:0 4px 14px rgba(60,52,48,0.08); }
  .nav-brand{
    display:flex; align-items:center; gap:9px;
    font-family:'Fredoka', sans-serif; font-weight:700; font-size:1.15rem;
    color:var(--ink); text-decoration:none;
  }
  .nav-brand img{ width:34px; display:block; }
  .nav-links{ display:flex; gap:8px; }
  .nav-link{
    display:flex; align-items:center; gap:6px;
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.82rem;
    color:var(--ink); text-decoration:none; padding:8px 14px;
    border-radius:100px; border:1.5px solid var(--line);
    transition: border-color 0.15s ease, transform 0.15s ease;
  }
  .nav-link:hover{ transform:translateY(-1px); border-color:var(--sun-dark); }
  .brand-icon{ width:14px; height:14px; flex-shrink:0; }
  .etsy .brand-icon{ color:#f1641e; }
  .ebay .brand-icon{ color:#0064d2; }
  .depop .brand-icon{ color:#ff2300; }
  .tiktok .brand-icon{ color:#25232a; }
  .instagram .brand-icon{ color:#e1306c; }

  .nav-right{ display:flex; align-items:center; gap:8px; }

  .cart-btn{
    position:relative; display:inline-flex; align-items:center; justify-content:center;
    width:44px; height:44px; border-radius:100px; border:1.5px solid var(--line);
    background:var(--paper); font-size:1.1rem; cursor:pointer;
    transition: border-color 0.15s ease, transform 0.15s ease;
  }
  .cart-btn svg { width:20px; height:20px; stroke:var(--ink); fill:none; stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round; }
  .cart-btn:hover{ transform:translateY(-1px); border-color:var(--sun-dark); }
  .cart-count{
    position:absolute; top:-6px; right:-6px; min-width:18px; height:18px;
    padding:0 4px; border-radius:100px; background:var(--clay); color:var(--paper);
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.68rem;
    line-height:18px; text-align:center; display:none;
  }
  .cart-count.visible{ display:block; }

  /* ---------- ANNOUNCEMENT ---------- */
  .announce{
    text-align:center; background:var(--sage); color:var(--paper);
    font-family:'Fredoka', sans-serif; font-weight:700; font-size:1.05rem;
    line-height:1.5;
    padding:12px 20px; letter-spacing:0.01em;
  }
  .announce strong{ font-weight:700; text-decoration:underline; text-underline-offset:2px; }

  /* THE FLASH OF UNHYDRATED CONTENT.
     The bar ships with real copy in the markup — that is deliberate, and it is
     what a crawler and a JS-less visitor read. But it also meant a visitor with
     JS watched "small batches" paint and then get replaced by the live drop a
     few hundred milliseconds later, which reads as a bug even though both
     states are correct.
     So the markup carries `announce--pending`, which hides the text WITHOUT
     collapsing the bar (visibility, not display — the strip keeps its height,
     so nothing below it shifts). app.js clears the class the moment the
     announcement resolves, in every outcome including failure and timeout.
     The <noscript> override in index.html un-hides it when there is no script
     to do that, so the no-JS floor is genuinely a floor. */
  .announce--pending .announce-stack{ visibility:hidden; }

  /* Messages are stacked in ONE grid cell rather than positioned absolutely,
     so the bar's height is the tallest message and no rotation can make the
     page jump. */
  .announce-stack{
    display:grid;
    grid-template-areas:'msg';
    align-items:center; justify-items:center;
  }
  .announce-msg{
    grid-area:msg;
    margin:0;
    display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
    max-width:100%;
    opacity:0; transform:translateY(-0.55em);
    transition: opacity 0.45s ease, transform 0.45s cubic-bezier(0.22,1,0.36,1);
    pointer-events:none;
  }
  .announce-msg.is-current{
    opacity:1; transform:none;
    pointer-events:auto;
  }
  /* Leaving downwards while the next one arrives from above, so the loop reads
     as one belt rather than a cross-fade in place. */
  .announce-msg.is-leaving{ opacity:0; transform:translateY(0.55em); }

  @media(max-width:640px){
    .announce{ font-size:0.95rem; padding:12px 14px; }
    .announce-msg{ flex-direction:column; gap:4px; }
    .announce .divider{ display:none; }
  }

  /* No rotation without motion: every message is shown at once, in the row the
     bar has always used. Handled in JS too (the timer never starts), but the
     rule stands on its own so a stale class cannot hide a message. */
  @media(prefers-reduced-motion:reduce){
    .announce-stack{ display:block; }
    .announce-msg{
      opacity:1; transform:none; transition:none; pointer-events:auto;
      display:inline-flex;
    }
    .announce-msg + .announce-msg::before{
      content:'\00a0·\00a0'; white-space:pre;
    }
  }

  /* ---------- HERO ---------- */
  .hero{
    max-width:640px; margin:0 auto; padding:60px 24px 36px; text-align:center;
  }
  .icon-wrap{
    width:160px; margin:0 auto 20px; cursor:pointer;
    transform-origin: 50% 85%;
    transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
  }
  .icon-wrap:hover{ transform: scale(1.1) rotate(-4deg); }
  .icon-wrap img{
    width:100%; display:block;
    filter: drop-shadow(0 10px 14px rgba(60,52,48,0.22));
    animation: heroFloat 3.5s ease-in-out infinite;
    transform-origin: 50% 85%;
    transition: filter 0.35s ease;
  }
  .icon-wrap:hover img{
    filter: drop-shadow(0 16px 20px rgba(60,52,48,0.32)) brightness(1.06) saturate(1.12);
  }
  .hero-price{
    display:inline-flex; align-items:center; gap:6px; cursor:pointer;
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.88rem;
    color:var(--clay); background:var(--paper); border:1.5px solid var(--line);
    padding:6px 16px; border-radius:100px; margin:0 auto 18px;
    transition: border-color 0.15s ease, transform 0.15s ease;
  }
  .hero-price:hover{ border-color:var(--sun-dark); transform:translateY(-1px); }
  @keyframes heroFloat{
    0%  { transform: translateY(0px) rotate(0deg) scale(1); }
    25% { transform: translateY(-10px) rotate(-2deg) scale(1.03,0.97); }
    50% { transform: translateY(-14px) rotate(1deg) scale(0.97,1.05); }
    75% { transform: translateY(-6px) rotate(2deg) scale(1.02,0.98); }
    100%{ transform: translateY(0px) rotate(0deg) scale(1); }
  }

  h1{
    font-family:'Fredoka', sans-serif; font-weight:700;
    font-size:clamp(2rem, 6vw, 2.7rem); margin-bottom:10px;
  }
  h1 .accent{ color:var(--clay); }
  .sub{ font-size:1.02rem; color:#6b6055; max-width:400px; margin:0 auto 22px; }
  .cta-main{
    display:inline-flex; align-items:center; gap:9px;
    background:var(--sage); color:var(--paper);
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:1.05rem;
    padding:15px 34px; border-radius:100px; text-decoration:none;
    box-shadow:0 6px 0 var(--sage-dark);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
  }
  .cta-main:hover{ transform: translateY(-3px); box-shadow:0 9px 0 var(--sage-dark); }
  .cta-main:active{ transform: translateY(3px); box-shadow:0 3px 0 var(--sage-dark); }

  /* ============================================================
     NEW DROP HERO — full-width, big impact, NO clipping
  ============================================================ */
  .new-drop-section{
    max-width:1100px;
    margin:0 auto 50px;
    padding:0 24px;
    overflow:visible;
  }
  .new-drop-inner{
    position:relative;
    min-height:260px;
    background:linear-gradient(135deg, #ff6b6b 0%, #ff8e53 40%, #ffc470 100%);
    border-radius:28px;
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:24px;
    overflow:visible;
    padding:36px 6%;
    box-shadow:0 16px 32px rgba(224,58,32,0.18);
  }
  .new-drop-inner::before{
    content:'';
    position:absolute;
    inset:0;
    background:radial-gradient(ellipse at 70% 50%, rgba(255,255,255,0.18) 0%, transparent 70%);
    pointer-events:none;
  }

  .new-drop-copy{
    position:relative;
    z-index:2;
    color:#fff;
    text-align:left;
    max-width:340px;
  }
  .new-drop-tag{
    display:inline-flex; align-items:center; gap:6px;
    font-family:'Fredoka', sans-serif; font-weight:700; font-size:0.78rem;
    color:#ff5533; background:#fff;
    padding:5px 14px; border-radius:100px; margin-bottom:14px;
    letter-spacing:0.05em; text-transform:uppercase;
    animation: tagPop 2.6s ease-in-out infinite;
  }
  @keyframes tagPop{
    0%,100%{ transform:scale(1) rotate(-1deg); }
    50%{ transform:scale(1.07) rotate(1deg); }
  }
  .new-drop-copy h2{
    font-family:'Fredoka', sans-serif; font-weight:700;
    font-size:clamp(1.5rem, 2.6vw, 2rem);
    margin-bottom:8px; color:#fff;
    text-shadow:0 2px 12px rgba(0,0,0,0.12);
  }
  .new-drop-copy p{
    font-size:0.9rem; color:rgba(255,255,255,0.9);
    margin-bottom:18px; line-height:1.55; max-width:300px;
  }
  .new-drop-copy .cta-drop{
    display:inline-flex; align-items:center; gap:8px;
    background:#fff; color:#e03a20;
    font-family:'Fredoka', sans-serif; font-weight:700; font-size:0.9rem;
    padding:12px 24px; border-radius:100px; text-decoration:none;
    box-shadow:0 6px 0 rgba(0,0,0,0.18);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
  }
  .new-drop-copy .cta-drop:hover{ transform:translateY(-3px); box-shadow:0 9px 0 rgba(0,0,0,0.18); }
  .new-drop-copy .cta-drop:active{ transform:translateY(3px); box-shadow:0 3px 0 rgba(0,0,0,0.18); }

  /* The mascot floats freely — no transform on parent */
  .new-drop-mascot{
    position:relative;
    z-index:3;
    flex-shrink:0;
    width:170px;
    display:flex;
    align-items:center;
    justify-content:center;
    /* No overflow:hidden, no border-radius, no transform — just a size box */
  }
  .new-drop-mascot-img{
    width:170px;
    height:auto;
    display:block;
    filter:
      drop-shadow(0 20px 30px rgba(180,40,0,0.35))
      drop-shadow(0 4px 8px rgba(180,40,0,0.2));
    /* smooth float+bounce, no clip parent */
    animation: mascotBounce 2.8s cubic-bezier(0.37, 0, 0.63, 1) infinite;
    transform-origin: center bottom;
  }
  @keyframes mascotBounce{
    0%   { transform: translateY(0)   scaleX(1)    scaleY(1)    rotate(0deg); }
    20%  { transform: translateY(-22px) scaleX(0.96) scaleY(1.04) rotate(-3deg); }
    40%  { transform: translateY(-30px) scaleX(0.95) scaleY(1.06) rotate(2deg); }
    60%  { transform: translateY(-18px) scaleX(0.97) scaleY(1.03) rotate(-1deg); }
    80%  { transform: translateY(-8px)  scaleX(0.98) scaleY(1.01) rotate(1deg); }
    100% { transform: translateY(0)   scaleX(1)    scaleY(1)    rotate(0deg); }
  }
  /* Several plushes landing at once. They overlap into one group rather than
     lining up in a row, because three side by side would each be too small to
     recognise. Each one keeps its own bounce, offset so they do not move as a
     single block.

     This used to pin children 2 and 3 with `position:absolute` and hard-coded
     left/right/margin-top values, which only ever composed correctly for
     exactly three images of exactly that size: two drops left an empty half,
     and the box was a fixed 240px regardless. It is now an overlapping flex
     row — the group sizes itself to however many images there actually are,
     and the negative margin is the only number involved. */
  .new-drop-mascot.is-composite{ width:auto; max-width:100%; align-items:flex-end; }
  .new-drop-mascot.is-composite .new-drop-mascot-img{
    width:clamp(84px, 22vw, 124px);
  }
  .new-drop-mascot.is-composite .new-drop-mascot-img + .new-drop-mascot-img{
    margin-left:clamp(-34px, -7vw, -22px);
  }
  /* Earlier images sit in front, so the first-named drop is the readable one. */
  .new-drop-mascot.is-composite .new-drop-mascot-img:nth-child(1){ z-index:3; }
  .new-drop-mascot.is-composite .new-drop-mascot-img:nth-child(2){ z-index:2; animation-delay:-0.6s; }
  .new-drop-mascot.is-composite .new-drop-mascot-img:nth-child(3){ z-index:1; animation-delay:-1.2s; }

  /* shadow under mascot for depth */
  .new-drop-mascot::after{
    content:'';
    position:absolute;
    bottom:-20px; left:50%; transform:translateX(-50%);
    width:120px; height:22px;
    background:radial-gradient(ellipse, rgba(160,30,0,0.35) 0%, transparent 80%);
    border-radius:50%;
    animation: shadowPulse 2.8s cubic-bezier(0.37, 0, 0.63, 1) infinite;
  }
  @keyframes shadowPulse{
    0%,100%{ transform:translateX(-50%) scaleX(1) scaleY(1); opacity:0.45; }
    40%{ transform:translateX(-50%) scaleX(0.7) scaleY(0.6); opacity:0.2; }
  }

  /* limited badge */
  .limited-badge{
    position:absolute; top:18px; right:18px;
    background:rgba(255,255,255,0.2);
    border:2px solid rgba(255,255,255,0.5);
    color:#fff; font-family:'Fredoka', sans-serif; font-weight:700;
    font-size:0.78rem; padding:6px 14px; border-radius:100px;
    letter-spacing:0.03em; text-transform:uppercase;
    backdrop-filter:blur(4px);
    animation: limitedPulse 3s ease-in-out infinite;
  }
  @keyframes limitedPulse{
    0%,100%{ opacity:1; }
    50%{ opacity:0.65; }
  }

  @media(max-width:700px){
    .new-drop-section{ padding:0 16px; }
    .new-drop-inner{ flex-direction:column-reverse; text-align:center; padding:32px 6% 36px; min-height:auto; border-radius:22px; }
    .new-drop-copy{ text-align:center; max-width:none; }
    .new-drop-copy p{ max-width:none; }
    .new-drop-mascot{ width:130px; }
    .new-drop-mascot-img{ width:130px; }
  }

  /* ---------- SCROLL REVEAL ---------- */
  .reveal{ opacity:0; transform:translateY(28px) scale(0.98); transition: opacity 0.6s cubic-bezier(0.22, 1, 0.36, 1), transform 0.6s cubic-bezier(0.22, 1, 0.36, 1); }
  .reveal.in-view{ opacity:1; transform:translateY(0) scale(1); }
  .reveal-stagger.in-view{ transition-delay: var(--d, 0s); }
  @media(prefers-reduced-motion:reduce){
    .reveal,.reveal.in-view{ opacity:1; transform:none; transition:none; }
    .icon-wrap img,.new-drop-mascot-img,.new-drop-tag{ animation:none; }
  }

  /* ---------- SHOP / COLLECTION ---------- */
  .shop{ max-width:1100px; margin:10px auto 0; padding:40px 24px 70px; }
  .shop h2,.bundles h2{ text-align:center; font-family:'Fredoka', sans-serif; font-weight:600; font-size:1.6rem; margin-bottom:8px; }
  .collection-quote{ text-align:center; color:#8a8073; font-size:0.92rem; max-width:420px; margin:0 auto 34px; }
  .grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(210px,1fr)); gap:24px; }

  /* ---- Product card with hover animation ---- */
  /* Flex column so the button can bottom-align. The grid already stretches
     every card in a row to the same height, but the content inside flowed
     top-down, so a card carrying an extra row — the star rating, which only
     appears once a product has reviews — pushed its "add to cart" 21px below
     its neighbours'. Measured, not guessed: 308px vs 287px from the card top.
     Any future variable row (a two-line name, a wrapped description) would
     have done the same thing, so the fix is to stop letting content decide
     where the button lands. */
  .product{
    background:var(--paper); border-radius:22px; padding:26px 18px 26px;
    text-align:center; transition: transform 0.2s ease, box-shadow 0.2s ease;
    position:relative; overflow:visible;
    display:flex; flex-direction:column;
  }
  /* The whole point of the flex column above. */
  .product .buy{ margin-top:auto; }
  .product:hover{ transform:translateY(-5px); box-shadow:0 14px 28px rgba(60,52,48,0.1); }

  /* product mascot wrapper — no overflow clipping */
  .product-img-wrap{
    width:130px; height:130px;
    margin:0 auto 14px;
    display:flex; align-items:center; justify-content:center;
    position:relative;
    overflow:visible; /* KEY: don't clip */
  }
  .product-img-wrap img{
    width:100%; height:auto; display:block;
    filter: drop-shadow(0 8px 10px rgba(60,52,48,0.2));
    transition: filter 0.2s ease;
  }
  /* coupon reveal on hover */
  .product:hover .product-img-wrap img{
    animation: cardHoverAnim 0.5s ease-in-out forwards;
  }
  @keyframes cardHoverAnim{
    0%  { transform: scale(1) rotate(0deg); }
    25% { transform: scale(1.15,0.9) rotate(-4deg); }
    55% { transform: scale(0.92,1.12) rotate(3deg) translateY(-8px); }
    75% { transform: scale(1.05,0.97) rotate(-1deg) translateY(-4px); }
    100%{ transform: scale(1) rotate(0deg) translateY(0); }
  }

  /* coupon tooltip */
  /* The wrapper is only 130px wide, so a coupon tip centred with
     translateX(-50%) spilled well past the card on a two-up mobile grid. Auto
     margins centre it instead, which frees `transform` for the scale-in and
     lets max-width clamp a long code to the card. The arrow keeps its own
     translate — it is centred on the tip, which is the one place the trick is
     the right tool. */
  .coupon-tip{
    position:absolute; top:-36px; left:50%;
    transform:translateX(-50%) scale(0.8);
    /* WITHOUT `width:max-content` this box is sized by its containing block —
       .product-img-wrap, 127px — and `left:50%` halves that again, so the tip
       had ~63px to work with and wrapped "🏷️ Use SUNNY10 for 10% off!" onto
       five lines. A 65px-tall slab of solid clay is the "heavy and cheap" the
       owner reported, and it is also the overlap: the rail of stock and drop
       badges sits at top:16px of the card, and a five-line tip grew straight
       down through it. One line is 24px and clears the rail with room to
       spare, so the collision and the look have the same one-word cause.
       max-width still clamps a long coupon code, and now it wraps inside the
       card instead of being the default. */
    width:max-content;
    max-width:min(200px, 92vw);
    /* Outline chip, not a solid block. The saturated fill plus the pop-in
       scale is what read as "intrusive" — it fired on ANY hover of the card
       (`.product:hover`, not just the image) and jumped straight to full size
       with no warning, so glancing at a card threw a bright tag over it. This
       keeps the same information one step quieter: a soft tint instead of
       solid clay, a plain fade with a short delay rather than an instant pop,
       and only the image itself as the trigger — a shopper reading the name
       or price below no longer summons it. */
    background:var(--cream); color:var(--clay); border:1.5px solid var(--clay);
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.7rem;
    padding:4px 12px; border-radius:100px; text-align:center;
    opacity:0; pointer-events:none;
    transition: opacity 0.25s ease 0.15s, transform 0.25s ease 0.15s;
    z-index:10;
  }
  .coupon-tip::after{
    content:''; position:absolute; top:100%; left:50%; transform:translateX(-50%);
    border:5px solid transparent; border-top-color:var(--clay);
  }
  .product-img-wrap:hover .coupon-tip{ opacity:1; transform:translateX(-50%); }

  .product .name{ font-family:'Fredoka', sans-serif; font-weight:600; font-size:1rem; margin-bottom:2px; }
  .product .desc{ font-size:0.82rem; color:#8a8073; margin-bottom:2px; }
  .product .size{ font-size:0.72rem; color:#a49a8c; margin-bottom:10px; }
  .product .price{ font-family:'Fredoka', sans-serif; font-weight:600; color:var(--clay); font-size:0.95rem; margin-bottom:14px; }

  /* A markdown, said out loud. The old price is struck through and stepped
     back; the new one is the loudest thing in the block, because a sale the
     customer has to work out for themselves is not a sale. Written as one
     rule for the card and the quick view so the two can never disagree about
     what a reduced price looks like. */
  .price.on-sale, .qv-price.on-sale{
    display:flex; align-items:baseline; justify-content:center; gap:8px;
  }
  .price.on-sale .was, .qv-price.on-sale .was{
    font-size:0.82em; font-weight:500; color:#a49a8c; text-decoration:line-through;
  }
  .price.on-sale .now, .qv-price.on-sale .now{
    color:#a3316f; font-weight:700; font-size:1.08em;
  }
  /* The quick view's price sits in a left-aligned column, not a centred card. */
  .qv-price.on-sale{ justify-content:flex-start; }
  /* The BUNDLE case renders its own pair of spans (the amount is tweened, so
     it has to survive re-renders) — give them the same treatment as a single's
     .was/.now rather than a second look for the same idea. The gap owns the
     spacing now, so the element's own margin has to go or it doubles up. */
  .qv-price.on-sale .qv-old-price{ margin-right:0; }
  .qv-price.on-sale .qv-amount{ color:#a3316f; }
  .product .buy{
    display:inline-block; width:100%;
    background:var(--cream); border:1.5px solid var(--line); color:var(--ink);
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.85rem;
    padding:10px; border-radius:100px; text-decoration:none; cursor:pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
  }
  .product .buy:hover{ background:var(--sun); border-color:var(--sun-dark); }

  /* ---------- BUNDLES ---------- */
  .bundles{ max-width:1100px; margin:0 auto; padding:10px 24px 70px; }
  .bundle-grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:22px; align-items:start; }
  .bundle-card{
    position:relative; background:var(--paper); border-radius:22px;
    padding:30px 22px 24px; text-align:center; cursor:pointer;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
  }
  .bundle-card:hover{ transform:translateY(-5px); box-shadow:0 14px 28px rgba(60,52,48,0.1); }
  .bundle-card.featured{ background:var(--sage); color:var(--paper); transform:scale(1.04); box-shadow:0 16px 30px rgba(111,143,104,0.28); }
  .bundle-card.featured:hover{ transform:scale(1.04) translateY(-5px); }
  .bundle-card.featured .desc{ color:#eaf1e8; }
  .bundle-card.featured .old{ color:#cfe0cb; }
  .bundle-imgs{ display:flex; justify-content:center; align-items:flex-end; margin-bottom:16px; height:80px; }
  .bundle-imgs img{ width:68px; margin-left:-16px; filter:drop-shadow(0 6px 8px rgba(60,52,48,0.18)); transform-origin:center bottom; }
  .bundle-imgs img:first-child{ margin-left:0; }
  .featured .bundle-imgs img{ width:74px; }

  /* jump for joy — each sunny in a bundle bounces in its own beat when hovered */
  .bundle-card:hover .bundle-imgs img{ animation: jumpForJoy 0.7s ease-in-out infinite; }
  .bundle-card:hover .bundle-imgs img:nth-child(1){ animation-delay:0s; }
  .bundle-card:hover .bundle-imgs img:nth-child(2){ animation-delay:0.1s; }
  .bundle-card:hover .bundle-imgs img:nth-child(3){ animation-delay:0.2s; }
  .bundle-card:hover .bundle-imgs img:nth-child(4){ animation-delay:0.3s; }
  @keyframes jumpForJoy{
    0%, 100%{ transform: translateY(0) rotate(0deg) scale(1,1); }
    30%{ transform: translateY(-16px) rotate(-6deg) scale(0.96,1.06); }
    50%{ transform: translateY(-20px) rotate(0deg) scale(1.02,0.96); }
    70%{ transform: translateY(-10px) rotate(6deg) scale(0.98,1.04); }
  }
  @media(prefers-reduced-motion:reduce){
    .bundle-card:hover .bundle-imgs img{ animation:none; }
  }
  .badge{ display:inline-block; background:var(--sun); color:#5a3800; text-shadow:none; font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.72rem; padding:5px 12px; border-radius:100px; margin-bottom:12px; }
  /* Same centring rule as the drop badge: auto margins inside a full-width
     inset, so "most loved · save 20%" cannot overhang the card on a narrow
     screen the way translateX(-50%) let it. */
  .badge.featured-badge{
    position:absolute; top:-13px; left:0; right:0;
    margin-inline:auto; margin-bottom:0;
    width:max-content; max-width:calc(100% - 24px);
    text-align:center;
    background:var(--clay); color:var(--paper);
  }
  .bundle-card .name{ font-family:'Fredoka', sans-serif; font-weight:600; font-size:1.05rem; margin-bottom:2px; }
  .bundle-card .desc{ font-size:0.83rem; color:#8a8073; margin-bottom:12px; }
  .price-row{ display:flex; justify-content:center; align-items:baseline; gap:8px; margin-bottom:16px; }
  .price-row .old{ font-size:0.85rem; color:#a49a8c; text-decoration:line-through; }
  .price-row .price{ font-family:'Fredoka', sans-serif; font-weight:700; font-size:1.2rem; color:var(--clay); }
  .featured .price-row .price{ color:var(--paper); }
  .bundle-card .buy{ display:inline-block; width:100%; background:var(--cream); border:1.5px solid var(--line); color:var(--ink); font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.85rem; padding:11px; border-radius:100px; text-decoration:none; cursor:pointer; transition: background 0.15s ease, border-color 0.15s ease; }
  .bundle-card .buy:hover{ background:var(--sun); border-color:var(--sun-dark); }
  .featured-buy{ background:var(--paper)!important; border-color:var(--paper)!important; color:var(--sage-dark)!important; }
  .featured-buy:hover{ background:var(--sun)!important; }

  /* ============================================================
     CART DRAWER
  ============================================================ */
  .cart-overlay{
    position:fixed; inset:0; background:rgba(60,52,48,0.45);
    z-index:200; opacity:0; pointer-events:none;
    transition: opacity 0.28s ease;
    backdrop-filter:blur(2px);
  }
  .cart-overlay.open{ opacity:1; pointer-events:all; }

  .cart-drawer{
    position:fixed; top:0; right:0; width:min(440px,100vw);
    height:100dvh; background:var(--paper);
    z-index:201; display:flex; flex-direction:column;
    transform:translateX(100%);
    transition: transform 0.32s cubic-bezier(0.22,1,0.36,1);
    box-shadow:-8px 0 40px rgba(60,52,48,0.12);
  }
  .cart-drawer.open{ transform:translateX(0); }

  .cart-header{
    display:flex; align-items:center; justify-content:space-between;
    padding:22px 24px 18px;
    border-bottom:1px solid var(--line);
    flex-shrink:0;
  }
  .cart-header h3{
    font-family:'Fredoka', sans-serif; font-weight:700; font-size:1.3rem; color:var(--ink);
  }
  .cart-close{
    width:36px; height:36px; border-radius:50%; border:1.5px solid var(--line);
    background:none; font-size:1.1rem; cursor:pointer; display:flex; align-items:center; justify-content:center;
    transition: background 0.15s; color:var(--ink);
  }
  .cart-close:hover{ background:var(--cream); }

  .cart-items{ flex:1; overflow-y:auto; padding:16px 24px; }

  .cart-empty{
    display:flex; flex-direction:column; align-items:center; justify-content:center;
    height:100%; gap:12px; color:#a49a8c; font-family:'Fredoka', sans-serif; font-size:1rem;
  }
  .cart-empty-emoji{ font-size:3rem; }

  .cart-item{
    display:flex; align-items:center; gap:14px;
    padding:14px 0; border-bottom:1px solid var(--line);
  }
  .cart-item-icon{
    width:54px; height:54px; border-radius:14px;
    background:var(--cream); display:flex; align-items:center; justify-content:center;
    font-size:1.8rem; flex-shrink:0; overflow:hidden;
  }
  .cart-item-icon img{ width:46px; height:46px; object-fit:contain; }
  .cart-item-info{ flex:1; }
  .cart-item-name{ font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.95rem; color:var(--ink); }
  .cart-item-price{ font-size:0.85rem; color:var(--clay); font-weight:600; }
  .cart-item-qty{
    display:flex; align-items:center; gap:8px; margin-top:4px;
  }
  .qty-btn{
    width:32px; height:32px; border-radius:50%; border:1.5px solid var(--line);
    background:var(--cream); font-size:0.9rem; cursor:pointer; display:flex; align-items:center; justify-content:center;
    color:var(--ink); font-weight:700; transition: background 0.1s;
  }
  .qty-btn:hover{ background:var(--sun); border-color:var(--sun-dark); }
  .qty-val{ font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.9rem; min-width:18px; text-align:center; }
  .cart-item-remove{
    background:none; border:none; color:#8a8078; font-size:1.15rem; cursor:pointer;
    width:36px; height:36px; display:flex; align-items:center; justify-content:center;
    transition: color 0.15s;
  }
  .cart-item-remove:hover{ color:var(--clay); }
  @media(max-width:640px){
    .qty-btn{ width:38px; height:38px; }
    .cart-item-remove{ width:40px; height:40px; }
  }

  /* coupon section */
  .cart-coupon{
    padding:14px 24px;
    border-top:1px solid var(--line);
    flex-shrink:0;
  }
  .coupon-row{ display:flex; gap:8px; }
  .coupon-input{
    flex:1; padding:10px 14px; border:1.5px solid var(--line);
    border-radius:100px; font-family:'Nunito', sans-serif; font-size:0.9rem;
    background:var(--cream); color:var(--ink); outline:none;
    transition: border-color 0.15s;
  }
  .coupon-input:focus{ border-color:var(--sun-dark); }
  .coupon-apply{
    padding:10px 18px; border-radius:100px;
    background:var(--sage); color:var(--paper);
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.9rem;
    border:none; cursor:pointer; transition: background 0.15s, transform 0.1s;
    white-space:nowrap;
  }
  .coupon-apply:hover{ background:var(--sage-dark); transform:translateY(-1px); }
  .coupon-msg{ font-size:0.82rem; margin-top:7px; padding-left:6px; min-height:18px; }
  .coupon-msg.ok{ color:var(--sage-dark); }
  .coupon-msg.err{ color:var(--clay); }

  /* cart footer */
  .cart-footer{
    padding:20px 24px 28px;
    border-top:1px solid var(--line);
    flex-shrink:0;
  }
  /* ---------- CART SUMMARY (was the checkout modal) ---------- */
  /* Subtotal and each discount, itemised in the drawer. Only rendered when
     there is actually something to explain — on a plain cart a "Subtotal" row
     that merely repeats the total below it is noise. */
  .cart-summary{ margin-bottom:10px; }
  .cart-summary:empty{ display:none; }
  .cart-summary .sum-line{
    display:flex; justify-content:space-between; gap:12px;
    font-size:0.84rem; color:#7a6a58; padding:3px 0;
  }
  .cart-summary .sum-line.save{ color:var(--sage-dark); font-weight:600; }

  .cart-total-row{
    display:flex; justify-content:space-between; align-items:baseline;
    padding-top:9px; border-top:1px solid var(--line); margin-bottom:6px;
  }
  .cart-total-row .label{ font-family:'Fredoka', sans-serif; font-weight:600; font-size:1rem; }
  .cart-total-row .amount{ font-family:'Fredoka', sans-serif; font-weight:700; font-size:1.25rem; color:var(--clay); }

  /* The payoff line the modal used to own. Loud enough to be the reason
     someone finishes, quiet enough not to look like an error. */
  .cart-saved{
    background:var(--sage-soft, #eef3e7); color:var(--sage-dark);
    border-radius:10px; padding:7px 12px; margin-bottom:12px;
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.85rem;
    text-align:center;
  }
  .cart-saved[hidden]{ display:none; }
  /* Automatic free shipping. Two states, both worth showing: the nudge is the
     reason the threshold exists, and the confirmation stops a shopper
     abandoning to go hunting for a shipping code that no longer matters. */
  .cart-shipping-row{ font-size:0.82rem; color:var(--ink-soft, #7a6a58); margin:-6px 0 12px; text-align:right; }
  .cart-shipping-row:empty{ display:none; }
  .cart-shipping-row.earned{ color:var(--sage-dark); font-weight:600; }
  /* Empty-cart escape hatch, so the drawer isn't a dead end */
  .cart-empty-cta{
    margin-top:16px; padding:11px 22px;
    background:var(--cream); border:1.5px solid var(--line); color:var(--ink);
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.85rem;
    border-radius:100px; cursor:pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
  }
  .cart-empty-cta:hover{ background:var(--sun); border-color:var(--sun-dark); }

  .checkout-btn:disabled{
    background:#dcd3c8; color:#fffaf1; box-shadow:0 6px 0 #c9bfb2;
    cursor:not-allowed; transform:none;
  }
  .checkout-btn:disabled:hover{ transform:none; box-shadow:0 6px 0 #c9bfb2; }

  .checkout-btn{
    display:block; width:100%; padding:16px;
    background:var(--clay); color:#fff;
    font-family:'Fredoka', sans-serif; font-weight:700; font-size:1.1rem;
    border:none; border-radius:100px; cursor:pointer; text-align:center;
    box-shadow:0 6px 0 #b85a40;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
  }
  .checkout-btn:hover{ transform:translateY(-3px); box-shadow:0 9px 0 #b85a40; }
  .checkout-btn:active{ transform:translateY(3px); box-shadow:0 3px 0 #b85a40; }

  .cart-checkout-error{
    background:var(--blush, #fdeaea); border:1.5px solid var(--clay);
    color:var(--clay); border-radius:12px; padding:10px 13px;
    font-size:0.82rem; line-height:1.5; margin-bottom:10px;
  }

  .checkout-note{ text-align:center; font-size:0.76rem; color:#a49a8c; margin-top:10px; }

  /* ---------- QUICK VIEW MODAL ---------- */
  .quickview-overlay{
    position:fixed; inset:0; background:rgba(60,52,48,0.6);
    z-index:300; opacity:0; pointer-events:none;
    transition: opacity 0.25s ease; backdrop-filter:blur(4px);
    display:flex; align-items:center; justify-content:center; padding:20px;
  }
  .quickview-overlay.open{ opacity:1; pointer-events:all; }
  .quickview-modal{
    background:var(--paper); border-radius:24px;
    width:100%; max-width:640px; max-height:90dvh; overflow-y:auto;
    padding:28px; box-shadow:0 30px 80px rgba(60,52,48,0.2);
    transform:translateY(20px) scale(0.97);
    transition: transform 0.3s cubic-bezier(0.22,1,0.36,1);
    position:relative;
  }
  .quickview-overlay.open .quickview-modal{ transform:translateY(0) scale(1); }
  .qv-close{
    position:absolute; top:18px; right:18px; z-index:2;
    width:34px; height:34px; border-radius:100px; border:1.5px solid var(--line);
    background:var(--paper); font-size:1.1rem; cursor:pointer; color:var(--ink);
    display:flex; align-items:center; justify-content:center;
    transition: border-color 0.15s ease, transform 0.15s ease;
  }
  .qv-close:hover{ transform:rotate(90deg); border-color:var(--sun-dark); }
  .qv-body{ display:grid; grid-template-columns:1fr 1fr; gap:26px; }
  .qv-gallery{ display:flex; flex-direction:column; gap:12px; }
  .qv-main-img-wrap{
    background:var(--cream); border-radius:18px; padding:20px;
    display:flex; align-items:center; justify-content:center; aspect-ratio:1;
  }
  .qv-main-img-wrap img{ width:80%; max-width:220px; display:block; filter:drop-shadow(0 10px 14px rgba(60,52,48,0.18)); }
  .qv-thumbs{ display:flex; gap:10px; justify-content:center; }
  .qv-thumb{
    width:52px; height:52px; padding:6px; border-radius:12px;
    border:1.5px solid var(--line); background:var(--cream); cursor:pointer;
    object-fit:contain; transition: border-color 0.15s ease, transform 0.15s ease;
  }
  .qv-thumb:hover{ transform:translateY(-2px); }
  .qv-thumb.active{ border-color:var(--sun-dark); background:var(--paper); }
  .qv-info{ display:flex; flex-direction:column; }
  .qv-info .name{
    font-family:'Fredoka', sans-serif; font-weight:700; font-size:1.5rem;
    color:var(--ink); margin-bottom:4px;
  }
  .qv-info .size{ font-size:0.85rem; color:#8a8073; margin-bottom:14px; }
  .qv-info .desc{ font-size:0.92rem; line-height:1.65; color:#6b6055; margin-bottom:18px; }
  .qv-coupon{
    display:inline-block; align-self:flex-start;
    background:var(--sun); color:#5a3800;
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.78rem;
    padding:6px 14px; border-radius:100px; margin-bottom:18px;
  }
  .qv-price{
    font-family:'Fredoka', sans-serif; font-weight:700; font-size:1.5rem;
    color:var(--clay); margin-bottom:18px;
  }
  .qv-old-price{
    font-size:1.05rem; color:#a49a8c; text-decoration:line-through; margin-right:8px;
  }
  .qv-savings{
    display:inline-block; align-self:flex-start;
    background:var(--sage); color:var(--paper);
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.78rem;
    padding:6px 14px; border-radius:100px; margin-bottom:18px;
  }
  .qv-includes{
    margin-bottom:18px;
  }
  .qv-includes-label{
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.82rem;
    color:#8a8073; margin-bottom:8px; text-transform:uppercase; letter-spacing:0.03em;
  }
  .qv-bundle-choice-note{ font-size:0.77rem; color:#a49a8c; margin-top:8px; line-height:1.5; font-style:italic; }
  .qv-include-item{
    display:flex; align-items:center; gap:12px;
    padding:8px 0; border-bottom:1px solid var(--line);
  }
  .qv-include-item:last-child{ border-bottom:none; }
  .qv-include-icon{
    width:38px; height:38px; border-radius:10px; background:var(--cream);
    display:flex; align-items:center; justify-content:center; flex-shrink:0; overflow:hidden;
  }
  .qv-include-icon img{ width:30px; height:30px; object-fit:contain; }
  .qv-include-info{ flex:1; }
  .qv-include-name{ font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.88rem; color:var(--ink); }
  .qv-include-desc{ font-size:0.78rem; color:#a49a8c; }
  .qv-qty-row{
    display:flex; align-items:center; gap:14px; margin-bottom:18px;
  }
  .qv-qty-label{
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.85rem; color:#6b6055;
  }
  .qv-qty-stepper{
    display:flex; align-items:center; gap:10px;
    border:1.5px solid var(--line); border-radius:100px; padding:4px;
  }
  .qv-qty-btn{
    width:34px; height:34px; border-radius:50%; border:none;
    background:var(--cream); font-size:1.05rem; font-weight:700; color:var(--ink);
    cursor:pointer; display:flex; align-items:center; justify-content:center;
    transition: background 0.1s;
  }
  .qv-qty-btn:hover{ background:var(--sun); }
  .qv-qty-val{
    font-family:'Fredoka', sans-serif; font-weight:700; font-size:1rem;
    min-width:22px; text-align:center;
  }
  .qv-buy{
    margin-top:auto; display:inline-flex; align-items:center; justify-content:center; gap:8px;
    background:var(--sage); color:var(--paper);
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:1rem;
    padding:14px; border-radius:100px; border:none; cursor:pointer;
    box-shadow:0 6px 0 var(--sage-dark);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
  }
  .qv-buy:hover{ transform:translateY(-2px); box-shadow:0 8px 0 var(--sage-dark); }
  .qv-buy:active{ transform:translateY(2px); box-shadow:0 3px 0 var(--sage-dark); }

  @media(max-width:560px){
    .qv-body{ grid-template-columns:1fr; }
    .qv-main-img-wrap{ aspect-ratio:auto; padding:26px; }
  }

  /* make product cards feel clickable for quick view, while buy button stays its own target */
  .product{ cursor:pointer; }
  .product .buy{ cursor:pointer; }
  .order-summary-mini{
    background:var(--cream); border-radius:14px; padding:16px;
    margin-bottom:20px; font-size:0.88rem;
  }
  .order-summary-mini .sum-title{
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:1rem;
    margin-bottom:10px; color:var(--ink);
  }
  .sum-line{ display:flex; justify-content:space-between; gap:14px; padding:3px 0; color:#6b6055; }
  .sum-line.total{ font-family:'Fredoka', sans-serif; font-weight:700; color:var(--clay); font-size:1rem; border-top:1px solid var(--line); padding-top:8px; margin-top:4px; }

  /* Undiscounted subtotal, so the savings below have something to subtract from */
  .sum-line.sum-sub{ border-top:1px solid var(--line); padding-top:8px; margin-top:5px; }
  /* Each discount line, green so it reads as money back rather than money owed */
  .sum-line.sum-save{ color:var(--sage-dark); font-weight:600; }
  /* Per-line struck-through original, for bundles */
  .sum-was{ color:#c0b8b0; text-decoration:line-through; margin-right:6px; font-size:0.9em; }

  .sum-saved-banner{
    margin-top:10px; text-align:center;
    background:#eef4ec; color:var(--sage-dark);
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.82rem;
    padding:7px 14px; border-radius:100px;
  }
  .place-order-btn{
    display:block; width:100%; padding:16px;
    background:var(--clay); color:#fff;
    font-family:'Fredoka', sans-serif; font-weight:700; font-size:1.1rem;
    border:none; border-radius:100px; cursor:pointer;
    box-shadow:0 6px 0 #b85a40; margin-top:10px;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
  }
  .place-order-btn:hover{ transform:translateY(-3px); box-shadow:0 9px 0 #b85a40; }
  .modal-close-row{
    display:flex; justify-content:flex-end; margin-bottom:16px;
  }
  .modal-close{
    background:none; border:1.5px solid var(--line);
    border-radius:100px; padding:6px 16px;
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.85rem;
    color:var(--ink); cursor:pointer; transition: background 0.15s;
  }
  .modal-close:hover{ background:var(--cream); }

  /* ---------- INFO & POLICIES ---------- */
  .info{ max-width:760px; margin:0 auto; padding:10px 24px 70px; }
  .info h2{ text-align:center; font-family:'Fredoka', sans-serif; font-weight:600; font-size:1.6rem; margin-bottom:8px; }
  .info-list{ margin-top:26px; display:flex; flex-direction:column; gap:10px; }

  .info-item{
    background:var(--paper); border:1.5px solid var(--line);
    border-radius:16px; overflow:hidden;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
  }
  .info-item[open]{ border-color:var(--sage); box-shadow:0 6px 16px rgba(60,52,48,0.06); }
  .info-item:hover{ border-color:var(--sage); }

  .info-item summary{
    cursor:pointer; list-style:none; padding:16px 20px;
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.98rem;
    display:flex; align-items:center; justify-content:space-between; gap:12px;
  }
  .info-item summary::-webkit-details-marker{ display:none; }
  /* chevron, rotates when the panel opens */
  .info-item summary::after{
    content:''; flex-shrink:0; width:9px; height:9px;
    border-right:2px solid #a49a8c; border-bottom:2px solid #a49a8c;
    transform:rotate(45deg) translate(-2px,-2px);
    transition: transform 0.2s ease;
  }
  .info-item[open] summary::after{ transform:rotate(-135deg) translate(-2px,-2px); }
  .info-item summary:focus-visible{ outline:2px solid var(--sage-dark); outline-offset:-2px; }

  .info-body{ padding:0 20px 18px; font-size:0.9rem; color:#6b6055; line-height:1.7; }
  .info-body p + p{ margin-top:10px; }
  .info-body a{ color:var(--sage-dark); text-decoration:underline; text-underline-offset:2px; }
  .info-body strong{ color:var(--ink); }

  /* target highlight when arriving from a footer anchor */
  .info-item:target{ border-color:var(--clay); box-shadow:0 0 0 3px rgba(224,142,109,0.18); }

  /* ---------- FOOTER ---------- */
  footer{ text-align:center; padding:0 20px 46px; font-size:0.82rem; color:#a49a8c; }
  .footer-note{ margin-top:12px; font-size:0.78rem; color:#a49a8c; font-style:italic; line-height:1.6; }

  /* ---------- SITE FOOTER ---------- */
  .site-footer{
    background:var(--paper);
    border-top:1px solid var(--line);
    padding:50px 24px 28px;
  }
  .site-footer-inner{
    max-width:1100px; margin:0 auto;
    display:grid;
    grid-template-columns:1.3fr 1fr 1fr;
    gap:32px;
  }
  .footer-col h4{
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.78rem;
    letter-spacing:0.08em; text-transform:uppercase;
    color:var(--sage-dark); margin-bottom:14px;
  }
  .footer-col p{
    font-size:0.85rem; color:#6b6055; margin-bottom:10px; line-height:1.5;
  }
  .footer-col p strong{
    display:block; font-family:'Fredoka', sans-serif; font-weight:600;
    color:var(--ink); font-size:0.78rem; margin-bottom:2px;
    text-transform:none; letter-spacing:0;
  }
  .footer-col a{
    color:#6b6055; text-decoration:none; font-size:0.85rem;
  }
  .footer-col a:hover{ color:var(--sun-dark); text-decoration:underline; }
  .footer-links{ display:flex; flex-direction:column; gap:10px; }
  /* Screen-reader-only label. Kept off-screen rather than display:none,
     because display:none removes it from the accessibility tree too. */
  .visually-hidden{
    position:absolute; width:1px; height:1px; padding:0; margin:-1px;
    overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
  }

  /* ---------- FOOTER SUBSCRIBE ---------- */
  /* Sits ABOVE the Contact columns, so it divides with a bottom border.
     A top border here would double up against the footer's own top edge. */
  .footer-subscribe{
    max-width:1100px; margin:0 auto 30px; padding-bottom:28px;
    border-bottom:1px solid var(--line); text-align:center;
  }
  .footer-subscribe[hidden]{ display:none; }
  .subscribe-copy h4{
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:1.05rem;
    color:var(--ink); margin-bottom:14px;
  }
  .subscribe-form{
    display:flex; gap:8px; justify-content:center;
    max-width:420px; margin:0 auto; flex-wrap:wrap;
  }
  .subscribe-form input{
    flex:1 1 220px; min-width:0; padding:11px 16px;
    border:1.5px solid var(--line); border-radius:100px;
    font-family:'Nunito', sans-serif; font-size:0.9rem;
    background:var(--paper); color:var(--ink); outline:none;
    transition: border-color 0.15s ease;
  }
  .subscribe-form input:focus{ border-color:var(--sun-dark); }
  .subscribe-form input:disabled{ opacity:0.6; cursor:not-allowed; }
  .subscribe-form button{
    flex:0 0 auto; padding:11px 24px; border:none; border-radius:100px;
    background:var(--sage); color:var(--paper); cursor:pointer;
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.88rem;
    box-shadow:0 4px 0 var(--sage-dark);
    transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
  }
  .subscribe-form button:hover:not(:disabled){
    transform:translateY(-2px); box-shadow:0 6px 0 var(--sage-dark);
  }
  .subscribe-form button:active:not(:disabled){
    transform:translateY(2px); box-shadow:0 2px 0 var(--sage-dark);
  }
  .subscribe-form button:disabled{
    background:#cfd8cb; box-shadow:0 4px 0 #b6c0b2; cursor:not-allowed;
  }
  .subscribe-form button:focus-visible,
  .subscribe-form input:focus-visible{ outline:2px solid var(--sage-dark); outline-offset:2px; }

  /* Reserve the line's height so a message appearing does not shove the
     footer down and shift what the reader was looking at. */
  .subscribe-msg{
    min-height:20px; margin-top:10px;
    font-size:0.8rem; line-height:1.5;
  }
  .subscribe-msg.ok{ color:var(--sage-dark); }
  .subscribe-msg.err{ color:var(--clay); }

  @media (prefers-reduced-motion: reduce){
    .subscribe-form button:hover:not(:disabled),
    .subscribe-form button:active:not(:disabled){ transform:none; }
  }

  .footer-marketplaces{
    max-width:1100px; margin:30px auto 0; padding-top:26px;
    border-top:1px solid var(--line); text-align:center;
  }
  .footer-marketplaces-label{
    display:block; font-size:0.78rem; color:#a49a8c;
    letter-spacing:0.06em; text-transform:uppercase; margin-bottom:14px;
  }
  .footer-marketplace-links{
    display:flex; gap:8px; flex-wrap:wrap; justify-content:center;
  }
  .site-footer-bottom{
    max-width:1100px; margin:34px auto 0; padding-top:20px;
    border-top:1px solid var(--line);
    text-align:center; font-size:0.78rem; color:#a49a8c;
  }
  @media(max-width:700px){
    .site-footer-inner{ grid-template-columns:1fr; gap:28px; text-align:center; }
    .footer-links{ align-items:center; }
  }

  /* ---------- MOBILE ---------- */
  @media(max-width:640px){
    .nav{ flex-wrap:wrap; row-gap:10px; padding:12px 16px; }
    .nav-brand{ order:1; }
    .nav-right{ order:2; }
    .nav-links{
      order:3; width:100%;
      gap:8px; flex-wrap:wrap; justify-content:center;
    }
    .nav-link{ padding:11px 13px; font-size:0.82rem; }
    .hero{ padding:40px 18px 20px; }
    .icon-wrap{ width:120px; }
    .sub{ font-size:0.96rem; }
    .cta-main{ width:100%; justify-content:center; }
    .shop{ padding:30px 16px 50px; }
    .grid{ grid-template-columns:repeat(2,1fr); gap:14px; }
    .product{ padding:18px 12px 14px; }
    .bundles{ padding:10px 16px 50px; }
    .bundle-grid{ grid-template-columns:1fr; }
    .bundle-card.featured{ transform:none; order:-1; }
    .bundle-card.featured:hover{ transform:translateY(-5px); }
    .form-row{ grid-template-columns:1fr; }
  }

  /* ---- New Drop card badge ---- */
  .new-drop-card{
    position:relative;
  }
  /* Centred by auto margins between left:0 and right:0, NOT by
     translateX(-50%). The translate trick centres the box on a point and then
     lets it grow past the card in both directions, so a longer label (or a
     narrow phone column) hangs off the edge — and it also occupies `transform`,
     which is why the pulse below had to keep re-stating the translation.
     `width:max-content` + `max-width` keeps a long label inside the card and
     lets it wrap instead. */
  /* Only until the database answers. This badge is baked into the markup on
     ONE card, so it says "new drop" about that plush forever — including
     after the drop ends, which is what shoppers saw and reported. It is the
     first-paint floor (crawlers, no-JS, a failed /drops request) and nothing
     more: `body.drops-live` retires it and the live `.drop-badge` written by
     applyDropsToDom() takes over, in the same style every other card wears. */
  body.drops-live .new-drop-card::before{ content:none; }
  .new-drop-card::before{
    content:'🔥 NEW DROP';
    position:absolute; top:-14px; left:0; right:0;
    margin-inline:auto;
    width:max-content; max-width:calc(100% - 20px);
    background:linear-gradient(90deg,#ff6b6b,#ff8e53);
    color:#fff; font-family:'Fredoka',sans-serif; font-weight:700;
    font-size:0.7rem; padding:5px 14px; border-radius:100px;
    text-align:center; letter-spacing:0.06em;
    box-shadow:0 3px 10px rgba(255,80,50,0.35);
    z-index:4;
    animation: newDropBadge 2.5s ease-in-out infinite;
  }
  @keyframes newDropBadge{
    0%,100%{ transform:scale(1); }
    50%{ transform:scale(1.06); }
  }

  .new-drop-highlight, .price-highlight{
    animation: attentionPulse 1.8s ease-in-out 2 !important;
  }
  @keyframes attentionPulse{
    0%, 100% { box-shadow:0 0 0 2.5px #ff6b6b, 0 8px 24px rgba(255,107,107,0.18); }
    50%      { box-shadow:0 0 0 6px #ff6b6b55, 0 8px 28px rgba(255,107,107,0.32); }
  }

  /* ---------- REDUCED MOTION (catch-all) ----------
     Two partial blocks above covered only reveal/hero/mascot/tag and the bundle
     hover jump — leaving heroFloat's siblings, shadowPulse, limitedPulse,
     cardHoverAnim, newDropBadge and attentionPulse still animating. This blanket
     rule covers those and anything added later, so new animations can't quietly
     reintroduce the problem. Every keyframe here starts and ends on the same
     values, so completing them instantly lands on the correct resting state.
     The explicit .reveal rule above is kept deliberately: it guarantees content
     is visible even if the IntersectionObserver never runs. */
  @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;
    }
  }

  /* ---------- AVAILABILITY: STOCK / PREORDER BADGES ---------- */
  /* The badges hang off the card now (see .badge-rail), not off this box. It
     stays position:relative because the bundle images are laid out against it. */
  .bundle-imgs{ position:relative; }

  /* ---------- THE BADGE RAIL ----------
     Every badge a card can wear — stock, low stock, preorder, and the live
     drop states — hangs off ONE flex row rather than each one owning a corner.
     That is the fix for the off-centre "sale" tag: the badges used to be
     independently absolutely positioned (`left:50%` for stock, `left:10px` for
     drop), so a card carrying both showed one centred and one visibly not, and
     each one's centring depended on its own text length.
     The rail is the positioned thing; the badges are ordinary in-flow children
     of a centred, wrapping flex row. That makes the group centre as a group,
     for any number of badges and any label length, and a badge too long for
     the card wraps onto a second line instead of hanging off the side.

     The rail hangs off the CARD, not off the image wrapper. The wrapper is only
     130px wide, so a card wearing two badges ("sale −21%" and "only 2 left")
     wrapped them onto two rows and pushed the second one down over the plush.
     The card is the width the badges are allowed to use, so the card is what
     they are measured against; the two `top` values below are the only numbers
     involved, and each reproduces exactly where that card's badges already
     sat. */
  .badge-rail{
    position:absolute; left:12px; right:12px;
    display:flex; flex-wrap:wrap; justify-content:center; align-items:center;
    gap:5px;
    z-index:12; pointer-events:none;
  }
  /* Level with the top of the image, which is where these have always sat. */
  .product .badge-rail{ top:16px; }
  .bundle-card .badge-rail{ top:20px; }
  /* Nothing to show — do not reserve the row. */
  .badge-rail:empty{ display:none; }

  .stock-badge,
  .drop-badge{
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.68rem;
    padding:4px 11px; border-radius:100px;
    /* Wrap rather than run off a narrow card. max-width is relative to the
       rail, so this holds at every breakpoint without a media query. */
    max-width:100%; text-align:center;
    letter-spacing:0.01em;
    box-shadow:0 2px 6px rgba(60,52,48,0.14);
  }
  .stock-badge:empty,
  .drop-badge:empty{ display:none; }
  .stock-badge.in_stock{ display:none; }
  .stock-badge.sold_out,
  .stock-badge.unavailable{ background:#8a8073; color:var(--paper); }
  .stock-badge.preorder{ background:var(--clay); color:#fff; }
  .stock-badge.low{ background:var(--drop-accent); color:#fff; }

  /* ---------- DROP STATE BADGES ----------
     Painted by js/app.js from the `drops` view, so any number of products can
     be upcoming, new or on sale at once — the ::before badge above is the
     single build-time hero flag and stays what it is. */
  .drop-badge{
    font-weight:700; font-size:0.66rem;
    letter-spacing:0.05em; text-transform:uppercase; color:#fff;
    box-shadow:0 2px 6px rgba(60,52,48,0.18);
  }
  .drop-badge.upcoming{ background:#2f8f63; }
  .drop-badge.new{ background:linear-gradient(90deg,#ff6b6b,#ff8e53); }
  .drop-badge.sale{ background:#7a3c8f; }

  /* Sold-out cards stay visible and keep their link value; they just read as
     unavailable. Hiding them would break deep links and lose the SEO. */
  .product.is-sold-out img,
  .bundle-card.is-sold-out .bundle-imgs img{ filter:grayscale(0.85) opacity(0.55); }
  .product.is-sold-out .price,
  .bundle-card.is-sold-out .price{ color:#a49a8c; }
  .product.is-sold-out:hover{ transform:none; box-shadow:none; }
  .product.is-sold-out:hover img{ animation:none; }

  .buy:disabled{
    background:#f0eae0; color:#a49a8c; border-color:#e4dbcc;
    cursor:not-allowed;
  }
  .buy:disabled:hover{ background:#f0eae0; border-color:#e4dbcc; transform:none; }

  /* Caption under the button, not a badge on the card — see buyPreorderNote()
     in app.js. Same clay as the old top-rail badge so it still reads as the
     same fact, just placed where the decision is made. */
  /* Absolutely positioned, so it takes NO flow height. In flow it would sit
     after the button and therefore be the thing `margin-top:auto` pushed to
     the bottom — which would lift a preorder card's button 24px above every
     other button in the row, trading one misalignment for another. The card's
     26px bottom padding is what this sits in. */
  .buy-preorder-note{
    position:absolute; left:18px; right:18px; bottom:5px;
    text-align:center;
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.72rem;
    color:var(--clay);
  }
  .buy-preorder-note[hidden]{ display:none; }

  /* ---------- QUICK VIEW AVAILABILITY LINE ---------- */
  .qv-availability{
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.8rem;
    margin-bottom:10px; letter-spacing:0.01em;
  }
  .qv-availability.in_stock{ color:var(--sage-dark); }
  .qv-availability.preorder{ color:var(--clay); }
  .qv-availability.sold_out,
  .qv-availability.unavailable{ color:#8a8073; }

  /* ---------- HYDRATION FAILURE BANNER ---------- */
  /* Shown only when Supabase is configured but unreachable, i.e. we cannot
     vouch for the prices on screen. Ordering is disabled behind it. */
  .hydration-banner{
    text-align:center; background:#8a4a3c; color:#fff;
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.9rem;
    padding:11px 20px; line-height:1.5;
  }

  /* ============================================================
     BUNDLE PICKER — selectable plushes
     ============================================================ */
  .qv-picker{ margin:14px 0 16px; }

  .qv-picker-head{
    display:flex; align-items:center; justify-content:space-between;
    gap:12px; margin-bottom:10px;
  }
  .qv-picker-label{
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.86rem; color:var(--ink);
  }
  .qv-picker-count{
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.74rem;
    padding:4px 11px; border-radius:100px; white-space:nowrap;
    background:var(--cream); color:#8a8073; border:1.5px solid var(--line);
    transition: background 0.25s ease, color 0.25s ease, border-color 0.25s ease;
  }
  .qv-picker-count.complete{
    background:var(--sage); color:var(--paper); border-color:var(--sage-dark);
  }

  .qv-picker-grid{
    display:grid; grid-template-columns:repeat(3, 1fr); gap:9px;
  }

  .qv-pick{
    position:relative; display:flex; flex-direction:column; align-items:center; gap:3px;
    padding:12px 6px 9px; border-radius:14px;
    background:var(--paper); border:2px solid var(--line);
    font-family:'Nunito', sans-serif; text-align:center;
    cursor:grab;
    transition: border-color 0.2s ease, background 0.2s ease,
                transform 0.22s cubic-bezier(0.34, 1.56, 0.64, 1),
                box-shadow 0.22s ease;
  }
  .qv-pick:active{ cursor:grabbing; transform:scale(0.96); }
  .qv-pick:hover:not(:disabled){
    border-color:var(--sage); transform:translateY(-3px);
    box-shadow:0 8px 16px rgba(60,52,48,0.10);
  }
  .qv-pick:focus-visible{ outline:2px solid var(--sage-dark); outline-offset:2px; }

  .qv-pick img{
    width:46px; height:46px; object-fit:contain;
    transition: transform 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
  }
  .qv-pick-name{
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.76rem;
    color:var(--ink); line-height:1.2;
  }
  .qv-pick-price{ font-size:0.7rem; color:#a49a8c; }
  /* A reduced pick, said the same way as everywhere else — the tile is where
     the choice is made, so it is where the markdown has to be legible. Flex
     with a gap rather than a margin, so the pair stays centred in the tile at
     any tile width. */
  .qv-pick-price.on-sale{
    display:flex; align-items:baseline; justify-content:center;
    flex-wrap:wrap; gap:5px;
  }
  .qv-pick-price.on-sale .was{ text-decoration:line-through; color:#c0b8b0; }
  .qv-pick-price.on-sale .now{ color:#a3316f; font-weight:700; }
  .qv-pick.picked .qv-pick-price.on-sale .now{ color:var(--sage-dark); }
  /* Preorder marker on a picker tile. Small, but it has to be visible at the
     moment of choosing, not after. */
  .qv-pick-pre{
    display:block; margin-top:2px; font-size:0.6rem; letter-spacing:0.04em;
    text-transform:uppercase; color:var(--clay); font-weight:700;
  }
  /* The disclosure itself. Amber rather than red: this is information the
     buyer needs, not a failure. */
  .qv-preorder-note{
    background:#fdf4e3; border:1.5px solid #e6c27a; color:#7a5a1e;
    border-radius:12px; padding:9px 12px; margin:10px 0 4px;
    font-size:0.8rem; line-height:1.5;
  }
  .qv-preorder-note[hidden]{ display:none; }
  .cart-item-pre{
    font-size:0.7rem; color:#8a6a2e; background:#fdf4e3;
    border-radius:7px; padding:3px 7px; margin-top:3px; display:inline-block;
    line-height:1.4;
  }

  /* selected */
  .qv-pick.picked{
    border-color:var(--sage-dark); background:#f2f7f0;
    box-shadow:0 6px 14px rgba(111,143,104,0.18);
  }
  .qv-pick.picked img{ transform:scale(1.12); }
  .qv-pick.picked .qv-pick-price{ color:var(--sage-dark); font-weight:700; }

  /* the order number tells you which pick was which, so removing one is predictable */
  .qv-pick-order{
    position:absolute; top:-8px; right:-8px;
    width:22px; height:22px; border-radius:100px;
    background:var(--sage-dark); color:#fff;
    font-family:'Fredoka', sans-serif; font-weight:700; font-size:0.72rem;
    display:flex; align-items:center; justify-content:center;
    box-shadow:0 2px 6px rgba(60,52,48,0.22);
    opacity:0; transform:scale(0.4);
    transition: opacity 0.2s ease, transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1);
  }
  .qv-pick.picked .qv-pick-order{ opacity:1; transform:scale(1); }

  /* sold out */
  .qv-pick:disabled,
  .qv-pick.unavailable{
    cursor:not-allowed; opacity:0.5; background:var(--cream);
  }
  .qv-pick:disabled img{ filter:grayscale(0.9); }
  .qv-pick:disabled:hover{ transform:none; box-shadow:none; border-color:var(--line); }

  /* price + savings */
  .qv-price-from{ font-size:0.8rem; color:#a49a8c; font-weight:400; }
  .qv-old-price{
    font-size:0.9rem; color:#c0b8b0; text-decoration:line-through;
    margin-right:9px; font-weight:400;
  }
  .qv-savings{
    display:inline-block;
    font-family:'Fredoka', sans-serif; font-weight:600; font-size:0.78rem;
    color:var(--sage-dark); background:#eef4ec;
    padding:5px 13px; border-radius:100px; margin-bottom:12px;
    transition: transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1), background 0.25s ease;
  }
  .qv-savings.bump{ animation: savingsBump 0.42s cubic-bezier(0.34, 1.56, 0.64, 1); }
  @keyframes savingsBump{
    0%{ transform:scale(1); }
    40%{ transform:scale(1.12); background:var(--sage); color:#fff; }
    100%{ transform:scale(1); }
  }

  @media(max-width:560px){
    .qv-picker-grid{ grid-template-columns:repeat(2, 1fr); }
  }

  /* ============================================================
     REVIEWS
     ============================================================ */
  /* Star glyphs are text characters, not emoji: they inherit colour and font
     so they sit in the type rather than on top of it. */
  .stars{ display:inline-flex; gap:1px; line-height:1; }
  .stars .star{ color:#e0d8cc; font-size:0.92rem; }
  .stars .star.on{ color:var(--sun-dark); }
  .stars .star.half{
    background:linear-gradient(90deg, var(--sun-dark) 50%, #e0d8cc 50%);
    -webkit-background-clip:text; background-clip:text; color:transparent;
  }
  .stars.sm .star{ font-size:0.82rem; }

  /* Card rating row. Empty when a product has no approved reviews — an empty
     star row would read as "rated zero", which is worse than silence. */
  .card-rating{ display:flex; align-items:center; gap:6px; justify-content:center;
    min-height:0; margin:2px 0 0; }
  .card-rating:empty{ display:none; }
  .rating-count{ font-size:0.74rem; color:#a49a8c; }

  /* Reviews are their own SECTION below the buy button, not part of the
     product panel — so they span the full modal width instead of being
     squeezed into the right-hand column. */
  /* .quickview-modal is a padded block, not a grid, so the section breaks out
     of that 28px padding with negative margins. That lets the divider run the
     full width of the modal instead of floating inside a gutter. */
  .qv-reviews{
    margin:26px -28px -28px;
    padding:22px 28px 28px;
    border-top:1.5px solid var(--line);
    background:var(--cream);
    border-radius:0 0 24px 24px;
  }
  .qv-reviews .rv-item{ background:var(--paper); }
  .qv-reviews-head{ display:flex; align-items:baseline; justify-content:space-between;
    gap:12px; margin-bottom:14px; flex-wrap:wrap; }
  .qv-reviews-title{ font-family:'Fredoka',sans-serif; font-weight:600; font-size:1.05rem; }
  .qv-reviews-summary{ display:flex; align-items:center; gap:7px; }

  /* Compact rating under the product title. A button because it scrolls. */
  .qv-rating-inline{
    display:inline-flex; align-items:center; gap:7px;
    background:none; border:none; padding:2px 0; margin-bottom:4px;
    cursor:pointer; font-family:inherit;
    border-bottom:1px solid transparent;
    transition:border-color .15s ease;
  }
  .qv-rating-inline:hover{ border-bottom-color:var(--sun-dark); }
  .qv-rating-inline:focus-visible{ outline:2px solid var(--sage-dark); outline-offset:2px; border-radius:4px; }

  /* No max-height/scroll: the section owns the modal's own scroll now, so a
     nested scroll area would trap the wheel. Pagination handles length. */
  .qv-reviews-list{ display:flex; flex-direction:column; gap:10px; margin-bottom:12px; }
  .rv-item{ background:var(--cream); border-radius:12px; padding:11px 13px; }
  .rv-item:focus{ outline:2px solid var(--sage); outline-offset:2px; }
  .rv-item-head{ display:flex; align-items:center; gap:8px; margin-bottom:5px; flex-wrap:wrap; }
  .rv-author{ font-family:'Fredoka',sans-serif; font-weight:600; font-size:0.8rem; }
  .rv-date{ font-size:0.72rem; color:#a49a8c; }
  /* Verified customer. Green reads as "confirmed" here, but the words carry
     the meaning on their own — the tick is decoration, not the signal. */
  .rv-verified{
    display:inline-flex; align-items:center; gap:4px;
    font-family:'Fredoka',sans-serif; font-weight:600; font-size:0.66rem;
    letter-spacing:.02em; text-transform:uppercase;
    color:#4d6b43; background:rgba(146,168,116,0.22);
    border:1px solid rgba(109,133,86,0.35);
    border-radius:100px; padding:2px 8px; white-space:nowrap;
  }
  .rv-body{ font-size:0.85rem; color:#6b6055; line-height:1.6; }
  /* Owner reply. Indented and rule-marked so it reads as an answer to the
     review above it rather than as another review — a reply that looks like
     a second customer voice is worse than no reply at all. */
  .rv-reply{ margin:10px 0 2px 14px; padding:10px 0 2px 14px; border-left:2px solid var(--sage, #b9c7a8); }
  .rv-reply-head{ display:flex; align-items:baseline; gap:8px; margin-bottom:3px; }
  .rv-reply-author{ font-family:'Fredoka',sans-serif; font-weight:700; font-size:0.8rem; color:var(--clay, #c98a5e); }
  .rv-reply .rv-body{ font-size:0.82rem; }
  .rv-loading,.rv-empty{ font-size:0.84rem; color:#a49a8c; padding:6px 0; }

  /* Load-more, with a chevron drawn in CSS (no emoji, no icon font) */
  .qv-load-more{
    display:flex; align-items:center; justify-content:center; gap:9px;
    width:100%; padding:10px; margin-bottom:16px;
    background:none; border:1.5px dashed var(--line); border-radius:12px;
    font-family:'Fredoka',sans-serif; font-weight:600; font-size:0.82rem;
    color:#8a8073; cursor:pointer;
    transition:border-color .15s ease, color .15s ease, background .15s ease;
  }
  .qv-load-more:hover{ border-color:var(--sage); color:var(--sage-dark); background:var(--cream); }
  .qv-load-more:focus-visible{ outline:2px solid var(--sage-dark); outline-offset:2px; }
  .qv-load-arrow{
    width:8px; height:8px; flex-shrink:0;
    border-right:2px solid currentColor; border-bottom:2px solid currentColor;
    transform:rotate(45deg) translate(-2px,-2px);
    transition:transform .2s ease;
  }
  .qv-load-more:hover .qv-load-arrow{ transform:rotate(45deg) translate(1px,1px); }

  .qv-review-write{ border-top:1.5px solid var(--line); padding-top:16px; }

  .qv-review-toggle{
    background:var(--cream); border:1.5px solid var(--line); color:var(--ink);
    font-family:'Fredoka',sans-serif; font-weight:600; font-size:0.82rem;
    padding:9px 18px; border-radius:100px; cursor:pointer;
    transition:background .15s, border-color .15s;
  }
  .qv-review-toggle:hover{ background:var(--sun); border-color:var(--sun-dark); }

  .qv-review-form{ margin-top:12px; max-width:520px; display:flex; flex-direction:column; gap:9px; }
  .qv-review-form input,.qv-review-form textarea{
    width:100%; padding:10px 13px; border-radius:12px;
    border:1.5px solid var(--line); background:var(--paper);
    font-family:'Nunito',sans-serif; font-size:0.87rem; color:var(--ink); resize:vertical;
  }
  .qv-review-form input:focus,.qv-review-form textarea:focus{
    outline:none; border-color:var(--sage);
  }
  .rv-stars{ display:flex; gap:3px; }
  .rv-star{
    background:none; border:none; padding:0 2px; cursor:pointer;
    font-size:1.5rem; line-height:1; color:#e0d8cc;
    transition:color .12s ease, transform .18s cubic-bezier(0.34,1.56,0.64,1);
  }
  .rv-star:hover{ transform:scale(1.18); }
  .rv-star.on{ color:var(--sun-dark); }
  .rv-star:focus-visible{ outline:2px solid var(--sage-dark); outline-offset:2px; border-radius:4px; }

  .rv-submit{
    background:var(--sage); color:var(--paper); border:none;
    font-family:'Fredoka',sans-serif; font-weight:600; font-size:0.87rem;
    padding:11px; border-radius:100px; cursor:pointer;
    box-shadow:0 4px 0 var(--sage-dark); transition:transform .15s, box-shadow .15s;
  }
  .rv-submit:hover:not(:disabled){ transform:translateY(-2px); box-shadow:0 6px 0 var(--sage-dark); }
  .rv-submit:disabled{ background:#dcd3c8; box-shadow:0 4px 0 #c9bfb2; cursor:not-allowed; }

  .rv-msg{ font-size:0.8rem; min-height:0; }
  .rv-msg:empty{ display:none; }
  .rv-msg.err{ color:#b8563c; }
  .rv-msg.ok{ color:var(--sage-dark); }
  .rv-note{ font-size:0.74rem; color:#a49a8c; text-align:center; }
