/* Self-contained on purpose. This site shares a look with lapartylights360.com but
     not a codebase — the two deploy separately so a problem on one cannot take the
     other down. Anything worth sharing gets extracted into modules later. */
/* ══════════════════════════════════════════════════════════════════════════════
   THE PALETTE — ONE SET OF TOKENS, EVERY PAGE
   ══════════════════════════════════════════════════════════════════════════════
   Not a second stylesheet. There is one set of rules for the whole site and the only
   thing that changes is what these names resolve to — because "half the site one style
   and half another" is a complaint that has already been made once, and a light landing
   page bolted onto a dark app is exactly how you earn it again. All eighteen pages read
   this block. `light.css` — the earlier landing-page-only attempt — is dead and is no
   longer loaded anywhere.

   WARM WHITE, NOT CREAM. Cream with gold on it looks like a wedding invitation from
   1998; pure #fff with gold on it looks like a tax form. #fffcf7 has enough warmth to
   let gold be gold and enough brightness to still read as daylight.

   GOLD IS TWO COLOURS, AND THAT PART IS NOT NEGOTIABLE.
   #f5c445 on #fffcf7 measures 2.2:1. That is not a taste call — it is unreadable, and
   it is what sank the previous light attempt. So gold is split by JOB:
       --gold / --gold-hi / --gold-dp   METAL: fills, gradients, borders, rules
       --gold-tx                        INK:   anything read as words → 5.3:1
   Rules that set `color:` reach for --gold-tx; rules that set `background`/`border`
   reach for --gold. The names make the wrong choice hard to make by accident.

   Measured against #fffcf7 — all AA or better at body size:
       --ink 16.4:1 · --mute 7.7:1 · --mute2 5.4:1 · --gold-tx 5.3:1
       --ok-tx 5.3:1 · --bad-tx 6.0:1 · --warn-tx 5.4:1 · --info-tx 5.6:1
   Re-measure if you change one. Gold on white is unforgiving and the failure mode is
   silent: it always looks fine to whoever picked it. */
  :root{
    --paper:#fffcf7; --paper2:#f8f1e4;
    --ink:#1a141f; --mute:#574e5d; --mute2:#6f6676;

    --line:rgba(26,20,31,.10); --line2:rgba(26,20,31,.15);
    --line3:rgba(26,20,31,.22); --line-hi:rgba(26,20,31,.42);

    /* On dark these were white films over black. On paper the raised thing is WHITER
       than the page and the recessed thing is faintly grey — inverted, not dimmed. */
    --surf1:rgba(255,255,255,.70); --surf2:#ffffff; --surf3:rgba(26,20,31,.045);
    --field:#ffffff; --menu:#ffffff;

    --shadow:rgba(60,42,20,.10); --shadow-lg:rgba(60,42,20,.20);
    --on-gold:#2b1d03; --danger:#c31450;

    --gold:#d8a01c; --gold-hi:#f2ca5e; --gold-dp:#9d7208; --gold-tx:#8a6508;
    --magenta:#c9186b; --cyan:#0a7d97; --violet:#6d3fc4;

    --gold-w1:rgba(216,160,28,.10); --gold-w2:rgba(216,160,28,.17);
    --gold-w3:rgba(216,160,28,.28); --gold-e1:rgba(216,160,28,.42);
    --gold-e2:rgba(216,160,28,.60); --gold-shadow:rgba(157,114,8,.22);

    --ok-tx:#0f7a45;   --ok-w:rgba(15,122,69,.13);  --ok-e:rgba(15,122,69,.34);
    --bad-tx:#bf1358;  --bad-w:rgba(191,19,88,.12);
    --warn-tx:#9a5a06; --warn-w:rgba(154,90,6,.14);
    --info-tx:#0a6f88; --info-w:rgba(10,111,136,.13);
    --pink-tx:#c9186b;

    --bar-bg:rgba(255,252,247,.88);
    --scrim:rgba(26,20,31,.55);

    --disp:'Anton',system-ui,sans-serif; --body:'Outfit',system-ui,sans-serif;
    --hand:'Caveat',ui-rounded,cursive;

    /* Kept only so anything the sweep missed still resolves to a real colour instead of
       inheriting black on black. Do not use it in new rules. */
    --white:var(--ink);
  }

