
:root{
 /* ---- type ----
    Cormorant Garamond is the serif wedding stationery is set in: high
    contrast, light, and it holds up in wide-tracked capitals. Great Vibes is
    the calligraphic accent — used ONLY for the monogram, never for anything
    anyone has to read quickly. Both degrade to Georgia, which is what the site
    used before, so a failed font request costs elegance and nothing else. */
 --font-display:"Cormorant Garamond",Georgia,"Times New Roman",serif;
 --font-script:"Great Vibes","Cormorant Garamond",Georgia,cursive;

 /* Cormorant defaults to old-style figures, where 1 sits short and 6 ascends.
    Lovely in a sentence, awkward in a column of counts you're comparing — so
    every number that's data asks for lining figures instead. */

 /* ---- surfaces: one warm cream ramp ---- */
 --bg:#fcfaf6;
 --bg-deep:#f9f4ec;
 --card:#fffdf9;
 --card-2:#faf5ec;        /* nested surfaces: table heads, note blocks */
 --line:#ece1cd;          /* gold-tinted, so every card edge reads warm */
 --line-strong:#d6c39e;

 /* ---- text ---- */
 --ink:#2e2a24;
 --muted:#6d6355;         /* 5.8:1 on card */

 /* ---- brand: antique gold. Buttons, the monogram, the active page. ---- */
 --brand:#8a6a2f;         /* 4.9:1 on card */
 --brand-dark:#6b5220;    /* 7.4:1 under white */
 --brand-soft:#f7efdc;
 --brand-line:#ddc99c;

 /* ---- rose: no longer the brand, just Manusha's side and open questions ---- */
 --rose:#9c6470;
 --rose-dark:#7a4b55;
 --rose-soft:#f7eced;
 --rose-line:#e9d6da;

 /* ---- supporting accents ---- */
 --champ:#ecdcc6;
 --gold:#9c7c45;
 --gold-soft:#f7eeda;
 --gold-ink:#7d6234;
 --sage:#5a8270;
 --sage-soft:#e6efe9;
 --sage-ink:#3f6555;
 --plum:#7a5a86;
 --plum-soft:#f2ebf5;
 --plum-ink:#5d4a6b;

 /* ---- semantic ---- */
 /* Terracotta rather than maroon — it still reads as "stop" beside the golds
    without dragging the old plum-red back onto the page. 5.2:1 on its soft. */
 --danger:#9c4a3c;
 --danger-dark:#7c3a2f;
 --danger-soft:#fbe9e4;
 --danger-line:#f0d2c9;

 /* ---- depth & focus ---- */
 --shadow:0 1px 2px rgba(74,60,40,.04),0 12px 32px rgba(74,60,40,.07);
 --shadow-lg:0 24px 70px rgba(56,44,28,.20);
 --focus:0 0 0 3px rgba(138,106,47,.28);
}
*{box-sizing:border-box}
*:focus-visible{outline:none;box-shadow:var(--focus);border-radius:8px}
body{margin:0;background:var(--bg);background-image:radial-gradient(900px 520px at 8% -8%,#fff 0,rgba(255,255,255,0) 70%),linear-gradient(180deg,var(--bg) 0,var(--bg-deep) 100%);background-attachment:fixed;color:var(--ink);font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}
button,input,select,textarea{font:inherit}
button{cursor:pointer}
.app{display:flex;min-height:100vh}
.sidebar{flex:0 0 245px;background:rgba(255,253,251,.9);border-right:1px solid var(--line);
         padding:28px 18px;position:sticky;top:0;height:100vh;
         display:flex;flex-direction:column;overflow-y:auto}
/* The nav must be allowed to keep its full height; if everything together is
   taller than the viewport the sidebar scrolls, which is recoverable. Letting
   it shrink would squash the buttons instead. */
.brand,.user-chip,.nav,.sidebar-foot{flex:none}
.brand{padding:4px 10px 26px}
.brand .monogram{font-family:var(--font-script);color:var(--brand-dark);font-size:34px;line-height:1.1}
.brand h1{font-family:var(--font-display);font-weight:600;font-size:27px;letter-spacing:.01em;margin:6px 0 2px}
.brand p{margin:0;color:var(--muted);font-size:14px}
.nav{display:grid;gap:5px}
.nav button{border:0;background:transparent;text-align:left;padding:12px 13px;border-radius:12px;color:var(--muted);font-weight:600;transition:background .15s ease,color .15s ease;display:flex;align-items:center;gap:10px}
/* Emoji sit on a different baseline to text and read optically smaller, so the
   icon gets its own size and a fixed width — otherwise the labels jag, because
   the glyphs are not all the same advance width. */
.nav-icon{flex:none;width:21px;font-size:17px;line-height:1;text-align:center;
          font-family:"Apple Color Emoji","Segoe UI Emoji","Noto Color Emoji",sans-serif}
.nav button:hover,.nav button.active{background:var(--brand-soft);color:var(--brand-dark)}
.sidebar-foot{margin-top:auto;padding:24px 10px 0;color:var(--muted);font-size:12px;line-height:1.5}
/* min-width:0 is load-bearing. A flex item defaults to min-width:auto, so
   without it the guest table's min-width:1050px becomes a floor for this whole
   column and the page scrolls sideways instead of the table scrolling inside
   .table-wrap. That broke every width between 700px and about 1300px. */
.main{flex:1;min-width:0;padding:32px 42px 60px;max-width:1500px}
.topbar{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:26px}
.eyebrow{letter-spacing:.12em;text-transform:uppercase;font-size:12px;color:var(--brand);font-weight:800}
h2{font-family:var(--font-display);font-size:44px;font-weight:500;letter-spacing:.005em;line-height:1.12;margin:4px 0}
.subtitle{color:var(--muted);font-size:15px}
.actions{display:flex;gap:8px}
.btn{border:1px solid var(--line);background:white;padding:10px 14px;border-radius:11px;color:var(--ink);font-weight:700;transition:background .15s ease,border-color .15s ease,transform .06s ease}
.btn:hover{background:var(--card-2);border-color:var(--line-strong)}
.btn:active{transform:translateY(1px)}
.btn.primary{background:var(--brand-dark);color:white;border-color:var(--brand-dark)}
.btn.primary:hover{background:var(--brand);border-color:var(--brand)}
.btn.ghost{background:transparent}
.grid{display:grid;gap:16px}
.kpis{grid-template-columns:repeat(4,minmax(0,1fr))}
.card{background:rgba(255,253,251,.94);border:1px solid var(--line);border-radius:20px;padding:20px;box-shadow:var(--shadow)}
.kpi .label{font-size:12px;text-transform:uppercase;letter-spacing:.1em;color:var(--muted);font-weight:800}
.kpi .value{font-variant-numeric:lining-nums;font-family:var(--font-display);font-weight:600;font-size:37px;margin:7px 0 3px}
.kpi .hint{font-size:14px;color:var(--muted)}
.alert{margin:18px 0;background:var(--danger-soft);border:1px solid var(--danger-line);border-radius:16px;padding:15px 18px;color:var(--danger);font-weight:700}
.two{grid-template-columns:1.3fr .7fr}
.section-title{display:flex;justify-content:space-between;align-items:center;margin:28px 0 12px;gap:18px}
.section-title h3{font-family:var(--font-display);font-size:27px;font-weight:600;margin:0}
/* The thin rule trailing a heading, borrowed straight from wedding stationery.
   Ordered explicitly — heading, rule, then anything else — rather than relying
   on :last-child, which put the rule in FRONT of a heading that had nothing to
   its right. And the h3 is not itself a flex container: that made its text an
   anonymous flex item, which shrinks to its longest word, so "Four ways to do
   this" came out one word per line on a phone. */
.section-title h3{order:0;flex:none}
.section-title::after{content:"";flex:1;height:1px;background:var(--brand-line);order:1}
.section-title>*:not(h3){order:2;flex:none}
/* Below this there is no width to spare for decoration, and the sub-label has
   to be allowed onto its own line — flex:none above keeps it from shrinking,
   which clipped it off the edge of the card instead. */
@media(max-width:620px){
  .section-title{flex-wrap:wrap;gap:2px 12px}
  .section-title::after{display:none}
  .section-title>*:not(h3){flex:1 1 100%}
}
.section-title span{font-size:14px;color:var(--muted)}
.task{display:flex;align-items:center;gap:12px;padding:12px 0;border-bottom:1px solid var(--line)}
.task:last-child{border-bottom:0}
.dot{width:10px;height:10px;border-radius:50%;background:var(--champ);flex:none}
.dot.high{background:var(--danger)}.dot.medium{background:var(--gold)}.dot.done{background:var(--sage)}
.task-main{flex:1}.task-name{font-weight:650;font-size:15px}.task-meta{font-size:12px;color:var(--muted);margin-top:3px}
.pill{display:inline-flex;align-items:center;padding:5px 8px;border-radius:999px;font-size:11px;font-weight:800;background:var(--brand-soft);color:var(--brand-dark)}
.progress{height:8px;background:var(--line);border-radius:99px;overflow:hidden}.progress>span{display:block;height:100%;background:var(--brand);border-radius:99px}
.phases{grid-template-columns:repeat(7,minmax(0,1fr))}
.phase{min-height:90px}.phase.active{background:var(--brand-soft);border-color:var(--brand-line)}.phase .phase-name{font-size:11px;font-weight:800;letter-spacing:.08em;color:var(--brand-dark)}.phase .phase-sub{font-size:14px;color:var(--muted);margin-top:9px}
.page{display:none}.page.active{display:block}
.toolbar{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:15px}.toolbar input,.toolbar select,.form input,.form select,.form textarea{border:1px solid var(--line);background:white;border-radius:10px;padding:10px 12px;color:var(--ink)}.toolbar input{min-width:260px}
.table-wrap{overflow:auto;border:1px solid var(--line);border-radius:16px;background:white}
table{border-collapse:collapse;width:100%;min-width:1050px}th,td{padding:12px 11px;border-bottom:1px solid var(--line);text-align:left;font-size:14px;vertical-align:top}th{font-size:12px;text-align:center;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);background:var(--card-2);position:sticky;top:0;z-index:1;border-bottom:1px solid var(--line-strong)}
tbody tr{transition:background .12s ease}
tbody tr:hover{background:var(--card-2)}td input,td select,td textarea{width:100%;border:1px solid transparent;background:transparent;padding:5px;border-radius:7px}td input:focus,td select:focus,td textarea:focus{border-color:var(--line);background:white;outline:none}
.vendor-grid{grid-template-columns:repeat(auto-fill,minmax(310px,1fr))}
.vendor-card{position:relative;transition:box-shadow .18s ease,transform .18s ease}
.vendor-card:hover{box-shadow:var(--shadow-lg);transform:translateY(-2px)}.vendor-card h4{font-family:var(--font-display);font-size:25px;font-weight:600;margin:4px 0}.vendor-cat{color:var(--brand);font-size:11px;font-weight:800;letter-spacing:.1em;text-transform:uppercase}.vendor-links{display:flex;gap:8px;flex-wrap:wrap;margin:10px 0}.link{color:var(--brand-dark);font-size:14px;text-decoration:none;background:var(--brand-soft);padding:6px 9px;border-radius:8px}.vendor-price{font-size:20px;font-weight:750;margin:10px 0}.notes{background:var(--card-2);border-radius:12px;padding:11px;color:var(--muted);font-size:14px;line-height:1.55;min-height:68px}
.modal-actions{margin-top:18px;display:flex;gap:8px;justify-content:flex-end}
.form-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:12px}.form label{display:grid;gap:6px;font-size:12px;font-weight:800;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}.form textarea{min-height:110px;resize:vertical}.form .full{grid-column:1/-1}
.modal{position:fixed;inset:0;background:rgba(40,30,30,.35);display:none;align-items:center;justify-content:center;padding:20px;z-index:20}.modal.show{display:flex}.modal-box{background:var(--card);border:1px solid var(--line);border-radius:22px;padding:24px;max-width:720px;width:100%;max-height:90vh;overflow:auto;box-shadow:var(--shadow-lg)}.modal-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.modal-head h3{font-family:var(--font-display);font-size:31px;font-weight:600;letter-spacing:.01em;margin:0}.close{border:0;background:var(--brand-soft);border-radius:50%;width:34px;height:34px;color:var(--brand-dark)}
.empty{padding:40px;text-align:center;color:var(--muted)}
.small{font-size:12px;color:var(--muted)}
@media(max-width:1000px){.sidebar{flex-basis:190px}.main{padding:24px}.kpis{grid-template-columns:repeat(2,1fr)}.phases{grid-template-columns:repeat(3,1fr)}.two{grid-template-columns:1fr}}
@media(max-width:700px){.app{display:block}.sidebar{flex-basis:auto;width:auto;height:auto;position:relative;padding:14px}
  .nav{display:flex;flex-wrap:wrap;gap:6px}.nav button{white-space:nowrap;padding:8px 11px}
  /* 44px of Cormorant is a headline on a laptop and three wrapped lines on a
     phone. */
  h2{font-size:33px}.login-card{padding:40px 26px}.login-card .monogram{font-size:46px}.sidebar-foot{display:none}.main{padding:20px 14px}.kpis{grid-template-columns:1fr 1fr}.phases{grid-template-columns:1fr 1fr}.topbar{display:block}.actions{margin-top:14px}.form-grid{grid-template-columns:1fr}}

