/* ──────────────────────────────────────────────────────────────
   login-fullbleed.css: the sign-in page.
   Photo full bleed, hero copy left, form card right, tab rail and
   fleet stats along the bottom. On phones the photo sits on top
   and the form is a bottom sheet. login-recap.css loads after this
   and reads the scene tokens below (--lm-hero-*, --lm-recap-grad,
   --lm-node-*, --lm-enter-*, --lm-ink-rgb, --lm-pulse).
   ────────────────────────────────────────────────────────────── */

:root {
  --page-inset: 56px;
  --content-max: 1600px;
  --lm-radius-xl: 24px;
  --lm-radius-md: 12px;
  --lm-dwell: 8000ms;
  --lm-fade: 1000ms;

  --font-sans: 'General Sans', system-ui, sans-serif;
  --font-display: 'General Sans', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, monospace;

  /* Card tokens, light */
  --bg: #f6f4ef;
  --ink: #1a1a1a;
  --ink2: #4a4843;
  --mute: #7d7a72;
  --faint: #9a978c;
  --rule: #e8e3d6;
  --panel: #ffffff;
  --surface-2: #fafaf8;
  --card: rgba(255, 255, 255, 0.92);
  --card-border: rgba(255, 255, 255, 0.55);
  --card-shadow:
    0 30px 80px -40px rgba(0, 0, 0, 0.6),
    0 12px 30px -16px rgba(0, 0, 0, 0.4);
  --focus-ring: rgba(26, 26, 26, 0.06);
  --error: #b42318;
  --error-bg: rgba(217, 45, 32, 0.08);
  --error-border: rgba(217, 45, 32, 0.22);
  --ok: #2f7a4e;
  --ok-bg: rgba(58, 166, 106, 0.10);
  --ok-border: rgba(58, 166, 106, 0.25);
  --warn: #92610a;
  --warn-bg: rgba(245, 158, 11, 0.10);
  --warn-border: rgba(245, 158, 11, 0.28);

  /* Scene tokens read by the recap, light */
  --lm-hero-text:  #222a39;
  --lm-hero-mute:  rgba(34, 42, 57, 0.62);
  --lm-hero-faint: rgba(34, 42, 57, 0.42);
  --lm-hero-rule:  rgba(34, 42, 57, 0.12);
  --lm-hero-glass: rgba(34, 42, 57, 0.045);
  --lm-pulse:      #2fa968;
  --lm-ink-rgb: 46, 56, 78;
  --lm-grain:   rgba(30, 40, 60, 0.05);
  --lm-recap-grad:
    radial-gradient(ellipse 60% 60% at 50% 28%,  rgba(125, 106, 191, 0.16), transparent 60%),
    radial-gradient(ellipse 70% 60% at 14% 100%, rgba(58, 166, 106, 0.13), transparent 60%),
    radial-gradient(ellipse 60% 50% at 100% 4%,  rgba(217, 154, 58, 0.10), transparent 60%),
    linear-gradient(165deg, #f7f5ef 0%, #f0ede4 60%, #e9e5d9 100%);
  --lm-node-green:  #2f9d63;
  --lm-node-iris:   #6f5fce;
  --lm-node-honey:  #bd8628;
  --lm-node-cobalt: #4a8ccc;
  --lm-enter-bg:    #1c2230;
  --lm-enter-bg-h:  #2a3346;
  --lm-enter-ink:   #f4f6f9;
}

body.theme-dark {
  --bg: #12151f;
  --ink: #e7ebf2;
  --ink2: #b8bfcc;
  --mute: #8a93a4;
  --faint: #6b7585;
  --rule: #232a3e;
  --panel: #161b2a;
  --surface-2: #1d2538;
  --card: rgba(22, 27, 42, 0.86);
  --card-border: rgba(255, 255, 255, 0.08);
  --card-shadow:
    0 40px 100px -30px rgba(0, 0, 0, 0.85),
    0 16px 40px -12px rgba(0, 0, 0, 0.6);
  --focus-ring: rgba(231, 235, 242, 0.06);
  --error: #ff9a8f;
  --error-bg: rgba(217, 45, 32, 0.16);
  --error-border: rgba(217, 45, 32, 0.3);
  --ok: #6cd28e;
  --ok-bg: rgba(58, 166, 106, 0.16);
  --ok-border: rgba(58, 166, 106, 0.3);
  --warn: #f5c26b;
  --warn-bg: rgba(245, 158, 11, 0.14);
  --warn-border: rgba(245, 158, 11, 0.32);

  --lm-hero-text:  #ecf0f5;
  --lm-hero-mute:  rgba(236, 240, 245, 0.66);
  --lm-hero-faint: rgba(236, 240, 245, 0.42);
  --lm-hero-rule:  rgba(236, 240, 245, 0.14);
  --lm-hero-glass: rgba(236, 240, 245, 0.06);
  --lm-pulse:      #6cd28e;
  --lm-ink-rgb: 236, 240, 245;
  --lm-grain:   rgba(255, 255, 255, 0.06);
  --lm-recap-grad:
    radial-gradient(ellipse 60% 60% at 50% 28%,  rgba(125, 106, 191, 0.30), transparent 60%),
    radial-gradient(ellipse 70% 60% at 14% 100%, rgba(58, 166, 106, 0.22), transparent 60%),
    radial-gradient(ellipse 60% 50% at 100% 4%,  rgba(217, 154, 58, 0.16), transparent 60%),
    linear-gradient(165deg, #1c2230 0%, #141822 60%, #0e1118 100%);
  --lm-node-green:  #6cd28e;
  --lm-node-iris:   #9b8cf0;
  --lm-node-honey:  #e0b46a;
  --lm-node-cobalt: #7fb2e0;
  --lm-enter-bg:    #ecedef;
  --lm-enter-bg-h:  #ffffff;
  --lm-enter-ink:   #14171c;
}

*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; }
html { min-height: 100%; }

body[data-login="fullbleed"] {
  font-family: var(--font-sans);
  color: #ffffff;
  background: #0b0e14;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ── Page and layers ─────────────────────────────────────────── */
.lm-page {
  position: relative;
  min-height: 100dvh;
  isolation: isolate;
  overflow: hidden;
}

/* Photos. Two recycled layers; the incoming one fades in on top while the
   outgoing stays put underneath, so there is no midpoint dip. */
.lm-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--dominant, #0b0e14);
  overflow: hidden;
}
.lm-bg picture { display: contents; }
.lm-bg img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--pos-l, center);
  opacity: 0;
  transition: opacity var(--lm-fade) ease-in-out;
  transform: scale(1);
}
@media (orientation: portrait) { .lm-bg img { object-position: var(--pos-p, center); } }
.lm-bg img.is-in { opacity: 1; }
.lm-bg img.is-fading { will-change: opacity; }
/* Ken Burns: desktop only, on the active layer, over the whole dwell. */
.lm-bg img.is-kb {
  transform: scale(1.06);
  transition: opacity var(--lm-fade) ease-in-out, transform var(--lm-dwell) linear;
}