/* /original and /dark-home set data-theme="dark", so there is always something to
   compare against. They are the ONLY two pages that do. */
  [data-theme="dark"]{
    --paper:#07050c; --paper2:#0d0a16;
    --ink:#ffffff; --mute:rgba(255,255,255,.72); --mute2:rgba(255,255,255,.45);

    --line:rgba(255,255,255,.12); --line2:rgba(255,255,255,.16);
    --line3:rgba(255,255,255,.24); --line-hi:rgba(255,255,255,.42);

    --surf1:rgba(255,255,255,.03); --surf2:rgba(255,255,255,.05);
    --surf3:rgba(255,255,255,.09);
    --field:rgba(0,0,0,.35); --menu:#17121f;

    --shadow:rgba(0,0,0,.34); --shadow-lg:rgba(0,0,0,.6);
    --on-gold:#1a1206; --danger:#d0245c;

    --gold:#f5c445; --gold-hi:#ffe08a; --gold-dp:#c9932a; --gold-tx:#ffe08a;
    --magenta:#ff2d95; --cyan:#22e7ff; --violet:#b06bff;

    --gold-w1:rgba(245,196,69,.08); --gold-w2:rgba(245,196,69,.12);
    --gold-w3:rgba(245,196,69,.2);  --gold-e1:rgba(245,196,69,.32);
    --gold-e2:rgba(245,196,69,.45); --gold-shadow:rgba(245,196,69,.16);

    --ok-tx:#8bf5b3;   --ok-w:rgba(62,232,122,.18); --ok-e:rgba(62,232,122,.3);
    --bad-tx:#ffb3d8;  --bad-w:rgba(255,45,149,.18);
    --warn-tx:#ffcf6b; --warn-w:rgba(255,145,60,.2);
    --info-tx:#9beeff; --info-w:rgba(34,231,255,.15);
    --pink-tx:#ff9ecb;

    --bar-bg:rgba(7,5,12,.86);
    --scrim:rgba(6,3,11,.94);
  }

  *{box-sizing:border-box;margin:0;padding:0}
  [hidden]{display:none!important}
  body{
    background:var(--paper);color:var(--ink);font-family:var(--body);
    min-height:100vh;display:flex;flex-direction:column;line-height:1.6;
    -webkit-font-smoothing:antialiased;
  }
  a{color:inherit}
  /* The lighting rig, in daylight. On black these were glows ADDED to the dark; on paper
     the same idea has to be colour SETTLING onto white, so the alphas come right down —
     at dark-theme strength they read as smudges on the page rather than light in a room. */
  .glow{
    position:fixed;inset:0;pointer-events:none;z-index:0;
    background:
      radial-gradient(60vw 50vh at 20% 15%, rgba(216,160,28,.13), transparent 65%),
      radial-gradient(50vw 45vh at 85% 75%, rgba(201,24,107,.07), transparent 65%),
      radial-gradient(45vw 40vh at 60% 40%, rgba(10,125,151,.05), transparent 65%);
  }
  [data-theme="dark"] .glow{
    background:
      radial-gradient(60vw 50vh at 20% 15%, rgba(245,196,69,.16), transparent 65%),
      radial-gradient(50vw 45vh at 85% 75%, rgba(255,45,149,.13), transparent 65%),
      radial-gradient(45vw 40vh at 60% 40%, rgba(34,231,255,.07), transparent 65%);
  }
  main{position:relative;z-index:1;flex:1 1 auto;display:grid;place-items:center;padding:8vh 22px}
  .wrap{width:min(880px,100%);text-align:center}

  /* The emblem is circular but the file is a black square, so the corners showed as a
     hard edge against the page. Clipping to a circle loses nothing — the corners are
     pure black — and the glow then reads as coming off the mark itself. */
  .logo{
    width:158px;height:158px;border-radius:50%;object-fit:cover;
    filter:drop-shadow(0 10px 26px rgba(157,114,8,.26));margin-bottom:26px;
  }

  .kicker{
    display:inline-flex;align-items:center;gap:9px;
    font-size:11.5px;font-weight:900;letter-spacing:.2em;text-transform:uppercase;
    color:var(--gold-tx);border:1px solid var(--gold-e2);background:var(--gold-w1);
    padding:7px 16px;border-radius:999px;margin-bottom:22px;
  }
  .kicker i{width:7px;height:7px;border-radius:50%;background:var(--gold);
    box-shadow:0 0 12px var(--gold);animation:pulse 2.2s ease-in-out infinite}
  @keyframes pulse{50%{opacity:.35}}

  h1{
    font-family:var(--disp);font-weight:400;line-height:.98;letter-spacing:.01em;
    font-size:clamp(40px,8.5vw,86px);text-transform:uppercase;margin-bottom:18px;
  }
  h1 em{
    font-style:normal;
    background:linear-gradient(120deg,var(--gold-hi),var(--gold) 45%,var(--gold-dp));
    -webkit-background-clip:text;background-clip:text;color:transparent;
  }
  .lede{font-size:clamp(16px,2.1vw,19.5px);color:var(--mute);max-width:56ch;margin:0 auto 30px}

  .cats{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;margin-bottom:34px}
  .cat{
    font-size:13px;font-weight:700;padding:8px 15px;border-radius:999px;
    border:1px solid var(--line);background:var(--surf2);color:var(--mute);
  }
  .cat--live{border-color:var(--gold-e2);background:var(--gold-w2);color:var(--gold-tx)}

  .cta{display:flex;flex-wrap:wrap;gap:13px;justify-content:center}
  .btn{
    display:inline-flex;align-items:center;gap:9px;text-decoration:none;cursor:pointer;
    font-weight:800;font-size:15.5px;padding:15px 26px;border-radius:999px;
    border:1px solid var(--line);color:var(--ink);background:var(--surf2);
    transition:transform .18s,border-color .2s,background .2s;
  }
  .btn:hover{transform:translateY(-2px);border-color:var(--line-hi)}
  .btn--gold{
    border:0;color:var(--on-gold);font-weight:900;
    background:linear-gradient(180deg,var(--gold-hi) 0%,var(--gold) 48%,var(--gold-dp) 100%);
    box-shadow:0 1px 0 rgba(255,255,255,.5) inset, 0 6px 16px var(--gold-shadow);
  }
  .btn--gold:hover{box-shadow:0 14px 34px var(--gold-shadow)}

  .note{
    margin-top:34px;padding:16px 20px;border-radius:15px;
    border:1px solid var(--line);background:var(--surf1);
    font-size:14.5px;color:var(--mute);max-width:60ch;margin-inline:auto;
  }
  .note b{color:var(--gold-tx)}

  footer{
    position:relative;z-index:1;padding:26px 22px;text-align:center;
    border-top:1px solid var(--line);font-size:13px;color:var(--mute2);
  }
  footer a{color:var(--mute);text-decoration:none}
  footer a:hover{color:var(--gold-tx)}

  /* ── shared chrome ─────────────────────────────────────── */
  .bar{
    position:sticky;top:0;z-index:20;display:flex;align-items:center;gap:14px;flex-wrap:wrap;
    padding:14px 22px;border-bottom:1px solid var(--line);
    background:var(--bar-bg);backdrop-filter:blur(12px) saturate(1.4);
  }
  .bar__brand{display:flex;align-items:center;gap:10px;text-decoration:none;font-weight:900;letter-spacing:.02em}
  .bar__brand img{width:38px;height:38px;object-fit:contain}
  .bar__sp{margin-left:auto}
  .bar .btn{padding:10px 18px;font-size:14px}

  .page{position:relative;z-index:1;width:min(1080px,94vw);margin:0 auto;padding:38px 0 90px}
  .h2{font-family:var(--disp);font-weight:400;font-size:clamp(28px,4.6vw,44px);text-transform:uppercase;letter-spacing:.02em;margin-bottom:10px}
  .sub{color:var(--mute);font-size:15.5px;max-width:62ch;margin-bottom:26px}

  .card{padding:24px;border-radius:18px;border:1px solid var(--line);
    background:linear-gradient(180deg,var(--surf2),var(--surf1))}
  .field{display:grid;gap:7px;margin-bottom:15px}
  .field label{font-size:11.5px;font-weight:900;letter-spacing:.11em;text-transform:uppercase;color:var(--gold-tx)}
  .field input,.field select,.field textarea{
    width:100%;padding:13px 15px;border-radius:12px;font:inherit;font-size:15px;
    background:var(--field);border:1px solid var(--line2);color:var(--ink);
  }
  .field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--gold-tx);background:var(--field)}
  .field .hint{font-size:12.5px;color:var(--mute2);line-height:1.5}
  /* Grid items stretch by default, so a field WITHOUT a hint grows its input to match
     the height of a neighbour that has one — which is the taller-box bug all over
     again. Fields sit at the top of their row and keep their natural height. */
  .row2{display:grid;grid-template-columns:1fr 1fr;gap:15px;align-items:start}
  .row2 > .field{align-self:start}
  @media (max-width:620px){.row2{grid-template-columns:1fr}}

  .msg{font-size:14px;font-weight:700;margin-top:12px;display:none}
  .msg.ok{display:block;color:var(--ok-tx)}
  .msg.bad{display:block;color:var(--bad-tx)}
  .quiet{color:var(--mute);font-size:14px}
  .center{text-align:center}

  /* ── a vendor's public page ────────────────────────────── */
  .pvbar{
    position:relative;z-index:2;display:flex;flex-wrap:wrap;gap:14px;align-items:center;
    justify-content:center;padding:12px 22px;
    background:var(--gold-w2);border-bottom:1px solid var(--gold-e2);
  }
  .pvbar b{color:var(--gold-tx);font-size:14px}
  .pvbar .btn{padding:8px 16px;font-size:13.5px}

  .vhead{display:flex;flex-wrap:wrap;gap:22px;align-items:center;margin-bottom:22px}
  .vhead__logo{
    width:120px;height:120px;border-radius:22px;object-fit:cover;flex-shrink:0;
    border:1px solid var(--line);background:var(--surf2);
  }
  .vhead__body{flex:1 1 260px;min-width:0}
  .vhead__cat{
    font-size:11.5px;font-weight:900;letter-spacing:.16em;text-transform:uppercase;
    color:var(--vendor,var(--gold-tx));margin-bottom:6px;
  }
  .vhead__tag{font-size:17px;color:var(--ink);margin-bottom:4px}
  .vhead__where{color:var(--mute2);font-size:14px}

  .vcta{display:flex;flex-wrap:wrap;gap:11px;margin-bottom:26px}
  .vh{
    font-family:var(--disp);font-weight:400;font-size:18px;letter-spacing:.07em;
    text-transform:uppercase;color:var(--gold-tx);margin-bottom:12px;
  }

  .vgal{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px}
  .vgal__i{margin:0;border-radius:14px;overflow:hidden;border:1px solid var(--line);background:var(--surf1)}
  .vgal__i img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block}
  .vgal__i figcaption{padding:9px 12px;font-size:12.5px;color:var(--mute2)}

  /* ── admin ─────────────────────────────────────────────── */
  .tabs{display:flex;gap:6px;flex-wrap:wrap}
  .tab{
    font:inherit;font-size:13.5px;font-weight:800;cursor:pointer;
    padding:9px 16px;border-radius:999px;
    border:1px solid var(--line2);background:var(--surf2);color:var(--mute);
  }
  .tab:hover{color:var(--ink);border-color:var(--line-hi)}
  .tab.is-on{background:var(--gold);border-color:var(--gold-tx);color:var(--on-gold)}

  .vrow{
    padding:18px;border-radius:16px;margin-bottom:13px;
    border:1px solid var(--line);background:var(--surf1);
  }
  .vrow__top{display:flex;flex-wrap:wrap;gap:10px;align-items:baseline;margin-bottom:7px}
  .vrow__name{font-size:17px;font-weight:800}
  .vrow__line{margin:3px 0;font-size:13.8px;color:var(--mute);line-height:1.55}
  .vrow__acts{display:flex;flex-wrap:wrap;gap:8px;margin-top:13px;align-items:center}
  .vrow .btn{padding:9px 16px;font-size:13.5px}
  .vrow input[type=text]{
    flex:1 1 220px;padding:9px 13px;border-radius:10px;font:inherit;font-size:13.5px;
    background:var(--field);border:1px solid var(--line2);color:var(--ink);
  }

  .pill{
    font-size:10.5px;font-weight:900;letter-spacing:.1em;text-transform:uppercase;
    padding:3px 10px;border-radius:999px;
  }
  .pill--draft{background:var(--surf3);color:var(--mute)}
  .pill--pending{background:var(--gold-w3);color:var(--gold-tx)}
  .pill--changes_requested{background:var(--warn-w);color:var(--warn-tx)}
  .pill--live{background:var(--ok-w);color:var(--ok-tx)}
  .pill--rejected,.pill--paused{background:var(--bad-w);color:var(--bad-tx)}

/* ── password fields ───────────────────────────────────────
   The eye sits inside the box rather than beside it, so the input keeps the same width
   as every other field on the form and nothing shifts when the button appears. */
.pw { position: relative; display: block }
.pw input { width: 100%; padding-right: 46px }
.pw__eye {
  position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
  width: 34px; height: 34px; display: grid; place-items: center;
  background: none; border: 0; border-radius: 8px; cursor: pointer;
  font-size: 15px; line-height: 1; opacity: .62;
}
.pw__eye:hover { opacity: 1; background: var(--surf3) }
.pw__eye:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px }

.linkbtn {
  background: none; border: 0; padding: 0; cursor: pointer;
  color:var(--gold-tx); font: inherit; font-size: 14px; text-decoration: underline;
  text-underline-offset: 3px;
}
.linkbtn:hover { color:var(--gold-tx) }

.forgot {
  margin-top: 12px; padding: 13px; border-radius: 12px;
  border: 1px solid var(--line); background: var(--surf2);
}
.forgot__row { display: flex; gap: 8px; flex-wrap: wrap }
.forgot__row input { flex: 1 1 190px }

/* ── uploads ───────────────────────────────────────────────
   A big obvious target rather than a bare file input. Vendors do this on a phone as
   often as on a laptop, and a 90px tap target beats a 20px "Choose file". */
.drop {
  position: relative; display: grid; place-items: center; gap: 8px;
  min-height: 104px; padding: 14px; cursor: pointer; text-align: center;
  border: 1.5px dashed var(--line3); border-radius: 14px;
  background: var(--surf1); transition: border-color .15s, background .15s;
}
.drop:hover, .drop:focus-visible, .drop.is-over {
  border-color:var(--gold-tx); background: var(--gold-w1); outline: none;
}
.drop--wide { min-height: 78px }
.drop__say { color: var(--mute); font-size: 14px }
.drop__pv { max-height: 108px; max-width: 100%; border-radius: 10px; object-fit: contain }
.drop__pv--sq { max-height: 84px }
.drop.is-busy { opacity: .55; pointer-events: none }

