/* denz — dark, calm, built to be read on a phone in bed.
   Deliberately unlike the party site: that one shouts, this one doesn't. */

:root {
  /* Soft gold on black. The gold is muted rather than brassy — a bright
     saturated gold on near-black vibrates badly on an OLED phone, which is
     where this actually gets read. Everything neutral carries a slight warm
     tint so the gold sits in the palette instead of on top of it. */
  --bg:        #0a0a0b;
  --surface:   #141310;
  --surface-2: #1d1b16;
  --line:      #2e2b24;
  --ink:       #f2ece0;
  --ink-dim:   #9a9182;

  --gold:      #d9b877;
  --gold-soft: #e8d2a0;
  --gold-dim:  #8a734a;

  --accent:    var(--gold);
  /* Yes is the gold — it is the colour the whole page is built around, so the
     thing you want to happen wears it. No is a warm clay: clearly different in
     hue, but still inside the palette rather than an alarm state. The 👍/👎
     glyphs carry the meaning anyway; colour is only reinforcement. */
  --yes:       #d9b877;
  --no:        #a9614a;

  --r:         14px;
  --r-sm:      9px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: ui-sans-serif, -apple-system, "Segoe UI", Inter, system-ui, sans-serif;
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

[hidden] { display: none !important; }
.muted { color: var(--ink-dim); }
.tiny  { font-size: 12px; }

/* ------------------------------------------------------------------- gate */

.gate {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 24px;
  /* A quiet wash so the login screen doesn't read as an error page. */
  background: radial-gradient(120% 90% at 50% 0%, #1b1813 0%, var(--bg) 62%);
}
.gate-card {
  width: min(360px, 100%);
  display: grid;
  gap: 14px;
  padding: 28px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.gate-card h1 { margin: 0; font-size: 26px; letter-spacing: -0.02em; }
.gate-card p  { margin: -8px 0 4px; font-size: 13px; }

/* Google's button renders itself; this just centres it and separates it from
   the password fallback below. */
#google-block { display: grid; gap: 14px; justify-items: center; }
#google-btn { min-height: 40px; }
.or {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-dim);
}
.or::before, .or::after { content: ""; flex: 1; height: 1px; background: var(--line); }

.field { display: grid; gap: 6px; font-size: 12px; font-weight: 600; color: var(--ink-dim); }
input[type=text], input[type=password] {
  padding: 11px 13px;
  font: inherit;
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}
input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

.btn {
  padding: 11px 16px;
  font: inherit; font-weight: 650;
  color: #17130a;
  background: var(--gold);
  border: 0; border-radius: var(--r-sm);
  cursor: pointer;
}
.btn:disabled { opacity: .55; cursor: default; }
.linkish {
  padding: 0; font: inherit; font-size: 13px;
  color: var(--ink-dim);
  background: none; border: 0; cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
.linkish:hover { color: var(--ink); }
.error { margin: 0; font-size: 13px; color: var(--no); }

/* -------------------------------------------------------------- chrome */

.top {
  position: sticky; top: 0; z-index: 10;
  display: flex; align-items: center; gap: 16px;
  padding: 14px 18px;
  background: rgb(10 10 11 / .84);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}
.brand { font-weight: 750; letter-spacing: -0.02em; }
.tabs { display: flex; gap: 4px; flex: 1; }
.tab {
  padding: 6px 12px;
  font: inherit; font-size: 13px; font-weight: 600;
  color: var(--ink-dim);
  background: none; border: 0; border-radius: 999px;
  cursor: pointer;
}
.tab[aria-current] { color: var(--ink); background: var(--surface-2); }

main { padding: 20px 18px 40px; max-width: 1100px; margin: 0 auto; }

.foot {
  display: flex; justify-content: space-between; align-items: center;
  gap: 12px;
  padding: 16px 18px 28px;
  max-width: 1100px; margin: 0 auto;
  border-top: 1px solid var(--line);
}

/* --------------------------------------------------------------- events */

.day-head {
  margin: 26px 0 12px;
  font-size: 12px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-dim);
}
.day-head:first-child { margin-top: 4px; }

.grid { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }

.card {
  display: flex; flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  transition: border-color .18s, transform .18s;
}
.card:hover { border-color: var(--gold-dim); }
/* A card both have said yes to should be obvious at a glance. */
.card.agreed { border-color: var(--yes); }

.shot {
  aspect-ratio: 16 / 9;
  background: var(--surface-2) center/cover no-repeat;
  border-bottom: 1px solid var(--line);
}
.card-body { display: grid; gap: 8px; padding: 15px 16px; }

.meta { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.chip {
  padding: 3px 9px;
  font-size: 11px; font-weight: 650; letter-spacing: .02em;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--ink-dim);
}
.chip.cat  { color: var(--gold-soft); background: #d9b8771c; }
.chip.when { color: var(--ink); }

.card h3 { margin: 0; font-size: 16.5px; font-weight: 680; letter-spacing: -0.01em; line-height: 1.3; }
.card p  { margin: 0; font-size: 13.5px; color: var(--ink-dim); }
.where   { font-size: 12.5px; color: var(--ink-dim); }
.where a { color: var(--ink-dim); }

.actions {
  display: flex; align-items: center; gap: 8px;
  margin-top: auto;
  padding: 12px 16px;
  border-top: 1px solid var(--line);
  background: #100f0d;
}
.vote {
  flex: 1;
  padding: 8px 10px;
  font: inherit; font-size: 13px; font-weight: 650;
  color: var(--ink-dim);
  background: var(--surface-2);
  border: 1px solid transparent; border-radius: var(--r-sm);
  cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}
.vote:hover { color: var(--ink); }
.vote.on.yes { color: #17130a; background: var(--yes); }
.vote.on.no  { color: #1a0d09; background: var(--no); }

/* The other person's standing answer, so you can see it without asking. */
.theirs {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11.5px; font-weight: 620;
  color: var(--ink-dim);
  white-space: nowrap;
}
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--line); }
.dot.yes { background: var(--yes); }
.dot.no  { background: var(--no); }

.empty {
  padding: 60px 20px;
  text-align: center;
  color: var(--ink-dim);
}
.empty .big { display: block; font-size: 40px; margin-bottom: 10px; }

.spinner {
  width: 15px; height: 15px;
  border: 2px solid var(--line); border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin .7s linear infinite;
  display: inline-block;
}
@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ------------------------------------------- votes, reasons, image fallback */

/* No picture found: a tinted panel keyed to the category, so a card without an
   image still reads as designed rather than broken. */
.shot.none { position: relative; }
.shot.none::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(135deg, #26221a, #131210);
}
.shot.none[data-cat="music"]::after    { background: linear-gradient(135deg,#2a2318,#131210); }
.shot.none[data-cat="culture"]::after  { background: linear-gradient(135deg,#2b2419,#131210); }
.shot.none[data-cat="sport"]::after    { background: linear-gradient(135deg,#232619,#131210); }
.shot.none[data-cat="film"]::after     { background: linear-gradient(135deg,#2a2017,#131210); }
.shot.none[data-cat="market"]::after   { background: linear-gradient(135deg,#2e2717,#131210); }
.shot.none[data-cat="festival"]::after { background: linear-gradient(135deg,#302614,#131210); }
.shot.none[data-cat="food"]::after     { background: linear-gradient(135deg,#2c2016,#131210); }
.shot.none[data-cat="outdoors"]::after { background: linear-gradient(135deg,#212618,#131210); }

/* Emoji reads at a glance on a phone; the words never did much work here. */
.vote { font-size: 17px; line-height: 1; padding: 7px 10px; }
.vote.say { flex: 0 0 auto; font-size: 15px; }
.vote.on.yes { background: var(--yes); }
.vote.on.no  { background: var(--no); }

.theirs { gap: 6px; }
.face {
  display: grid; place-items: center;
  width: 20px; height: 20px;
  font-size: 10.5px; font-weight: 800;
  color: var(--ink-dim);
  background: var(--surface-2);
  border-radius: 50%;
}
.verdict { font-size: 14px; line-height: 1; }

.note {
  padding: 7px 10px;
  font-size: 12.5px;
  color: var(--ink-dim);
  background: var(--surface-2);
  border-radius: var(--r-sm);
  border-left: 2px solid var(--line);
}
.note b { color: var(--ink); font-weight: 650; }
.note.their { border-left-color: var(--accent); }

.say-box { display: flex; gap: 8px; padding: 0 16px 14px; }
.say-box input {
  flex: 1;
  padding: 8px 11px;
  font: inherit; font-size: 13px;
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}
.btn.small { padding: 8px 12px; font-size: 13px; }

/* ----------------------------------------------------------- ambient motion */

/* Behind everything, ignores the mouse, and contributes nothing to layout.
   Anything in here is decoration: the page is fully usable with it removed. */
.ambient {
  position: fixed; inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}
.top, main, .foot, .gate { position: relative; z-index: 1; }

.drifter {
  position: absolute;
  bottom: -60px;
  will-change: transform;
  animation-name: drift;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  user-select: none;
}
@keyframes drift {
  from { transform: translate3d(0, 0, 0) rotate(0deg); }
  to   { transform: translate3d(var(--sway), -115vh, 0) rotate(var(--spin)); }
}

.confetti {
  position: fixed;
  width: 7px; height: 11px;
  z-index: 60;
  pointer-events: none;
  animation-name: burst;
  animation-timing-function: cubic-bezier(.2, .7, .3, 1);
  animation-fill-mode: forwards;
}
@keyframes burst {
  from { transform: translate(0, 0) rotate(0deg); opacity: 1; }
  to   { transform: translate(var(--dx), calc(var(--dy) + 220px)) rotate(var(--rot)); opacity: 0; }
}

/* The gate gets its own gentle pulse so the sign-in screen isn't dead flat. */
.gate-card { animation: rise .5s cubic-bezier(.2,.8,.2,1) both; }
@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* A card the two of you just agreed on gives a small nudge. */
.card.agreed { animation: agree .5s cubic-bezier(.3,1.4,.4,1) both; }
@keyframes agree {
  0%   { transform: none; }
  40%  { transform: scale(1.015); }
  100% { transform: none; }
}

/* The image is an <img> rather than a background so loading="lazy" applies —
   with a board this size that's the difference between 34 requests on first
   paint and about six. width/height are set in the markup so the card reserves
   its space and the grid doesn't jump as pictures arrive. */
.shot { position: relative; overflow: hidden; }
.shot img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  /* Fades in rather than snapping, which hides the decode on a slow phone. */
  animation: fade-in .4s ease both;
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

.toast {
  position: fixed; left: 50%; bottom: 26px;
  transform: translateX(-50%) translateY(12px);
  z-index: 80;
  padding: 10px 16px;
  font-size: 13px; font-weight: 600;
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  opacity: 0; pointer-events: none;
  transition: opacity .2s, transform .2s;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* A card whose picture couldn't be resolved still needs to look composed. */
.shot.none { display: grid; place-items: center; }
.shot.none .glyph,
.shot.none .fallback-city { position: relative; z-index: 1; }
.shot.none .glyph { font-size: 34px; opacity: .30; line-height: 1; }
.shot.none .fallback-city {
  margin-top: 6px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-dim); opacity: .7;
}

/* ------------------------------------------------------- gold flourishes */

/* A single hairline under the header, brightest in the middle. Cheap, and it
   does most of the work of making black-and-gold read as deliberate. */
.top::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold-dim) 22%, var(--gold) 50%, var(--gold-dim) 78%, transparent);
  opacity: .55;
}

.brand {
  background: linear-gradient(100deg, var(--gold-soft), var(--gold) 45%, var(--gold-dim));
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}

.gate-card {
  /* A faint warm bloom from the top edge, so the sign-in card has some depth
     against the black without needing a border that fights the gold. */
  background:
    radial-gradient(120% 100% at 50% -20%, #221d14 0%, transparent 65%),
    var(--surface);
  border-color: #2a2620;
}
.gate-card h1 {
  background: linear-gradient(100deg, var(--gold-soft), var(--gold) 50%, var(--gold-dim));
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}

/* Both of you said yes: gold edge plus a soft halo, rather than a plain border
   swap. This is the one state on the page worth making a little bit special. */
.card.agreed {
  border-color: var(--gold);
  box-shadow: 0 0 0 1px rgb(217 184 119 / .28), 0 8px 34px -14px rgb(217 184 119 / .45);
}

.day-head { color: var(--gold-dim); }
.tab[aria-current] { color: var(--gold-soft); }
.chip.when { color: var(--ink); }
.spinner { border-top-color: var(--gold); }
input:focus { outline-color: var(--gold); }
.where a { color: var(--gold-dim); }
.where a:hover { color: var(--gold); }

/* ============================================================ movies theme */

/* A dark auditorium: deep red-black walls, warm marquee bulbs, and the screen's
   own glow. Same structure as the gold theme — only the variables move — so the
   whole rubrique re-skins without a single component knowing about it. */
body.theme-movies {
  --bg:        #0d0708;
  --surface:   #1a1012;
  --surface-2: #241618;
  --line:      #3a2126;
  --ink:       #f6ebe6;
  --ink-dim:   #ab9089;

  --gold:      #edc074;   /* marquee bulb */
  --gold-soft: #f7dfae;
  --gold-dim:  #8d6636;

  --accent:    var(--gold);
  --yes:       #edc074;
  --no:        #8f3b3b;
}

/* Curtain: two soft red falls at the edges of the viewport, well behind
   everything. Fixed, so it doesn't move as you scroll — it's the room, not the
   content. */
body.theme-movies::before {
  content: "";
  position: fixed; inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    linear-gradient(90deg, rgb(112 22 28 / .30) 0%, transparent 16%),
    linear-gradient(270deg, rgb(112 22 28 / .30) 0%, transparent 16%),
    radial-gradient(120% 60% at 50% -10%, rgb(237 192 116 / .07) 0%, transparent 60%);
}

body.theme-movies .brand,
body.theme-movies .gate-card h1 {
  background: linear-gradient(100deg, #f7dfae, #edc074 45%, #b5502f);
  -webkit-background-clip: text; background-clip: text;
}

/* ------------------------------------------------------------- film cards */

/* Posters are 2:3, so films get their own tighter grid rather than reusing the
   16:9 event card. */
.grid.films { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }

.poster { aspect-ratio: 2 / 3; overflow: hidden; background: var(--surface-2); position: relative; }
.poster img { display: block; width: 100%; height: 100%; object-fit: cover; animation: fade-in .4s ease both; }
.poster.none { display: grid; place-items: center; }
.poster.none .glyph { font-size: 40px; opacity: .25; }

.card.film h3 { font-size: 15.5px; }
.card.film .card-body { gap: 6px; padding: 13px 14px; }
.card.film p { font-size: 12.5px; }

/* Wanted floats to the top of its genre and says so; passed sinks and dims,
   but stays readable — tastes change, and it can be taken back. */
.card.film.wanted { border-color: var(--gold-dim); }
.card.film.passed { opacity: .5; }
.card.film.passed:hover { opacity: 1; }

.chip.want { color: var(--gold-soft); background: rgb(237 192 116 / .12); }
.chip.svc { font-weight: 700; }
.chip.svc.netflix { color: #ff6b6b; background: #ff6b6b1a; }
.chip.svc.hbo     { color: #b79bff; background: #b79bff1a; }
.chip.svc.canal   { color: #7fd4e8; background: #7fd4e81a; }
.chip.svc.appletv { color: #e6e2dd; background: #e6e2dd14; }

.seen-chip {
  padding: 3px 9px;
  font-size: 11px; font-weight: 650;
  border-radius: 999px;
  background: var(--surface-2); color: var(--ink-dim);
}
.seen-chip.liked    { color: var(--gold-soft); }
.seen-chip.disliked { color: var(--no); }

.vote.on.liked    { color: #1a1206; background: var(--gold); }
.vote.on.disliked { color: #f6ebe6; background: var(--no); }
.vote.seen, .vote.back { flex: 0 0 auto; font-size: 15px; }

/* Service filter row. */
.filters { display: flex; flex-wrap: wrap; gap: 7px; margin: 2px 0 18px; }
.pill {
  padding: 6px 13px;
  font: inherit; font-size: 12.5px; font-weight: 650;
  color: var(--ink-dim);
  background: var(--surface-2);
  border: 1px solid transparent; border-radius: 999px;
  cursor: pointer;
}
.pill.on { color: #1a1206; background: var(--gold); }
.pill:hover:not(.on) { color: var(--ink); }

.day-head .count {
  margin-left: 6px;
  font-size: 11px; font-weight: 600;
  color: var(--ink-dim); opacity: .7;
}

/* A deep-linked card announces itself briefly, so following a link lands on the
   thing rather than somewhere near it. */
.card.focused {
  border-color: var(--gold);
  box-shadow: 0 0 0 2px rgb(217 184 119 / .4), 0 10px 40px -12px rgb(217 184 119 / .5);
  animation: knock .6s cubic-bezier(.3,1.4,.4,1) both;
}
@keyframes knock { 0%,100% { transform: none; } 45% { transform: scale(1.02); } }
.vote.link { flex: 0 0 auto; font-size: 14px; }

/* ============================================================= shows theme */

/* Late evening on the sofa: a blue-black room lit by the screen. Cooler than
   the cinema red, warmer than the gold — it should feel like the hour you'd
   actually start a series at. */
body.theme-shows {
  --bg:        #080b10;
  --surface:   #101620;
  --surface-2: #171f2b;
  --line:      #24303f;
  --ink:       #e9eef5;
  --ink-dim:   #8b98aa;

  --gold:      #6fd4e0;   /* screen glow */
  --gold-soft: #a9e8ef;
  --gold-dim:  #3d7f89;

  --accent:    var(--gold);
  --yes:       #6fd4e0;
  --no:        #6b7a8d;
}

/* The glow itself: cool light spilling from the top of the room. */
body.theme-shows::before {
  content: "";
  position: fixed; inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(140% 55% at 50% -12%, rgb(111 212 224 / .10) 0%, transparent 62%),
    linear-gradient(180deg, transparent 60%, rgb(6 9 13 / .55) 100%);
}

body.theme-shows .brand,
body.theme-shows .gate-card h1 {
  background: linear-gradient(100deg, #a9e8ef, #6fd4e0 45%, #3d7f89);
  -webkit-background-clip: text; background-clip: text;
}

/* Where you're up to, which is the whole point of the Watching list. */
.progress {
  flex: 1;
  font-size: 13px; font-weight: 750; letter-spacing: .04em;
  font-variant-numeric: tabular-nums;
  color: var(--gold-soft);
}
.vote.bump { flex: 0 0 auto; font-size: 13px; font-weight: 800; }
.vote.done, .vote.start { flex: 0 0 auto; font-size: 14px; }
.vote.on.abandoned { color: #0b0f14; background: #93a3b5; }
.seen-chip.abandoned { color: #93a3b5; }

/* The three-state row sits above the cards and reads as one control. */
.filters.states { gap: 0; margin-bottom: 16px; border-radius: 999px;
  background: var(--surface-2); padding: 3px; width: fit-content; }
.filters.states .pill { background: transparent; border-radius: 999px; }
.filters.states .pill.on { background: var(--gold); color: #08151a; }