/* Scrim: fixed, never animates. Left edge for the copy, top strip for the
   logo, bottom strip for the rail. */
.lm-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(90deg, rgba(0, 0, 0, 0.65) 0%, transparent 55%),
    linear-gradient(180deg, rgba(0, 0, 0, 0.45) 0%, transparent 160px),
    linear-gradient(0deg, rgba(0, 0, 0, 0.6) 0%, transparent 200px);
}
.lm-grain {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background-image: radial-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 22px 22px;
  opacity: 0.5;
  mask-image: linear-gradient(180deg, rgba(0, 0, 0, 0.6), transparent 60%);
  -webkit-mask-image: linear-gradient(180deg, rgba(0, 0, 0, 0.6), transparent 60%);
}

/* Content: top bar, content, rail. Capped and centred on ultra-wide. */
.lm-layer {
  position: relative;
  z-index: 3;
  min-height: 100dvh;
  max-width: var(--content-max);
  margin-inline: auto;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: 36px var(--page-inset) 32px;
}

/* ── Top bar ─────────────────────────────────────────────────── */
.lm-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.lm-brand { display: inline-flex; align-items: center; text-decoration: none; }
.lm-brand img { height: 26px; width: auto; display: block; }
.lm-chip {
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.7);
  white-space: nowrap;
}
.lm-chip-short { display: none; }