.gal { display: grid; grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); gap: 10px; margin-top: 12px }
.gal__i { position: relative; border-radius: 12px; overflow: hidden; background: var(--surf2); cursor: grab }
.gal__i.is-drag { opacity: .35 }
.gal__i img { display: block; width: 100%; aspect-ratio: 1; object-fit: cover }
.gal__x {
  position: absolute; top: 5px; right: 5px; width: 26px; height: 26px;
  display: grid; place-items: center; border: 0; border-radius: 50%; cursor: pointer;
  background: rgba(8,4,14,.78); color: #fff; font-size: 15px; line-height: 1;
}
.gal__x:hover { background: var(--danger) }
.gal__n {
  position: absolute; bottom: 5px; left: 5px; padding: 1px 7px; border-radius: 20px;
  background: rgba(8,4,14,.78); color:var(--gold-tx); font-size: 11px; font-weight: 700;
}

.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(112px, 1fr)); gap: 11px }
.stat { padding: 13px; border-radius: 13px; background: var(--surf2); text-align: center }
.stat b { display: block; font-family: var(--disp); font-size: 27px; color:var(--gold-tx); line-height: 1.1 }
.stat span { display: block; margin-top: 3px; font-size: 12.5px; color: var(--mute) }

/* ── video ─────────────────────────────────────────────────
   Sized by ratio, not by height. A fixed height letterboxes on a phone and crops on a
   desktop, and there is no single number that is right on both. */
.vid { position: relative; aspect-ratio: 16/9; border-radius: 14px; overflow: hidden; background: #000 }
.vid iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0 }
.vid--ig { aspect-ratio: 4/5; max-width: 420px }

.vcover {
  display: block; width: 100%; max-height: 320px; object-fit: cover;
  border-radius: 16px; margin-bottom: 18px;
}

/* ── the photo viewer ──────────────────────────────────────
   A gallery thumbnail nobody can open is a gallery nobody looks at. Keyboard works
   because half of these get opened on a laptop. */
.lbox {
  position: fixed; inset: 0; z-index: 90; display: grid; place-items: center;
  padding: 42px 14px; background: rgba(12,8,16,.95); backdrop-filter: blur(6px);
}
.lbox img { max-width: 100%; max-height: 100%; border-radius: 12px; object-fit: contain }
.lbox__x, .lbox__nav {
  position: absolute; display: grid; place-items: center; cursor: pointer;
  border: 1px solid rgba(255,255,255,.2); background: rgba(255,255,255,.09);
  color: #fff; border-radius: 50%;
}
.lbox__x { top: 14px; right: 14px; width: 40px; height: 40px; font-size: 22px }
.lbox__nav { top: 50%; transform: translateY(-50%); width: 46px; height: 46px; font-size: 27px }
.lbox__nav--p { left: 12px }
.lbox__nav--n { right: 12px }
.lbox__x:hover, .lbox__nav:hover { background: rgba(255,255,255,.2) }
@media (max-width: 560px) { .lbox__nav { width: 38px; height: 38px; font-size: 22px } }

/* ── a themed vendor page ──────────────────────────────────
   Scoped to #page on purpose. The header bar, the footer and the "find someone else"
   button keep the house look on every single vendor page — that is the thing that makes
   360 different-looking pages still obviously one platform. Inside #page it is theirs.

   Everything below reads the custom properties THEME.apply writes. No rule here names a
   colour, so a new palette is a line in theme.js and nothing else. */
#page[data-dark] { color: var(--text) }
#page[data-dark] .card {
  background: var(--card); border-color: var(--line); color: var(--text);
}
#page[data-dark] .vh,
#page[data-dark] .h2,
#page[data-dark] .vhead__cat { color: var(--hi) }
#page[data-dark] h1, #page[data-dark] h2 { font-family: var(--face), var(--disp) }
#page[data-dark] .quiet,
#page[data-dark] .vhead__where,
#page[data-dark] .vhead__tag { color: var(--mute) }
#page[data-dark] .btn {
  border-color: var(--line2); color: var(--text); background: var(--soft);
}
#page[data-dark] .btn:hover { border-color: var(--hi) }
#page[data-dark] .btn--gold {
  background: var(--hi); border-color: var(--hi); color: var(--ink);
}
#page[data-dark] .btn--gold:hover { background: var(--hi2); border-color: var(--hi2) }
#page[data-dark] input,
#page[data-dark] textarea,
#page[data-dark] select {
  background: var(--soft); border-color: var(--line); color: var(--text);
}
#page[data-dark] input::placeholder,
#page[data-dark] textarea::placeholder { color: var(--mute) }
#page[data-dark] label { color: var(--text) }

/* A light palette needs a light page behind it, or a cream card floats on black. */
#page[data-dark="0"] {
  background: var(--ink); border-radius: 18px; padding: 20px;
  margin: 0 -20px;
}
@media (max-width: 640px) { #page[data-dark="0"] { margin: 0; padding: 14px } }

/* The arrangements. Each one is a different order and a different emphasis on the same
   markup — nothing is duplicated, so a fix to the enquiry form is one fix. */
#page[data-arrange="center"] .vhead { flex-direction: column; text-align: center; align-items: center }
#page[data-arrange="center"] .vcta { justify-content: center }
#page[data-arrange="center"] .vcover { display: none }
#page[data-arrange="plain"] .vcover { display: none }
#page[data-arrange="split"] .vcover { max-height: 260px }
@media (min-width: 780px) {
  #page[data-arrange="split"] .vsplit { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: center }
  #page[data-arrange="split"] .vsplit .vcover { max-height: 100%; height: 100%; margin: 0 }
}

/* ══════════════════════════════════════════════════════════
   THE LOOK PICKER
   ══════════════════════════════════════════════════════════
   A PANEL THAT SITS STILL. The whole thing is sized to the viewport and never grows
   past it, so choosing a colour never moves the page under you and the live preview is
   never scrolled away. Anything that does not fit scrolls INSIDE the options column —
   which is the one place scrolling costs nothing, because the preview stays put while
   it happens.

   The first version stacked all three dials down the page, ~1050px tall, with the
   preview stuck beside them. `position: sticky` cannot survive that: an element only
   stays stuck for (container height − its own height), and measuring it showed the
   preview held for 280px and was gone before you reached Lettering. Exactly as
   reported. Tabs plus a fixed panel fix the cause rather than fighting the symptom. */

.look { display: flex; flex-direction: column }
.look__top { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 4px }
.look__h {
  font-family: var(--disp); font-weight: 400; font-size: 19px; letter-spacing: .06em;
  text-transform: uppercase; color:var(--gold-tx);
}
.look__step { margin-left: auto; font-size: 12.5px; color: var(--mute2) }
.dirty {
  padding: 5px 13px; border-radius: 999px; font-size: 11.5px; font-weight: 900;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--warn-tx); border: 1px solid var(--gold-e2); background: var(--gold-w2);
}
.look__lab {
  font-size: 11.5px; font-weight: 900; letter-spacing: .11em; text-transform: uppercase;
  color:var(--gold-tx);
}

/* Options narrow and scrolling, the live page wide. The preview is the thing being
   judged, so it gets the room — on a desktop it was the smaller half, which is
   backwards. */
.look__grid { display: grid; gap: 18px; grid-template-columns: 1fr; margin-top: 14px }
/* The options stay exactly where they are. Phone and Desktop change the SCREEN, not the
   layout — an earlier version moved the options from 622px to 310px when you switched,
   and everything you were reading jumped somewhere else. Switching preview size is
   supposed to tell you about your page, not make you find your place again. */
@media (min-width: 900px) {
  .look__grid { grid-template-columns: 344px minmax(0, 1fr) }
}

.look__side { display: flex; flex-direction: column; min-height: 0 }
.look__scroll {
  overflow-y: auto; overscroll-behavior: contain; padding-right: 4px;
  scrollbar-width: thin; scrollbar-color: var(--line3) transparent;
}
.look__scroll::-webkit-scrollbar { width: 7px }
.look__scroll::-webkit-scrollbar-thumb { background: var(--line3); border-radius: 4px }

.dtabs { display: flex; gap: 6px; margin-bottom: 12px }
.dtab {
  flex: 1 1 0; min-width: 0; padding: 8px 10px; cursor: pointer; font: inherit;
  text-align: left; border: 1px solid var(--line2); border-radius: 11px;
  background: var(--field); color: var(--ink);
  transition: border-color .16s, background .16s;
}
.dtab:hover { border-color: var(--line-hi) }
.dtab:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px }
.dtab.is-on { border-color:var(--gold-tx); background: var(--gold-w2) }
.dtab__k {
  display: block; font-size: 9.5px; font-weight: 900; letter-spacing: .09em;
  text-transform: uppercase; color: var(--mute2);
}
.dtab.is-on .dtab__k { color:var(--gold-tx) }
/* Wraps rather than truncating. "Midnight & …" and "Bold & con…" tell you nothing, and
   the whole reason the value is on the tab is so a setting on another tab is not hidden. */
.dtab__v { display: block; margin-top: 2px; font-size: 12.5px; font-weight: 700; line-height: 1.25 }

.cards { display: grid; gap: 9px; align-content: start }
.cards--sw { grid-template-columns: repeat(auto-fill, minmax(133px, 1fr)) }
.cards--ar { grid-template-columns: repeat(auto-fill, minmax(133px, 1fr)) }
.cards--le { grid-template-columns: 1fr }

