@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Instrument+Serif&display=swap');
    *{box-sizing:border-box;margin:0;padding:0}
    /* Inline SVG icons (js/icons.js). Sit on the text baseline and inherit
       colour, which is the whole point of replacing the emoji. */
    .dt-icon{display:inline-block;vertical-align:-0.15em;flex-shrink:0}
    :root{
      --pink:#FF6B81;--peach:#FFD6C9;--bg:#FFF8F6;--text:#2D2D2D;
      /* --muted was #9B8B8E: 3.24:1 on white, under the 4.5:1 AA floor for
         body text, and it is used for every secondary label on the site.
         #786A6D is the same warm grey a few steps darker and clears 4.5:1
         on all three light surfaces (white 5.15, --bg 4.90, --pink-light
         4.66). Dark mode's --muted already passed and is unchanged. */
      --white:#FFFFFF;--muted:#786A6D;--border:#EDD9D3;
      --pink-light:#FFF0F2;--pink-dark:#E8526A;--pink-xlight:#FFF8F9;
      /* Pink for small TEXT. --pink is 2.7:1 on white, fine for fills and
         large type but under AA for a 12px hint or a link. #C7374F is 5.1:1
         on white. Dark mode swaps back to --pink, which reads fine there. */
      --pink-text:#C7374F;
      /* Pink FILL behind white text (buttons, selected chips, map pins).
         White on --pink is 2.7:1, under AA for button labels; #D33F58 is the
         nearest pink that clears 4.5:1 (audit, 2 Oct). Hover goes darker. */
      --pink-fill:#D33F58;--pink-fill-hover:#C7374F;
      /* The one pink word in a heading ("Plan a date"). Headings are large
         text, so 3:1 is the floor; --pink is 2.6:1 on cream, this is 3.4:1.
         Dark mode swaps back to --pink, which is 5.9:1 there. */
      --pink-head:#E8526A;
      --purple:#8B5CF6;--purple-light:#F5F3FF;
      /* Purple for small text (category badges): --purple is 3.9:1 on its
         tint; this is 5.2:1. */
      --purple-text:#7C3AED;
      /* Drinks stops: amber badge, and a node dark enough for a white icon. */
      --amber-bg:#FEF3C7;--amber-text:#92400E;--amber-fill:#D97706;
      /* Free stops' map pins: white number on green, 5.5:1. */
      --green-fill:#047857;
      --green:#10B981;--amber:#F59E0B;--red:#EF4444;
      /* Card-gate banner: dark amber text on pale amber, 7:1. */
      --gate-bg:#FEF3C7;--gate-text:#92400E;--gate-border:#F59E0B;
      /* No-card badge: dark green on pale green. */
      --nocard-bg:#ECFDF5;--nocard-text:#065F46;--nocard-border:#6EE7B7;
      --shadow:0 4px 24px rgba(255,107,129,0.10);
      --shadow-sm:0 2px 12px rgba(255,107,129,0.07);
      --r:20px;--r-sm:12px;--r-lg:28px;
      /* Type scale. Six steps. There were eleven distinct sizes between 10 and
         16px — 13 vs 14 vs 15 is not a decision anyone can see — so everything
         rounds onto these. Sizes above 32px are emoji artwork (deals carry an
         `emoji` column), not type, and stay as literals. */
      --fs-xs:12px;--fs-sm:14px;--fs-md:16px;--fs-lg:20px;--fs-xl:24px;--fs-2xl:32px;
      --nav-bg:rgba(255,248,246,0.96);--on-accent:#FFFFFF;
      /* Display face, headings only. Body, buttons and inputs stay on Inter —
         a serif is wrong for long text and wrong for UI chrome. This is the
         same split Resy, Substack and Eatbook all use. */
      --font-display:'Instrument Serif',Georgia,serif;
    }
    /* DARK MODE — follows system preference by default; the toggle
       button sets data-theme explicitly to override it either way. */
    @media (prefers-color-scheme: dark){
      :root:not([data-theme="light"]){
        --bg:#17151A;--text:#F1E5E7;--white:#221F26;--muted:#B3A4A9;--border:#34303A;
        --pink-light:#3A2530;--pink-xlight:#2A2229;--purple-light:#2A2440;--pink-text:#FF6B81;
        --pink-head:#FF6B81;--purple-text:#A78BFA;--amber-bg:#3A2A10;--amber-text:#FCD34D;
        --shadow:0 4px 24px rgba(0,0,0,0.45);--shadow-sm:0 2px 12px rgba(0,0,0,0.35);
        --nav-bg:rgba(23,21,26,0.92);
        --gate-bg:#3A2A10;--gate-text:#FCD34D;--gate-border:#B45309;
        --nocard-bg:#0F2E24;--nocard-text:#6EE7B7;--nocard-border:#047857;
      }
    }
    :root[data-theme="dark"]{
      --bg:#17151A;--text:#F1E5E7;--white:#221F26;--muted:#B3A4A9;--border:#34303A;
      --pink-light:#3A2530;--pink-xlight:#2A2229;--purple-light:#2A2440;--pink-text:#FF6B81;
      --pink-head:#FF6B81;--purple-text:#A78BFA;--amber-bg:#3A2A10;--amber-text:#FCD34D;
      --shadow:0 4px 24px rgba(0,0,0,0.45);--shadow-sm:0 2px 12px rgba(0,0,0,0.35);
      --nav-bg:rgba(23,21,26,0.92);
      --gate-bg:#3A2A10;--gate-text:#FCD34D;--gate-border:#B45309;
        --nocard-bg:#0F2E24;--nocard-text:#6EE7B7;--nocard-border:#047857;
    }
    html,body{font-family:'Inter',sans-serif;background:var(--bg);color:var(--text);min-height:100vh;font-size:var(--fs-md);line-height:1.6;transition:background 0.2s,color 0.2s}
    /* color matters now that the glyph is an SVG inheriting currentColor —
       a button with no colour set falls back to the UA default (black), which
       is invisible on the dark theme. The emoji used to hide this. */
    .theme-toggle{width:36px;height:36px;border-radius:100px;border:1.5px solid var(--border);background:transparent;color:var(--text);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:var(--fs-md);flex-shrink:0}
    .theme-toggle:hover{border-color:var(--pink)}
    .hidden{display:none!important}
    .page{display:none}
    .page.active{display:block}

    /* NAV */
    /* Above Leaflet. Its controls sit at z-index 1000 and its panes at 400,
       and nothing between them and the page root makes a stacking context, so
       at 200 the nav lost: the map zoom buttons painted over the logo when the
       route map scrolled under the bar, and punched a clickable hole through
       the open hamburger menu. Tapping there zoomed the map instead of
       choosing a page. The toast stays above both at 9998. */
    .nav{background:var(--nav-bg);border-bottom:1px solid var(--border);padding:0 32px;height:64px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:1100;backdrop-filter:blur(8px)}
    .nav-logo{display:flex;align-items:center;gap:10px;cursor:pointer}
    .nav-logo-mark{width:36px;height:36px;display:flex;align-items:center;justify-content:center}
    .nav-logo-mark svg{width:32px;height:32px}
    .nav-brand{font-size:var(--fs-lg);font-weight:800;color:var(--pink);letter-spacing:-0.5px}
    /* Navigation lives entirely in the hamburger menu now, at every width.
       The inline link row is gone, so the nav bar stays clean. */
    .nav-links{display:none}
    .nav-link{padding:8px 14px;border-radius:10px;font-size:var(--fs-sm);font-weight:500;cursor:pointer;border:none;background:transparent;color:var(--muted);font-family:'Inter',sans-serif;transition:all 0.18s}
    .nav-link:hover{background:var(--pink-light);color:var(--pink-text)}
    .nav-link.active{color:var(--pink-text);background:var(--pink-light)}
    /* "List your deal" is a real link to another page, not a button; match it. */
    a.nav-link{display:block;line-height:normal;text-decoration:none}
    .nav-right{display:flex;gap:8px;align-items:center}
    /* Hamburger shows at EVERY width, desktop included. On wide screens it
       sits beside the full nav links as a second way in; the menu it opens
       is the same one, so nothing is hidden from desktop visitors. */
    .nav-hamburger{display:flex;flex-direction:column;justify-content:center;gap:5px;width:36px;height:36px;border:none;background:transparent;cursor:pointer;padding:0}
    /* Inline text button inside an error/notice message (e.g. "resend the
       confirmation email") — looks like a link, behaves like a button. */
    .link-btn{background:none;border:none;padding:0;font:inherit;color:inherit;
              text-decoration:underline;cursor:pointer;font-weight:700}
    .link-btn:hover{opacity:0.75}
    .nav-hamburger span{display:block;width:22px;height:2px;background:var(--text);border-radius:2px;transition:transform 0.2s,opacity 0.2s}
    .nav-hamburger.open span:nth-child(1){transform:translateY(7px) rotate(45deg)}
    .nav-hamburger.open span:nth-child(2){opacity:0}
    .nav-hamburger.open span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
    .nav-mobile-menu{display:none;position:fixed;top:64px;left:0;right:0;background:var(--white);border-bottom:1px solid var(--border);box-shadow:var(--shadow);z-index:1090;padding:12px 16px 20px;flex-direction:column;gap:4px}
    .nav-mobile-menu.open{display:flex}
    .nav-mobile-menu .nav-link{width:100%;text-align:left;padding:12px 14px}
    .nav-mobile-menu .nav-mobile-auth{display:flex;gap:8px;margin-top:10px;padding-top:14px;border-top:1px solid var(--border)}
    .nav-mobile-menu .nav-mobile-auth button,
    .nav-mobile-menu .nav-mobile-auth a{flex:1;text-align:center}
    /* Pages outside the app (js/site-nav.js) use links, not buttons, for
       Sign in / Join free; buttons don't inherit the body's line height. */
    #nav-auth-area a,.nav-mobile-auth a{line-height:normal}
    #nav-auth-area a:not(.nav-user-btn),.nav-mobile-auth a:not(.nav-user-btn){display:inline-block}
    /* On desktop the same menu becomes a tidy right-hand dropdown instead of
       a full-width sheet, which would look odd across a wide screen. */
    @media(min-width:801px){
      .nav-mobile-menu{left:auto;right:24px;width:260px;border:1px solid var(--border);
                       border-radius:var(--r-sm);top:70px;padding:10px}
    }
    @media(max-width:800px){
      /* Sign in / Join free move into the menu on small screens so the bar
         doesn't crowd. (.nav-links is hidden at all widths now.) */
      #nav-auth-area{display:none}
    }
    .btn-ghost{padding:8px 18px;border-radius:10px;font-size:var(--fs-sm);font-weight:600;cursor:pointer;border:1.5px solid var(--border);background:transparent;color:var(--text);font-family:'Inter',sans-serif;transition:all 0.18s}
    .btn-ghost:hover{border-color:var(--pink);color:var(--pink-text)}
    .btn-pink{padding:9px 20px;border-radius:10px;font-size:var(--fs-sm);font-weight:700;cursor:pointer;border:none;background:var(--pink-fill);color:var(--on-accent);font-family:'Inter',sans-serif;transition:all 0.18s}
    .btn-pink:hover{background:var(--pink-fill-hover);transform:translateY(-1px)}
    .btn-pink:active{transform:translateY(0)}
    .btn-outline{padding:9px 20px;border-radius:10px;font-size:var(--fs-sm);font-weight:600;cursor:pointer;border:1.5px solid var(--pink);background:transparent;color:var(--pink-text);font-family:'Inter',sans-serif;transition:all 0.18s}
    .btn-outline:hover{background:var(--pink-light)}

    /* NAV USER BUTTON */
    .nav-user-btn{display:flex;align-items:center;gap:8px;padding:6px 14px 6px 8px;
                  border-radius:100px;border:1.5px solid var(--border);background:var(--white);
                  cursor:pointer;font-family:'Inter',sans-serif;transition:all 0.18s;
                  font-size:var(--fs-sm);font-weight:600;color:var(--text)}
    .nav-user-btn:hover{border-color:var(--pink);color:var(--pink-text)}
    .nav-user-avatar{width:28px;height:28px;border-radius:50%;background:var(--pink-fill);
                     display:flex;align-items:center;justify-content:center;
                     font-size:var(--fs-xs);font-weight:800;color:var(--on-accent);flex-shrink:0}
    .nav-user-chevron{font-size:var(--fs-xs);color:var(--muted);margin-left:2px}

    /* PROFILE PAGE */
    .profile-wrap{max-width:680px;margin:0 auto;padding:40px 24px}
    .profile-header{margin-bottom:32px}
    .profile-header h1{font-size:var(--fs-xl);font-weight:800;letter-spacing:-0.5px;margin-bottom:6px}
    .profile-header p{color:var(--muted);font-size:var(--fs-sm)}
    .profile-avatar-row{display:flex;align-items:center;gap:20px;
                         background:var(--white);border:1px solid var(--border);
                         border-radius:var(--r);padding:24px 28px;margin-bottom:20px;
                         box-shadow:var(--shadow-sm)}
    .profile-avatar-lg{width:72px;height:72px;border-radius:50%;background:var(--pink-fill);
                        display:flex;align-items:center;justify-content:center;
                        font-size:var(--fs-xl);font-weight:800;color:var(--on-accent);flex-shrink:0}
    .profile-avatar-info h2{font-size:var(--fs-lg);font-weight:800;margin-bottom:3px}
    .profile-avatar-info p{font-size:var(--fs-sm);color:var(--muted)}
    .profile-card{background:var(--white);border:1px solid var(--border);border-radius:var(--r);
                  padding:28px;margin-bottom:20px;box-shadow:var(--shadow-sm)}
    .profile-card h3{font-size:var(--fs-sm);font-weight:700;margin-bottom:18px;
                     padding-bottom:14px;border-bottom:1px solid var(--border)}
    .profile-field{margin-bottom:16px}
    .profile-field label{display:block;font-size:var(--fs-xs);font-weight:700;color:var(--muted);
                         text-transform:uppercase;letter-spacing:0.4px;margin-bottom:6px}
    .profile-field input{width:100%;padding:11px 14px;border:1.5px solid var(--border);
                          border-radius:12px;font-size:var(--fs-md);font-family:'Inter',sans-serif;
                          background:var(--bg);color:var(--text);transition:border-color 0.15s}
    .profile-field input:focus-visible{border-color:var(--pink);outline:2px solid var(--pink);outline-offset:2px}
    .profile-field input:focus:not(:focus-visible){outline:none;border-color:var(--pink)}
    .profile-field input[readonly]{background:var(--bg);color:var(--muted);cursor:not-allowed}
    .profile-field-row{display:grid;grid-template-columns:1fr 1fr;gap:12px}
    .profile-save-btn{padding:12px 28px;border-radius:12px;font-size:var(--fs-sm);font-weight:700;
                       cursor:pointer;border:none;background:var(--pink-fill);color:var(--on-accent);
                       font-family:'Inter',sans-serif;transition:all 0.18s}
    .profile-save-btn:hover{background:var(--pink-fill-hover)}
    .profile-save-btn:disabled{background:#ccc;cursor:not-allowed}
    .profile-msg{padding:10px 14px;border-radius:10px;font-size:var(--fs-sm);font-weight:500;
                  margin-top:12px;display:none}
    .profile-msg.ok{background:#DCFCE7;color:#15803D}
    .profile-msg.err{background:#FEE2E2;color:#991B1B}
    .profile-danger-btn{padding:10px 20px;border-radius:10px;font-size:var(--fs-sm);font-weight:700;
                         cursor:pointer;border:1.5px solid var(--border);background:transparent;
                         color:var(--muted);font-family:'Inter',sans-serif;transition:all 0.15s}
    .profile-danger-btn:hover{border-color:var(--red);color:var(--red)}

    /* HERO */
    /* HERO — photo-led. The image carries the page; type sits on top of it,
       left-aligned rather than centred. */
    .hero{position:relative;min-height:min(72vh,620px);display:flex;align-items:flex-end;
          padding:0;margin:0;overflow:hidden;isolation:isolate}
    .hero-media{position:absolute;inset:0;z-index:-1}
    .hero-media img{width:100%;height:100%;object-fit:cover;display:block}
    .hero-media::after{content:'';position:absolute;inset:0;
      background:linear-gradient(to top,rgba(10,8,12,0.92) 0%,rgba(10,8,12,0.65) 45%,rgba(10,8,12,0.25) 100%)}
    .hero-content{position:relative;width:100%;max-width:1100px;margin:0 auto;padding:0 40px 56px;color:#fff}
    .hero h1{font-size:clamp(32px,5.2vw,58px);line-height:1.08;margin-bottom:18px;letter-spacing:-0.015em;color:#fff;max-width:17ch}
    .hero h1 em{color:var(--pink);font-style:normal}
    .hero .nw{white-space:nowrap}
    .hero-sub{font-size:clamp(var(--fs-md),1.6vw,var(--fs-lg));color:rgba(255,255,255,0.82);max-width:54ch;margin:0 0 30px;line-height:1.65}
    .hero-actions{display:flex;gap:14px;justify-content:flex-start;flex-wrap:wrap}
    .hero-proof{margin-top:26px;font-size:var(--fs-sm);color:rgba(255,255,255,0.72);display:flex;gap:10px;flex-wrap:wrap;align-items:center}
    .hero-proof strong{color:#fff;font-weight:800}
    .hero-proof-dot{opacity:0.45}
    .btn-hero-primary{padding:16px 32px;border-radius:14px;font-size:var(--fs-md);font-weight:700;cursor:pointer;border:none;background:var(--pink-fill);color:var(--on-accent);font-family:'Inter',sans-serif;transition:all 0.2s;display:flex;align-items:center;gap:8px}
    .btn-hero-primary:hover{background:var(--pink-fill-hover);transform:translateY(-2px);box-shadow:0 8px 28px rgba(255,107,129,0.35)}
    .btn-hero-secondary{padding:16px 32px;border-radius:14px;font-size:var(--fs-md);font-weight:700;cursor:pointer;border:2px solid var(--border);background:var(--white);color:var(--text);font-family:'Inter',sans-serif;transition:all 0.2s}
    .btn-hero-secondary:hover{border-color:var(--pink);color:var(--pink-text)}

    /* STATS */
    .stats-bar{display:flex;justify-content:center;gap:0;max-width:600px;margin:48px auto 0;background:var(--white);border:1px solid var(--border);border-radius:18px;overflow:hidden;box-shadow:var(--shadow-sm)}
    .stat-item{flex:1;padding:18px 16px;text-align:center;border-right:1px solid var(--border)}
    .stat-item:last-child{border-right:none}
    .stat-num{font-size:var(--fs-lg);font-weight:800;color:var(--pink-text)}
    .stat-lbl{font-size:var(--fs-xs);color:var(--muted);font-weight:500;margin-top:2px}

    /* SECTIONS */
    .section{padding:60px 32px;max-width:1100px;margin:0 auto}
    .section-head{display:flex;align-items:flex-end;justify-content:space-between;margin-bottom:28px}
    .section-title{font-size:var(--fs-xl);font-weight:800;letter-spacing:-0.5px}
    .section-title span{color:var(--pink-head)}
    .section-sub{font-size:var(--fs-sm);color:var(--muted);margin-top:4px}
    .see-all{font-size:var(--fs-sm);font-weight:600;color:var(--pink-text);cursor:pointer;background:none;border:none;font-family:'Inter',sans-serif;display:flex;align-items:center;gap:4px}
    .see-all:hover{text-decoration:underline}

    /* DEAL CARDS */
    .deals-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:20px}
    .deal-card{background:var(--white);border-radius:var(--r);border:1px solid var(--border);overflow:hidden;cursor:pointer;transition:all 0.22s;box-shadow:var(--shadow-sm)}
    .deal-card:hover{transform:translateY(-6px);box-shadow:var(--shadow)}
    .deal-img{height:170px;display:flex;align-items:center;justify-content:center;font-size:52px;position:relative;overflow:hidden;color:var(--pink-dark)}
    .deal-img-overlay{position:absolute;top:10px;left:10px;display:flex;gap:6px;flex-wrap:wrap}
    .deal-tag{background:var(--white);color:var(--text);font-size:var(--fs-xs);font-weight:700;padding:4px 10px;border-radius:100px;border:1px solid var(--border)}
    /* "Needs a UOB card" — shown on every deal card, swipe card, plan stop and
       the deal page. Deliberately loud: the price is only true with the card. */
    .card-gate{display:flex;align-items:center;gap:6px;width:fit-content;max-width:100%;
      background:var(--gate-bg);color:var(--gate-text);border:1.5px solid var(--gate-border);
      font-size:var(--fs-sm);font-weight:800;line-height:1.3;padding:5px 10px;border-radius:8px;margin:4px 0 8px}
    .card-gate-lg{font-size:var(--fs-md);padding:10px 14px;margin:8px 0 14px}
    /* Browse-grid size: a tidy chip under the name rather than a block. The
       list is cut to two banks there ("+3"); the deal page shows them all. */
    /* The opposite of a card gate, on discounted deals anyone can get
       (1-for-1s and % off are where people expect a card). */
    .no-card{display:inline-flex;align-items:center;gap:5px;width:fit-content;
      background:var(--nocard-bg);color:var(--nocard-text);border:1px solid var(--nocard-border);
      font-size:var(--fs-xs);font-weight:700;line-height:1.3;padding:4px 9px;border-radius:7px;margin:4px 0 10px}
    .card-gate-sm{font-size:var(--fs-xs);font-weight:700;padding:4px 9px;gap:5px;border-width:1px;border-radius:7px;margin:4px 0 10px}
    /* "Open now · till 10pm" / "Opens 5pm" on browse cards (openNowHTML()).
       Quiet text, not a badge: the card gate stays the loudest thing. Open
       uses the no-card green, which already reads as "you can go". */
    .open-note{display:flex;align-items:center;gap:5px;font-size:var(--fs-xs);font-weight:600;
      color:var(--muted);margin:-4px 0 10px}
    .open-note.is-open{color:var(--nocard-text)}
    /* The fine print (finePrintHTML()): on every plan stop, closed, and on
       the deal page, open. A native <details>, so it works with no script. */
    .fine-print{margin:10px 0 2px;font-size:var(--fs-xs);color:var(--text);line-height:1.55}
    .fine-print summary{cursor:pointer;font-weight:700;color:var(--pink-text);width:fit-content;
      padding:4px 0;list-style:none}
    .fine-print summary::-webkit-details-marker{display:none}
    .fine-print summary::after{content:' ▾';font-size:10px}
    .fine-print[open] summary::after{content:' ▴'}
    .fine-print ul{margin:6px 0 6px 18px;padding:0}
    .fine-print li{margin-bottom:3px}
    .fine-print p{margin:6px 0 0;color:var(--muted)}
    .fine-print .fine-print-check{font-style:italic}
    .detail-info .fine-print{font-size:var(--fs-sm);background:var(--pink-xlight);border:1px solid var(--border);
      border-radius:var(--r-sm);padding:10px 16px;margin:0 0 20px}
    /* We went: the deal page button, and the "Did you go?" row on a saved
       plan once its date is over. */
    .sidebar-btn.went-btn.went{border-color:var(--green-fill);color:var(--nocard-text)}
    .spc-went{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:8px;font-size:var(--fs-xs);color:var(--muted);font-weight:600}
    .spc-went.is-went{color:var(--nocard-text)}
    .spc-went-btn{font:inherit;font-weight:700;color:var(--nocard-text);background:var(--nocard-bg);
      border:1px solid var(--nocard-border);border-radius:100px;padding:6px 12px;min-height:32px;cursor:pointer}
    /* Datify-only deals: the deal-page banner, the Show code buttons, and the
       full-screen code held up at the counter (showCode() in app.js). Above
       the nav (1100), below toasts (9998). */
    .only-datify{display:flex;align-items:flex-start;gap:8px;width:fit-content;max-width:100%;
      background:var(--pink-light);color:var(--text);border:1.5px solid var(--pink);
      font-size:var(--fs-sm);line-height:1.4;padding:10px 14px;border-radius:10px;margin:8px 0 14px}
    .only-datify svg{color:var(--pink-text);flex-shrink:0;margin-top:2px}
    .sidebar-btn.code{display:flex;align-items:center;justify-content:center;gap:8px;
      border:1.5px solid var(--pink);background:var(--pink-light);color:var(--pink-text)}
    .sidebar-btn.code:hover{background:var(--pink-fill);color:var(--on-accent)}
    .tl-code-btn{display:inline-flex;align-items:center;gap:6px;margin:0 0 8px;padding:6px 12px;border-radius:8px;
      font-size:var(--fs-xs);font-weight:700;font-family:'Inter',sans-serif;cursor:pointer;
      border:1.5px solid var(--pink);background:var(--pink-light);color:var(--pink-text)}
    .tl-code-btn:hover{background:var(--pink-fill);color:var(--on-accent)}
    .code-screen{position:fixed;inset:0;z-index:2000;background:var(--white);color:var(--text);
      overflow-y:auto;display:flex;padding:64px 16px 32px}
    .code-inner{margin:auto;width:100%;max-width:420px;text-align:center}
    .code-close{position:absolute;top:12px;right:12px;width:44px;height:44px;border-radius:50%;
      border:1.5px solid var(--border);background:var(--white);color:var(--text);font-size:26px;line-height:1;cursor:pointer}
    .code-kicker{font-size:var(--fs-sm);font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:8px}
    .code-title{font-family:var(--font-display);font-size:var(--fs-2xl);font-weight:400;line-height:1.15;margin:0 0 10px}
    .code-outlet{display:inline-flex;align-items:center;gap:5px;font-size:var(--fs-sm);color:var(--muted);margin-bottom:10px}
    .code-deal{font-size:var(--fs-xl);font-weight:800;margin-bottom:20px}
    .code-deal span{font-size:var(--fs-sm);font-weight:600;color:var(--muted)}
    .code-big{font-size:clamp(40px,13vw,64px);font-weight:800;letter-spacing:.06em;color:var(--pink-text);
      border:2px dashed var(--pink);border-radius:var(--r);padding:18px 8px;margin-bottom:20px;font-variant-numeric:tabular-nums}
    .code-when{display:flex;justify-content:center;align-items:baseline;gap:14px;font-size:var(--fs-lg);font-weight:700}
    .code-clock{font-variant-numeric:tabular-nums;color:var(--pink-text)}
    .code-note{font-size:var(--fs-xs);color:var(--muted);margin-top:18px}
    .code-outlets{display:flex;flex-direction:column;gap:10px;margin-top:18px}
    .code-outlet-btn{padding:14px;border-radius:12px;border:1.5px solid var(--border);background:var(--white);color:var(--text);
      font-size:var(--fs-md);font-weight:700;font-family:'Inter',sans-serif;cursor:pointer;text-align:left}
    .code-outlet-btn:hover,.code-outlet-btn:focus-visible{border-color:var(--pink)}
    .deal-tag.pink{background:var(--pink-light);color:var(--pink-text);border-color:transparent}
    .deal-save{position:absolute;top:10px;right:10px;width:32px;height:32px;background:var(--white);border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;border:1px solid var(--border);font-size:var(--fs-md);transition:all 0.15s}
    /* Saved = the heart itself fills pink; the circle stays white. Tap again to unsave. */
    .deal-save{color:var(--muted)}
    .deal-save:hover{color:var(--pink);border-color:var(--pink)}
    .deal-save.saved{color:var(--pink);border-color:var(--pink)}
    .deal-save.saved svg{fill:currentColor}
    /* Saved page: ✕ in the heart's place. */
    .deal-remove{position:absolute;top:10px;right:10px;width:32px;height:32px;background:var(--white);border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;border:1px solid var(--border);font-size:var(--fs-sm);color:var(--muted);font-family:inherit;transition:all 0.15s}
    .deal-remove:hover,.deal-remove:focus-visible{color:var(--red);border-color:var(--red);background:var(--pink-light)}
    .deal-body{padding:16px}
    .deal-name{font-size:var(--fs-sm);font-weight:700;margin-bottom:4px;line-height:1.35}
    .deal-loc{font-size:var(--fs-xs);color:var(--muted);display:flex;align-items:center;gap:4px;margin-bottom:10px}
    /* Wraps instead of squeezing: a numeric price ($25.00) and a worded
       discount label ("Up to 26% off") take very different widths, and the
       button needs to stay a full tap target either way rather than shrink. */
    .deal-footer{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:6px 10px}
    .deal-price{font-size:var(--fs-lg);font-weight:800;color:var(--text);flex:1 1 auto;min-width:0}
    .deal-price span{font-size:var(--fs-xs);font-weight:400;color:var(--muted)}
    .deal-cta{background:var(--pink-light);color:var(--pink-text);border:none;border-radius:8px;padding:7px 13px;font-size:var(--fs-xs);font-weight:700;cursor:pointer;font-family:'Inter',sans-serif;transition:all 0.15s;flex-shrink:0;white-space:nowrap}
    .deal-cta:hover{background:var(--pink-fill);color:var(--on-accent)}
    /* Explore → Free to do. Not clickable, so no lift on hover. */
    .free-card{cursor:default}
    .free-card:hover{transform:none;box-shadow:none}
    .free-card-desc{font-size:var(--fs-xs);color:var(--muted);line-height:1.45;margin:0 0 10px;
      display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
    .free-card-dur{display:flex;align-items:center;gap:4px;font-size:var(--fs-xs);color:var(--muted)}

    /* VIBES */
    .vibes-row{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:16px}
    .vibe-card{border-radius:var(--r);border:1px solid var(--border);cursor:pointer;transition:all 0.2s;background:var(--white);overflow:hidden;position:relative}
    .vibe-card:hover,.vibe-card.picked{border-color:var(--pink);transform:translateY(-2px);box-shadow:var(--shadow-sm)}
    .vibe-card img{width:100%;height:132px;object-fit:cover;display:block}
    .vibe-card .vibe-body{padding:14px 16px 16px}
    .vibe-card .vibe-name{font-size:var(--fs-sm);font-weight:700;margin-bottom:3px}
    .vibe-card .vibe-desc{font-size:var(--fs-xs);color:var(--muted)}

    /* HOW IT WORKS */
    .hiw{background:var(--white);border:1px solid var(--border);border-radius:var(--r-lg);padding:48px 40px;text-align:center;margin:40px 32px}
    .hiw h2{font-size:var(--fs-xl);font-weight:800;margin-bottom:8px;letter-spacing:-0.5px}
    .hiw-sub{font-size:var(--fs-sm);color:var(--muted);margin-bottom:36px}
    .hiw-steps{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:24px}
    .hiw-step{padding:16px}
    .hiw-num{width:44px;height:44px;border-radius:14px;background:var(--pink-light);display:flex;align-items:center;justify-content:center;margin:0 auto 14px;font-size:var(--fs-lg);font-weight:800;color:var(--pink-text)}
    .hiw-title{font-size:var(--fs-sm);font-weight:700;margin-bottom:6px}
    .hiw-body{font-size:var(--fs-sm);color:var(--muted);line-height:1.6}

    /* AUTH */
    .auth-wrap{min-height:calc(100vh - 64px);display:flex;align-items:center;justify-content:center;padding:32px 20px}
    .auth-card{background:var(--white);border:1px solid var(--border);border-radius:var(--r-lg);padding:44px 40px;width:100%;max-width:420px;box-shadow:var(--shadow)}
    .auth-logo{text-align:center;margin-bottom:28px}
    .auth-logo .mark{width:52px;height:52px;display:inline-flex;align-items:center;justify-content:center;margin-bottom:12px}
    .auth-logo .mark svg{width:48px;height:48px}
    .auth-title{font-size:var(--fs-lg);font-weight:800;text-align:center;margin-bottom:6px}
    .auth-sub{font-size:var(--fs-sm);color:var(--muted);text-align:center;margin-bottom:28px}
    .social-btns{display:flex;flex-direction:column;gap:10px;margin-bottom:20px}
    .social-btn{display:flex;align-items:center;justify-content:center;gap:10px;padding:12px;border:1.5px solid var(--border);border-radius:12px;font-size:var(--fs-sm);font-weight:600;cursor:pointer;background:var(--white);font-family:'Inter',sans-serif;transition:border-color 0.15s}
    .social-btn:hover{border-color:var(--pink)}
    .divider-row{display:flex;align-items:center;gap:12px;margin:18px 0;color:var(--muted);font-size:var(--fs-sm)}
    .divider-row::before,.divider-row::after{content:'';flex:1;height:1px;background:var(--border)}
    .form-group{margin-bottom:16px}
    .form-label{font-size:var(--fs-sm);font-weight:600;color:var(--text);display:block;margin-bottom:6px}
    /* 16px, not 14: iOS Safari auto-zooms any field below 16px and leaves the
       page zoomed. Focus ring is :focus-visible so keyboard users get a clear
       indicator while mouse clicks look exactly as before. */
    .form-input{width:100%;padding:12px 16px;border:1.5px solid var(--border);border-radius:12px;font-size:var(--fs-md);font-family:'Inter',sans-serif;background:var(--bg);color:var(--text);transition:border-color 0.15s}
    .form-input:focus-visible{border-color:var(--pink);outline:2px solid var(--pink);outline-offset:2px}
    .form-input:focus:not(:focus-visible){outline:none;border-color:var(--pink)}
    .form-row{display:flex;gap:12px}
    .form-row .form-group{flex:1}
    .btn-full{width:100%;padding:14px;border-radius:12px;font-size:var(--fs-sm);font-weight:700;cursor:pointer;border:none;background:var(--pink-fill);color:var(--on-accent);font-family:'Inter',sans-serif;transition:all 0.18s;margin-top:4px}
    .btn-full:hover{background:var(--pink-fill-hover)}
    .btn-full:disabled{background:#ccc;cursor:not-allowed;transform:none}
    /* The line under a form that says what happens to what you just typed.
       Deliberately quiet — it is a notice, not a call to action — but the
       links are the normal pink so they read as links. */
    .form-consent{margin-top:14px;font-size:var(--fs-xs);line-height:1.6;color:var(--muted);text-align:center}
    .form-consent a{color:var(--pink-text);font-weight:600}
    .form-consent a:focus-visible{outline:2px solid var(--pink);outline-offset:2px;border-radius:3px}
    .auth-footer{text-align:center;margin-top:20px;font-size:var(--fs-sm);color:var(--muted)}
    .auth-footer a{color:var(--pink-text);font-weight:600;cursor:pointer}

    /* The "don't count my visits" control on the privacy policy. Sits in a
       tinted box so it reads as a thing you can act on rather than more
       policy text. --white is a surface token and flips in dark mode. */
    .optout-row{margin-top:18px;padding:16px 18px;border:1px solid var(--border);
      border-radius:12px;background:var(--white)}
    .optout-label{display:flex;align-items:center;gap:10px;cursor:pointer;
      font-size:var(--fs-sm);font-weight:600;color:var(--text)}
    .optout-label input[type=checkbox]{width:17px;height:17px;accent-color:var(--pink);
      cursor:pointer;flex:none;margin:0}
    .optout-label input[type=checkbox]:focus-visible{outline:2px solid var(--pink);
      outline-offset:2px}
    .optout-state{margin:8px 0 0 27px;font-size:var(--fs-xs);color:var(--muted)}

    /* AUTH FEEDBACK MESSAGES */
    .auth-error{background:#FEE2E2;color:#991B1B;border:1px solid #FECACA;border-radius:10px;padding:12px 16px;font-size:var(--fs-sm);font-weight:500;margin-bottom:16px;display:none}
    .auth-success{background:#DCFCE7;color:#15803D;border:1px solid #BBF7D0;border-radius:10px;padding:12px 16px;font-size:var(--fs-sm);font-weight:500;margin-bottom:16px;display:none}

    /* PLANNER */
    /* .planner-card is all that survives of the planner page: the cards were
       lifted onto the results page, under the plan. See .plan-tuner below. */
    .planner-card{background:var(--white);border:1px solid var(--border);border-radius:var(--r-lg);padding:36px;box-shadow:var(--shadow-sm);margin-bottom:20px}
    .planner-card h3{font-size:var(--fs-md);font-weight:700;margin-bottom:18px;display:flex;align-items:center;gap:8px}
    .budget-row{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}
    .budget-amount{font-size:var(--fs-xl);font-weight:800;color:var(--pink-text)}
    .budget-max{font-size:var(--fs-sm);color:var(--muted)}
    input[type=range]{-webkit-appearance:none;width:100%;height:6px;background:var(--peach);border-radius:99px;border:none!important;padding:0!important}
    input[type=range]:focus-visible{outline:2px solid var(--pink);outline-offset:4px}
    input[type=range]:focus:not(:focus-visible){outline:none}
    input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:24px;height:24px;background:var(--pink);border-radius:50%;cursor:pointer;border:3px solid white;box-shadow:0 2px 10px rgba(255,107,129,0.4)}
    /* minmax(0,1fr), not 1fr: a grid item's default min-width is auto, and
       input[type=date]/[type=time] have a wide intrinsic size, so 1fr tracks
       refuse to shrink below it and push the page sideways at 375px. */
    .input-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}
    select,input[type=date],input[type=time]{width:100%;padding:12px 14px;border:1.5px solid var(--border);border-radius:12px;font-size:var(--fs-md);font-family:'Inter',sans-serif;background:var(--bg);color:var(--text);appearance:none;-webkit-appearance:none;transition:border-color 0.15s}
    select:focus-visible,input[type=date]:focus-visible,input[type=time]:focus-visible{border-color:var(--pink);outline:2px solid var(--pink);outline-offset:2px}
    select:focus:not(:focus-visible),input[type=date]:focus:not(:focus-visible),input[type=time]:focus:not(:focus-visible){outline:none;border-color:var(--pink)}
    .chips-row{display:flex;gap:10px;flex-wrap:wrap}
    .chip{padding:9px 18px;border-radius:100px;border:1.5px solid var(--border);font-size:var(--fs-sm);font-weight:600;cursor:pointer;background:var(--white);color:var(--muted);transition:all 0.18s;display:flex;align-items:center;gap:6px;font-family:'Inter',sans-serif}
    .chip:hover{border-color:var(--pink);color:var(--pink-text)}
    .chip.on{background:var(--pink-fill);border-color:var(--pink-fill);color:var(--on-accent)}
    .vibes-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:12px}
    /* Buttons don't inherit font-size, so without this the label falls back to
       the UA default (13.33px) — the same trap as the missing colour above. */
    .vibe-btn{font-size:var(--fs-sm);border:1.5px solid var(--border);border-radius:16px;padding:16px 10px;text-align:center;cursor:pointer;background:var(--white);color:var(--text);transition:all 0.18s;font-family:'Inter',sans-serif}
    .vibe-btn:hover,.vibe-btn.sel{border-color:var(--pink);background:var(--pink-xlight)}
    .vibe-btn .ve{display:block;margin-bottom:6px;color:var(--pink);line-height:1}
    .vibe-btn .vn{font-size:var(--fs-sm);font-weight:700;color:var(--text)}
    .vibe-btn .vd{font-size:var(--fs-xs);color:var(--muted);margin-top:2px}

    /* LOADING */
    .loading-screen{display:none;min-height:60vh;align-items:center;justify-content:center;flex-direction:column;gap:20px;padding:40px}
    .loading-screen.show{display:flex}
    .loading-ring-wrap{position:relative;width:88px;height:88px}
    .l-ring{width:88px;height:88px;border:3px solid var(--peach);border-top-color:var(--pink);border-radius:50%;animation:spin 0.85s linear infinite}
    .l-heart{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}
    @keyframes spin{to{transform:rotate(360deg)}}
    .loading-title{font-size:var(--fs-lg);font-weight:700}
    .loading-msg{font-size:var(--fs-sm);color:var(--muted)}
    .loading-dots span{animation:blink 1.4s infinite both}
    .loading-dots span:nth-child(2){animation-delay:.2s}
    .loading-dots span:nth-child(3){animation-delay:.4s}
    @keyframes blink{0%,80%,100%{opacity:0}40%{opacity:1}}

    /* RESULTS */
    .results-wrap{max-width:860px;margin:0 auto;padding:32px 24px}

    /* ROUTE MAP. The basemap is OneMap (Singapore Land Authority), not Google:
       free, no API key, and it draws MRT stations and local place names
       properly. Leaflet supplies the chrome, so a few of its own classes are
       themed here to stop a white popup appearing on the dark theme. */
    .plan-map-wrap{margin-bottom:28px}
    .plan-map{height:320px;border-radius:var(--r);border:1px solid var(--border);overflow:hidden;background:var(--pink-xlight);position:relative}
    /* Shown for a beat when someone scrolls over the map without the modifier
       key, the way an embedded Google map explains itself. z-index sits above
       Leaflet's own panes (400) and controls (800). */
    .plan-map-hint{position:absolute;inset:0;z-index:900;display:flex;align-items:center;justify-content:center;
                   background:rgba(0,0,0,0.45);color:#fff;font-size:var(--fs-sm);font-weight:600;
                   text-align:center;padding:0 24px;opacity:0;pointer-events:none;transition:opacity 0.18s}
    .plan-map-hint.show{opacity:1}
    .plan-map-note{font-size:var(--fs-xs);color:var(--muted);line-height:1.5;margin-top:8px}
    /* Numbered pins matching the timeline. Free stops take the green the rest
       of the site uses for "no ticket needed". */
    .plan-pin{display:flex;align-items:center;justify-content:center;width:28px;height:28px;
              border-radius:50%;background:var(--pink-fill);color:var(--on-accent);
              font-family:'Inter',sans-serif;font-size:var(--fs-xs);font-weight:800;
              border:2px solid var(--white);box-shadow:0 2px 8px rgba(0,0,0,0.28)}
    .plan-pin.free{background:var(--green-fill)}
    .leaflet-container{font-family:'Inter',sans-serif;background:var(--pink-xlight)}
    .leaflet-popup-content-wrapper,.leaflet-popup-tip{background:var(--white);color:var(--text)}
    .leaflet-popup-content{font-family:'Inter',sans-serif;font-size:var(--fs-sm);margin:10px 12px;line-height:1.5}
    .leaflet-control-attribution{font-size:10px}
    /* The sparkle beside the plan name is an icon now, not an emoji — it has
       to be told to take the accent colour like the rest of the heading. */
    .results-plan-name .dt-icon{color:var(--pink-head);vertical-align:-0.12em}
    @media(max-width:650px){
      .plan-map{height:240px}
    }

    /* THE TUNER — the plan's controls, sitting under the plan instead of in
       front of it. The cards inside are the old .planner-card blocks; these
       rules turn four full-page steps into one panel. */
    .plan-tuner{background:var(--white);border:1px solid var(--border);border-radius:var(--r-lg);box-shadow:var(--shadow-sm);margin-bottom:28px;overflow:hidden}
    .plan-tuner-head{display:flex;align-items:center;flex-wrap:wrap;gap:10px 12px;padding:16px 24px}
    .plan-tuner-title{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
    .plan-tuner-label{font-weight:700;font-size:var(--fs-sm)}
    .plan-tuner-hint{font-size:var(--fs-xs);font-weight:600;color:var(--pink-text)}
    .plan-tuner-toggle{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border-radius:8px;background:transparent;border:none;cursor:pointer;font-family:'Inter',sans-serif;font-size:var(--fs-sm);font-weight:600;color:var(--muted)}
    .plan-tuner-toggle:hover{color:var(--pink-text);background:var(--pink-xlight)}
    .plan-tuner-toggle:focus-visible,.tuner-chip:focus-visible{outline:2px solid var(--pink);outline-offset:2px}
    .plan-tuner-chev{transition:transform 0.18s}
    .plan-tuner-toggle[aria-expanded="true"] .plan-tuner-chev{transform:rotate(180deg)}
    /* The settings as chips: each one is a button that opens only its own
       card, and the caret says so. */
    .tuner-chips{display:flex;flex-wrap:wrap;gap:8px;flex-basis:100%}
    .tuner-chip{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;border-radius:100px;border:1.5px solid var(--border);background:var(--white);color:var(--text);font-family:'Inter',sans-serif;font-size:var(--fs-sm);font-weight:600;cursor:pointer;transition:border-color .15s,color .15s}
    .tuner-chip:hover{border-color:var(--pink);color:var(--pink-text)}
    .tuner-chip-chev{font-size:0.8em;color:var(--muted);transition:transform .18s}
    .tuner-chip[aria-expanded="true"]{border-color:var(--pink);color:var(--pink-text);background:var(--pink-light)}
    .tuner-chip[aria-expanded="true"] .tuner-chip-chev{transform:rotate(180deg);color:var(--pink-text)}
    .plan-tuner[data-focus] .plan-tuner-body .planner-card{grid-column:1/-1}
    .plan-notes:empty{display:none}
    .plan-notes{margin-bottom:20px}
    .plan-notes .travel-ok,.plan-notes .travel-warn{margin:0}
    .plan-notes > * + *{margin-top:8px}
    /* Collapsed unless .open, which app.js sets at boot on any screen wide
       enough to show the controls without pushing the plan off it. */
    .plan-tuner-body{display:none;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;padding:0 24px 24px}
    .plan-tuner.open .plan-tuner-body{display:grid}
    .plan-tuner-body .pin-banner,.plan-tuner-body .tuner-wide{grid-column:1/-1}
    .plan-tuner-body .planner-card{padding:20px;margin-bottom:0;border-radius:var(--r-sm);box-shadow:none;background:var(--bg)}
    .plan-tuner-body .planner-card h3{font-size:var(--fs-xs);font-weight:700;text-transform:uppercase;letter-spacing:0.06em;color:var(--muted);margin-bottom:14px}
    @media(max-width:760px){
      .plan-tuner-body{grid-template-columns:minmax(0,1fr);padding:0 16px 16px}
      .plan-tuner-head{padding:16px 16px 12px;row-gap:14px}
      /* One swipeable row instead of three wrapped ones. It runs to the card
         edges, and fades on the right while there is more to swipe to. */
      .tuner-chips{flex-wrap:nowrap;overflow-x:auto;gap:10px;margin:0 -16px;padding:2px 16px 4px;
                   scrollbar-width:none;-webkit-overflow-scrolling:touch;
                   -webkit-mask-image:linear-gradient(to right,#000 78%,transparent);
                           mask-image:linear-gradient(to right,#000 78%,transparent)}
      .tuner-chips::-webkit-scrollbar{display:none}
      .tuner-chips.at-end{-webkit-mask-image:none;mask-image:none}
      .tuner-chip{flex:none;padding:10px 16px}
    }
    .results-intro{margin-bottom:20px}
    .results-top{background:var(--white);border:1px solid var(--border);border-radius:var(--r-lg);padding:28px 32px;margin-bottom:28px}
    .results-top-head{display:flex;align-items:flex-start;justify-content:space-between;flex-wrap:wrap;gap:16px;margin-bottom:20px}
    /* A plan opened from a shared link: framed like an invitation. */
    .results-top.is-invite{border:2px solid var(--pink);box-shadow:var(--shadow)}
    .results-plan-name{font-size:var(--fs-lg);font-weight:800;letter-spacing:-0.4px}
    .results-plan-name span{color:var(--pink-head)}
    .results-date{font-size:var(--fs-sm);color:var(--muted);margin-top:3px}
    .results-pills{display:flex;gap:8px;flex-wrap:wrap}
    .r-pill{background:var(--pink-light);border:1px solid var(--border);border-radius:100px;padding:6px 14px;font-size:var(--fs-sm);font-weight:600;color:var(--pink-text)}
    /* inline-flex + gap so the Share and Calendar icons do not sit flush
       against their labels. */
    .replan-btn{display:inline-flex;align-items:center;gap:6px;padding:10px 20px;border-radius:10px;font-size:var(--fs-sm);font-weight:700;cursor:pointer;border:1.5px solid var(--border);background:var(--white);color:var(--text);font-family:'Inter',sans-serif;transition:all 0.15s}
    .replan-btn:hover{border-color:var(--pink);color:var(--pink-text)}
    .timeline{position:relative;padding-left:56px}
    .tl-spine{position:absolute;left:22px;top:12px;bottom:12px;width:2px;background:linear-gradient(to bottom,var(--pink),var(--peach) 70%,transparent)}
    .tl-item{position:relative;margin-bottom:0}
    .tl-node{position:absolute;left:-44px;width:36px;height:36px;border-radius:50%;background:var(--white);border:2.5px solid var(--pink);display:flex;align-items:center;justify-content:center;font-size:var(--fs-md);z-index:2;color:var(--pink-text)}
    /* Saturated node backgrounds need the icon in on-accent, not the theme text
       colour, or a light-mode icon lands on a light fill. */
    .tl-node.food,.tl-node.activity,.tl-node.drinks{color:var(--on-accent)}
    .tl-node.food{background:var(--pink-fill);border-color:var(--pink-fill)}
    .tl-node.activity{background:var(--purple);border-color:var(--purple)}
    .tl-node.drinks{background:var(--amber-fill);border-color:var(--amber-fill)}
    .tl-card{background:var(--white);border:1px solid var(--border);border-radius:var(--r);padding:20px 24px;margin-bottom:6px;display:flex;gap:18px;transition:box-shadow 0.2s}
    .tl-card:hover{box-shadow:var(--shadow-sm)}
    /* The inline background here is a fixed pastel that doesn't flip with the
       theme, so the placeholder icon takes a fixed dark pink rather than
       var(--text), which would go light and vanish in dark mode. */
    .tl-card-img{width:80px;height:80px;border-radius:14px;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:32px;background:var(--pink-light);color:var(--pink-dark)}
    .tl-card-body{flex:1}
    .tl-badge{display:inline-flex;align-items:center;gap:4px;font-size:var(--fs-xs);font-weight:700;padding:3px 10px;border-radius:100px;margin-bottom:6px;text-transform:uppercase;letter-spacing:0.5px}
    .tl-badge.food{background:var(--pink-light);color:var(--pink-text)}
    .tl-badge.activity{background:var(--purple-light);color:var(--purple-text)}
    .tl-badge.drinks{background:var(--amber-bg);color:var(--amber-text)}
    .tl-name{font-size:var(--fs-md);font-weight:700;margin-bottom:3px}
    .tl-loc{font-size:var(--fs-xs);color:var(--muted);margin-bottom:8px}
    .tl-times{display:flex;gap:8px;flex-wrap:wrap}
    .tl-time-chip{background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:4px 10px;font-size:var(--fs-xs);font-weight:500;color:var(--text)}
    .tl-time-chip.tl-wet{background:#FEF3C7;border-color:#FDE68A;color:#92400E}
    .tl-price-col{text-align:right;display:flex;flex-direction:column;align-items:flex-end;justify-content:space-between;min-width:80px}
    .tl-price{font-size:var(--fs-lg);font-weight:800;color:var(--text)}
    .tl-price-sub{font-size:var(--fs-xs);color:var(--muted)}
    .tl-actions{display:flex;gap:6px;margin-top:8px}
    .tl-act-btn{padding:5px 12px;border-radius:8px;font-size:var(--fs-xs);font-weight:700;cursor:pointer;border:1px solid var(--border);background:var(--white);color:var(--muted);font-family:'Inter',sans-serif;transition:all 0.15s}
    .tl-act-btn:hover{border-color:var(--pink);color:var(--pink-text)}
    .tl-act-btn.remove:hover{border-color:var(--red);color:var(--red)}
    .travel-ok,.travel-warn{margin:12px 0 0;padding:10px 14px;border-radius:12px;font-size:var(--fs-sm);line-height:1.5}
    .travel-ok{background:var(--pink-light);color:var(--text)}
    .travel-warn{background:#FEF3C7;color:#92400E;border:1px solid #FDE68A}
    .travel-warn + .travel-warn{margin-top:8px}
    .travel-seg{display:flex;align-items:center;gap:10px;padding:6px 0;margin-bottom:6px}
    .travel-line{flex:1;height:0;border-top:2px dashed var(--border)}
    .travel-pill{background:#FEF9C3;border:1px solid #FDE68A;border-radius:100px;padding:5px 14px;font-size:var(--fs-xs);font-weight:600;color:#854D0E;white-space:nowrap}
    .travel-pill.warn{background:#FEF3C7;color:#92400E}
    .travel-pill.alert{background:#FFEDD5;border-color:#FDBA74;color:#9A3412}
    .total-summary{background:var(--white);border:1.5px solid var(--pink);border-radius:var(--r);padding:22px 28px;margin-top:20px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:16px}
    .ts-item{text-align:center}
    .ts-label{font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:0.5px;color:var(--muted);font-weight:600}
    .ts-val{font-size:var(--fs-lg);font-weight:800;margin-top:2px}
    .ts-val.pink{color:var(--pink-text)}
    .ts-divider{width:1px;height:44px;background:var(--border)}
    .save-plan-btn{padding:12px 24px;border-radius:12px;font-size:var(--fs-sm);font-weight:700;cursor:pointer;border:none;background:var(--pink-fill);color:var(--on-accent);font-family:'Inter',sans-serif;transition:all 0.18s}
    .save-plan-btn:hover{background:var(--pink-fill-hover)}

    /* EXPLORE */
    .explore-wrap{padding:32px 32px;max-width:1100px;margin:0 auto}
    .explore-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:28px;flex-wrap:wrap;gap:12px}
    .explore-actions{display:flex;gap:10px;flex-wrap:wrap}
    .form-optional{font-weight:400;color:var(--muted)}
    /* Honeypot for bots — off-screen rather than display:none, which some bots skip. */
    .hp-field{position:absolute;left:-9999px;width:1px;height:1px;opacity:0}
    .explore-title h1{font-size:var(--fs-xl);font-weight:800;letter-spacing:-0.5px}
    .explore-title p{font-size:var(--fs-sm);color:var(--muted);margin-top:4px}
    .filter-bar{background:var(--white);border:1px solid var(--border);border-radius:16px;padding:16px 20px;display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-bottom:24px}
    .filter-label{font-size:var(--fs-sm);font-weight:600;color:var(--muted);white-space:nowrap}
    .filter-label-price{margin-left:8px}
    .filter-group{display:contents}
    .filter-chip{padding:7px 16px;border-radius:100px;border:1.5px solid var(--border);font-size:var(--fs-sm);font-weight:600;cursor:pointer;background:var(--white);color:var(--muted);transition:all 0.15s;font-family:'Inter',sans-serif}
    .filter-chip:hover,.filter-chip.on{background:var(--pink-fill);border-color:var(--pink-fill);color:var(--on-accent)}
    .explore-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:20px}

    /* DEAL DETAIL */
    .detail-wrap{max-width:800px;margin:0 auto;padding:32px 24px}
    .detail-back{display:flex;align-items:center;gap:8px;font-size:var(--fs-sm);font-weight:600;color:var(--muted);cursor:pointer;margin-bottom:24px;background:none;border:none;font-family:'Inter',sans-serif;transition:color 0.15s}
    .detail-back:hover{color:var(--pink-text)}
    .detail-hero{height:320px;border-radius:var(--r-lg);display:flex;align-items:center;justify-content:center;font-size:80px;background:var(--pink-light);margin-bottom:28px;overflow:hidden;position:relative}
    .detail-tags{position:absolute;bottom:16px;left:16px;display:flex;gap:8px}
    .detail-main{display:grid;grid-template-columns:1fr 320px;gap:28px}
    .detail-info h1{font-size:var(--fs-xl);font-weight:800;letter-spacing:-0.5px;margin-bottom:8px}
    .detail-loc{font-size:var(--fs-sm);color:var(--muted);display:flex;align-items:center;gap:5px;margin-bottom:16px}
    .detail-desc{font-size:var(--fs-md);color:var(--text);line-height:1.7;margin-bottom:20px}
    .detail-meta-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:20px}
    .detail-meta-item{background:var(--bg);border-radius:12px;padding:14px;border:1px solid var(--border)}
    .detail-meta-label{font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:0.5px;color:var(--muted);font-weight:600;margin-bottom:4px}
    .detail-meta-val{font-size:var(--fs-sm);font-weight:700}
    .detail-sidebar{background:var(--white);border:1px solid var(--border);border-radius:var(--r);padding:24px;height:fit-content;box-shadow:var(--shadow-sm)}
    .sidebar-price{font-size:var(--fs-2xl);font-weight:800;margin-bottom:4px}
    .sidebar-price-sub{font-size:var(--fs-sm);color:var(--muted);margin-bottom:20px}
    .sidebar-btn{width:100%;padding:14px;border-radius:12px;font-size:var(--fs-sm);font-weight:700;cursor:pointer;font-family:'Inter',sans-serif;transition:all 0.18s;margin-bottom:10px}
    .sidebar-btn.primary{border:none;background:var(--pink-fill);color:var(--on-accent)}
    .sidebar-btn.primary:hover{background:var(--pink-fill-hover)}
    .sidebar-btn.secondary{border:1.5px solid var(--border);background:var(--white);color:var(--text)}
    .sidebar-btn.secondary:hover{border-color:var(--pink);color:var(--pink-text)}
    a.sidebar-btn{display:flex;align-items:center;justify-content:center;gap:6px;text-decoration:none;box-sizing:border-box}

    /* SAVED */
    .saved-wrap{max-width:800px;margin:0 auto;padding:40px 24px}
    .saved-header{margin-bottom:32px}
    .saved-header h1{font-size:var(--fs-xl);font-weight:800;letter-spacing:-0.5px;margin-bottom:6px}
    .saved-header p{color:var(--muted);font-size:var(--fs-sm)}
    .saved-plan-card{background:var(--white);border:1px solid var(--border);border-radius:var(--r);padding:20px 24px;margin-bottom:16px;display:flex;align-items:center;gap:20px;cursor:pointer;transition:all 0.18s}
    .saved-plan-card:hover{box-shadow:var(--shadow-sm);border-color:var(--pink)}
    .spc-delete{background:none;border:none;color:var(--muted);font-size:var(--fs-sm);cursor:pointer;padding:6px;margin-left:-8px;border-radius:8px}
    .spc-delete:hover{color:var(--red);background:var(--pink-light)}
    /* REPLACE SHEET (replaceStop() in app.js). A bottom sheet over the plan,
       which stays in view behind it, blurred and dimmed. Above the nav
       (1100) and Leaflet (1000), below the code screen (2000) and toasts. */
    .rs-overlay{position:fixed;inset:0;z-index:1500;display:none}
    .rs-overlay.open{display:block}
    .rs-backdrop{position:absolute;inset:0;background:rgba(23,21,26,0.45);
      backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);animation:rs-fade 0.2s ease-out}
    .rs-sheet{position:absolute;left:50%;bottom:0;transform:translateX(-50%);width:100%;max-width:560px;
      max-height:88vh;overflow-y:auto;overscroll-behavior:contain;background:var(--bg);color:var(--text);
      border-radius:var(--r) var(--r) 0 0;box-shadow:0 -8px 30px rgba(0,0,0,0.2);
      padding:8px 16px calc(24px + env(safe-area-inset-bottom));animation:rs-up 0.26s cubic-bezier(.2,.8,.2,1)}
    .rs-sheet:focus{outline:none}
    @keyframes rs-up{from{transform:translate(-50%,100%)}to{transform:translate(-50%,0)}}
    @keyframes rs-fade{from{opacity:0}to{opacity:1}}
    body.rs-locked{overflow:hidden}
    .rs-grab{width:40px;height:4px;border-radius:4px;background:var(--border);margin:4px auto 10px}
    .rs-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:6px}
    .rs-kicker{font-size:var(--fs-xs);font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:0.5px}
    .rs-title{font-size:var(--fs-lg);font-weight:800;letter-spacing:-0.3px;line-height:1.3;margin-top:2px}
    .rs-close{width:44px;height:44px;flex-shrink:0;border-radius:50%;border:1.5px solid var(--border);
      background:var(--white);color:var(--text);font-size:var(--fs-md);cursor:pointer}
    .rs-close:hover{border-color:var(--pink);color:var(--pink-text)}
    .rs-sec{margin-top:18px}
    .rs-sec-head{font-size:var(--fs-sm);font-weight:800;margin-bottom:2px}
    .rs-sec-sub{font-size:var(--fs-xs);color:var(--muted);margin-bottom:8px}
    .rs-sec-head + .rs-card, .rs-sec-head + .rs-none{margin-top:8px}
    .rs-none{font-size:var(--fs-sm);color:var(--muted);background:var(--white);border:1px dashed var(--border);
      border-radius:var(--r-sm);padding:12px 14px}
    .rs-card{display:flex;align-items:center;gap:12px;background:var(--white);border:1px solid var(--border);
      border-radius:var(--r-sm);padding:12px 14px;margin-bottom:8px}
    .rs-info{flex:1;min-width:0}
    .rs-name{font-size:var(--fs-md);font-weight:700;line-height:1.3}
    .rs-badges{display:flex;flex-wrap:wrap;gap:6px;margin-top:4px}
    .rs-badge{display:inline-flex;align-items:center;gap:4px;font-size:var(--fs-xs);font-weight:700;
      padding:2px 8px;border-radius:100px;border:1px solid var(--border);color:var(--muted)}
    .rs-badge.excl{background:var(--pink-light);border-color:var(--pink);color:var(--pink-text)}
    .rs-card .card-gate-sm{margin:6px 0 2px}
    .rs-line{font-size:var(--fs-sm);margin-top:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
    .rs-meta{font-size:var(--fs-xs);color:var(--muted);margin-top:4px}
    .rs-impact{font-size:var(--fs-xs);font-weight:700;margin-top:4px}
    .rs-swap{min-height:44px;flex-shrink:0;white-space:nowrap}
    .rs-empty{margin-top:18px;border-top:1px solid var(--border);padding-top:14px}
    .rs-empty-head{font-size:var(--fs-md);font-weight:800;margin-bottom:10px}
    .rs-remove{display:block;min-height:44px;margin:6px auto 0;padding:0 12px;background:none;border:none;
      color:var(--pink-text);font-size:var(--fs-sm);font-weight:700;text-decoration:underline;cursor:pointer;font-family:'Inter',sans-serif}
    /* The "what would you rather do?" box: a search-bar pill, then the
       filters it understood as removable chips. */
    .rs-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
    .rs-ask{margin-top:12px}
    .rs-ask-bar{display:flex;align-items:center;gap:8px;background:var(--white);border:1.5px solid var(--border);
      border-radius:100px;padding:4px 4px 4px 16px;color:var(--muted);transition:border-color 0.15s}
    .rs-ask-bar:focus-within{border-color:var(--pink)}
    .rs-ask-bar input{flex:1;min-width:0;border:none;background:transparent;color:var(--text);outline:none;
      font-family:'Inter',sans-serif;font-size:var(--fs-md);padding:8px 0}
    .rs-ask-bar input::placeholder{color:var(--muted)}
    .rs-ask-go{width:44px;height:44px;flex-shrink:0;border-radius:50%;border:none;background:var(--pink-fill);
      color:var(--on-accent);cursor:pointer;display:flex;align-items:center;justify-content:center}
    .rs-ask-go:hover{background:var(--pink-fill-hover)}
    .rs-understood-head{font-size:var(--fs-xs);font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:0.5px;margin:12px 0 6px}
    .rs-chips{display:flex;flex-wrap:wrap;gap:8px}
    .rs-chip{display:inline-flex;align-items:center;gap:2px;background:var(--pink-light);border:1px solid var(--pink);
      color:var(--text);border-radius:100px;padding:0 0 0 12px;font-size:var(--fs-sm);font-weight:600;min-height:36px}
    .rs-chip button{position:relative;width:36px;height:36px;border:none;background:none;color:var(--pink-text);
      font-size:var(--fs-sm);cursor:pointer;border-radius:50%}
    .rs-chip button::before{content:'';position:absolute;inset:-4px}
    .rs-hint{font-size:var(--fs-xs);color:var(--muted);margin-top:8px}
    .rs-drop{display:block;width:100%;min-height:44px;text-align:left;margin-bottom:8px;padding:10px 14px;
      background:var(--white);border:1.5px solid var(--border);border-radius:var(--r-sm);color:var(--text);
      font-family:'Inter',sans-serif;font-size:var(--fs-sm);cursor:pointer}
    .rs-drop:hover{border-color:var(--pink)}
    .rs-sub-head{margin-top:14px;margin-bottom:8px}
    .tl-card.just-swapped{border:2px solid var(--pink);box-shadow:var(--shadow)}
    .just-swapped-label{display:inline-block;font-size:var(--fs-xs);font-weight:800;color:var(--pink-text);margin-right:8px}
    .pin-banner{display:flex;align-items:center;justify-content:space-between;gap:12px;background:var(--pink-light);border:1px solid var(--pink);border-radius:12px;padding:10px 14px;margin-bottom:16px;font-size:var(--fs-sm);color:var(--text)}
    .pin-note{color:var(--muted);font-size:var(--fs-xs)}
    .pin-clear{background:none;border:none;color:var(--muted);font-size:var(--fs-sm);cursor:pointer;padding:4px 6px;border-radius:6px;flex-shrink:0}
    .pin-clear:hover{color:var(--pink-text)}
    .save-plan-btn.saved{background:#10B981;cursor:default}
    .spc-icon{width:60px;height:60px;border-radius:16px;background:var(--pink-light);color:var(--pink);display:flex;align-items:center;justify-content:center;flex-shrink:0}
    .spc-body{flex:1}
    .spc-name{font-size:var(--fs-md);font-weight:700;margin-bottom:3px}
    .spc-meta{font-size:var(--fs-sm);color:var(--muted);display:flex;gap:12px;flex-wrap:wrap}
    .spc-right{text-align:right}
    .spc-cost{font-size:var(--fs-lg);font-weight:800;color:var(--pink-text)}
    .spc-stops{font-size:var(--fs-xs);color:var(--muted);margin-top:2px}
    .empty-state{text-align:center;padding:56px 24px;border:1px dashed var(--border);border-radius:var(--r);background:var(--white)}
    .empty-state .es-icon{margin-bottom:16px;color:var(--pink);line-height:1}
    .empty-state h3{font-size:var(--fs-lg);font-weight:700;margin-bottom:8px}
    .empty-state p{font-size:var(--fs-sm);color:var(--muted);margin-bottom:20px}

    /* TOAST — transient feedback so nothing happens silently */
    .toast{position:fixed;left:50%;bottom:24px;transform:translate(-50%,120%);
           background:var(--text);color:var(--bg);padding:13px 18px;border-radius:14px;
           box-shadow:0 8px 30px rgba(0,0,0,0.28);display:flex;align-items:center;gap:14px;
           font-size:var(--fs-sm);font-weight:600;z-index:9998;max-width:min(92vw,520px);
           transition:transform 0.28s cubic-bezier(.2,.8,.2,1),opacity 0.28s;opacity:0}
    .toast.show{transform:translate(-50%,0);opacity:1}
    .toast-action{background:var(--pink-fill);color:var(--on-accent);border:none;border-radius:10px;
                  padding:8px 14px;font-weight:700;font-size:var(--fs-sm);cursor:pointer;
                  font-family:'Inter',sans-serif;white-space:nowrap;flex-shrink:0}
    .toast-action:hover{background:var(--pink-fill-hover)}

    /* Guest shortlist banner on the Saved page */
    .guest-banner{display:flex;align-items:center;justify-content:space-between;gap:16px;
                  flex-wrap:wrap;background:var(--pink-light);border:1px solid var(--border);
                  border-radius:var(--r-sm);padding:14px 18px;margin-bottom:20px;font-size:var(--fs-sm)}
    .guest-banner strong{color:var(--pink-text)}

    /* HOW IT WORKS */
    .hiw-wrap{max-width:780px;margin:0 auto;padding:44px 24px 72px}
    .hiw-head h1{font-size:var(--fs-2xl);font-weight:800;letter-spacing:-0.7px;margin-bottom:8px}
    .hiw-head p{color:var(--muted);font-size:var(--fs-md);margin-bottom:36px;line-height:1.65}
    .hiw-block{border-top:1px solid var(--border);padding:26px 0}
    .hiw-block h2{font-size:var(--fs-lg);font-weight:800;margin-bottom:10px;letter-spacing:-0.3px}
    .hiw-block h2 span{color:var(--pink-head)}

    /* ============================================================
       DISPLAY TYPE — headings only. Body, buttons and inputs stay on
       Inter: a serif is wrong for long text and wrong for UI chrome.

       This block sits here, after every one of these selectors has been
       declared above, on purpose. All of them are single-class rules, so
       specificity is equal and the later declaration wins — put this block
       higher up the file and the original font-weight:800 quietly beats it,
       which is exactly what happened first time.

       Instrument Serif ships in 400 and italic and nothing else, so anything
       wearing it must drop to 400. Asking a 400-only face for 800 makes the
       browser synthesise a fake bold that smears the thin strokes the face is
       built around. The heavy negative tracking was tuned for a bold sans and
       is wrong on a high-contrast serif, so it relaxes to near zero. Sizes go
       up a step because at the same size a 400 serif sits noticeably lighter
       on the page than the 800 sans it replaced, and section headings were
       disappearing.
       ============================================================ */
    .hero h1,
    .section-title,
    .hiw-head h1,
    .hiw-block h2,
    .auth-title,
    .explore-title h1,
    .loading-title{font-family:var(--font-display);font-weight:400;letter-spacing:-0.01em}

    .section-title,
    .explore-title h1{font-size:30px}
    .hiw-head h1{font-size:40px}
    .hiw-block h2{font-size:26px}
    .auth-title{font-size:26px}
    .hiw-block p{font-size:var(--fs-md);line-height:1.7;color:var(--muted);margin-bottom:10px}
    .hiw-block p strong{color:var(--text);font-weight:700}
    .hiw-block:last-of-type{border-bottom:1px solid var(--border)}
    .hiw-cta{display:flex;gap:12px;flex-wrap:wrap;margin-top:32px}
    .hiw-note{background:var(--pink-xlight);border:1px solid var(--border);border-radius:var(--r-sm);
              padding:14px 18px;font-size:var(--fs-sm);line-height:1.6;color:var(--muted);margin-top:10px}

    /* DATE IDEAS GUIDES — the static /date-ideas/ pages written by
       scripts/build-guides.mjs. They reuse the how-it-works layout. */
    .g-crumb{font-size:var(--fs-xs);font-weight:600;color:var(--muted);margin-bottom:10px !important}
    .g-crumb a{color:var(--pink-text);text-decoration:none}
    .hiw-block .g-list{list-style:none;padding:0;margin:14px 0 0;display:grid;gap:12px}
    .hiw-block .g-item{margin:0;font-size:inherit;line-height:inherit;color:var(--text)}
    .g-item{background:var(--white);border:1px solid var(--border);border-radius:var(--r-sm);padding:16px 18px}
    .g-top{display:flex;align-items:flex-start;justify-content:space-between;gap:14px}
    .g-item h3{font-size:var(--fs-md);font-weight:700;line-height:1.35;margin:0}
    .g-price{font-weight:800;font-size:var(--fs-md);color:var(--text);text-align:right;white-space:nowrap}
    .g-price small{display:block;font-size:var(--fs-xs);font-weight:500;color:var(--muted)}
    .g-meta{font-size:var(--fs-xs) !important;color:var(--muted);margin:6px 0 0 !important;line-height:1.5 !important}
    .g-line{font-size:var(--fs-sm) !important;color:var(--text) !important;margin:8px 0 0 !important;line-height:1.55 !important}
    .g-links{display:flex;flex-wrap:wrap;gap:8px 18px;margin-top:12px;font-size:var(--fs-sm);font-weight:600}
    .g-links a{color:var(--muted);text-decoration:none}
    .g-links a:hover{color:var(--pink-text)}
    .g-links a.g-plan{color:var(--pink-text)}
    .g-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:10px;margin-top:14px}
    .g-card{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;border:1px solid var(--border);
            border-radius:var(--r-sm);background:var(--white);color:var(--text);font-weight:600;font-size:var(--fs-sm);text-decoration:none}
    .g-card span{color:var(--pink-text)}
    .g-card:hover{border-color:var(--pink);color:var(--pink-text)}
    .g-more{margin-top:40px}
    .g-more h2{font-size:var(--fs-md);font-weight:700;margin-bottom:12px}
    .g-more-links{display:flex;flex-wrap:wrap;gap:8px}
    .g-more-links a{padding:7px 14px;border-radius:100px;border:1px solid var(--border);color:var(--text);font-size:var(--fs-sm);font-weight:600;text-decoration:none}
    .g-more-links a:hover{border-color:var(--pink);color:var(--pink-text)}

    /* Once the filter bar has to wrap, give each group its own line — otherwise
       "Price:" trails a row of category chips and reads as one of them. */
    @media(max-width:900px){
      .filter-bar{gap:10px;padding:14px 16px}
      .filter-label{flex:1 0 100%}
      .filter-label-price{margin-left:0;margin-top:6px}
    }

    /* Tablet / iPad portrait. Five vibe tiles across is legible but cramped
       here; three gives the labels room without dropping to a phone layout. */
    @media(min-width:651px) and (max-width:900px){
      .vibes-grid{grid-template-columns:repeat(3,1fr)}
      .explore-wrap{padding:28px 20px}
      .detail-main{grid-template-columns:1fr 260px;gap:20px}
    }

    @media(max-width:650px){
      .nav{padding:0 16px}
      .hero{min-height:min(76vh,520px)}
      .hero-content{padding:0 20px 40px}
      /* The desktop line break leaves a short ragged line at phone width,
         and a wrapped proof row starts its second line with a stray dot. */
      .hero h1 br{display:none}
      .hero-sub{text-wrap:pretty}
      .hero-proof{flex-direction:column;align-items:flex-start;gap:6px}
      .hero-proof-dot{display:none}
      .hero-actions{gap:10px}
      .hero-actions button{flex:1;min-width:0;justify-content:center;
                           padding:15px 16px;font-size:var(--fs-sm);white-space:nowrap}
      .section{padding:40px 16px}
      .input-grid,.vibes-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
      /* A date input half a phone wide clips the year ("24/09/20"). Date and
         area get full rows; start time and duration share the one between. */
      .input-grid > .form-group:first-child,.input-grid > .form-group:last-child{grid-column:1/-1}
      .r-pill{font-size:var(--fs-xs);padding:5px 11px}
      .detail-main{grid-template-columns:1fr}
      .total-summary{justify-content:center}
      .ts-divider{display:none}
      .tl-card{flex-direction:column}
      /* Side by side on a phone, so the price block and the buttons need a gap
         between them: a worded unit like "no ticket needed" used to wrap into
         three lines pressed right up against the Replace button. */
      .tl-price-col{flex-direction:row;align-items:center;justify-content:space-between;
                    min-width:0;gap:12px;text-align:left}
      .tl-price-col > div:first-child{min-width:0}
      .tl-actions{margin-top:0;flex-shrink:0}
      .hiw{margin:20px 16px;padding:32px 20px}
      .explore-wrap,.results-wrap,.detail-wrap,.saved-wrap,.swipe-wrap,.contact-wrap{padding:24px 16px}
      /* Wrapped, the filters filled a whole phone screen before the first deal.
         Each group becomes one row that scrolls sideways instead; the fade on
         the right edge says there's more. */
      .filter-bar{flex-direction:column;flex-wrap:nowrap;align-items:stretch;gap:8px;padding:10px 0 10px 12px}
      .filter-group{display:flex;align-items:center;gap:8px;overflow-x:auto;
                    scrollbar-width:none;padding-right:24px;
                    -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 28px),transparent);
                            mask-image:linear-gradient(to right,#000 calc(100% - 28px),transparent)}
      .filter-group::-webkit-scrollbar{display:none}
      .filter-group .filter-label{flex:0 0 auto}
      .filter-label-price{margin-top:0}
      .filter-chip{flex:0 0 auto;white-space:nowrap}
    }

    /* Used on the deal detail page when a venue hasn't stated its hours. */
    .meta-unknown{color:var(--muted);font-weight:500;font-size:var(--fs-sm)}

    .deal-price-was{font-weight:600;color:var(--muted);text-decoration:line-through;font-size:var(--fs-xs)}
    .sidebar-expiry{font-size:var(--fs-xs);color:var(--muted);margin-bottom:12px}
    .detail-source{font-size:var(--fs-xs);color:var(--muted);margin-top:18px;line-height:1.5}
    .detail-source a{color:var(--pink-text);font-weight:600}

    /* SAVED TABS */
    .saved-tabs{display:flex;gap:8px;margin-bottom:24px;border-bottom:1px solid var(--border)}
    .saved-tab-btn{padding:10px 18px;border:none;background:transparent;font-family:'Inter',sans-serif;font-size:var(--fs-sm);font-weight:600;color:var(--muted);cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px}
    .saved-tab-btn.on{color:var(--pink-text);border-bottom-color:var(--pink)}

    /* SWIPE */
    .swipe-wrap{max-width:420px;margin:0 auto;padding:32px 16px 60px;text-align:center}
    .swipe-header h1{font-size:var(--fs-xl);font-weight:800;letter-spacing:-0.5px;margin-bottom:4px}
    .swipe-header p{color:var(--muted);font-size:var(--fs-sm);margin-bottom:24px}
    /* A card flying off at translateX(±600px) is absolutely positioned, so its
       overflow reaches the document: mid-swipe the page grew from 375px to
       1036px wide, which let the browser pan sideways and dumped the scroll
       position back to the top on every swipe. Clip it at the page edge.
       `clip` rather than `hidden` so this never becomes a scroll container. */
    #page-swipe{overflow-x:clip}
    /* pan-y, not none: the deck is most of a phone screen, and touch-action:none
       meant a finger starting on it could not scroll the page at all. The drag
       handler in app.js decides the axis on the first move. */
    .swipe-stack{position:relative;height:440px;margin-bottom:24px;touch-action:pan-y}
    .swipe-card{position:absolute;inset:0;border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--shadow);display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:grab;user-select:none;touch-action:pan-y;-webkit-user-select:none}
    .swipe-card:active{cursor:grabbing}
    /* Belt-and-braces against the native drag ghost sticking to the cursor. */
    .swipe-card img{-webkit-user-drag:none;user-select:none;pointer-events:none}
    .swipe-card:not(.swipe-card-top){transform:scale(0.95) translateY(10px);opacity:0.6;z-index:1}
    .swipe-card-top{z-index:2}
    /* The old scrim faded to fully transparent across the whole info block, so on
       a pale photo (or the pale placeholder) the deal name sat as white text on
       near-white — it read as the words overlapping the picture. This keeps a solid
       floor under the text and only fades out above it. */
    .swipe-card-info{position:absolute;left:0;right:0;bottom:0;padding:26px 20px 20px;
                     background:linear-gradient(to top,rgba(0,0,0,0.88) 0%,rgba(0,0,0,0.84) 70%,rgba(0,0,0,0.72) 86%,rgba(0,0,0,0.34) 95%,rgba(0,0,0,0) 100%);
                     color:#fff;text-align:left;text-shadow:0 1px 3px rgba(0,0,0,0.55)}
    .swipe-card-name{font-size:var(--fs-lg);font-weight:800}
    .swipe-card-loc{font-size:var(--fs-sm);opacity:0.9;margin:2px 0}
    .swipe-card-price{font-size:var(--fs-sm);font-weight:700}
    .swipe-actions{display:flex;justify-content:center;gap:24px}
    .swipe-btn{width:60px;height:60px;border-radius:50%;border:1.5px solid var(--border);background:var(--white);font-size:var(--fs-xl);cursor:pointer;box-shadow:var(--shadow-sm);transition:transform 0.15s}
    .swipe-btn:hover{transform:scale(1.08)}
    .swipe-btn-pass{color:var(--red)}
    .swipe-btn-like{color:var(--pink-text)}
    .meta-days{font-size:var(--fs-xs);font-weight:600;color:var(--muted)}
    .swipe-setup{text-align:left;background:var(--white);border:1px solid var(--border);border-radius:var(--r-lg);padding:20px;box-shadow:var(--shadow-sm)}
    .swipe-setup-group{margin-bottom:18px}
    .swipe-setup-label{font-size:var(--fs-sm);font-weight:700;margin-bottom:8px}
    .swipe-setup-opt{font-weight:500;color:var(--muted)}
    .swipe-setup-chips{display:flex;flex-wrap:wrap;gap:8px}
    .swipe-setup-chips .chip{padding:7px 14px}
    .swipe-setup-go{width:100%;margin-top:4px}
    .swipe-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin:-12px 0 4px}
    /* Padding rather than bare text: this is a thumb target on a phone. */
    .swipe-change-btn{display:inline-flex;align-items:center;gap:6px;background:none;border:none;color:var(--muted);font-size:var(--fs-sm);font-weight:600;cursor:pointer;padding:10px 2px;font-family:inherit}
    .swipe-change-btn:hover{color:var(--pink-text)}
    /* Guest save counter. Lives up here because the toast it replaces landed
       on top of the ✕ / ♡ buttons on a short phone. Quiet and always-on
       rather than a pop-up, so it never has to interrupt a swipe. */
    .swipe-saved-note{font-size:var(--fs-xs);color:var(--muted)}
    .swipe-saved-note button{background:none;border:none;padding:10px 0;font:inherit;
                             font-weight:700;color:var(--pink-text);cursor:pointer}
    .swipe-saved-note button:hover{text-decoration:underline}
    .swipe-divider{background:var(--white);border:1.5px dashed var(--border)}
    .swipe-divider-inner{padding:28px;text-align:center}
    .swipe-divider-inner h3{font-size:var(--fs-lg);font-weight:800;margin:8px 0 6px}
    .swipe-divider-inner p{color:var(--muted);font-size:var(--fs-sm);margin-bottom:16px}
    .swipe-stretch-note{position:absolute;top:14px;left:14px;background:rgba(0,0,0,0.6);color:#fff;font-size:var(--fs-xs);font-weight:600;padding:5px 10px;border-radius:100px}

    /* CONTACT */
    .contact-wrap{max-width:520px;margin:0 auto;padding:40px 16px 60px}
    .contact-header h1{font-size:var(--fs-xl);font-weight:800;letter-spacing:-0.5px;margin-bottom:6px}
    .contact-header p{color:var(--muted);font-size:var(--fs-sm);margin-bottom:24px}
    .contact-tabs{display:flex;gap:8px;margin-bottom:24px;border-bottom:1px solid var(--border)}
    .contact-tab-btn{padding:10px 18px;border:none;background:transparent;font-family:'Inter',sans-serif;font-size:var(--fs-sm);font-weight:600;color:var(--muted);cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px}
    .contact-tab-btn.on{color:var(--pink-text);border-bottom-color:var(--pink)}
    .contact-form textarea.form-input{resize:vertical;font-family:'Inter',sans-serif}

    /* ============================================================
       REDUCED MOTION
       Honours the OS-level "reduce motion" setting. Last in the file so it
       wins over the transitions and animations declared above.
       Motion isn't removed outright — durations collapse to near-zero so
       state changes still register, they just don't travel. The swipe card
       still leaves the deck, it simply doesn't fly.
       ============================================================ */
    @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;
      }
      /* go() and the plan page call scrollTo({behavior:'smooth'}) directly */
      html{scroll-behavior:auto !important}
    }

    /* FOOTER
       Lives outside the .page divs, so one copy serves every view. Colours are
       all tokens: --white, --border, --muted and --text each flip in dark mode,
       and --pink reads correctly on both backgrounds. */
    .site-footer{border-top:1px solid var(--border);background:var(--white);margin-top:64px;padding:48px 24px 28px}
    .footer-inner{max-width:1100px;margin:0 auto;display:flex;flex-wrap:wrap;gap:40px;justify-content:space-between}
    .footer-brand{max-width:340px}
    .footer-logo{font-size:var(--fs-lg);font-weight:800;color:var(--pink)}
    .footer-tagline{font-size:var(--fs-sm);color:var(--muted);line-height:1.6;margin:8px 0 0}
    .footer-links{display:flex;gap:56px;flex-wrap:wrap}
    .footer-col{display:flex;flex-direction:column;align-items:flex-start;gap:10px}
    .footer-col h4{font-size:var(--fs-xs);font-weight:700;text-transform:uppercase;letter-spacing:0.06em;color:var(--text);margin:0}
    .footer-col button,.footer-col a{background:none;border:none;padding:0;font-family:'Inter',sans-serif;font-size:var(--fs-sm);color:var(--muted);cursor:pointer;text-decoration:none;text-align:left}
    .footer-col button:hover,.footer-col a:hover{color:var(--pink-text)}
    /* Visible focus ring: these are the only footer controls, and they are
       reachable by keyboard before anything else on a long page. */
    .footer-col button:focus-visible,.footer-col a:focus-visible{outline:2px solid var(--pink);outline-offset:3px;border-radius:4px}
    .footer-note{max-width:1100px;margin:36px auto 0;padding-top:24px;border-top:1px solid var(--border)}
    .footer-note p{font-size:var(--fs-xs);color:var(--muted);line-height:1.6;margin:0;max-width:760px}
    .footer-bottom{max-width:1100px;margin:20px auto 0;font-size:var(--fs-xs);color:var(--muted)}
    @media(max-width:700px){
      .site-footer{margin-top:48px;padding:36px 20px 20px}
      .footer-inner{gap:28px}
      .footer-links{gap:40px}
      .footer-note{margin-top:28px}
    }

    /* LEGAL PAGES (terms.html, privacy.html) and the 404 page. They reuse the
       .hiw-* blocks from How it works rather than inventing a second set of
       type styles; these are only the extras those pages need. The reset at
       the top of this file strips list indentation and markers, so a plain
       <ul> in a legal page would otherwise render flush left as prose. */
    .legal-meta{font-size:var(--fs-sm);color:var(--muted);margin-bottom:22px}
    .hiw-block h3{font-size:var(--fs-md);font-weight:700;margin:18px 0 8px;color:var(--text)}
    .hiw-block ul{margin:0 0 12px 22px;padding:0;list-style:disc}
    .hiw-block li{font-size:var(--fs-md);line-height:1.7;color:var(--muted);margin-bottom:8px}
    .hiw-block li strong,.hiw-block li em{color:var(--text)}
    .hiw-block li::marker{color:var(--pink-text)}
    .hiw-block a,.hiw-note a{color:var(--pink-text);font-weight:600}
    .hiw-note strong{color:var(--text)}

    /* for-business.html: the page Elisa shows at a venue. */
    .biz-facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px;margin:0 0 30px}
    .biz-fact{background:var(--white);border:1px solid var(--border);border-radius:var(--r);padding:16px 18px}
    .biz-fact-label{font-size:var(--fs-xs);font-weight:700;text-transform:uppercase;letter-spacing:0.5px;color:var(--muted)}
    .biz-fact-value{font-size:var(--fs-xl);font-weight:800;color:var(--pink-text);margin:2px 0 4px;letter-spacing:-0.4px}
    .biz-fact-note{font-size:var(--fs-sm);color:var(--muted);line-height:1.45}
    .hiw-block ol.biz-steps{margin:0 0 12px 22px;padding:0;list-style:decimal}
    .biz-sample{display:grid;grid-template-columns:minmax(0,260px) 1fr;gap:24px;align-items:start;margin-top:14px}
    .biz-sample-card{cursor:default}
    .biz-sample-card:hover{transform:none;box-shadow:var(--shadow-sm)}
    .biz-sample-img{background:var(--pink-xlight);font-size:var(--fs-sm);font-weight:600;color:var(--muted)}
    .hiw-block ul.biz-sample-notes{margin-top:0}
    @media (max-width:640px){ .biz-sample{grid-template-columns:1fr} .biz-sample-card{max-width:320px} }
    /* A legal page linked to by #your-data must not open with the target
       heading jammed under the sticky nav. */
    .hiw-block[id]{scroll-margin-top:80px}

    /* 404. Its own wrapper because it is centred and short, not a column of
       prose — .hiw-wrap would leave it stranded at the top of a tall page. */
    .legal-wrap{max-width:780px;margin:0 auto;padding:44px 24px 72px}
    .legal-404-code{font-size:64px;font-weight:800;color:var(--pink);letter-spacing:-2px;line-height:1}

    /* PLAN PAGE AUDIT (2 Oct).
       Deal cards open on a tap anywhere, but a div isn't reachable by Tab, so
       the name is now the real button; it keeps looking like the title. The
       heart became a <button> for the same reason. */
    .deal-open{all:unset;cursor:pointer;font:inherit;color:inherit;text-align:left}
    .deal-open:focus-visible,
    .deal-save:focus-visible{outline:2px solid var(--pink);outline-offset:2px;border-radius:6px}
    .deal-save{padding:0;font-family:inherit}
    /* Tap targets: 44px is a comfortable fingertip. Where the visible button
       is smaller on purpose (the heart, Replace / Remove, All settings), an
       invisible layer grows the area you can hit without changing the look.
       Replace and Remove sit side by side, so theirs only grows up and down. */
    .deal-save::before{content:'';position:absolute;inset:-6px}
    .tl-act-btn,.plan-tuner-toggle,.deal-cta{position:relative}
    .tl-act-btn::after{content:'';position:absolute;left:0;right:0;top:-9px;bottom:-9px}
    .deal-cta::after{content:'';position:absolute;left:0;right:0;top:-8px;bottom:-8px}
    .plan-tuner-toggle::after{content:'';position:absolute;left:0;right:0;top:-7px;bottom:-7px}
    .replan-btn,#res-save-btn,.tuner-chip,.save-plan-btn{min-height:44px}
    /* Leaflet's zoom buttons are 30px; on a touch screen make them 44. */
    @media (pointer:coarse){
      .plan-map .leaflet-bar.leaflet-control-zoom a{width:44px;height:44px;line-height:44px;font-size:22px}
    }

    /* Quiz — "Where should we go?" One question at a time on a card, sized
       for a phone held between two people; the shortlist widens to the grid. */
    .quiz-wrap{max-width:560px;margin:0 auto;padding:32px 16px 60px}
    .quiz-wrap:has(.quiz-grid){max-width:1100px}
    .quiz-header{text-align:center;margin-bottom:20px}
    .quiz-header p{color:var(--muted);font-size:var(--fs-sm);margin-top:4px}
    .quiz-card{background:var(--white);border:1px solid var(--border);border-radius:var(--r-lg);padding:24px;box-shadow:var(--shadow-sm)}
    .quiz-card h2{font-family:var(--font-display);font-weight:400;font-size:26px;line-height:1.2;margin:16px 0 6px}
    .quiz-steps{margin:0 0 16px 20px;line-height:1.9;font-size:var(--fs-md)}
    .quiz-note,.quiz-hint{color:var(--muted);font-size:var(--fs-sm);line-height:1.5}
    .quiz-hint{margin-bottom:4px}
    .quiz-go{width:100%;margin-top:20px;padding:14px 20px;font-size:var(--fs-md)}
    .quiz-progress{display:flex;justify-content:space-between;font-size:var(--fs-sm);color:var(--muted);font-weight:600}
    .quiz-who{color:var(--pink-text);font-weight:700}
    .quiz-bar{height:4px;border-radius:4px;background:var(--border);margin-top:8px;overflow:hidden}
    .quiz-bar span{display:block;height:100%;background:var(--pink-fill);transform-origin:left;transition:transform 0.25s ease}
    .quiz-opts{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}
    .quiz-opts .chip{min-height:44px}
    .quiz-nav{display:flex;justify-content:space-between;margin-top:24px}
    .quiz-nav .btn-pink:disabled{opacity:0.45;cursor:default}
    .quiz-handoff{text-align:center}
    .quiz-handoff h2{margin-top:6px}
    .quiz-results-head{text-align:center;max-width:560px;margin:0 auto 24px}
    .quiz-results-head h2{font-family:var(--font-display);font-weight:400;font-size:30px}
    .quiz-results-head p{color:var(--muted);font-size:var(--fs-sm);line-height:1.5;margin-top:6px}
    .quiz-results-actions{display:flex;gap:10px;justify-content:center;margin-top:16px}
    .quiz-pick{display:flex;flex-direction:column;gap:8px}
    .quiz-pick .deal-card{flex:1}
    .quiz-warn{display:flex;align-items:center;gap:6px;font-size:var(--fs-xs);font-weight:700;padding:6px 10px;border-radius:8px;
               background:var(--gate-bg);color:var(--gate-text);border:1px solid var(--gate-border)}
    @media (prefers-reduced-motion: reduce){ .quiz-bar span{transition:none} }

    /* The page titles the display block above missed (1 Oct): Saved, Swipe,
       Contact / Suggest a deal and Profile were still bold Inter while Plan
       and Explore were serif. These are class + h1 rules and two of them are
       declared after the display block, so this has to stay the last thing
       in the file. Same size as .explore-title h1. */
    .saved-header h1,
    .swipe-header h1,
    .quiz-header h1,
    .contact-header h1,
    .profile-header h1{font-family:var(--font-display);font-weight:400;letter-spacing:-0.01em;font-size:30px}