/* ── Middle row: hero copy and card ─────────────────────────── */
.lm-main {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 64px;
  padding: 24px 0;
  min-height: 0;
}

.lm-hero {
  display: flex;
  flex-direction: column;
  max-width: 560px;
  /* Set by login-venues.js to the tallest venue so swaps never move the card. */
  min-height: var(--hero-copy-min, 0);
}
.lm-eyebrow {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 22px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.85);
}
.lm-eyebrow .num { font-weight: 600; color: #ffffff; }
.lm-eyebrow .bar { width: 28px; height: 1px; background: rgba(255, 255, 255, 0.4); }
.lm-eyebrow .cat { color: rgba(255, 255, 255, 0.65); }
.lm-head {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(36px, 3.9vw, 56px);
  font-weight: 700;
  letter-spacing: -0.035em;
  line-height: 1.04;
  color: #ffffff;
  text-wrap: balance;
}
.lm-head em {
  font-style: normal;
  background: linear-gradient(100deg, #ffffff 0%, rgba(255, 255, 255, 0.62) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.lm-sub {
  margin: 22px 0 0;
  font-size: 16px;
  font-weight: 500;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.78);
  max-width: 400px;
}
/* Copy swap: out 250ms, in 350ms. Only opacity and transform move. */
.lm-head, .lm-sub {
  transition: opacity 350ms ease, transform 350ms ease;
}
.lm-hero.is-swapping .lm-head,
.lm-hero.is-swapping .lm-sub {
  opacity: 0;
  transform: translateY(6px);
  transition-duration: 250ms;
}

/* ── Card ────────────────────────────────────────────────────── */
.lm-card {
  flex: none;
  width: 440px;
  min-height: var(--card-min, 0);
  padding: 40px 40px 36px;
  border-radius: var(--lm-radius-xl);
  background: var(--card);
  border: 1px solid var(--card-border);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  box-shadow: var(--card-shadow);
  color: var(--ink);
  display: grid;
}
/* Both panels share one cell so the crossfade never resizes the card. */
.lm-view {
  grid-area: 1 / 1;
  min-width: 0;
  transition: opacity 200ms ease;
}
.lm-view[hidden] { display: none; }
.lm-view.is-out { opacity: 0; }
.lm-view.is-in { opacity: 1; }

/* The collapsible sheet is a phone affordance. Above the breakpoint the
   wrapper is a plain grid cell and both its controls are gone, so the card
   behaves exactly as it did before. */
.lm-sheet {
  grid-area: 1 / 1;
  display: grid;
}
.lm-sheet-open,
.lm-sheet-close { display: none; }

.lm-welcome {
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.025em;
  color: var(--ink);
  margin: 0 0 8px;
  text-wrap: pretty;
}
/* Two blocks so the cycled headings always break in the same place. The
   old single-line heading relied on nowrap; these lines are longer and
   must be free to wrap on a narrow card. */
.lm-welcome .lead,
.lm-welcome .accent { display: block; }
.lm-welcome .accent {
  color: var(--mute);
  font-weight: 500;
}
/* Heading swap, matched to the hero copy: out 260ms, in 350ms. */
.lm-welcome .lead,
.lm-welcome .accent {
  transition: opacity 350ms ease, transform 350ms ease;
}
.lm-welcome.is-swapping .lead,
.lm-welcome.is-swapping .accent {
  opacity: 0;
  transform: translateY(5px);
  transition-duration: 260ms;
}
.lm-lede {
  margin: 0 0 28px;
  font-size: 14px;
  line-height: 1.55;
  color: var(--mute);
  max-width: 36ch;
}

.lm-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
  margin: 0;
}
.lm-form[hidden] { display: none; }