.pk {
  position: relative; display: block; width: 100%; padding: 0; cursor: pointer;
  font: inherit; text-align: left; overflow: hidden;
  border: 1.5px solid var(--line2); border-radius: 13px;
  background: var(--field); color: var(--ink);
  transition: border-color .16s, background .16s;
}
.pk:hover { border-color: var(--line-hi) }
.pk:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px }
.pk.is-on { border-color:var(--gold-tx); background: var(--gold-w2) }
.pk.is-on::after {
  content: '✓'; position: absolute; top: 7px; right: 7px;
  width: 20px; height: 20px; display: grid; place-items: center;
  border-radius: 50%; background: var(--gold); color: var(--on-gold);
  font-size: 12px; font-weight: 900; line-height: 1;
}
.pk__n { display: block; padding: 8px 11px 9px; font-size: 12.5px; font-weight: 700; line-height: 1.3 }
.pk__h { display: block; padding: 0 11px 9px; font-size: 11px; color: var(--mute2); line-height: 1.4 }
.pk.is-on .pk__n { color:var(--gold-tx) }
.pk__bar { display: flex; height: 34px }
.pk__bar i { flex: 1 }

.pk__d { height: 46px; padding: 6px; display: grid; gap: 3px; background: var(--surf2) }
.pk__d b { display: block; background: var(--mute2); border-radius: 2px; height: 5px }
.pk__d i { display: block; background: var(--line2); border-radius: 2px; height: 3px }
.pk__d u { display: block; background: var(--gold-e2); border-radius: 3px; flex: 1 }
.pk__d--split { grid-template-columns: 1fr 1fr; align-items: center }
.pk__d--center { justify-items: center }
.pk__d--center b { width: 60% } .pk__d--center i { width: 78% }
.pk__d--grid { grid-template-columns: repeat(4, 1fr); grid-auto-rows: min-content }
.pk__d--grid u { height: 11px }
.pk__d--vid u { height: 20px; background: var(--line); display: grid; place-items: center }
.pk__d--vid u::before { content: '▶'; color:var(--gold-tx); font-size: 9px }
.pk.is-on .pk__d { background: var(--gold-w1) }

/* A typeface shown in itself — a list of typeface names all set in one typeface asks
   somebody to choose between words they cannot see. Faded rather than cut, because a
   hard clip mid-letter reads as a broken card. */
.pk__t {
  display: block; padding: 11px 11px 4px; font-size: 23px; line-height: 1.05;
  color: var(--ink); white-space: nowrap; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, #000 78%, transparent 99%);
          mask-image: linear-gradient(90deg, #000 78%, transparent 99%);
}

/* ── the live page ─────────────────────────────────────────
   Their REAL page, not a drawing of it. An approximate preview is worse than none — it
   makes somebody confident about something they have not actually seen. */
.look__pv { display: flex; flex-direction: column; min-height: 0 }
.look__pvtop { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 9px }

.seg { display: inline-flex; border: 1px solid var(--line2); border-radius: 999px; overflow: hidden }
.seg__b {
  padding: 6px 14px; border: 0; cursor: pointer; font: inherit; font-size: 12.5px;
  font-weight: 700; background: none; color: var(--mute2);
}
.seg__b.is-on { background: var(--gold); color: var(--on-gold) }

/* The frame is the "screen". It keeps its place in the layout and only its width
   changes — a phone-shaped screen centred in the same box, or the full width of it. */
.frame {
  position: relative; border-radius: 16px; overflow: hidden; flex: 1 1 auto;
  border: 1px solid var(--line2); background: var(--paper);
  margin-inline: auto; width: 100%; max-width: 340px; min-height: 0;
}
/* No transition on max-width. The desktop scale is worked out from the box's measured
   width, and an animating box measures whatever it happens to be part-way through — so
   the preview came out at 0.28 scale instead of 0.6, from a width that was still moving.
   A snap is honest; a 220ms animation that corrupts a measurement is not. */
.frame--wide { max-width: 100% }
.frame iframe { width: 100%; height: 100%; border: 0; display: block; background: var(--paper) }
/* Desktop: a real 1180px-wide page scaled down. The scale is set in JS from the actual
   box, so it fills whatever room there is instead of a number guessed once. */
.frame--wide iframe { width: 1180px; height: 1500px; transform-origin: 0 0 }
.frame__wait {
  position: absolute; inset: 0; display: grid; place-items: center;
  color: var(--mute2); font-size: 13.5px; background: var(--paper); pointer-events: none;
}

.look__bar {
  display: flex; gap: 12px; flex-wrap: wrap; align-items: center;
  margin-top: 16px; padding-top: 15px; border-top: 1px solid var(--surf3);
}
.look__nav { display: flex; gap: 8px; flex-wrap: wrap }
.btn--sm { padding: 10px 17px; font-size: 14px }
.look__warn { flex: 1 1 200px; margin: 0; font-size: 13.5px; color: var(--mute2); text-align: center }
.look__warn.warn { color: var(--warn-tx); font-weight: 700 }
.look__warn.ok { color: var(--ok-tx) }
.look__warn.bad { color: var(--bad-tx) }
.btn[disabled] { opacity: .38; cursor: default }
.btn[disabled]:hover { border-color: var(--line) }

/* Inside the dashboard's preview frame. The header bar and footer are the platform's,
   not the vendor's, and repeating them at 30% scale inside a 300px box tells nobody
   anything — the frame is there to show the part that changes. */
.inframe .bar, .inframe footer, .inframe .glow { display: none !important }
.inframe main { padding: 14px 12px }
.inframe .page { padding: 0 0 30px }

/* ── the couple's checklist ────────────────────────────────
   Every line is one thing that needs sorting, and every line can be settled three ways.
   The status is the loudest thing on the row because "what is left" is the only question
   anybody opens this page to answer. */
.plan__head { display: flex; gap: 22px; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; margin-bottom: 20px }
.plan__prog { flex: 1 1 240px; max-width: 340px }
.bar2 { height: 9px; border-radius: 999px; background: var(--surf3); overflow: hidden }
.bar2 i { display: block; height: 100%; width: 0; border-radius: 999px;
  background: linear-gradient(90deg, var(--gold-dp), var(--gold)); transition: width .35s }

.prow { padding: 15px 17px; border-radius: 15px; margin-bottom: 10px;
  border: 1px solid var(--line); background: linear-gradient(180deg,var(--surf2),var(--surf1)) }
.prow__top { display: flex; gap: 12px; align-items: center; flex-wrap: wrap }
.prow__n { font-weight: 800; font-size: 16px }
.prow__who { color: var(--mute); font-size: 14px }
.prow__sp { flex: 1 1 auto }
.prow--done { border-color: var(--ok-e) }
.prow--pending { border-color: var(--gold-e1) }

.tag { padding: 4px 12px; border-radius: 999px; font-size: 11px; font-weight: 900;
  letter-spacing: .09em; text-transform: uppercase; white-space: nowrap }
.tag--needed     { background: var(--surf3);  color: var(--mute) }
.tag--pending    { background: var(--gold-w3);   color:var(--gold-tx) }
.tag--booked     { background: var(--ok-w);  color: var(--ok-tx) }
.tag--outsourced { background: var(--info-w);  color: var(--info-tx) }
.tag--skipped    { background: var(--surf2); color: var(--mute2) }

.prow__open { margin-top: 13px; padding-top: 13px; border-top: 1px solid var(--surf3) }
.prow__ways { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px }
.way { padding: 9px 15px; border-radius: 999px; cursor: pointer; font: inherit; font-size: 13.5px;
  font-weight: 700; border: 1px solid var(--line2); background: var(--field); color: var(--ink) }
.way:hover { border-color: var(--line-hi) }
.way.is-on { border-color:var(--gold-tx); background: var(--gold-w2); color:var(--gold-tx) }
.prow2 { display: flex; gap: 9px; flex-wrap: wrap; align-items: center }
.prow2 select, .prow2 input { flex: 1 1 170px; padding: 11px 13px; border-radius: 11px; font: inherit;
  font-size: 14.5px; background: var(--field); border: 1px solid var(--line2); color: var(--ink) }
.vpick { display: grid; gap: 7px; max-height: 230px; overflow-y: auto; margin-bottom: 11px }
.vpick button { padding: 11px 14px; border-radius: 12px; cursor: pointer; font: inherit; text-align: left;
  border: 1px solid var(--line2); background: var(--field); color: var(--ink) }
.vpick button:hover { border-color:var(--gold-tx) }
.vpick b { display: block; font-size: 14.5px }
.vpick span { color: var(--mute2); font-size: 12.5px }

/* ── getting started ───────────────────────────────────────
   One question a screen. Three short questions asked in order beat one form with three
   sections — nobody abandons a screen with a single question on it, and each answer
   genuinely changes what the next screen should say. */
.step__n { font-size: 11.5px; font-weight: 900; letter-spacing: .14em; text-transform: uppercase;
  color:var(--gold-tx); margin-bottom: 8px }
.picks { display: grid; gap: 12px; grid-template-columns: 1fr }
@media (min-width: 700px) { .picks { grid-template-columns: 1fr 1fr } }
.pick {
  display: block; width: 100%; padding: 22px; cursor: pointer; font: inherit; text-align: left;
  border: 1.5px solid var(--line2); border-radius: 18px; color: var(--ink);
  background: linear-gradient(180deg,var(--surf2),var(--surf1));
  transition: border-color .16s, background .16s, transform .16s;
}
.pick:hover { border-color:var(--gold-tx); transform: translateY(-2px) }
.pick:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px }
.pick__e { display: block; font-size: 30px; line-height: 1; margin-bottom: 11px }
.pick b { display: block; font-size: 18px; margin-bottom: 5px }
.pick span:not(.pick__e) { display: block; color: var(--mute); font-size: 14px; line-height: 1.55 }