/* ============================================================
   Additions for the real site: auth, roles, saving state.
   Everything above this line is the original mockup styling.
   ============================================================ */

/* --- signed-in user chip in the sidebar --- */
.user-chip{display:flex;align-items:center;gap:10px;padding:10px;border-radius:14px;background:var(--brand-soft);margin-bottom:18px}
.user-chip img{width:34px;height:34px;border-radius:50%;flex:none;object-fit:cover}
.user-chip-fallback{width:34px;height:34px;border-radius:50%;flex:none;display:flex;align-items:center;justify-content:center;background:var(--brand);color:#fff;font-family:var(--font-display);font-weight:600;font-size:19px}
.user-chip .who{flex:1;min-width:0}
.user-chip .who b{display:block;font-size:14px;color:var(--brand-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.user-chip .who span{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.08em;font-weight:800}
.user-chip .signout{border:0;background:transparent;color:var(--brand-dark);font-size:12px;font-weight:800;padding:4px}
.role-badge{display:inline-block;padding:3px 7px;border-radius:999px;font-size:11px;font-weight:800;letter-spacing:.06em;background:var(--champ);color:var(--gold-ink)}
.role-badge.admin{background:var(--brand-soft);color:var(--brand-dark)}
.role-badge.editor{background:var(--sage-soft);color:var(--sage-ink)}

/* --- read-only mode for parents (VIEWER) --- */
.readonly .btn.primary,.readonly .row-delete{display:none!important}
.readonly td input,.readonly td select,.readonly td textarea{pointer-events:none;color:var(--ink);opacity:.85}
.readonly .form input,.readonly .form select,.readonly .form textarea{pointer-events:none;opacity:.7}
.viewer-note{background:var(--sage-soft);border:1px solid #cddfd4;color:var(--sage-ink);border-radius:14px;padding:12px 16px;font-size:14px;margin-bottom:18px;font-weight:600}

/* --- toast / save indicator --- */
.toast-wrap{position:fixed;right:20px;bottom:20px;display:grid;gap:8px;z-index:50}
.toast{background:var(--ink);color:#fff;padding:11px 16px;border-radius:12px;font-size:14px;font-weight:600;box-shadow:0 10px 30px rgba(0,0,0,.2);animation:toast-in .18s ease-out}
.toast.err{background:var(--danger)}
.toast.ok{background:var(--sage)}
@keyframes toast-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

/* --- loading + empty states --- */
.loading{padding:60px;text-align:center;color:var(--muted);font-size:15px}
.spinner{width:26px;height:26px;border:3px solid var(--line);border-top-color:var(--brand);border-radius:50%;animation:spin .7s linear infinite;margin:0 auto 14px}
@keyframes spin{to{transform:rotate(360deg)}}

/* --- login page --- */
.login-wrap{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px}
/* An inner hairline inside the card edge — the double rule an invitation is
   printed with. Drawn with a pseudo-element so it doesn't fight the border. */
.login-card{position:relative;background:var(--card);border:1px solid var(--brand-line);border-radius:26px;
            padding:52px 44px;max-width:430px;width:100%;text-align:center;box-shadow:var(--shadow)}
.login-card::before{content:"";position:absolute;inset:10px;border:1px solid var(--brand-line);
                    border-radius:18px;opacity:.55;pointer-events:none}
.login-card>*{position:relative}
.login-card .monogram{font-family:var(--font-script);color:var(--brand-dark);font-size:54px;line-height:1.15}
.login-card h1{font-family:var(--font-display);font-weight:600;font-size:34px;letter-spacing:.02em;margin:10px 0 6px}
.login-card p{color:var(--muted);font-size:15px;margin:0 0 28px;line-height:1.6}
.google-btn{display:inline-flex;align-items:center;justify-content:center;gap:11px;width:100%;padding:13px 18px;border-radius:12px;border:1px solid var(--line);background:#fff;color:var(--ink);font-weight:700;font-size:16px;text-decoration:none}
.google-btn:hover{background:var(--card-2)}
.google-btn svg{width:19px;height:19px;flex:none}
.login-err{background:var(--danger-soft);border:1px solid var(--danger-line);color:var(--danger);border-radius:14px;padding:13px 16px;font-size:14px;margin-bottom:22px;text-align:left;line-height:1.55;font-weight:600}
.login-foot{margin-top:26px;font-size:12px;color:var(--muted);line-height:1.6}

/* --- table row actions --- */
.row-delete{border:0;background:transparent;color:var(--danger);font-weight:800;font-size:16px;padding:4px 8px;border-radius:8px}
.row-delete:hover{background:var(--danger-soft)}
.row-keep{border:0;background:transparent;color:var(--muted);font-weight:800;font-size:16px;padding:4px 8px;border-radius:8px}
.row-keep:hover{background:var(--card-2);color:var(--ink)}
.readonly .row-keep{display:none!important}
.btn.danger{background:var(--danger);border-color:var(--danger);color:#fff}
.btn.danger:hover{background:var(--danger-dark);border-color:var(--danger-dark)}
td.actions-cell{width:44px;text-align:center}

/* --- budget bars --- */
.budget-bar{height:10px;background:var(--line);border-radius:99px;overflow:hidden;display:flex}
.budget-bar i{display:block;height:100%}
.budget-bar i.paid{background:var(--sage)}
.budget-bar i.committed{background:var(--gold)}
.budget-bar i.estimate{background:var(--brand-soft)}
.legend{display:flex;gap:14px;flex-wrap:wrap;font-size:12px;color:var(--muted);margin-top:10px}
.legend b{display:inline-block;width:9px;height:9px;border-radius:3px;margin-right:5px}
.over-budget{color:var(--danger);font-weight:800}

/* --- activity feed --- */
.activity{display:grid;gap:0}
.activity-row{display:flex;gap:10px;align-items:center;padding:9px 0;border-bottom:1px solid var(--line);font-size:14px}
.activity-row:last-child{border-bottom:0}
.activity-row img{width:24px;height:24px;border-radius:50%;flex:none}
.activity-row .when{color:var(--muted);font-size:12px;margin-left:auto;white-space:nowrap}

/* --- honeymoon --- */
.honeymoon-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
.honeymoon-card{display:flex;flex-direction:column;gap:14px}
.honeymoon-card.chosen{border-color:var(--sage);box-shadow:var(--shadow),inset 0 0 0 1px var(--sage)}
.honeymoon-card.chosen .pill{background:var(--sage-soft);color:var(--sage-ink)}
.honeymoon-hero{display:flex;justify-content:space-between;align-items:flex-start;gap:10px}
.honeymoon-tag{color:var(--brand);font-size:11px;font-weight:800;letter-spacing:.12em;text-transform:uppercase}
.honeymoon-name{font-family:var(--font-display);font-size:33px;font-weight:600;margin-top:4px}
.honeymoon-price{font-variant-numeric:lining-nums;font-family:var(--font-display);font-weight:600;font-size:44px;color:var(--brand-dark)}
.honeymoon-for{font-family:Inter,ui-sans-serif,system-ui,sans-serif;font-size:14px;color:var(--muted);font-weight:600}
.honeymoon-vibe{color:var(--ink);font-size:14px;line-height:1.65;margin:0}
.honeymoon-section-label{font-size:11px;text-transform:uppercase;letter-spacing:.1em;color:var(--muted);font-weight:800;margin-top:6px}
.honeymoon-costs{border:1px solid var(--line);border-radius:14px;overflow:hidden;background:white}
.honeymoon-cost-row{display:flex;justify-content:space-between;gap:14px;padding:9px 14px;border-bottom:1px solid var(--line);font-size:14px}
.honeymoon-cost-row:last-child{border-bottom:0}
.honeymoon-cost-row span{color:var(--muted)}
.honeymoon-cost-row b{white-space:nowrap;color:var(--ink)}
.honeymoon-cost-row.total{background:var(--card-2)}
.honeymoon-cost-row.total span,.honeymoon-cost-row.total b{color:var(--brand-dark);font-weight:800}
.honeymoon-days{display:grid;gap:11px}
.honeymoon-day{border-left:3px solid var(--brand-line);padding:1px 0 1px 13px}
.honeymoon-day-head{display:flex;gap:10px;align-items:baseline;flex-wrap:wrap}
.honeymoon-day-num{font-size:11px;font-weight:800;letter-spacing:.06em;color:var(--brand);text-transform:uppercase;white-space:nowrap}
.honeymoon-day-head b{font-size:14px}
.honeymoon-day .small{display:block;margin-top:4px;line-height:1.5}
/* Widens with the number of options rather than a fixed floor, so the wrapper
   scrolls instead of the columns crushing. */
.honeymoon-compare{display:grid;min-width:calc(140px + var(--cols,2) * 130px);background:rgba(255,253,251,.94);border:1px solid var(--line);border-radius:20px;box-shadow:var(--shadow);overflow:hidden}
/* Column count comes from the markup (--cols), so a fifth option needs no CSS.
   Below about five columns this fits; past that the wrapper scrolls rather than
   crushing every cell to nothing. */
.honeymoon-compare-wrap{overflow-x:auto}
.honeymoon-compare-row{display:grid;grid-template-columns:minmax(120px,1.1fr) repeat(var(--cols,2),minmax(120px,1fr));gap:12px;padding:12px 16px;border-bottom:1px solid var(--line);font-size:14px;align-items:baseline}
.honeymoon-compare-row:last-child{border-bottom:0}
.honeymoon-compare-row.head{background:var(--card-2)}
.honeymoon-compare-row.head b{font-family:var(--font-display);font-weight:600;font-size:19px}
.honeymoon-compare-key{color:var(--muted);font-weight:700}
.honeymoon-compare-row span{line-height:1.5}
@media(max-width:1000px){.honeymoon-grid{grid-template-columns:1fr}}
@media(max-width:700px){.honeymoon-compare-row{font-size:12px;padding:9px 10px;gap:8px}}

/* --- ideas: editable topic + question --- */
.idea-topic{width:100%;border:1px solid transparent;background:transparent;color:var(--brand);font-size:11px;font-weight:800;letter-spacing:.08em;padding:4px;border-radius:7px}
.idea-question{width:100%;border:1px solid transparent;background:transparent;font-family:var(--font-display);font-size:22px;font-weight:600;line-height:1.35;margin:8px 0 12px;padding:4px;border-radius:7px;resize:none;overflow:hidden;display:block}
.idea-topic:focus,.idea-question:focus{border-color:var(--line);background:white;outline:none}
.note-box{width:100%;margin-top:10px;border:1px solid var(--line);border-radius:11px;padding:10px;min-height:80px;font-size:14px;background:white;color:var(--ink);resize:vertical}

/* --- ideas: status colours ---------------------------------------------
   Each status owns three values: a soft fill, an ink that clears WCAG AA
   on that fill, and a saturated accent for the card's left edge. Set them
   once per status class, then the chip / select / card all read the vars,
   so a new status means one block here and one entry in IDEA_STATUS.
   ---------------------------------------------------------------------- */
.st-idea{--st-soft:var(--gold-soft);--st-ink:var(--gold-ink);--st-accent:var(--gold)}
.st-discuss{--st-soft:var(--rose-soft);--st-ink:var(--rose-dark);--st-accent:var(--rose)}
.st-researching{--st-soft:var(--plum-soft);--st-ink:var(--plum-ink);--st-accent:var(--plum)}
.st-waiting{--st-soft:var(--card-2);--st-ink:var(--muted);--st-accent:var(--line-strong)}
.st-decided{--st-soft:var(--sage-soft);--st-ink:var(--sage-ink);--st-accent:var(--sage)}
.st-other{--st-soft:var(--champ);--st-ink:var(--gold-ink);--st-accent:var(--gold)}

/* Guest sides. Same --st-* trio as the statuses above, so .chip.on and the
   group headings both pick up the colour without any extra rules. */
/* Everyone is the default, so it's lit almost all the time — card-2 is now so
   close to the panel behind it that "selected" stopped reading at all. */
.side-all{--st-soft:var(--brand-soft);--st-ink:var(--ink);--st-accent:var(--brand-line)}
.side-manusha{--st-soft:var(--rose-soft);--st-ink:var(--rose-dark);--st-accent:var(--rose)}
.side-david{--st-soft:var(--plum-soft);--st-ink:var(--plum-ink);--st-accent:var(--plum)}
.side-family{--st-soft:var(--sage-soft);--st-ink:var(--sage-ink);--st-accent:var(--sage)}
.side-other{--st-soft:var(--champ);--st-ink:var(--gold-ink);--st-accent:var(--gold)}
/* Decision piles. Traffic-light logic: on the list, undecided, cut. */
.dec-discuss{--st-soft:var(--card-2);--st-ink:var(--muted);--st-accent:var(--line-strong)}
.dec-yes{--st-soft:var(--sage-soft);--st-ink:var(--sage-ink);--st-accent:var(--sage)}
.dec-maybe{--st-soft:var(--gold-soft);--st-ink:var(--gold-ink);--st-accent:var(--gold)}
.dec-no{--st-soft:var(--danger-soft);--st-ink:var(--danger);--st-accent:var(--danger-line)}

/* RSVP. Every pairing below was checked against WCAG AA on its own soft
   background before being used: 4.96:1 is the tightest (gold on gold-soft). */
.rsvp-all{--st-soft:var(--card-2);--st-ink:var(--ink);--st-accent:var(--line-strong)}
.rsvp-notset{--st-soft:var(--card-2);--st-ink:var(--muted);--st-accent:var(--line-strong)}
.rsvp-pending{--st-soft:var(--gold-soft);--st-ink:var(--gold-ink);--st-accent:var(--gold)}
.rsvp-attending{--st-soft:var(--sage-soft);--st-ink:var(--sage-ink);--st-accent:var(--sage)}
.rsvp-declined{--st-soft:var(--danger-soft);--st-ink:var(--danger);--st-accent:var(--danger-line)}

/* --- chip row: the ideas status filter, and the honeymoon picker --- */
.chip-row{display:flex;gap:8px;flex-wrap:wrap;margin:20px 0 18px}
.chip-row.tight{margin-top:-10px}
.chip{display:inline-flex;align-items:center;gap:7px;border:1px solid var(--line);background:white;color:var(--muted);
      padding:8px 14px;border-radius:999px;font-size:14px;font-weight:700;transition:background .15s ease,border-color .15s ease,color .15s ease}
.chip:hover{border-color:var(--line-strong);background:var(--card-2)}
.chip-emoji{font-size:15px;line-height:1;margin-right:-2px}
.chip .count{font-size:11px;font-weight:800;background:var(--card-2);color:var(--muted);border-radius:999px;padding:2px 7px;min-width:20px;text-align:center}
.chip.on{background:var(--st-soft,var(--brand-soft));border-color:var(--st-accent,var(--brand));color:var(--st-ink,var(--brand-dark))}
.chip.on .count{background:rgba(255,255,255,.65);color:var(--st-ink,var(--brand-dark))}
.linkish{background:none;border:0;padding:0;color:var(--brand);font-weight:800;font-size:inherit;text-decoration:underline}
/* Marks the seam between the two axes in the guests chip row: the side chips
   pick one list, the maybe chip narrows whichever list that is. */
.chip-sep{width:1px;align-self:stretch;background:var(--line);margin:3px 5px}
/* Says "this combination is empty" before you click it. Still clickable, and
   never applied to the chip that's currently on — a lit-but-dimmed chip in a
   dead end (David + maybe pile, say) reads as broken rather than as empty. */
.chip-empty{opacity:.45}

/* The offer to fill in the rest of the checklist. Sits above the table and
   goes away for good once nothing is missing. */
.checklist-offer{display:flex;align-items:center;gap:20px;justify-content:space-between;
                 flex-wrap:wrap;margin-bottom:18px;border-color:var(--brand-line);
                 background:linear-gradient(180deg,var(--brand-soft) 0,var(--card) 70%)}
.checklist-offer .small{margin-top:5px;max-width:64ch}
.checklist-offer .btn{flex:none}
/* Task titles are sentences, not labels — "Apply for the Ontario marriage
   licence — valid 90 days, two pieces of ID each" needs somewhere to sit. */
/* Task titles are sentences, not labels — "Apply for the Ontario marriage
   licence — valid 90 days, two pieces of ID each" needs somewhere to sit. */
.tasks td:nth-child(2),.tasks th:nth-child(2){min-width:330px}

/* --- ticking tasks off --- */
td.check-cell,th.check-cell{width:44px;min-width:44px;text-align:center;padding-left:14px}
.task-check{width:19px;height:19px;accent-color:var(--sage);cursor:pointer;margin:0}
.readonly .task-check{pointer-events:none;opacity:.55}

/* A done row steps back so the remaining work is what your eye lands on
   scrolling through eighty-six of them. */
.task-done td input,.task-done td select{color:var(--muted)}
.task-done td:nth-child(2) input{text-decoration:line-through}
.task-done{background:var(--card-2)}

/* A task someone has asked to remove. The banner sits directly above its own
   row so there's no doubt which task it refers to in a list of eighty-six. */
tr.delete-request td{background:var(--danger-soft);border-bottom:0;
                     padding:10px 14px;font-size:13px;color:var(--danger)}
tr.delete-request td>span:first-child{margin-right:14px}
.request-actions{display:inline-flex;gap:8px;vertical-align:middle}
.request-actions .btn{padding:5px 11px;font-size:12px}
tr.flagged td{border-bottom:1px solid var(--danger-line)}
tr.flagged td:first-child{box-shadow:inset 3px 0 0 var(--danger)}

/* A whole axis switched off. Still readable — the counts are real and the row
   says what it will do — but plainly not in play yet. */
.filter-row.off{opacity:.5}
.filter-row.off .chip{cursor:default}
.filter-row.off .chip:hover{background:white;border-color:var(--line)}
.filter-note{font-size:12px;color:var(--muted);font-weight:600;margin:0 0 8px 2px}

/* One tile shouldn't stretch across four columns' worth of page. */
/* --- the two panels above the guest table --- */
.panel{background:var(--card);border:1px solid var(--line);border-radius:16px;
       box-shadow:var(--shadow);padding:18px 20px;margin-bottom:14px}

.stats .label{font-size:12px;text-transform:uppercase;letter-spacing:.1em;color:var(--muted);font-weight:800}
.stats-head{display:flex;align-items:flex-start;gap:80px;flex-wrap:wrap}
.stats-value{font-variant-numeric:lining-nums;font-family:var(--font-display);font-weight:600;font-size:41px;line-height:1.1;margin-top:5px}
.stats-sub{font-size:12px;color:var(--muted);font-weight:600;margin-top:4px}
/* Emoji carry no side bearing, so a plain space between one and a word reads
   as no space at all at this size. */
.sub-emoji{margin:0 4px 0 2px}
.stats-note{margin-left:auto;text-align:right;font-size:14px;font-weight:700;color:var(--muted);padding-top:2px}
.stats-note .small{font-weight:600;margin-top:3px}

/* Stacked: solid = decided yes, soft = still being decided on. The gap at the
   end is the headroom left against the maximum. */
.meter{display:flex;height:9px;border-radius:999px;background:var(--card-2);
       border:1px solid var(--line);overflow:hidden;margin:16px 0}
.meter span{display:block;height:100%;transition:width .25s ease}
.meter-yes{background:var(--sage)}
.meter-open{background:var(--sage-soft)}
.meter.over .meter-yes{background:var(--danger)}
.meter.over .meter-open{background:var(--danger-soft)}

/* The piles are the readout and the filter at once, so they're sized to be
   read across the room and still obviously clickable. */
/* Fixed four columns rather than auto-fit so the two rows line up with each
   other — that alignment is the whole reason the tile is readable at a glance.
   A fifth side (it's free text) wraps onto a second line still in column. */
.pile-row{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}
.pile-row+.pile-row{margin-top:10px}

/* The panels that head a page wear the gold properly, rather than every border
   on the site shouting at once. */
.panel.stats,.card.kpi,.login-card,.checklist-offer{border-color:var(--brand-line)}
@media(max-width:900px){.pile-row{grid-template-columns:repeat(2,minmax(0,1fr))}
  .filter-row{display:block}.filter-label{padding-top:0}
  .stats-head{gap:26px}}

/* iOS Safari zooms the whole page when you focus a field whose text is under
   16px, and then leaves you scrolled sideways. Nothing else about the layout
   needs to change — the fields just have to ask for 16px on a phone. */
@media(max-width:700px){
  input,select,textarea,.toolbar input,.form input,.form select,.form textarea,
  td input,td select,td textarea{font-size:16px}
}

@media(max-width:620px){
  /* The three figures sit side by side while there's room; below this the note
     was landing beside a stat label and reading as if it belonged to it. */
  .stats-note{margin-left:0;text-align:left;width:100%;
              border-top:1px solid var(--line);padding-top:10px;margin-top:4px}
  .stats-value{font-size:28px}
  /* Two cards across leaves "Not inviting" wrapping mid-phrase. */
  .pile-row{grid-template-columns:minmax(0,1fr)}
  .pile{padding:10px 12px}
  .filter-foot input{flex:1 1 100%}
}
.pile{display:flex;align-items:center;gap:10px;padding:11px 13px;border-radius:13px;
      border:1px solid var(--line);background:white;text-align:left;
      transition:background .15s ease,border-color .15s ease}
.pile:hover{border-color:var(--line-strong);background:var(--card-2)}
.pile-emoji{font-size:19px;line-height:1}
.pile-n{font-variant-numeric:lining-nums;font-family:var(--font-display);font-weight:600;font-size:24px;color:var(--ink)}
.pile-label{font-size:12px;font-weight:700;color:var(--muted);line-height:1.2}
.pile.on{background:var(--st-soft);border-color:var(--st-accent)}
.pile.on .pile-n,.pile.on .pile-label{color:var(--st-ink)}

.filters{padding:14px 18px}
.filter-row{display:flex;align-items:baseline;gap:14px}
.filter-label{flex:0 0 58px;font-size:11px;text-transform:uppercase;letter-spacing:.09em;
              font-weight:800;color:var(--muted);padding-top:9px}
.filters .chip-row{margin:8px 0}
.filter-foot{display:flex;align-items:center;gap:12px;flex-wrap:wrap;
             border-top:1px solid var(--line);margin-top:6px;padding-top:13px}
.filter-foot input{flex:1 1 240px;min-width:200px;border:1px solid var(--line);background:white;
                   border-radius:10px;padding:9px 12px;color:var(--ink)}

/* --- the three decision buttons on each row --- */
/* Three separate targets rather than one welded strip: these set whether a real
   person is invited, so the cost of a slip is higher than the cost of the extra
   width. The gap is what stops a near-miss landing on the neighbour.

   Unselected buttons are desaturated so the chosen one is what your eye lands
   on down a column of 70 rows — but not so far that they read as disabled,
   which is exactly what grayscale(1) at 0.4 opacity looked like. */
.seg{display:inline-flex;gap:7px}
/* The label is never faded — dimming the whole button was what made these hard
   to read. Only the emoji desaturates when the option isn't the chosen one;
   the selected state is carried by the fill, the border and the ink colour,
   which is plenty of contrast without hiding the other two words. */
.seg-btn{display:inline-flex;align-items:center;gap:5px;padding:7px 11px;cursor:pointer;
         font-size:14px;font-weight:700;line-height:1.3;color:var(--muted);
         background:white;border:1px solid var(--line);border-radius:10px;
         transition:color .12s ease,background .12s ease,border-color .12s ease}
/* No desaturation at all. These three carry their meaning in their colour —
   any greyscale turned the orange circle into a brown dot that read as nothing.
   The chosen option is marked by the pill's fill, border and ink instead, which
   is a stronger signal than dimming the other two ever was. */
.seg-emoji{font-size:16px;line-height:1;opacity:.9;transition:opacity .12s ease}
.seg-btn:hover{background:var(--card-2);border-color:var(--line-strong);color:var(--ink)}
.seg-btn:hover .seg-emoji{opacity:1}
.seg-btn.on{color:var(--st-ink);background:var(--st-soft);border-color:var(--st-accent);
            box-shadow:inset 0 0 0 1px var(--st-accent)}
.seg-btn.on .seg-emoji{opacity:1}
td.decision-cell{width:280px}

/* Once a row is decided, the two options not taken fade right back. Three
   equally-weighted buttons made every settled row still look like an open
   question; now the answer is the only thing your eye catches scanning down the
   column. They return on hover, because changing your mind is one click away.
   Undecided rows keep all three even — there, they really are a question. */
.seg.decided .seg-btn:not(.on){opacity:.3}
.seg.decided .seg-btn:not(.on):hover{opacity:1}

/* Parents read this list. They can't press the buttons, but they do need to see
   which one is set — so on an undecided row the options stay readable rather
   than vanish. (A decided row is already handled above, and more sharply: the
   unchosen options carry nothing for someone who can't click them.) */
.readonly .seg-btn{pointer-events:none}
.readonly .seg-btn:not(.on){opacity:.6}


/* --- export / print --- */
.toolbar-right{display:flex;gap:8px;margin-left:auto}
.menu{position:relative}
.menu>summary{list-style:none;cursor:pointer;display:inline-block}
.menu>summary::-webkit-details-marker{display:none}
.menu[open]>summary{background:var(--card-2);border-color:var(--line-strong)}
.menu-pop{position:absolute;right:0;top:calc(100% + 6px);z-index:20;min-width:230px;
          background:white;border:1px solid var(--line);border-radius:12px;
          box-shadow:var(--shadow);padding:6px;text-align:left}
.menu-pop button{display:flex;flex-direction:column;gap:2px;width:100%;text-align:left;
                 padding:9px 11px;border-radius:8px;background:none;border:0;
                 color:var(--ink);font-weight:700;font-size:14px}
.menu-pop button:hover{background:var(--card-2)}
.menu-hint{font-size:12px;font-weight:600;color:var(--muted)}
.menu-note{padding:7px 11px 4px;font-size:12px;color:var(--muted);border-top:1px solid var(--line);margin-top:4px}

/* --- guests: group headings inside the table --- */
/* th is sticky by default (the real table head); these live in the tbody and
   must scroll with their rows, hence position:static. */
.group-row th{position:static;text-align:left;background:var(--st-soft,var(--card-2));color:var(--st-ink,var(--ink));
              border-top:1px solid var(--st-accent,var(--line-strong));border-bottom:1px solid var(--st-accent,var(--line-strong));
              text-transform:none;letter-spacing:0;font-size:14px;padding:11px 12px}
.group-row:first-child th{border-top:0}
.group-name{font-weight:800}
.group-count{font-weight:600;opacity:.72;margin-left:10px;font-size:12px}

/* --- ideas: the status picker on each tile --- */
.idea-card{border-left:4px solid var(--st-accent,var(--line))}
.idea-status{width:100%;-webkit-appearance:none;appearance:none;border:1px solid var(--st-accent,var(--line));
             background:var(--st-soft,white);color:var(--st-ink,var(--ink));border-radius:999px;
             padding:8px 30px 8px 13px;font-size:12px;font-weight:800;letter-spacing:.04em;
             background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,transparent 50%);
             background-position:calc(100% - 15px) calc(50% + 1px),calc(100% - 11px) calc(50% + 1px);
             background-size:4px 4px,4px 4px;background-repeat:no-repeat}
.readonly .idea-topic,.readonly .idea-question,.readonly .note-box,.readonly .idea-status,
.readonly .chip.pick{pointer-events:none}
.readonly .chip.pick:not(.on){opacity:.5}

/* ------------------------------------------------------------------ print */
/* The screen chrome is meaningless on paper, and the controls that filtered
   the list are already summarised in .print-head. What's left is a plain table
   of names — which is the whole reason someone hit Print. */
.print-head{display:none}

@media print{
  @page{margin:14mm}
  .sidebar,.nav,.topbar .actions,.chip-row,.toolbar,.kpis,.viewer-note,
  .panel.filters,.panel.stats,.actions-cell,.modal,.toast-wrap{display:none!important}
  .app,.main{display:block;padding:0;background:white}
  body{background:white;color:black}

  /* The topbar already prints the title, the couple and the season, so the
     print-only line adds just the part paper can't infer: which slice of the
     list this is, how big it is, and when it was run. */
  .print-head{display:block;font-size:11px;color:#555;margin:2px 0 14px}
  .topbar{margin-bottom:0}

  .table-wrap{border:0;border-radius:0;overflow:visible}
  table{min-width:0;width:100%}
  th,td{padding:5px 7px;font-size:10px;border-bottom:1px solid #ddd}
  thead th{background:#f2f2f2;color:black;position:static}

  /* Inputs print their value, but the browser keeps the widget metrics unless
     they're flattened — otherwise every cell is padded like a form field. */
  td input,td select,td textarea{border:0;background:none;padding:0;
                                 -webkit-appearance:none;appearance:none;
                                 color:black;font-size:10px}
  td select{background-image:none}
  /* An empty Notes field otherwise prints its placeholder — a column of "…". */
  td input::placeholder,td textarea::placeholder{color:transparent}

  /* Greyed-out emoji buttons are meaningless on paper — print the word, and
     flatten every trace of the control so the cell is the same height as one
     holding plain text. */
  .seg{border:0;display:inline;gap:0}
  .seg-btn{display:none}
  .seg-btn.on{display:inline-flex;gap:5px;width:auto;padding:0;border:0;box-shadow:none;
              background:none;opacity:1;font-size:10px;color:black}

  .group-row th{background:#eee!important;color:black;border-top:1px solid #bbb;
                border-bottom:1px solid #bbb;font-size:11px;padding:6px 7px}
  .group-row{break-inside:avoid;break-after:avoid}
  tr{break-inside:avoid}
}

/* ───────────────────────────────────────────────────────────── venues ── */
/* Mockup. See web/js/venues.js — the numbers are invented. */


/* Four items at the 80px gap the other pages use wrap onto two rows and leave
   a hole. Tighter, and the note sits on the same line as the figures. */

/* The upload target. Big, obvious, and the only thing on the page that looks
   like it wants something from you. */
.dropzone{border:2px dashed var(--brand-line);border-radius:18px;background:var(--card);
          padding:30px 24px;text-align:center;cursor:pointer;margin-bottom:6px;
          transition:background .15s ease,border-color .15s ease}
.dropzone:hover{background:var(--brand-soft);border-color:var(--brand)}
.dropzone-icon{font-size:30px;line-height:1;margin-bottom:8px}
.dropzone .small{margin:7px auto 0;max-width:62ch}

.venue-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
.venue-card{display:flex;flex-direction:column;gap:14px;border-left:4px solid var(--st-accent,var(--line))}
.venue-passed{opacity:.6}
.venue-head{display:flex;justify-content:space-between;align-items:flex-start;gap:14px}
.venue-head h4{font-family:var(--font-display);font-size:25px;font-weight:600;margin:2px 0}
.venue-area{font-size:11px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--brand)}
.venue-status{flex:none;pointer-events:none}

/* The number the whole page exists to show. */
.venue-headline{border-top:1px solid var(--line);border-bottom:1px solid var(--line);padding:12px 0}
.venue-total{font-family:var(--font-display);font-variant-numeric:lining-nums;
             font-size:36px;font-weight:600;color:var(--brand-dark);line-height:1.1}

.venue-breakdown{display:grid;gap:5px}
.venue-line{display:flex;justify-content:space-between;gap:12px;font-size:13px}
.venue-line-sub{color:var(--muted);font-weight:600;margin-left:7px;font-size:11px}

.venue-facts{display:flex;flex-wrap:wrap;gap:7px}
.venue-fact{font-size:11px;font-weight:700;padding:5px 9px;border-radius:999px;
            background:var(--sage-soft);color:var(--sage-ink)}
.venue-fact.warn{background:var(--gold-soft);color:var(--gold-ink)}
.venue-fact.bad{background:var(--danger-soft);color:var(--danger)}

.venue-files{display:flex;flex-wrap:wrap;gap:7px;align-items:center;row-gap:7px}
.venue-file{display:inline-flex;align-items:center;gap:6px;font-size:11px;font-weight:700;
            padding:6px 10px;border-radius:9px;border:1px solid var(--line);background:white;
            color:var(--ink);cursor:pointer;text-decoration:none}
.venue-file:hover{border-color:var(--brand-line);background:var(--brand-soft)}
.venue-file-count{margin-left:auto;white-space:nowrap}
.venue-more{align-self:flex-start;margin-top:auto}

/* status colours — same --st-* trio every other vocabulary on the site uses */
.vst-brochure{--st-soft:var(--card-2);--st-ink:var(--muted);--st-accent:var(--line-strong)}
.vst-toured{--st-soft:var(--plum-soft);--st-ink:var(--plum-ink);--st-accent:var(--plum)}
.vst-quoted{--st-soft:var(--gold-soft);--st-ink:var(--gold-ink);--st-accent:var(--gold)}
.vst-shortlist{--st-soft:var(--sage-soft);--st-ink:var(--sage-ink);--st-accent:var(--sage)}
.vst-passed{--st-soft:var(--danger-soft);--st-ink:var(--danger);--st-accent:var(--danger-line)}

/* detail modal */
.venue-modal-total{display:flex;justify-content:space-between;align-items:flex-end;gap:16px;
                   border-top:1px solid var(--line);border-bottom:1px solid var(--line);
                   padding:14px 0;margin-top:12px}
.venue-modal-total .stats-value{font-variant-numeric:lining-nums;color:var(--brand-dark)}
.venue-modal-avail{text-align:right}
.venue-chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:7px}
.venue-chip{font-size:12px;font-weight:700;padding:5px 10px;border-radius:999px}
.venue-chip.yes{background:var(--sage-soft);color:var(--sage-ink)}
.venue-chip.no{background:var(--gold-soft);color:var(--gold-ink)}
.venue-filelist{display:grid;gap:7px;margin-top:7px}
.venue-filerow{display:flex;align-items:center;gap:12px;text-align:left;width:100%;
               padding:11px 13px;border:1px solid var(--line);border-radius:12px;
               background:white;cursor:pointer}
.venue-filerow:hover{border-color:var(--brand-line);background:var(--brand-soft)}
.venue-filerow-main{flex:1;min-width:0;display:grid}
.venue-filerow-main b{font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.venue-file-emoji{font-size:19px}
.venue-notes{min-height:0;margin-top:7px}

@media(max-width:1000px){.venue-grid{grid-template-columns:1fr}}
@media(max-width:620px){
  .venue-head{display:block}
  .venue-status{margin-top:8px}
  .venue-total{font-size:30px}
}

/* --- venue photos, map link, compare picker --- */

/* Placeholder frames. Real photos land here once the upload box works — these
   exist so the space is designed for rather than retrofitted. */
.venue-photos{display:grid;grid-template-columns:repeat(auto-fit,minmax(90px,1fr));gap:8px}
.venue-photo{position:relative;height:104px;border-radius:12px;border:1px solid var(--line);
             cursor:pointer;overflow:hidden;display:flex;align-items:flex-end;padding:0}
.venue-photo-none::after{content:"⌸";position:absolute;inset:0;display:flex;align-items:center;
                         justify-content:center;font-size:24px;color:rgba(255,255,255,.65)}
/* Real photographs out of the venues' own brochures. object-fit keeps a
   portrait crop from stretching next to a landscape one. */
.venue-photo img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.venue-photo.p0{background:linear-gradient(135deg,#b9a77f,#8a6a2f)}
.venue-photo.p1{background:linear-gradient(135deg,#a8b3a0,#5a8270)}
.venue-photo.p2{background:linear-gradient(135deg,#c2a9ae,#96555f)}
.venue-photo.p3{background:linear-gradient(135deg,#a9a0b8,#7a5a86)}
.venue-photo:hover{border-color:var(--brand)}
/* The scrim is what makes the caption legible, not the gradient underneath —
   white on the lightest of those tints is only 4.3:1 on its own. At 0.7 the
   worst case blends to roughly #2a2010, which is >12:1. */
.venue-photo-cap{position:relative;z-index:1;width:100%;text-align:left;padding:14px 9px 7px;
                 font-size:11px;font-weight:700;color:#fff;
                 background:linear-gradient(180deg,rgba(0,0,0,0) 0,rgba(0,0,0,.7) 55%)}

.venue-map{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--brand-dark);
           text-decoration:none;font-weight:600}
.venue-map:hover{text-decoration:underline}

.venue-actions{display:flex;align-items:center;gap:12px;margin-top:auto}
.venue-compare{display:inline-flex;align-items:center;gap:7px;font-size:12px;font-weight:700;
               padding:8px 12px;border:1px solid var(--line);border-radius:10px;
               background:white;color:var(--muted);cursor:pointer;flex:none}
.venue-compare input{width:16px;height:16px;accent-color:var(--brand);margin:0;cursor:pointer}
.venue-compare:hover{border-color:var(--brand-line)}
.venue-compare.on{background:var(--brand-soft);border-color:var(--brand);color:var(--brand-dark)}
.venue-picked{box-shadow:var(--shadow),0 0 0 2px var(--brand-line)}
.readonly .venue-compare{opacity:1}

@media(max-width:620px){
  .venue-photo{height:88px}
  .venue-actions{flex-wrap:wrap}
  .venue-more{flex:1 1 100%}
}

/* --- venue map view --- */

.venue-viewtabs{display:inline-flex;gap:0;border:1px solid var(--line-strong);border-radius:10px;overflow:hidden;flex:none}
.venue-tab{padding:7px 15px;font-size:13px;font-weight:700;background:white;border:0;white-space:nowrap;
           color:var(--muted);cursor:pointer}
.venue-tab+.venue-tab{border-left:1px solid var(--line)}
.venue-tab:hover{background:var(--card-2);color:var(--ink)}
.venue-tab.on{background:var(--brand-dark);color:#fff}

.venue-maprow{display:flex;align-items:center;justify-content:space-between;gap:14px;
              flex-wrap:wrap;margin-bottom:14px}

/* auto-fit so the three you're comparing land side by side, and "all" wraps
   3 + 2 instead of forcing a scrollbar. */
.venue-map-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px}
.venue-map-card{padding:0;overflow:hidden;display:flex;flex-direction:column;
                border-left:4px solid var(--st-accent,var(--line))}
/* The embed is an iframe, so it brings its own scrollbars and border unless
   told otherwise. */
.venue-map-frame{width:100%;height:260px;border:0;display:block;background:var(--card-2)}
.venue-map-body{display:flex;justify-content:space-between;align-items:flex-start;gap:14px;
                padding:14px 16px 10px}
.venue-map-body b{font-family:var(--font-display);font-size:21px;font-weight:600}
.venue-map-cost{text-align:right;flex:none}
.venue-map-cost b{display:block;font-variant-numeric:lining-nums;color:var(--brand-dark);font-size:22px}
.venue-map-open{margin:0 16px 16px;align-self:flex-start}

@media(max-width:700px){.venue-map-grid{grid-template-columns:1fr}}
@media(max-width:620px){
  .venue-map-frame{height:200px}
  .venue-map-body{display:block}
  .venue-map-cost{text-align:left;margin-top:8px}
}

/* --- capacity / missing-pricing alerts --- */
/* Loud on purpose: a venue that cannot seat everyone is not a price question,
   and it must not be something you only notice in the detail modal. */
.venue-alert{display:flex;gap:7px;align-items:center;font-size:12px;font-weight:700;
             padding:9px 11px;border-radius:10px;
             background:var(--danger-soft);color:var(--danger-dark);
             border:1px solid var(--danger-line)}
.venue-alert.warn{background:var(--gold-soft);color:var(--gold-ink);border-color:var(--gold)}

.venue-caveats{margin:7px 0 0;padding-left:19px;font-size:13px;color:var(--ink)}
.venue-caveats li{margin:5px 0}
.venue-modal-pkg{color:var(--brand-dark);font-weight:700;margin-top:3px}

.venue-photo-full img{width:100%;border-radius:12px;display:block;margin-bottom:9px}


/* --- ruled out on capacity --- */
/* Considered and dismissed. Faded so it drops back visually, but deliberately
   still legible and still comparable — the point is to see WHY it's out, not
   to hide it. Hover restores it fully for when you do want to read it. */
.venue-dismissed{opacity:.55;border-color:var(--danger);background:var(--danger-soft);
                 box-shadow:none}
.venue-dismissed:hover,
.venue-dismissed:focus-within{opacity:1}
.venue-dismissed .venue-photos,
.venue-dismissed .venue-total{filter:grayscale(.75)}
.venue-dismissed .venue-total{color:var(--muted)}
/* The alert itself must not fade with the rest — it is the reason. */
.venue-dismissed .venue-alert{opacity:1;font-weight:800}

@media(prefers-reduced-motion:no-preference){
  .venue-dismissed{transition:opacity .15s ease}
}

/* --- seat target --- */
/* The single most consequential choice on the page, so it sits above the
   numbers it changes rather than being tucked in a corner. */
.seat-target{display:flex;align-items:center;gap:14px;flex-wrap:wrap;
             padding-bottom:16px;margin-bottom:16px;border-bottom:1px solid var(--line)}
/* Four of these now, so they wrap instead of forcing a scrollbar on a phone. */
.seat-tabs{display:inline-flex;gap:8px;flex-wrap:wrap}
.seat-tab{display:flex;flex-direction:column;align-items:center;gap:1px;
          padding:7px 20px;border-radius:11px;border:1px solid var(--line-strong);
          background:var(--card);color:var(--muted);cursor:pointer;line-height:1.15}
.seat-tab b{font-family:var(--font-display);font-size:25px;font-weight:700;
            font-variant-numeric:lining-nums;color:var(--ink)}
.seat-tab span{font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase}
.seat-tab:hover{border-color:var(--brand-line);background:var(--brand-soft)}
.seat-tab.on{border-color:var(--brand);background:var(--brand-soft);color:var(--brand-dark);
             box-shadow:inset 0 0 0 1px var(--brand)}
.seat-tab.on b{color:var(--brand-dark)}
.seat-target-note{margin-left:auto}

/* When the target outgrows the small room, say which room we switched to. */
.venue-room{font-size:12px;padding:8px 11px;border-radius:10px;
            background:var(--brand-soft);color:var(--brand-dark);
            border:1px solid var(--brand-line)}

/* --- archived --- */
.archive-title{margin-top:34px}
.archive-note{font-size:13px;color:var(--muted);padding:13px 16px;margin-bottom:14px}
/* Already faded by .venue-dismissed; this just keeps the whole block quiet. */
.venue-archive .venue-card{box-shadow:none}

@media(max-width:620px){
  .seat-target{gap:10px}
  .seat-target-note{margin-left:0;flex-basis:100%}
  /* Share the row four ways rather than letting the widest label set the pace. */
  .seat-tabs{display:grid;grid-template-columns:repeat(4,1fr);width:100%;gap:6px}
  .seat-tab{padding:6px 4px}
  .seat-tab b{font-size:21px}
  .seat-tab span{font-size:9px;letter-spacing:.02em}
}

/* --- review ratings --- */
.venue-reviews{display:flex;flex-direction:column;gap:5px;padding:11px 13px;
               border-radius:11px;background:var(--card-2);border:1px solid var(--line)}
/* Says whose judgement this is. The scores are synthesised, not scraped off
   one site, and the card should not let anyone assume otherwise. */
.venue-review-head{font-size:10px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;
                   color:var(--brand-dark);margin-bottom:2px}
.venue-review-row{display:flex;align-items:center;gap:10px}
.venue-review-key{font-size:11px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
                  color:var(--muted);width:56px;flex:none}
/* Two copies of the same glyphs, the filled one clipped to the score, so 4.7
   reads as 4.7 rather than rounding to five gold stars. */
.stars{position:relative;display:inline-block;white-space:nowrap;font-size:15px;
       letter-spacing:2px;line-height:1}
.stars-off{color:var(--line-strong)}
.stars-on{position:absolute;left:0;top:0;overflow:hidden;color:var(--gold);
          white-space:nowrap}
.stars-num{font-size:13px;font-variant-numeric:lining-nums;color:var(--ink)}
.stars-none{font-size:12px;font-style:italic;color:var(--muted)}
.venue-reviews.big{gap:8px}
.venue-reviews.big .venue-review-head{font-size:12px}
.venue-reviews.big .stars{font-size:23px}
.venue-reviews.big .stars-num{font-size:18px}

.venue-review-src{margin-top:3px;text-align:left;font-size:11px;font-weight:700;
                  background:none;border:0;padding:0;cursor:pointer;color:var(--muted);
                  text-decoration:underline;text-underline-offset:2px}
.venue-review-src:hover{color:var(--brand-dark)}
.venue-review-src.conf-high{color:var(--brand-dark)}
.venue-review-src.conf-low,
.venue-review-src.conf-none{color:var(--danger-dark)}
.venue-review-method{line-height:1.5;margin-top:7px}

/* --- open question on a card --- */
/* Amber rather than red: nothing is wrong, something is unanswered. Sits
   directly under the cost breakdown because that is the number it changes. */
.venue-ask{display:flex;gap:9px;align-items:flex-start;font-size:12px;line-height:1.45;
           padding:10px 12px;border-radius:10px;
           background:var(--gold-soft);color:var(--gold-ink);border:1px solid var(--gold)}
.venue-ask-icon{flex:none;font-size:14px;line-height:1.3}
.venue-ask b{color:var(--ink)}
.venue-ask-copy{display:block;margin-top:5px;padding:0;border:0;background:none;
                font-size:11px;font-weight:800;color:var(--brand-dark);cursor:pointer;
                text-decoration:underline;text-underline-offset:2px}
.venue-ask-copy:hover{color:var(--ink)}

/* --- enquiry email --- */
.venue-email-subject,
.venue-email-body{width:100%;font-family:inherit;font-size:14px;color:var(--ink);
                  background:var(--card);border:1px solid var(--line-strong);
                  border-radius:10px;padding:10px 12px;margin-top:5px}
.venue-email-body{line-height:1.55;resize:vertical;min-height:220px}
.venue-email-subject:focus,
.venue-email-body:focus{outline:2px solid var(--brand);outline-offset:1px;border-color:var(--brand)}
.venue-email-actions{flex-wrap:wrap;gap:8px}
/* The mail-app link is an <a>, so it needs the button's centring. */
.venue-email-actions .btn{display:inline-flex;align-items:center;justify-content:center;
                          text-decoration:none}
.venue-email-btn{white-space:nowrap}

@media(max-width:620px){
  .venue-email-actions .btn{flex:1 1 100%}
}

/* --- ceremony toggle --- */
/* Second row under the seat buttons, sharing their look so the two read as one
   set of controls over the same numbers. Its labels are words not numbers, so
   they need a smaller face than the 150/200 digits. */
.ceremony-target{padding-bottom:0;margin-bottom:0;border-bottom:0;padding-top:2px}
.ceremony-target .seat-tab b{font-size:15px;letter-spacing:.01em;padding:3px 0}

@media(max-width:620px){
  .ceremony-target .seat-tabs{grid-template-columns:repeat(2,1fr)}
  .ceremony-target .seat-tab b{font-size:14px}
}

/* --- deposit --- */
/* Quieter than the amber questions: this is information, not a task. But it is
   the only money on the page due this year, so it gets its own line. */
.venue-deposit{display:flex;gap:9px;align-items:flex-start;font-size:12px;line-height:1.45;
               padding:9px 12px;border-radius:10px;
               background:var(--card-2);border:1px solid var(--line)}
.venue-deposit b{color:var(--ink)}
.venue-deposit-note{display:block;color:var(--muted);margin-top:2px}

/* Three date buttons carry two lines of text each; give them room. */
.ceremony-target .seat-tab{padding:6px 14px}
@media(max-width:620px){
  .ceremony-target .seat-tabs{grid-template-columns:repeat(3,1fr)}
  .ceremony-target .seat-tab{padding:6px 2px}
  .ceremony-target .seat-tab b{font-size:12px}
}

/* --- practical small print --- */
.venue-practical{display:flex;flex-wrap:wrap;gap:5px 7px;list-style:none;margin:0;padding:0}
.venue-practical li{display:inline-flex;align-items:center;gap:5px;font-size:11px;font-weight:600;
                    padding:4px 9px;border-radius:999px;background:var(--card-2);
                    border:1px solid var(--line);color:var(--muted);cursor:help}
.venue-practical li.good{color:var(--ink)}
/* The catches earn colour; the conveniences don't. */
.venue-practical li.watch{background:var(--gold-soft);border-color:var(--gold);color:var(--gold-ink)}
.venue-practical-more{font-style:italic;cursor:default}
.venue-practical-icon{font-size:12px;line-height:1}

.venue-practical-full{display:flex;flex-direction:column;gap:9px;margin-top:8px}
.venue-practical-row{display:flex;gap:10px;align-items:flex-start;font-size:13px;
                     padding:9px 12px;border-radius:10px;background:var(--card-2);
                     border:1px solid var(--line)}
.venue-practical-row.watch{background:var(--gold-soft);border-color:var(--gold)}
.venue-practical-row .small{display:block;margin-top:2px;line-height:1.45}
.venue-practical-row .venue-practical-icon{font-size:16px;line-height:1.3}

/* Divider between the Date and Ceremony rows, matching the one under the seat
   buttons so all three controls read as separate questions. */
.date-target{padding-bottom:14px;margin-bottom:14px;border-bottom:1px solid var(--line)}
@media(max-width:620px){
  .date-target{padding-bottom:11px;margin-bottom:11px}
}

/* The control rows are one block of questions; the stats below are the answer.
   .ceremony-target zeroes its own margin so the Date/Ceremony rows sit tight
   together, which left the last one touching the numbers. Space it off here so
   the gap belongs to the boundary rather than to whichever row happens to be
   last. */

/* --- best case --- */
.bestcase{margin-bottom:18px;padding:16px 0 4px}
.bestcase .fold-head{padding-left:20px;padding-right:20px}
.bestcase .fold-title{font-size:24px}
.bestcase-title{margin:0;padding:4px 20px 0}
.bestcase-title h3{margin:0}
.bestcase-body{display:grid;grid-template-columns:1fr 1fr;gap:20px;padding:16px 20px 4px}
.bestcase-pick{display:flex;flex-direction:column;gap:2px}
.bestcase-venue{font-family:var(--font-display);font-size:26px;font-weight:600;color:var(--ink);
                line-height:1.15}
.bestcase-total{font-family:var(--font-display);font-size:40px;font-weight:700;
                font-variant-numeric:lining-nums;color:var(--brand-dark);line-height:1.1;
                margin-top:4px}
/* The left-over number is the point of the card, so it gets its own panel and
   a colour that says whether it is enough. */
.bestcase-left{padding:14px 16px;border-radius:12px;border:1px solid var(--line);
               background:var(--card-2)}
.bestcase-remain{font-family:var(--font-display);font-size:34px;font-weight:700;
                 font-variant-numeric:lining-nums;line-height:1.15;margin:2px 0 4px}
.bestcase-left.good{background:var(--sage-soft);border-color:var(--sage)}
.bestcase-left.good .bestcase-remain{color:var(--sage-ink)}
.bestcase-left.good .label,
.bestcase-left.good .small{color:var(--sage-ink)}
.bestcase-left.ok{background:var(--gold-soft);border-color:var(--gold)}
.bestcase-left.ok .bestcase-remain{color:var(--gold-ink)}
.bestcase-left.bad{background:var(--danger-soft);border-color:var(--danger-line)}
.bestcase-left.bad .bestcase-remain{color:var(--danger-dark)}
.bestcase-benchmark{display:block;margin-top:7px;color:var(--muted);line-height:1.45}

.bestcase-notes{display:flex;flex-direction:column;gap:7px;font-size:13px;
                padding:6px 20px 16px;color:var(--ink)}
.bestcase-warn{padding:9px 12px;border-radius:10px;background:var(--gold-soft);
               border:1px solid var(--gold);color:var(--gold-ink);line-height:1.45}
.bestcase.empty{padding:18px 20px}

@media(max-width:760px){
  .bestcase-body{grid-template-columns:1fr;gap:14px}
  .bestcase-total{font-size:34px}
  .bestcase-remain{font-size:28px}
}

/* --- first-look clarity --- */
/* The headline figure is the whole point of the page and was going unexplained
   once the old stats block came out. One line, where the cards start. */
.price-legend{font-size:13px;line-height:1.55;color:var(--muted);
              padding:11px 14px;margin-bottom:14px;border-radius:10px;
              background:var(--card-2);border:1px solid var(--line)}
.price-legend b{color:var(--ink);font-weight:700}

.controls-intro{font-size:13px;color:var(--muted);padding-bottom:13px;margin-bottom:14px;
                border-bottom:1px solid var(--line)}

/* Cheapest-first only reads as deliberate if the order is numbered. */
.venue-rank{display:inline-flex;align-items:center;justify-content:center;
            min-width:19px;height:19px;padding:0 5px;margin-right:7px;border-radius:999px;
            background:var(--brand);color:#fff;font-size:11px;font-weight:800;
            font-variant-numeric:lining-nums;letter-spacing:0;vertical-align:1px}

/* Chip detail lives in title=, which never shows on a touch screen. Both rows
   open the modal that spells everything out. */
.venue-facts,
.venue-practical.tappable{cursor:pointer}
.venue-facts:focus-visible,
.venue-practical.tappable:focus-visible{outline:2px solid var(--brand);outline-offset:3px;
                                        border-radius:8px}
@media(hover:none){
  /* Only worth saying where hovering isn't an option. */
  .venue-practical.tappable::after{content:"tap for detail";font-size:10px;font-style:italic;
                                   color:var(--muted);align-self:center;margin-left:2px}
}

/* The upload box now closes the page, so it needs air between it and the last
   run of cards rather than butting straight onto them. */
.venue-grid + .dropzone,
.venue-archive + .dropzone{margin-top:34px}
@media(max-width:620px){
  .venue-grid + .dropzone,
  .venue-archive + .dropzone{margin-top:26px}
}

/* The ceremony row is the last thing in the control panel and zeroes its own
   bottom margin, so give the panel itself the closing space. */
.venues-stats{padding-bottom:20px}

/* --- spreadsheet export --- */
/* Sits in the section heading beside the "cheapest first" label; the heading is
   a flex row with a hairline rule, so the pair needs to travel together. */
.venue-export-wrap{display:flex;align-items:center;gap:12px;flex:none}
.venue-export{padding:6px 12px;font-size:12px;white-space:nowrap}

@media(max-width:620px){
  .venue-export-wrap{flex-wrap:wrap;gap:7px}
}

/* --- immediate next steps --- */
/* Sits above the progress bar, so it is the first thing on the planning page.
   Gold rather than the usual card, because its whole job is to be noticed. */
.next-steps{margin-bottom:18px;border-color:var(--brand-line);background:var(--brand-soft)}
.next-steps-head{display:flex;justify-content:space-between;align-items:baseline;gap:14px;
                 flex-wrap:wrap;margin-bottom:12px}
.next-steps-head h3{font-family:var(--font-display);font-size:24px;font-weight:600;margin:0;
                    color:var(--ink)}

/* One block per person. The name is the heading and their tasks sit under it,
   so nobody has to read the whole card to find their own. */
.next-group + .next-group{margin-top:16px}
.next-group-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
                 padding-bottom:6px;margin-bottom:8px;border-bottom:1px solid var(--brand-line)}
.next-group-name{font-family:var(--font-display);font-size:20px;font-weight:600;color:var(--ink)}
.next-group-you{display:inline-block;margin-left:5px;padding:2px 7px;border-radius:999px;
                background:var(--brand-dark);color:#fff;font-family:var(--font-sans,inherit);
                font-size:10px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
                vertical-align:2px}

.next-steps-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.next-step{display:flex;align-items:flex-start;gap:12px;padding:12px 14px;border-radius:12px;
           background:var(--card);border:1px solid var(--brand-line)}
.next-step.late{border-color:var(--danger-line);background:var(--danger-soft)}
.next-step-tick{flex:none;display:flex;align-items:center;padding-top:1px}
.next-step-tick input{width:19px;height:19px;accent-color:var(--brand-dark);cursor:pointer}
.next-step-main{flex:1;min-width:0}
.next-step-main b{font-size:15px;color:var(--ink);line-height:1.35}
/* Notes carry the detail of what to actually ask, but must not crowd out the
   three or four titles above them. */
.next-step-notes{margin-top:4px;line-height:1.5;display:-webkit-box;-webkit-line-clamp:2;
                 -webkit-box-orient:vertical;overflow:hidden}
.next-step-meta{flex:none;text-align:right;display:flex;flex-direction:column;gap:2px}
.next-step-due{font-size:12px;font-weight:800;color:var(--brand-dark);white-space:nowrap}
.next-step.late .next-step-due{color:var(--danger-dark)}
.next-step.soon .next-step-due{color:var(--brand-dark)}

@media(max-width:620px){
  .next-step{flex-wrap:wrap}
  .next-step-meta{flex-basis:100%;text-align:left;flex-direction:row;gap:10px;
                  padding-left:31px}
}

/* Reminder button on a next-step row. Small and quiet — the task and its due
   date are the message, this is only the action. */
.next-step-remind{margin-top:5px;padding:4px 10px;font-size:11px;white-space:nowrap}
.next-step-remind:disabled{opacity:.6;cursor:default}
@media(max-width:620px){
  .next-step-remind{margin-top:0;margin-left:auto}
}

/* --- venue search summary on the dashboard --- */
.venue-summary{margin-top:20px}
.venue-summary-lead{display:flex;justify-content:space-between;align-items:flex-end;gap:20px;
                    flex-wrap:wrap;padding:14px 16px;border-radius:12px;
                    background:var(--brand-soft);border:1px solid var(--brand-line)}
.venue-summary-name{font-family:var(--font-display);font-size:25px;font-weight:600;
                    color:var(--ink);line-height:1.2;margin-top:2px}
.venue-summary-cost{text-align:right}
.venue-summary-cost b{display:block;font-family:var(--font-display);font-size:31px;font-weight:700;
                      font-variant-numeric:lining-nums;color:var(--brand-dark);line-height:1.1}
.venue-summary-stats{display:flex;flex-wrap:wrap;gap:8px;margin:14px 0}
.venue-summary-stats span{font-size:12px;font-weight:600;padding:5px 11px;border-radius:999px;
                          background:var(--card-2);border:1px solid var(--line);color:var(--muted)}
.venue-summary-stats span b{color:var(--ink)}
.venue-summary-stats .watch{background:var(--gold-soft);border-color:var(--gold);color:var(--gold-ink)}
.venue-summary-stats .watch b{color:var(--gold-ink)}

@media(max-width:620px){
  .venue-summary-cost{text-align:left}
  .venue-summary-cost b{font-size:27px}
}

/* Laptop screens are wide but short. Ten nav items, the brand block and the
   user chip together overrun a ~700px viewport, so claw back the padding
   that is pure decoration before the sidebar has to scroll. */
@media(max-height:820px){
  .sidebar{padding:20px 18px}
  .brand{padding-bottom:14px}
  .brand .monogram{font-size:26px}
  .brand h1{font-size:23px;margin:4px 0 1px}
  .brand p{font-size:13px}
  .nav{gap:4px}
  .nav button{padding:8px 13px}
  .sidebar-foot{padding-top:14px}
}
@media(max-height:700px){
  /* Below this the tagline is the first thing worth losing — it is decoration,
     the navigation is not. */
  .sidebar-foot{display:none}
  .nav button{padding:7px 13px}
}

/* --- venue list view --- */
/* One grid shared by the header row and every venue row, so the columns line
   up without a table and can be collapsed wholesale on a phone. */
.venue-list{display:flex;flex-direction:column;gap:6px;margin-bottom:8px}
.venue-list-head,
.venue-list-row{display:grid;
                grid-template-columns:34px minmax(140px,1fr) 72px 96px 104px 104px 62px 164px;
                align-items:center;gap:12px}
.venue-list-head{padding:0 14px 6px;border:1px solid transparent;border-bottom:0;
                 font-size:11px;font-weight:800;letter-spacing:.06em;
                 text-transform:uppercase;color:var(--muted)}
.venue-list-head .num,
.venue-list-row .num{text-align:right;font-variant-numeric:lining-nums}

.venue-list-row{padding:11px 14px;border-radius:12px;background:var(--card);
                border:1px solid var(--line);font-size:13px}
.venue-list-row:hover{border-color:var(--brand-line)}
.venue-list-row.picked{border-color:var(--brand);background:var(--brand-soft)}
.venue-list-row.dismissed{opacity:.55;border-color:var(--danger);background:var(--danger-soft)}
.venue-list-row.dismissed:hover{opacity:1}
.venue-list-row .bad{color:var(--danger-dark);font-weight:700}

.vl-name{display:flex;flex-direction:column;min-width:0}
.vl-name b{font-family:var(--font-display);font-size:17px;font-weight:600;line-height:1.2}
.vl-total{font-weight:800;font-size:15px;color:var(--brand-dark);white-space:nowrap}
/* A quiet marker that the figure has an open gratuity question behind it. */
.vl-gap{display:inline-block;margin-left:3px;width:15px;height:15px;line-height:15px;
        text-align:center;border-radius:50%;background:var(--gold-ink);color:#fff;
        font-size:10px;font-weight:800;cursor:help}
.vl-actions{display:flex;align-items:center;gap:8px;justify-self:end}
.vl-actions .btn{padding:5px 10px;font-size:11px;white-space:nowrap}
.vl-actions .venue-compare span{display:none}
.vl-rank .venue-rank{margin-right:0}

@media(max-width:1100px){
  .venue-list-head{display:none}
  .venue-list-row{grid-template-columns:34px 1fr;gap:6px 12px;padding:13px 15px}
  .vl-name{grid-column:2}
  /* Without the header row, each cell carries its own label. */
  .venue-list-row > span[data-label]{grid-column:2;display:flex;justify-content:space-between;
                                     gap:14px;text-align:left}
  .venue-list-row > span[data-label]::before{content:attr(data-label);color:var(--muted);
                                             font-weight:700;font-size:11px;
                                             letter-spacing:.05em;text-transform:uppercase}
  .venue-list-row .num{text-align:right}
  .vl-actions{grid-column:2;justify-self:stretch;justify-content:space-between;margin-top:5px}
  .vl-actions .venue-compare span{display:inline}
}
@media(max-width:620px){
  .venue-export-wrap{width:100%;justify-content:space-between}
}

/* --- collapsible panels --- */
/* The header is the control, so it is a real button: keyboard reachable and
   announced with its expanded state. */
.fold-head{display:flex;align-items:baseline;gap:14px;width:100%;padding:0 0 12px;
           background:none;border:0;border-bottom:1px solid var(--line);
           cursor:pointer;text-align:left;margin-bottom:14px}
.fold-head:hover .fold-title{color:var(--brand-dark)}
.fold-title{font-family:var(--font-display);font-size:22px;font-weight:600;color:var(--ink);
            flex:none}
/* Folding must not hide the answer — the summary carries it. */
.fold-summary{flex:1;min-width:0;font-size:13px;color:var(--muted);
              overflow:hidden;text-overflow:ellipsis;white-space:nowrap;align-self:center}
/* A bare chevron was too easy to miss, so it is a labelled pill: the word
   says what will happen, the arrow says which way. */
.fold-toggle{flex:none;margin-left:auto;display:inline-flex;align-items:center;gap:5px;
             padding:5px 11px;border-radius:999px;background:var(--brand-soft);
             border:1px solid var(--brand-line);color:var(--brand-dark);
             font-size:12px;font-weight:800;letter-spacing:.03em}
.fold-head:hover .fold-toggle,
.price-fold:hover .fold-toggle{background:var(--brand-dark);border-color:var(--brand-dark);color:#fff}
.fold-chev{display:inline-block;font-size:11px;line-height:1;transition:transform .15s ease}
.fold-chev.open{transform:rotate(180deg)}

/* A folded card keeps only its header, so the header's own bottom margin is
   the whole spacing job — drop the rule underneath it. */
.fold-body.shut{display:none}
.card:has(> .fold-body.shut) .fold-head,
.panel:has(> .fold-body.shut) .fold-head{border-bottom:0;margin-bottom:0;padding-bottom:0}

/* --- price breakdown fold --- */
.price-fold{display:flex;align-items:center;gap:10px;width:100%;
            padding:8px 0;background:none;border:0;border-top:1px solid var(--line);
            font-size:12px;font-weight:700;color:var(--muted);cursor:pointer}
.price-fold:hover{color:var(--brand-dark)}
.venue-breakdown.shut{display:none}

@media(max-width:620px){
  .fold-head{flex-wrap:wrap;gap:4px 10px}
  .fold-summary{flex-basis:100%;white-space:normal}
}

/* Address and website sit together — both answer "who and where is this". */
.venue-links{display:flex;flex-wrap:wrap;gap:6px 16px;align-items:center}
.venue-site{color:var(--muted)}
.venue-site:hover{color:var(--brand-dark)}
.vl-name a{color:var(--brand-dark);text-decoration:none;font-weight:600}
.vl-name a:hover{text-decoration:underline}

/* An unpriced venue states that plainly rather than showing a figure. */
.venue-total.unpriced{font-size:27px;color:var(--muted);font-style:italic}

/* Video links sit with the address and website — all three answer "show me". */
.venue-video{color:var(--muted)}
.venue-video:hover{color:var(--danger-dark)}

/* ---- venue tour plan (dashboard) ----
   Three day-columns, each a route. The drive legs sit between stops rather
   than beside them so the column reads top-to-bottom as the day happens. */
.tour-days{grid-template-columns:repeat(3,minmax(0,1fr));align-items:start}
.tour-day{display:flex;flex-direction:column}
.tour-day-head{display:flex;gap:11px;align-items:center;margin-bottom:9px;min-height:46px}
.tour-day-emoji{font-size:23px;line-height:1}
.tour-day-name{font-family:var(--font-display);font-size:21px;font-weight:600;color:var(--ink);line-height:1.2}
.tour-day-why{font-size:12.5px;color:var(--muted);margin-bottom:13px;line-height:1.5}
.tour-stops{list-style:none;margin:0;padding:0}
.tour-stop{display:grid;grid-template-columns:22px 1fr auto;gap:9px;align-items:start;
           padding:9px 0;border-top:1px solid var(--line)}
.tour-stops>.tour-stop:first-child{border-top:none;padding-top:0}
.tour-num{width:22px;height:22px;border-radius:50%;background:var(--brand-soft);
          border:1px solid var(--brand-line);color:var(--brand-dark);
          font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center}
.tour-stop-main{min-width:0}
.tour-stop-name{font-weight:600;font-size:13.5px;color:var(--ink);line-height:1.3}
.tour-cost{font-size:13px;font-weight:700;color:var(--ink);font-variant-numeric:lining-nums tabular-nums;white-space:nowrap}
.tour-star{color:var(--muted);font-weight:600;margin-left:1px}
.tour-badges{display:flex;flex-wrap:wrap;gap:4px;margin-top:5px}
.tour-badge{font-size:10.5px;font-weight:600;padding:2px 7px;border-radius:999px;
            background:var(--card-2);border:1px solid var(--line);color:var(--muted);white-space:nowrap}
.tour-badge.good{background:var(--sage-soft);border-color:var(--sage);color:var(--sage-ink)}
.tour-badge.warn{background:var(--gold-soft);border-color:var(--gold);color:var(--gold-ink)}
.tour-badge.bad{background:var(--danger-soft);border-color:var(--danger-line);color:var(--danger-dark)}
.tour-leg{display:flex;justify-content:center;padding:0}
.tour-leg span{font-size:10.5px;font-weight:600;color:var(--muted);letter-spacing:.03em}
.tour-day-foot{margin-top:auto;padding-top:12px;font-size:11.5px;color:var(--muted);
               border-top:1px solid var(--line)}
.tour-note{margin-top:16px;font-size:13px;line-height:1.6}
.tour-note .small{display:block;margin-top:7px}
@media (max-width:1100px){
  .tour-days{grid-template-columns:1fr}
}
@media (max-width:700px){
  .tour-day-name{font-size:19px}
  .tour-stop{grid-template-columns:20px 1fr auto}
}

/* ---- venues → touring page ---- */
.nav-sub{display:grid;gap:3px;margin:3px 0 3px 15px;padding-left:9px;
         border-left:1px solid var(--line-strong)}
.nav-sub button{padding:8px 11px;font-size:13.5px;border-radius:10px}
.nav-sub .nav-icon{width:18px;font-size:14px}

.tour-intro{margin-bottom:18px;font-size:14px;line-height:1.6}
.tour-section{margin-bottom:16px}
.tour-row{padding:15px 0;border-top:1px solid var(--line)}
.tour-row-head{display:grid;grid-template-columns:22px 1fr auto;gap:10px;align-items:start}
.tour-row .tour-badges{margin:9px 0 0 32px}
.tour-hours{margin:9px 0 0 32px;font-size:13px;color:var(--ink)}
.tour-hours b{color:var(--brand-dark);margin-right:5px}
.tour-row-note{margin:8px 0 0 32px;font-size:13px;color:var(--muted);line-height:1.6}
.tour-row-foot{display:flex;flex-wrap:wrap;gap:7px;align-items:center;margin:11px 0 0 32px}
.tour-row-foot .btn{padding:6px 11px;font-size:12.5px;text-decoration:none}
.tour-asks{color:var(--gold-ink);font-weight:600}
.tour-source{margin:8px 0 0 32px;font-size:11.5px;color:var(--muted);font-style:italic}
.tour-row-leg{text-align:center;font-size:11.5px;font-weight:600;color:var(--muted);padding:2px 0}
@media (max-width:700px){
  .tour-row .tour-badges,.tour-hours,.tour-row-note,.tour-row-foot,.tour-source{margin-left:0}
  .tour-row-head{grid-template-columns:22px 1fr}
  .tour-row-head .tour-cost{grid-column:2;margin-top:4px}
}

/* ---- the screen you see when the app can't start ---- */
.load-failure{max-width:560px;margin:48px auto;text-align:center}
.load-failure h3{font-family:var(--font-display);font-size:25px;margin:0 0 10px}
.load-failure p{color:var(--muted);margin:0 0 16px;line-height:1.6}
.load-ref{display:flex;flex-direction:column;align-items:center;gap:7px;
          background:var(--card-2);border:1px solid var(--line);border-radius:14px;padding:15px}
.load-ref-code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:23px;
               font-weight:700;letter-spacing:.14em;color:var(--brand-dark);
               background:transparent;border:0;padding:2px 6px;border-radius:8px}
.load-ref-code:hover{background:var(--brand-soft)}