.lm-inset {
  display: flex;
  align-items: center;
  gap: 12px;
  border: 1px solid var(--rule);
  border-radius: var(--lm-radius-md);
  padding: 0 14px;
  min-height: 50px;
  background: var(--surface-2);
  transition: border-color 0.15s, background 0.15s, box-shadow 0.15s;
}
.lm-inset:hover:not(:focus-within) { border-color: #d5dbe3; }
.lm-inset:focus-within {
  background: var(--panel);
  border-color: var(--ink);
  box-shadow: 0 0 0 4px var(--focus-ring);
}
.lm-inset-label {
  flex: none;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink2);
  min-width: 72px;
}
.lm-inset input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: 14px;
  color: var(--ink);
  padding: 13px 0;
  outline: none;
  text-align: right;
}
.lm-inset input::placeholder { color: var(--faint); }

/* Autofill. Chrome paints its own yellow over a transparent field, so the
   inset would light up the moment the browser filled it in. A large inset
   shadow repaints the field in our own surface colour, and the text fill
   carries the ink colour that the shadow would otherwise cover. The long
   transition is the standard way to keep the yellow from flashing back:
   the browser only restyles on a transition end that never arrives. */
.lm-inset input:-webkit-autofill,
.lm-inset input:-webkit-autofill:hover,
.lm-inset input:-webkit-autofill:focus,
.lm-inset input:-webkit-autofill:active {
  -webkit-text-fill-color: var(--ink);
  -webkit-box-shadow: 0 0 0 100px var(--surface-2) inset;
  box-shadow: 0 0 0 100px var(--surface-2) inset;
  transition: background-color 100000s ease-in-out 0s, color 100000s ease-in-out 0s;
  caret-color: var(--ink);
}
/* Focus lifts the inset to the lighter panel colour, so the filled field
   has to follow it rather than stay on the resting surface. */
.lm-inset:focus-within input:-webkit-autofill,
.lm-inset:focus-within input:-webkit-autofill:hover,
.lm-inset:focus-within input:-webkit-autofill:focus {
  -webkit-box-shadow: 0 0 0 100px var(--panel) inset;
  box-shadow: 0 0 0 100px var(--panel) inset;
}
.lm-inset.has-toggle { padding-right: 6px; }
.lm-inset-toggle {
  flex: none;
  width: 32px;
  height: 32px;
  border: 0;
  background: transparent;
  border-radius: 8px;
  display: grid;
  place-items: center;
  cursor: pointer;
  color: var(--faint);
  transition: color 0.15s, background 0.15s;
}
.lm-inset-toggle:hover { color: var(--ink); background: var(--rule); }

.lm-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 4px 0 0;
}
.lm-check {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 13px;
  color: var(--mute);
  cursor: pointer;
  user-select: none;
}
.lm-check input {
  appearance: none;
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  border: 1.5px solid var(--rule);
  border-radius: 5px;
  flex: none;
  cursor: pointer;
  display: grid;
  place-items: center;
  background: var(--panel);
  transition: border-color 0.15s, background 0.15s;
  margin: 0;
}
.lm-check input:checked { background: var(--ink); border-color: var(--ink); }
.lm-check input:checked::after {
  content: '';
  width: 9px;
  height: 5px;
  border-left: 1.6px solid var(--panel);
  border-bottom: 1.6px solid var(--panel);
  transform: rotate(-45deg) translate(1px, -1px);
}
.lm-link {
  font-size: 13px;
  color: var(--ink);
  font-weight: 500;
  text-decoration: none;
}
.lm-link:hover { text-decoration: underline; text-underline-offset: 3px; }