.types { display: grid; gap: 10px; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)) }
.type {
  display: block; padding: 16px 15px; cursor: pointer; font: inherit; text-align: left;
  border: 1.5px solid var(--line2); border-radius: 15px; color: var(--ink);
  background: var(--field); transition: border-color .16s, background .16s, transform .16s;
}
.type:hover { border-color:var(--gold-tx); background: var(--gold-w1); transform: translateY(-2px) }
.type__e { display: block; font-size: 24px; line-height: 1; margin-bottom: 8px }
.type b { display: block; font-size: 15px; margin-bottom: 3px }
.type span:not(.type__e) { display: block; color: var(--mute2); font-size: 12.5px; line-height: 1.45 }

.plan__pick { display: flex; gap: 9px; align-items: center; flex-wrap: wrap; margin-top: 10px }
.plan__pick select {
  padding: 9px 13px; border-radius: 11px; font: inherit; font-size: 14px; max-width: 260px;
  background: var(--field); border: 1px solid var(--line2); color: var(--ink);
}

/* ── people and songs ──────────────────────────────────────
   Compact rows rather than cards. These are lists you scan and add to, not things you
   study one at a time. */
.lrow { display: flex; gap: 11px; align-items: center; flex-wrap: wrap;
  padding: 10px 0; border-top: 1px solid var(--surf3) }
.lrow:first-child { border-top: 0 }
.lrow__b { font-weight: 700; font-size: 14.5px }
.lrow__m { color: var(--mute2); font-size: 13px }
.lrow__x { margin-left: auto; width: 26px; height: 26px; display: grid; place-items: center;
  border: 0; border-radius: 50%; cursor: pointer; background: var(--surf3);
  color: var(--mute); font-size: 15px; line-height: 1 }
.lrow__x:hover { background: var(--danger); color: #fff }
.roletag { padding: 3px 10px; border-radius: 999px; font-size: 10.5px; font-weight: 900;
  letter-spacing: .08em; text-transform: uppercase; background: var(--surf3); color: var(--mute) }
.roletag--no { background: var(--bad-w); color: var(--bad-tx) }

@media print {
  body > *:not(#printsheet) { display: none !important }
  #printsheet { display: block !important; color: #000; background: #fff; padding: 0 }
}
#printsheet { display: none }

/* ── what the platform is for ──────────────────────────────
   Written as what somebody gets, not as a feature list. "Guest list management" is a
   feature; "one place that knows who is coming" is a reason to sign up. */
.bio { width: min(1000px, 92vw); margin: 78px auto 0; text-align: left }
.bio__h { font-family: var(--disp); font-weight: 400; font-size: clamp(24px, 3.6vw, 36px);
  text-transform: uppercase; letter-spacing: .02em; margin-bottom: 14px }
.bio__p { color: var(--mute); font-size: 16px; max-width: 66ch; line-height: 1.7 }
.bio__grid { display: grid; gap: 16px; margin-top: 30px;
  grid-template-columns: repeat(auto-fit, minmax(258px, 1fr)) }
.bio__i { padding: 19px; border-radius: 15px; border: 1px solid var(--line);
  background: linear-gradient(180deg,var(--surf2),var(--surf1));
  color: var(--mute); font-size: 14.5px; line-height: 1.65 }
.bio__i b { display: block; color:var(--gold-tx); font-size: 15.5px; margin-bottom: 6px }

/* ── the dashboard ─────────────────────────────────────────
   Live events first, soonest at the top. Finished ones drop below and go quiet — they
   are reference material now, not work, and they are the whole reason nothing is deleted. */
.ev { display: block; width: 100%; text-align: left; padding: 19px 21px; margin-bottom: 11px;
  border-radius: 17px; cursor: pointer; font: inherit; color: var(--ink);
  border: 1px solid var(--line);
  background: linear-gradient(180deg,var(--surf2),var(--surf1));
  transition: border-color .16s, transform .16s }
.ev:hover { border-color:var(--gold-tx); transform: translateY(-2px) }
.ev__top { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin-bottom: 9px }
.ev__e { font-size: 22px; line-height: 1 }
.ev__n { font-size: 18px; font-weight: 800 }
.ev__m { color: var(--mute2); font-size: 13.5px }
.ev__sp { flex: 1 1 auto }
.ev__when { font-weight: 800; font-size: 14px; color:var(--gold-tx) }
.ev__when--soon { color: var(--bad-tx) }
.ev--done { opacity: .62 }
.ev--done:hover { opacity: 1 }
.ev__bar { height: 7px; border-radius: 999px; background: var(--surf3); overflow: hidden }
.ev__bar i { display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg,var(--gold-dp),var(--gold)) }
.board__h { font-size: 11.5px; font-weight: 900; letter-spacing: .12em; text-transform: uppercase;
  color: var(--mute2); margin-bottom: 12px }

/* The base stylesheet centres everything inside `main` — right for the marketing pages,
   wrong for a dashboard, which shrank to the width of its widest card and floated in the
   middle of the screen. Panels inside a working page fill it and start at the top. */
main.page > section { width: 100%; justify-self: stretch; align-self: start }
main.page { align-content: start }

/* ── site navigation ───────────────────────────────────────
   The old homepage said everything at once and linked to almost none of it. Tabs, so a
   couple, a business and a planner each have somewhere that is theirs — three audiences
   reading one page all read it badly. */
.nav { display: flex; gap: 4px; align-items: center; flex-wrap: wrap }
.nav a {
  padding: 9px 15px; border-radius: 999px; text-decoration: none; font-size: 14.5px;
  font-weight: 700; color: var(--mute); transition: color .16s, background .16s;
}
.nav a:hover { color: var(--ink); background: var(--surf3) }
.nav a.is-on { color:var(--gold-tx); background: var(--gold-w2) }
@media (max-width: 860px) { .nav a { padding: 7px 11px; font-size: 13.5px } }

.hero2 { text-align: center; padding: 6vh 0 2vh }
.hero2 h1 {
  font-family: var(--disp); font-weight: 400; font-size: clamp(38px, 7.6vw, 88px);
  line-height: .96; text-transform: uppercase; letter-spacing: .01em; margin-bottom: 18px;
}
.hero2 h1 em { font-style: normal; color:var(--gold-tx) }
.hero2 .lede { color: var(--mute); font-size: clamp(16px, 2vw, 20px); max-width: 60ch;
  margin: 0 auto 30px; line-height: 1.65 }
.cta { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap }

.sect { margin: 74px auto 0 }
.sect__k { font-size: 11.5px; font-weight: 900; letter-spacing: .16em; text-transform: uppercase;
  color:var(--gold-tx); margin-bottom: 10px }
.sect__h { font-family: var(--disp); font-weight: 400; font-size: clamp(24px, 3.8vw, 38px);
  text-transform: uppercase; letter-spacing: .02em; margin-bottom: 12px }
.sect__p { color: var(--mute); font-size: 16px; max-width: 68ch; line-height: 1.7 }

.tiles { display: grid; gap: 14px; margin-top: 26px;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)) }
.tile { padding: 22px; border-radius: 17px; border: 1px solid var(--line);
  background: linear-gradient(180deg,var(--surf2),var(--surf1)) }
.tile__e { font-size: 26px; line-height: 1; margin-bottom: 12px; display: block }
.tile h3 { font-size: 17px; margin-bottom: 7px }
.tile p { color: var(--mute); font-size: 14.5px; line-height: 1.65 }

.ours { border-color: var(--gold-e2); background: var(--gold-w1) }
.ours__tag { display: inline-block; padding: 3px 11px; border-radius: 999px; margin-bottom: 11px;
  font-size: 10.5px; font-weight: 900; letter-spacing: .1em; text-transform: uppercase;
  background: var(--gold); color: var(--on-gold) }

.cats { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px }
.cat { padding: 9px 15px; border-radius: 999px; font-size: 13.5px; text-decoration: none;
  border: 1px solid var(--line); color: var(--mute); background: var(--surf1) }
.cat:hover { border-color:var(--gold-tx); color:var(--gold-tx) }

.steps { display: grid; gap: 16px; margin-top: 26px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)) }
.stepc { padding: 20px; border-radius: 16px; border: 1px solid var(--line) }
.stepc b { display: block; font-family: var(--disp); font-size: 30px; color:var(--gold-tx);
  line-height: 1; margin-bottom: 10px }
.stepc h4 { font-size: 15.5px; margin-bottom: 6px }
.stepc p { color: var(--mute); font-size: 14px; line-height: 1.6 }

.foot { margin-top: 90px; padding: 30px 0 10px; border-top: 1px solid var(--line);
  color: var(--mute2); font-size: 13.5px; display: flex; gap: 18px; flex-wrap: wrap; align-items: center }
.foot a { color: var(--mute); text-decoration: none }
.foot a:hover { color:var(--gold-tx) }

/* ── find a vendor ─────────────────────────────────────────
   Search first, filters beside it. Not a sidebar — on a phone a sidebar becomes a wall
   you scroll past before ever seeing a business. */
.find { display: flex; gap: 9px; flex-wrap: wrap }
.find input, .find select {
  padding: 13px 16px; border-radius: 13px; font: inherit; font-size: 15px;
  background: var(--field); border: 1px solid var(--line2); color: var(--ink);
}
.find input { flex: 3 1 260px }
.find select { flex: 1 1 150px }
.find input:focus, .find select:focus { outline: none; border-color:var(--gold-tx) }

/* ── the three promises ────────────────────────────────────
   Bigger than the tiles below them because they are the argument, not a feature list.
   Each is something the big wedding sites genuinely do not do. */
.props { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)) }
.prop { padding: 26px; border-radius: 19px; border: 1px solid var(--gold-e1);
  background: linear-gradient(180deg, var(--gold-w1), var(--surf1)) }
.prop__e { display: block; font-size: 28px; line-height: 1; margin-bottom: 13px }
.prop h3 { font-size: 19px; margin-bottom: 9px; color:var(--gold-tx) }
.prop p { color: var(--mute); font-size: 15px; line-height: 1.7 }
.prop b { color: var(--ink); font-weight: 700 }

/* ══════════════════════════════════════════════════════════
   LIGHT
   ══════════════════════════════════════════════════════════
   The brand is called Party Lights and the site was a flat dark rectangle. Dark is right
   — it is a room at night, and it makes gold and colour sing in a way white never will —
   but dark on its own is just absence. What was missing is the LIGHT: colour washing
   across a room, warm in one corner and cold in another, moving slowly enough that you
   feel it rather than watch it.

   So the base stays deep and the colour comes from lights on top of it. The palette was
   already in `:root` and almost unused — gold, magenta, cyan — which is exactly the
   lighting rig of every party anybody has ever thrown.

   Everything below is behind `prefers-reduced-motion`. Slow drifting colour is lovely
   until it makes somebody ill, and a party site that hurts to look at is not a party. */

.glow {
  background:
    radial-gradient(58vw 52vh at 18% 8%,  rgba(216,160,28,.15), transparent 62%),
    radial-gradient(52vw 48vh at 88% 26%, rgba(201,24,107,.075), transparent 62%),
    radial-gradient(46vw 44vh at 62% 62%, rgba(10,125,151,.05), transparent 62%),
    radial-gradient(64vw 58vh at 8%  88%, rgba(109,63,196,.055), transparent 66%);
}
@media (prefers-reduced-motion: no-preference) {
  .glow { animation: drift 34s ease-in-out infinite alternate }
  @keyframes drift {
    0%   { transform: translate3d(0,0,0)        scale(1) }
    50%  { transform: translate3d(-2.5%,1.5%,0) scale(1.07) }
    100% { transform: translate3d(2%,-2%,0)     scale(1.03) }
  }
}

/* A band of light across the top of the page, the way a room reads when the rig is on. */
body::before {
  content: ''; position: fixed; inset: 0 0 auto 0; height: 62vh; z-index: 0;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(216,160,28,.10) 0%, transparent 100%);
}

/* Each promise gets its own colour, so scrolling feels like moving past three lights
   rather than reading three identical boxes. */
.prop--gold { border-color: var(--gold-e1);
  background: linear-gradient(165deg, var(--gold-w2), var(--surf1)) }