.lm-continue {
  appearance: none;
  -webkit-appearance: none;
  border: 0;
  width: 100%;
  margin: 12px 0 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--panel);
  background: var(--ink);
  border-radius: var(--lm-radius-md);
  padding: 14px 18px;
  cursor: pointer;
  transition: background 0.15s, transform 0.05s;
}
.lm-continue:hover { background: #333; }
body.theme-dark .lm-continue { background: #ecedef; color: #14171c; }
body.theme-dark .lm-continue:hover { background: #ffffff; }
.lm-continue:active { transform: translateY(1px); }
.lm-continue svg { transition: transform 0.2s; }
.lm-continue:hover svg { transform: translateX(2px); }
.lm-continue.is-loading { opacity: 0.85; cursor: default; }
.lm-continue.is-loading svg { animation: lm-spin 0.8s linear infinite; transform: none; }
.lm-continue.is-ok { background: #2f9d63; color: #fff; }
body.theme-dark .lm-continue.is-ok { background: #6cd28e; color: #14171c; }
@keyframes lm-spin { to { transform: rotate(360deg); } }

.lm-foot {
  margin: 28px 0 0;
  font-size: 13px;
  color: var(--mute);
}
.lm-foot a { color: var(--ink); font-weight: 600; text-decoration: none; }
.lm-foot a:hover { text-decoration: underline; text-underline-offset: 3px; }
.lm-foot-back { margin-top: 22px; }
.lm-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--mute) !important;
  font-weight: 500 !important;
}
.lm-back svg { transition: transform 0.2s; }
.lm-back:hover { color: var(--ink) !important; text-decoration: none !important; }
.lm-back:hover svg { transform: translateX(-2px); }

/* Inline feedback. Never a toast. */
.lm-notice {
  margin: 0 0 16px;
  padding: 11px 14px;
  border-radius: var(--lm-radius-md);
  font-size: 13px;
  line-height: 1.4;
  color: var(--ink2);
  background: var(--surface-2);
  border: 1px solid var(--rule);
}
.lm-error {
  margin: 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--error);
}
.lm-error a { color: var(--error); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }
.lm-error[hidden] { display: none; }
.lm-error.is-box {
  padding: 11px 14px;
  border-radius: var(--lm-radius-md);
  background: var(--error-bg);
  border: 1px solid var(--error-border);
}
.lm-success {
  margin: 0 0 16px;
  padding: 11px 14px;
  border-radius: var(--lm-radius-md);
  font-size: 13px;
  line-height: 1.4;
  color: var(--ok);
  background: var(--ok-bg);
  border: 1px solid var(--ok-border);
}
.lm-verify {
  margin: 0 0 16px;
  padding: 12px 14px;
  border-radius: var(--lm-radius-md);
  font-size: 13px;
  line-height: 1.45;
  color: var(--warn);
  background: var(--warn-bg);
  border: 1px solid var(--warn-border);
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.lm-verify[hidden] { display: none; }
.lm-verify-btn {
  align-self: flex-start;
  appearance: none;
  border: 1px solid currentColor;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  padding: 8px 14px;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, opacity 0.15s;
}
.lm-verify-btn:hover { background: rgba(245, 158, 11, 0.16); }
.lm-verify-btn:disabled { cursor: default; opacity: 0.75; }
.lm-verify-btn.is-ok { color: var(--ok); border-color: var(--ok-border); background: var(--ok-bg); }

.lm-sent {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 14px 0 0;
  padding: 14px 16px;
  border: 1px solid var(--rule);
  background: var(--surface-2);
  border-radius: var(--lm-radius-md);
}
.lm-sent[hidden] { display: none; }
.lm-sent-mark {
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--ok-bg);
  color: var(--ok);
  display: grid;
  place-items: center;
}
.lm-sent b { display: block; font-size: 14px; font-weight: 600; color: var(--ink); margin-bottom: 2px; }
.lm-sent p { margin: 0; font-size: 13px; line-height: 1.5; color: var(--mute); }
.lm-sent [data-sent-email] { color: var(--ink); font-weight: 500; }

/* ── Rail: tabs, ticker, stats ──────────────────────────────── */
.lm-rail {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 32px;
  padding-top: 18px;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}
.lm-tabs { display: flex; gap: 28px; }
.lm-tab {
  appearance: none;
  border: 0;
  background: transparent;
  padding: 0;
  cursor: pointer;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 92px;
  opacity: 0.55;
  font-family: inherit;
  color: #ffffff;
  transition: opacity 0.25s ease;
  border-radius: 4px;
}
.lm-tab:hover { opacity: 0.85; }
.lm-tab.on { opacity: 1; }
.lm-tab .n {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.7);
}
.lm-tab .t { font-size: 13px; font-weight: 600; letter-spacing: -0.01em; color: #ffffff; }
.lm-tab .rail {
  display: block;
  height: 2px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.22);
  overflow: hidden;
}
.lm-tab .rail .fill {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: #ffffff;
}
/* The underline is the timer: restarted by login-venues.js on every swap. */
.lm-tab.on.is-timing .rail .fill {
  animation: lm-fill var(--lm-dwell) linear forwards;
}
.lm-tab.on.is-held .rail .fill { width: 100%; }
@keyframes lm-fill { from { width: 0; } to { width: 100%; } }

.lm-rail-right { display: flex; align-items: flex-end; gap: 36px; }
.lm-ticker {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 18px;
  width: 200px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.02em;
  color: rgba(255, 255, 255, 0.66);
  padding-bottom: 2px;
}
.lm-ticker-dot {
  position: relative;
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #6cd28e;
}
.lm-ticker-dot::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: #6cd28e;
  animation: lm-ping 2.4s ease-out infinite;
}
@keyframes lm-ping {
  0% { transform: scale(1); opacity: 0.6; }
  100% { transform: scale(3); opacity: 0; }
}
.lm-ticker-text {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: opacity 0.32s ease, transform 0.32s ease;
}
.lm-ticker-text.is-out { opacity: 0; transform: translateY(-6px); }