.prop--gold h3 { color:var(--gold-tx) }
.prop--pink { border-color: rgba(201,24,107,.30);
  background: linear-gradient(165deg, rgba(201,24,107,.09), #fff 62%) }
.prop--pink h3 { color: var(--pink-tx) }
.prop--cyan { border-color: rgba(10,125,151,.30);
  background: linear-gradient(165deg, rgba(10,125,151,.08), #fff 62%) }
.prop--cyan h3 { color: var(--info-tx) }
.prop { transition: transform .2s, box-shadow .25s }
.prop:hover { transform: translateY(-3px) }
.prop--gold:hover { box-shadow: 0 18px 40px var(--gold-shadow) }
.prop--pink:hover { box-shadow: 0 18px 40px rgba(201,24,107,.16) }
.prop--cyan:hover { box-shadow: 0 18px 40px rgba(10,125,151,.16) }

/* The headline lit rather than printed. */
.hero2 h1 em {
  background: linear-gradient(112deg, var(--gold-dp) 2%, var(--gold) 26%, var(--gold-hi) 48%, var(--gold) 70%, var(--gold-dp) 98%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
@media (prefers-reduced-motion: no-preference) {
  .hero2 h1 em { background-size: 190% 100%; animation: sweep 14s ease-in-out infinite alternate }
  @keyframes sweep { from { background-position: 12% 50% } to { background-position: 88% 50% } }
}

/* Section headings pick up the colour in turn, so the page has a rhythm instead of one
   note held all the way down. */
.sect:nth-of-type(3n+2) .sect__k { color: var(--pink-tx) }
.sect:nth-of-type(3n)   .sect__k { color: var(--info-tx) }

/* Cards lift out of the dark a little more, so the page reads as objects under light
   rather than text on a wall. */
.tile, .stepc {
  box-shadow: 0 1px 0 var(--surf2) inset, 0 20px 44px var(--shadow);
  transition: transform .18s, border-color .18s;
}
.tile:hover, .stepc:hover { transform: translateY(-2px); border-color: var(--line3) }

/* ══════════════════════════════════════════════════════════
   BIG SCREENS
   ══════════════════════════════════════════════════════════
   The container was `min(1080px, 94vw)`, which meant a 13" laptop and a 27" monitor got
   an identical 1080px column — one comfortably full, the other marooned in the middle of
   the desk with a foot of empty black either side. Measured: 1080px at 1280, 1440, 1680,
   1920 AND 2560. That is not adapting, it is stopping.
   
   Now it grows with the screen and then stops where a line of text gets too long to read
   comfortably (about 90 characters), which is a real limit rather than an arbitrary one.
   The grids use auto-fit, so extra width becomes extra columns on its own — four tiles
   across on a 27" where a laptop shows two. */
.page { width: min(1240px, 92vw) }
@media (min-width: 1600px) { .page { width: min(1400px, 90vw) } }
@media (min-width: 2000px) { .page { width: min(1560px, 88vw) } }

/* Prose still stops at a readable measure however wide the page gets — a 1,500px line of
   body copy is unreadable no matter how much room there is for it. */
.sect__p, .hero2 .lede, .bio__p { max-width: 68ch }

/* And the type grows a little on very large screens, so a 27" does not feel like a 15"
   viewed from further away. */
@media (min-width: 2000px) {
  .prop p, .tile p, .sect__p { font-size: 16.5px }
  .prop h3 { font-size: 20px }
}

/* ── the full footer ───────────────────────────────────────
   Quick links in columns, then the disclaimer, then the copyright. The disclaimer sits
   ABOVE the copyright line rather than under it — the point of a disclaimer is that
   somebody reads it, and nothing below a © line is ever read. */
.foot--full { display: block; margin-top: 96px; padding-top: 34px }
.foot__cols { display: grid; gap: 26px; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)) }
.foot__cols h4 { font-size: 11.5px; font-weight: 900; letter-spacing: .13em;
  text-transform: uppercase; color:var(--gold-tx); margin-bottom: 12px }
.foot__cols a { display: block; margin-bottom: 9px; color: var(--mute); font-size: 14.5px;
  text-decoration: none }
.foot__cols a:hover { color: var(--ink) }
.foot__legal { margin-top: 32px; padding-top: 22px; border-top: 1px solid var(--line) }
.foot__legal p { color: var(--mute2); font-size: 12.5px; line-height: 1.7; margin-bottom: 10px;
  max-width: 92ch }
.foot__legal b { color: var(--mute) }
.foot__end { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 20px; padding-top: 18px;
  border-top: 1px solid var(--line); font-size: 13px; color: var(--mute2) }

/* ── the header, on every page ─────────────────────────────
   The app pages had their own stripped-down bar with no navigation, so opening "Plan an
   event" put you inside something with no way back to the website. That is what "there
   is still no back button" meant, and it was asked about repeatedly before it was
   understood. One header everywhere. */
.bar { gap: 14px; flex-wrap: wrap; padding-block: 10px }
.bar__brand img { width: 54px; height: 54px }
.bar__brand span { font-size: 17px }
@media (min-width: 1000px) {
  .bar__brand img { width: 62px; height: 62px }
  .bar__brand span { font-size: 19px }
}

.signin { position: relative }
.signin__menu {
  position: absolute; right: 0; top: calc(100% + 10px); z-index: 60; width: 268px;
  padding: 8px; border-radius: 16px; border: 1px solid var(--line2);
  background: var(--menu); box-shadow: 0 26px 60px var(--shadow-lg);
}
.signin__menu a {
  display: block; padding: 11px 13px; border-radius: 11px; text-decoration: none; color: var(--ink);
}
.signin__menu a:hover { background: var(--gold-w2) }
.signin__menu b { display: block; font-size: 14.5px }
.signin__menu span { display: block; font-size: 12.5px; color: var(--mute2); margin-top: 2px }
.signin__sep { height: 1px; margin: 7px 9px; background: var(--line) }

/* ── dropdowns that match the app ──────────────────────────
   A native <select> renders as the operating system's own control — grey, square, and
   nothing like anything else on the page. The arrow is drawn as a background image so
   the box can be styled like every other field. */
select {
  appearance: none; -webkit-appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%238a6508' stroke-width='2' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center;
  padding-right: 38px !important; cursor: pointer;
}
select option { background: var(--menu); color: var(--ink) }

/* ── icons ─────────────────────────────────────────────────
   Line icons, not emoji. An emoji is somebody else's cartoon — a different drawing on
   every platform, arriving with its own colours and its own opinion about your palette.
   These inherit `currentColor`, so they are gold in a gold card and pink in a pink one,
   and they look drawn rather than pasted. */
.ic { width: 26px; height: 26px; display: block; margin-bottom: 13px; color:var(--gold-tx); opacity: .95 }
.prop--pink .ic { color: var(--pink-tx) }
.prop--cyan .ic { color: var(--info-tx) }
.pick .ic, .type .ic { margin-bottom: 11px }

.pwic { width: 18px; height: 18px }
.ic--in { display: inline-block; width: 17px; height: 17px; margin: 0 }

/* ══════════════════════════════════════════════════════════════════════════════
   THE HOME HERO
   ══════════════════════════════════════════════════════════════════════════════
   Lives here and not in a <style> block on index.html, because eight pages carrying
   their own copy of the shared look is exactly the fault that was just removed.

   Asymmetric on purpose: words left, one object right. lapartylights360.com is built
   that way and it reads as a business; the hub centred everything under a 158px logo
   and read as an announcement. The palette was never the difference. */
main.home{display:block;place-items:initial;padding:0}

.hero{
  position:relative;z-index:1;overflow:hidden;
  /* One screen, told to be one screen — not padded and hoped for. min-height and not
     height, so a short window grows instead of clipping the buttons off. svh and not vh
     because on a phone vh is the address-bar-hidden height, which is taller than what
     you can actually see, and the CTA lands under the browser chrome. */
  min-height:calc(100svh - 78px);display:grid;align-items:center;
  padding:clamp(26px,3vw,52px) 0;
}
.hero__glow{
  position:absolute;inset:-30% -10% auto;height:135%;pointer-events:none;
  background:
    radial-gradient(48% 44% at 18% 22%, rgba(216,160,28,.20), transparent 70%),
    radial-gradient(44% 40% at 86% 16%, rgba(201,24,107,.09), transparent 70%),
    radial-gradient(62% 50% at 52% 84%, rgba(216,160,28,.13), transparent 72%);
  filter:blur(26px);
}
/* Light beams. The brand is called Party Lights, so the background is lights — but on
   paper a beam is a place the page gets WARMER, not brighter, or it disappears. */
.hero__beams{position:absolute;inset:0;overflow:hidden;opacity:.28;pointer-events:none}
.hero__beams i{
  position:absolute;top:-30%;left:var(--x);width:10px;height:160%;
  background:linear-gradient(180deg,transparent,var(--c),transparent);
  transform-origin:top center;filter:blur(7px);transform:rotate(-4deg);
}
.hero__beams i:nth-child(1){--x:7%;--c:rgba(216,160,28,.42);--d:9s}
.hero__beams i:nth-child(2){--x:23%;--c:rgba(201,24,107,.16);--d:11s;animation-delay:-2s}
.hero__beams i:nth-child(3){--x:40%;--c:rgba(10,125,151,.13);--d:8s;animation-delay:-5s}
.hero__beams i:nth-child(4){--x:62%;--c:rgba(216,160,28,.34);--d:12s;animation-delay:-1s}
.hero__beams i:nth-child(5){--x:78%;--c:rgba(109,63,196,.14);--d:10s;animation-delay:-6s}
.hero__beams i:nth-child(6){--x:92%;--c:rgba(201,24,107,.13);--d:13s;animation-delay:-3s}
@media (prefers-reduced-motion:no-preference){
  .hero__beams i{animation:sweepbeam var(--d) ease-in-out infinite alternate}
  @keyframes sweepbeam{from{transform:rotate(-12deg)}to{transform:rotate(12deg)}}
}

.hero__inner{
  position:relative;width:min(1180px,92vw);margin-inline:auto;
  display:grid;grid-template-columns:1.06fr .94fr;gap:clamp(26px,4vw,60px);align-items:center;
}
@media (min-width:1600px){ .hero__inner{width:min(1360px,92vw)} }
@media (min-width:2000px){ .hero__inner{width:min(1620px,90vw)} }
@media (min-width:2400px){ .hero__inner{width:min(1780px,90vw)} }

.kick{
  display:inline-flex;align-items:center;gap:9px;
  font-size:11.5px;font-weight:900;letter-spacing:.2em;text-transform:uppercase;
  color:var(--gold-tx);border:1px solid var(--gold-e1);background:var(--gold-w1);
  padding:7px 16px;border-radius:999px;margin-bottom:clamp(18px,2.4vw,26px);
}
.kick i{width:7px;height:7px;border-radius:50%;background:var(--gold);
  box-shadow:0 0 10px var(--gold);animation:pulse 2.2s ease-in-out infinite}

/* The ceiling is 104px and not 76px. At 76 the whole hero sat as a small island in the
   middle of a 2560 screen, which is the "a big screen gets nothing for being big"
   complaint — not a truncation one. It has to KEEP GROWING, not merely not break. */
.hero h1{
  font-family:var(--disp);font-weight:400;text-transform:uppercase;
  font-size:clamp(40px,4.55vw,104px);line-height:.92;letter-spacing:.005em;
  margin:0 0 clamp(16px,2vw,30px);color:var(--ink);
}
.hero h1 span{display:block}
/* Gold as METAL here, not as ink: this is 100px of type, the contrast rules for body
   text do not apply, and a flat --gold-tx at this size looks like brown paint. The
   gradient runs dark→light→dark so it reads as a struck surface rather than a fill. */
.hero h1 em{
  font-style:normal;
  background:linear-gradient(112deg,
    var(--gold-dp) 2%, var(--gold) 26%, var(--gold-hi) 48%,
    var(--gold) 70%, var(--gold-dp) 98%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
.hero h1 u{text-decoration:none;color:var(--magenta)}

.hero__lede{
  font-size:clamp(16px,1.32vw,23px);color:var(--mute);
  max-width:46ch;margin:0 0 clamp(24px,3vw,38px);
}
.hero__lede b{color:var(--ink);font-weight:800}

.hero__cta{display:flex;flex-wrap:wrap;gap:13px;align-items:center}
@media (min-width:1600px){
  .kick{font-size:13px;padding:9px 20px}
  .hero__cta .btn{font-size:17px;padding:17px 32px}
  .hand{font-size:23px}
}
@media (min-width:2200px){
  .hero__cta .btn{font-size:19px;padding:19px 38px}
  .hand{font-size:26px}
}

.hand{
  font-family:var(--hand);font-size:19.5px;line-height:1.35;color:var(--gold-tx);
  margin-top:16px;display:flex;align-items:flex-start;gap:7px;
}
.hand svg{width:15px;height:19px;flex:none;margin-top:3px;opacity:.8}

.hero__art{position:relative;display:flex;justify-content:center;align-items:center}
.hero__art svg{width:100%;height:auto;max-width:min(100%,760px);overflow:visible}

/* Every bulb and glyph is a stroke inheriting currentColor, so the whole rig recolours
   from one property — and nothing here is somebody else's cartoon. */
.rig{color:var(--gold-dp)}
.rig .wire{fill:none;stroke:currentColor;stroke-width:1.8;opacity:.5}
.rig .drop{stroke:currentColor;stroke-width:1.2;opacity:.32}
.rig .glyph{fill:none;stroke:currentColor;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
/* A <use> clones into a SHADOW tree and a descendant selector does not cross it —
   `.bulb circle{stroke:…}` matched nothing and every bulb rendered as a plain black
   disc, the SVG default fill. Inheritable properties DO cross it. */
.rig .bulb{fill:currentColor;fill-opacity:.5;stroke:currentColor;stroke-width:1.6}
.rig .ring{fill:#fff;stroke:currentColor;stroke-width:1.7;opacity:.95}
.rig .spk{fill:currentColor}
@media (prefers-reduced-motion:no-preference){
  .rig .bulb{animation:twinkle var(--t,5s) ease-in-out infinite alternate}
  @keyframes twinkle{from{opacity:.5}to{opacity:1}}
  .rig .spk{animation:shimmer var(--t,4s) ease-in-out infinite alternate}
  @keyframes shimmer{from{opacity:.25}to{opacity:.9}}
}

/* Below this the two columns STOP being two columns, rather than getting narrower and
   narrower until neither works — which is where a half-landed page comes from. */
@media (max-width:940px){
  .hero__inner{grid-template-columns:1fr;gap:34px}
  .hero__art{order:-1;max-width:420px;margin-inline:auto}
  .hero__lede{max-width:56ch}
}
@media (max-width:560px){
  .hero{padding-top:26px}
  .hero h1{font-size:clamp(38px,11vw,52px)}
  .hero__cta .btn{flex:1 1 100%;justify-content:center}
}

/* ── the signed-in strip ───────────────────────────────────
   Tabs on the left, the way out on the right. /admin, /vendor and /plan each had a way
   IN and no way out, and admin had no tab strip at all even though admin.js binds to
   one — which is why all three pages came up blank.

   No margin of its own: on the sign-in screen both children are [hidden], and a bar with
   its own margin would leave a mystery gap above the form. The children carry it, so an
   empty strip is genuinely zero-height. */
.apptop { display: flex; gap: 12px; align-items: center; flex-wrap: wrap }
.apptop__sp { flex: 1 1 auto }
.apptop > .tabs, .apptop > .btn { margin-bottom: 20px }
.apptop > .btn { margin-left: auto }


/* Grid items stretch to the tallest in their row by default. On the dark page that
   trailing space was invisible; on paper it is a visible empty block under short cards.
   They keep their own height and sit at the top of the row instead. */
.bio__grid, .tiles, .steps, .props { align-items: start }

/* Cards need an EDGE on paper. On black a card was defined by being lighter than the
   page it sat on; on white nothing is lighter than the page, so definition has to come
   from a border and a shadow or the card simply is not there. */
.card, .tile, .stepc, .bio__i, .prop, .ev, .pick, .vrow, .prow {
  box-shadow: 0 1px 2px var(--shadow), 0 8px 24px var(--shadow);
}
[data-theme="dark"] .card, [data-theme="dark"] .tile, [data-theme="dark"] .stepc,
[data-theme="dark"] .bio__i, [data-theme="dark"] .prop, [data-theme="dark"] .ev,
[data-theme="dark"] .pick, [data-theme="dark"] .vrow, [data-theme="dark"] .prow {
  box-shadow: none;
}

/* Inputs are sunken wells on dark and RAISED boxes on paper. The focus state has to be
   a real ring: on black, changing the border to gold was a big visible jump, and on
   white the same change is a few percent and reads as nothing happening. */
.field input, .field select, .field textarea, .find input, .find select {
  box-shadow: 0 1px 2px var(--shadow) inset;
}
.field input:focus, .field select:focus, .field textarea:focus,
.find input:focus, .find select:focus {
  box-shadow: 0 0 0 3px var(--gold-w2);
}
[data-theme="dark"] .field input, [data-theme="dark"] .field select,
[data-theme="dark"] .field textarea, [data-theme="dark"] .find input,
[data-theme="dark"] .find select { box-shadow: none }

/* ══════════════════════════════════════════════════════════════════════════════
   THE GOLD RIBBON
   ══════════════════════════════════════════════════════════════════════════════
   Lifted from lapartylights360.com's `.marquee` — the geometry, the rotation, the
   scaleX, the 26s roll and the two-copy track are its numbers, not new ones, because
   the brief was to replicate it exactly. Only two things differ, and both had to:

   1. THE WORDS. On 360 it is what the booth does — CAPTURE ✦ SPIN ✦ SHARE ✦ SHINE.
      Here it is who is on the platform, which is the whole product.
   2. THE FILL. On 360 the ribbon is gold on black and glows. On paper a gold band
      needs a dark EDGE to be a band at all, and its shadow drops rather than glows —
      the same object, lit from a different room.

   Note: this is a marquee, and a scrolling ribbon was previously rejected outright.
   It is here because it was asked for again by name, pointing at the 360 one. If it
   is wrong again, it is one <div> in index.html and this block.

   THE TRACK MUST BE EXACTLY TWO IDENTICAL COPIES. The animation translates -50% and
   restarts, which is seamless only if the second copy is pixel-identical to the first.
   Three copies, or copies of different lengths, and it visibly jumps every lap. */
.marqwrap{
  position:relative;z-index:4;overflow:hidden;
  padding-block:16px;margin-block:-4px;
}
.marquee{
  position:relative;overflow:hidden;padding:15px 0;
  background:linear-gradient(90deg,var(--gold-dp),var(--gold) 22%,var(--gold-hi) 50%,var(--gold) 78%,var(--gold-dp));
  border-block:2px solid rgba(64,44,4,.42);
  /* scaled wider than the viewport so the tilted ends never leave a gap at the corners */
  transform:rotate(-1.4deg) scaleX(1.08);
  box-shadow:0 10px 30px -8px var(--gold-shadow);
}
[data-theme="dark"] .marquee{
  border-block:2px solid rgba(0,0,0,.35);
  box-shadow:0 0 60px -10px rgba(245,196,69,.6);
}
.marquee__track{display:flex;width:max-content;animation:roll 26s linear infinite}
.marquee span{
  font-family:var(--disp);font-size:clamp(19px,2.4vw,30px);letter-spacing:.1em;
  color:#140e04;padding-right:28px;white-space:nowrap;
}
@keyframes roll{to{transform:translateX(-50%)}}
/* A band of type sliding sideways forever is exactly the thing that triggers people.
   It holds still and stays perfectly readable — nothing is lost by stopping. */
@media (prefers-reduced-motion:reduce){
  .marquee__track{animation:none}
}
/* Pausing on hover is not a flourish: it is how somebody reads a name they half-caught. */
.marquee:hover .marquee__track{animation-play-state:paused}

/* ══════════════════════════════════════════════════════════════════════════════
   THE DISPLAY HEADINGS — WHITE, WITH A SHADE
   ══════════════════════════════════════════════════════════════════════════════
   Flat near-black Anton on warm white is correct and dull. The ask was white with a
   dark shade, and at this size that is a real poster treatment rather than a trick:
   white face, a crisp ink edge so it survives on a light page, and a hard offset
   shade so the letter has a body and a side.

   ONLY on the big display sizes. A hard 3px offset under a 24px heading is mud — the
   shade is thicker than the stroke it sits behind. Smaller headings get --ink-title
   instead: a deep plum-brown rather than black, which is the same fix at a size where
   an outline cannot work.

   -webkit-text-stroke is doing load-bearing work here, not decoration: without it the
   white face has 1.05:1 against the page and the whole heading is the shade only. */
:root{ --ink-title:#2b1c30 }
[data-theme="dark"]{ --ink-title:#ffffff }

.hero h1, .hero2 h1{
  color:#fff;
  -webkit-text-stroke:1.6px var(--ink);
  paint-order:stroke fill;
  text-shadow:
     3px 3px 0 var(--ink),
     6px 6px 0 rgba(43,28,48,.30),
     0 14px 26px rgba(43,28,48,.16);
}
/* The struck-gold words keep their gradient — a gradient clipped to text cannot also
   carry a stroke, so they get the shade only, and the stroke is switched off rather
   than fighting the background-clip and painting a black box. */
.hero h1 em, .hero2 h1 em{
  -webkit-text-stroke:0;
  text-shadow:none;
  filter:drop-shadow(3px 3px 0 var(--ink)) drop-shadow(0 10px 20px rgba(43,28,48,.18));
}
[data-theme="dark"] .hero h1, [data-theme="dark"] .hero2 h1{
  color:#fff; -webkit-text-stroke:0; text-shadow:none;
}
[data-theme="dark"] .hero h1 em, [data-theme="dark"] .hero2 h1 em{ filter:none }

/* Everything smaller: not black, but not outlined either. */
.h2, .sect__h, .bio__h, .look__h, .ph{ color:var(--ink-title) }

@media (max-width:560px){
  /* The offset does not scale with the type, so at phone sizes it goes from a shade
     to a smear. Halved, and the second layer dropped entirely. */
  .hero h1, .hero2 h1{
    -webkit-text-stroke:1.2px var(--ink);
    text-shadow:2px 2px 0 var(--ink), 0 8px 16px rgba(43,28,48,.16);
  }
  .hero h1 em, .hero2 h1 em{ filter:drop-shadow(2px 2px 0 var(--ink)) }
}

/* ══════════════════════════════════════════════════════════════════════════════
   MOVEMENT
   ══════════════════════════════════════════════════════════════════════════════
   All of it behind prefers-reduced-motion, and all of it on a property the compositor
   can animate on its own — transform and opacity. Animating anything else here means
   a layout pass per frame on a page full of cards. */
.reveal{opacity:0;transform:translateY(26px);
  transition:opacity .7s ease, transform .7s cubic-bezier(.2,.8,.2,1)}
.reveal.in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){
  .reveal{opacity:1;transform:none;transition:none}
}

/* Cards lift toward the cursor. The shadow grows with the lift, or the card looks like
   it slid up the page rather than off it. */
@media (hover:hover) and (prefers-reduced-motion:no-preference){
  .tile, .stepc, .bio__i, .ev, .pick, .type, .card--lift{
    transition:transform .22s cubic-bezier(.2,.8,.2,1), box-shadow .22s, border-color .18s;
  }
  .tile:hover, .stepc:hover, .bio__i:hover, .ev:hover, .pick:hover, .type:hover, .card--lift:hover{
    transform:translateY(-4px);
    box-shadow:0 2px 4px var(--shadow), 0 18px 40px var(--shadow);
    border-color:var(--gold-e1);
  }
  /* A gold hairline crossing the top edge on hover: it reads as light catching the
     card, which is the one metaphor this brand actually owns. */
  .tile, .stepc, .bio__i{ position:relative; overflow:hidden }
  .tile::after, .stepc::after, .bio__i::after{
    content:''; position:absolute; inset:0 0 auto 0; height:2px; transform:scaleX(0);
    transform-origin:left; transition:transform .35s cubic-bezier(.2,.8,.2,1);
    background:linear-gradient(90deg,transparent,var(--gold),transparent);
  }
  .tile:hover::after, .stepc:hover::after, .bio__i:hover::after{ transform:scaleX(1) }

  .btn{ transition:transform .18s cubic-bezier(.2,.8,.2,1), box-shadow .2s, border-color .2s, background .2s }
  .btn--gold:hover{ transform:translateY(-2px) }
  .btn--gold:active{ transform:translateY(0) }
}

/* The kicker dot already pulses. The hero sparkles already shimmer. This is for the
   one element that is genuinely an invitation: the primary button, once, on arrival. */
@media (prefers-reduced-motion:no-preference){
  .hero__cta .btn--gold{ animation:arrive .9s cubic-bezier(.2,.8,.2,1) both .35s }
  @keyframes arrive{
    from{ opacity:0; transform:translateY(10px) scale(.97) }
    to  { opacity:1; transform:none }
  }
}

/* ── the walkthrough placeholder ───────────────────────────
   An empty grey rectangle on a live homepage reads as something broken. This says what
   it is and what to do instead, so it is an empty shelf rather than a fault. Same 16/9
   as the real embed will be, so dropping the iframe in changes nothing around it. */
.howto__frame{
  margin-top:24px; aspect-ratio:16/9; width:min(880px,100%);
  display:grid; place-content:center; justify-items:center; gap:10px; text-align:center;
  padding:28px; border-radius:20px;
  border:1.5px dashed var(--gold-e1); background:var(--gold-w1);
}
.howto__frame svg{ width:52px; height:52px; color:var(--gold-tx); opacity:.8 }
.howto__frame b{ font-size:17px; color:var(--ink-title) }
.howto__frame span{ font-size:14.5px; color:var(--mute); max-width:44ch; line-height:1.6 }