.lm-stats { display: flex; gap: 18px; }
.lm-stat { display: flex; flex-direction: column; gap: 6px; }
.lm-stat .v {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1;
  color: #ffffff;
  font-variant-numeric: tabular-nums;
  transition: color 0.3s ease;
}
.lm-stat .v.is-bump { color: #6cd28e; }
.lm-stat .l {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.42);
}

/* ── Focus rings ─────────────────────────────────────────────── */
.lm-tab:focus-visible { outline: 2px solid #ffffff; outline-offset: 2px; }
.lm-continue:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
.lm-inset-toggle:focus-visible,
.lm-link:focus-visible,
.lm-foot a:focus-visible,
.lm-verify-btn:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; border-radius: 6px; }
.lm-check input:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.lm-brand:focus-visible { outline: 2px solid #ffffff; outline-offset: 4px; border-radius: 4px; }

/* ── Short desktop viewports ────────────────────────────────── */
@media (min-width: 881px) and (max-height: 760px) {
  .lm-stats { display: none; }
  .lm-card { padding: 28px 28px 24px; }
  .lm-welcome { font-size: 26px; }
  .lm-tabs { gap: 6px; align-items: center; }
  .lm-tab { width: 24px; height: 24px; align-items: center; justify-content: center; opacity: 1; }
  .lm-tab .n, .lm-tab .t { display: none; }
  .lm-tab .rail { width: 6px; height: 6px; background: rgba(255, 255, 255, 0.35); transition: width 0.25s ease, background 0.25s ease; }
  .lm-tab.on .rail { width: 18px; background: rgba(255, 255, 255, 0.35); }
  .lm-tab .rail .fill { height: 6px; }
}

/* ── Phone ───────────────────────────────────────────────────── */
@media (max-width: 880px) {
  .lm-page { overflow: visible; }
  .lm-scrim {
    background:
      linear-gradient(180deg, rgba(0, 0, 0, 0.55) 0%, transparent 140px),
      linear-gradient(0deg, rgba(0, 0, 0, 0.7) 0%, transparent 60%);
  }
  .lm-layer {
    display: flex;
    flex-direction: column;
    padding: 0;
    min-height: 100dvh;
  }
  .lm-top {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    padding: 56px 24px 0;
    z-index: 2;
  }
  .lm-brand img { height: 22px; }
  .lm-chip-long { display: none; }
  .lm-chip-short { display: inline; }

  .lm-main {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0;
  }
  /* Photo band: dvh so Safari's toolbar does not cause jumps. */
  .lm-hero {
    height: clamp(240px, 38dvh, 445px);
    min-height: 0;
    max-width: none;
    justify-content: flex-end;
    padding: 96px 24px 22px;
  }
  .lm-eyebrow { margin-bottom: 12px; }
  .lm-head { font-size: 30px; }
  .lm-sub { display: none; }

  /* The sheet stays in normal flow so a focused field scrolls into view
     when the keyboard opens. */
  .lm-card {
    width: auto;
    min-height: 0;
    flex: 1 0 auto;
    border-radius: 24px 24px 0 0;
    border-width: 1px 0 0;
    padding: 28px 24px max(24px, env(safe-area-inset-bottom));
    background: var(--card);
    box-shadow: 0 -20px 60px -30px rgba(0, 0, 0, 0.6);
  }
  .lm-welcome { font-size: 24px; margin-bottom: 6px; }
  .lm-lede { margin-bottom: 22px; }
  .lm-inset input { text-align: left; }
  .lm-foot { margin-top: 22px; text-align: center; }
  .lm-rail { display: none; }

  /* ── Collapsible sheet ────────────────────────────────────── */

  /* Closed, the card is just the button: no min-height from the desktop
     measurement, no padding of its own, and it sits at the bottom of the
     column so the photo takes the rest of the screen. */
  .lm-card {
    flex: 0 0 auto;
    /* Anchors the close control. */
    position: relative;
    transition: padding 260ms cubic-bezier(0.32, 0.72, 0, 1);
  }
  .lm-card[data-sheet='closed'] {
    min-height: 0;
    padding: 0 0 max(18px, env(safe-area-inset-bottom));
    border-width: 0;
    background: transparent;
    box-shadow: none;
  }

  /* Closed, the hero gives up its fixed height and fills the column so the
     venue photo runs full bleed behind the button. Open, it returns to the
     band above the sheet. */
  /* The class is set by login-v7.js; the :has() twin keeps the layout right
     before the script runs, and on browsers without :has() the class covers
     it once it does. */
  .lm-main { flex: 1 1 auto; min-height: 0; }
  .lm-main.is-sheet-closed .lm-hero,
  .lm-main:has(.lm-card[data-sheet='closed']) .lm-hero {
    height: auto;
    flex: 1 1 auto;
  }

  .lm-sheet-open {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: calc(100% - 48px);
    margin: 0 24px;
    padding: 17px 22px;
    border: 0;
    border-radius: 999px;
    background: var(--ink);
    color: var(--bg);
    font-family: var(--font-sans);
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -0.01em;
    cursor: pointer;
    box-shadow: 0 10px 30px -10px rgba(0, 0, 0, 0.55);
    transition: transform 180ms ease, opacity 180ms ease;
  }
  .lm-sheet-open:active { transform: scale(0.985); }
  .lm-sheet-open svg { transition: transform 260ms cubic-bezier(0.32, 0.72, 0, 1); }

  /* Open: the button is done, the sheet is the card. */
  .lm-card[data-sheet='open'] .lm-sheet-open {
    display: none;
  }

  /* The sheet itself slides up from under its own bottom edge. Height is
     animated by the grid row so the photo above is never overlapped. */
  .lm-sheet {
    grid-template-rows: 1fr;
    transition: grid-template-rows 260ms cubic-bezier(0.32, 0.72, 0, 1);
  }
  /* The row cannot collapse below its item's min-content height without
     this, and the collapsed row has to clip what it no longer shows. */
  .lm-sheet > * { min-height: 0; }
  .lm-card[data-sheet='closed'] .lm-sheet {
    grid-template-rows: 0fr;
    overflow: hidden;
    visibility: hidden;
  }

  .lm-card[data-sheet='open'] .lm-sheet-close {
    display: grid;
    place-items: center;
    position: absolute;
    top: 14px;
    right: 16px;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--surface-2);
    color: var(--ink2);
    cursor: pointer;
    z-index: 3;
  }
  /* Room for the close control above the heading. */
  .lm-card[data-sheet='open'] .lm-welcome { padding-right: 44px; }
  .lm-bg img.is-kb { transform: scale(1); transition: opacity var(--lm-fade) ease-in-out; }
}

/* ── Phones: hero legibility ─────────────────────────────────
   The headline used to land on the brightest part of each photo (a lit
   laptop, a counter, a glass roof) while the quiet upper half went
   unused. Three things fix it together: the subject is pulled up, the
   copy is pushed down past the middle, and a gradient sits under it.
   Desktop is untouched; this block is phone width only. */
@media (max-width: 767px) {
  /* 1. Gradient under the text. It lives on .lm-scrim, which spans the
     page behind every slide, so it is not tied to one image. */
  .lm-scrim {
    background:
      linear-gradient(180deg, rgba(0, 0, 0, 0.5) 0%, transparent 140px),
      linear-gradient(to top, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0.35) 45%, transparent 100%)
        no-repeat bottom / 100% 55%;
  }

  /* 2. Focal point per slide, set from venues.json portrait_mobile and
     kept current by login-venues.js on every swap. */
  .lm-bg img { object-position: var(--pos-pm, var(--pos-p, center)); }

  /* 3 and 4. The copy sits low but not flush: the hero pads down to about
     62% of the viewport so the block clears the button beneath it. Closed
     sheet only: open, the hero goes back to the band above the sheet, or
     the form starts two thirds down the screen and the keyboard covers it. */
  .lm-hero { justify-content: flex-end; }
  .lm-main.is-sheet-closed .lm-hero,
  .lm-main:has(.lm-card[data-sheet='closed']) .lm-hero {
    padding-top: max(96px, 62dvh);
    padding-bottom: 30px;
  }
  .lm-eyebrow { margin-bottom: 16px; }
  .lm-head {
    font-size: clamp(2rem, 8.5vw, 3.5rem);
    line-height: 1.05;
    /* Keeps the longest headline off the right edge. */
    max-width: 15ch;
  }

  /* Breathing room between the headline and the sign-in button. */
  .lm-card[data-sheet='closed'] { padding-top: 26px; }
}

/* ── Reduced motion: nothing moves ──────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .lm-bg img { transition-duration: 300ms; transform: none !important; }
  .lm-bg img.is-kb { transition: opacity 300ms ease-in-out; }
  .lm-head, .lm-sub, .lm-view, .lm-ticker-text, .lm-continue svg, .lm-back svg { transition: none !important; transform: none !important; }
  .lm-hero.is-swapping .lm-head, .lm-hero.is-swapping .lm-sub { opacity: 1; }
  .lm-tab.on.is-timing .rail .fill { animation: none; width: 100%; }
  .lm-ticker-dot::after { animation: none; }
  .lm-continue.is-loading svg { animation: none; }
}

/* Keep the recap's body lock working. */
body.lm-recap-active { overflow: hidden; }
