/* Pull Up. Flat frosted glass (iOS 26 style): light tint, strong blur with a saturation boost, one hairline,
   one soft shadow. Active controls stay clear glass with a blue glyph and a faint blue wash. */

:root {
  --label: rgb(28, 28, 30);
  --secondary: rgb(110, 110, 115);
  --blue: rgb(0, 122, 255);
  --green: rgb(36, 138, 61);
  --red: rgb(215, 0, 21);
  --orange: rgb(178, 80, 0);
  --hairline: 0 0 0 .5px rgba(0, 0, 0, .10), inset 0 0 0 1px rgba(255, 255, 255, .45);
  --controls-clearance: calc(84px + env(safe-area-inset-bottom));
  --press-ease: cubic-bezier(.3, .7, .4, 1);
  --spring-bouncy: cubic-bezier(.2, .9, .3, 1.15);
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", system-ui, sans-serif;
  color: var(--label);
  -webkit-text-size-adjust: 100%;
  color-scheme: light dark;
}

@supports (animation-timing-function: linear(0, 1)) {
  :root {
    --spring-bouncy: linear(0, 0.049, 0.183, 0.375, 0.599, 0.828, 1.039, 1.215, 1.344, 1.42, 1.444, 1.422, 1.363, 1.277,
      1.178, 1.076, 0.983, 0.904, 0.847, 0.813, 0.803, 0.812, 0.839, 0.877, 0.921, 0.966, 1.008, 1.042, 1.068, 1.083,
      1.088, 1.083, 1.072, 1.055, 1.035, 1.015, 0.997, 0.981, 0.97, 0.963, 1);
  }
}

* { box-sizing: border-box; }
/* The hidden attribute always wins (a component's own display, like the opener chip's inline-flex, would beat it). */
[hidden] { display: none !important; }

html { min-height: 100%; background: #eef2f8; }

body {
  margin: 0;
  min-height: 100dvh;
  background:
    radial-gradient(60rem 40rem at 10% -10%, rgba(0, 122, 255, .16), transparent 60%),
    radial-gradient(50rem 40rem at 110% 20%, rgba(52, 199, 89, .14), transparent 60%),
    radial-gradient(40rem 30rem at 50% 110%, rgba(255, 149, 0, .12), transparent 60%),
    #eef2f8;
  background-attachment: fixed;
  line-height: 1.45;
}

.page {
  /* The page is the outer container; decks, the gate area and cards are containers too. */
  container: page / inline-size;
  max-width: 1440px;
  margin: 0 auto;
  padding: calc(env(safe-area-inset-top) + 12px) calc(env(safe-area-inset-right) + 16px) 32px calc(env(safe-area-inset-left) + 16px);
  display: flex;
  flex-direction: column;
  gap: 14px;
}
/* Pages with a single short form stay a comfortable reading width, centred. */
.page:not(.wide) > .flash:not(.toast) { width: 100%; max-width: 560px; margin-inline: auto; }

/* ── Layout: decks of cards ─────────────────────────────────────────────── */
.deck { display: grid; gap: 14px; grid-template-columns: minmax(0, 1fr); align-items: start; }
.deck.narrow { width: 100%; max-width: 560px; margin-inline: auto; }
@container page (min-width: 760px) {
  .deck:not(.narrow) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .page { padding-inline: calc(env(safe-area-inset-left) + 28px) calc(env(safe-area-inset-right) + 28px); }
}
@container page (min-width: 1180px) {
  .deck:not(.narrow) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.section-title { margin: 10px 4px 0; }

/* Every card is a container, so what's inside adapts to the card's own width. */
.card { container-type: inline-size; }
.card-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.card-head h1, .card-head h2, .card-head h3 { margin: 0; }
.card-head .device-status { margin: 0; }

/* Admin numbers */
.stats { display: grid; gap: 10px; grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 10px; }
@container (min-width: 640px) { .stats { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.stat { display: flex; flex-direction: column; gap: 2px; padding: 12px; border-radius: 14px; background: rgba(127, 127, 127, .08); }
.stat strong { font-size: 26px; line-height: 1.1; }
.stat span { font-size: 13px; }

/* ── Gate tab: the button and its activity side by side when there's room ── */
.gate-layout { display: grid; gap: 18px; grid-template-columns: minmax(0, 1fr); align-items: start; }
.gate-side { display: grid; gap: 14px; align-content: start; }
@container page (min-width: 860px) {
  .gate-layout { grid-template-columns: minmax(0, 1.1fr) minmax(340px, .9fr); }
  .gate { position: sticky; top: 24px; min-height: min(70vh, 640px); justify-content: center; }
}

body.has-controls .page { padding-bottom: calc(var(--controls-clearance) + 24px); }
h3 { font-size: 17px; margin: 0 0 6px; }
.right { text-align: right; }

.site-header { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 2px 2px 0; min-height: 30px; }
.site-name { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; font-size: 15px; color: var(--secondary); letter-spacing: .02em; }

/* Large page titles, iOS style. The aside (a status chip, buttons) sits beside the title when there's room. */
.page-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 8px 14px; padding: 6px 4px 2px; }
.page-head h1 { font-size: 34px; line-height: 1.1; letter-spacing: -.02em; margin: 0; }
.page-head p { margin: 4px 0 0; }
.page-head .device-status { margin: 0; }

/* Test mode: a small chip that opens to explain. */
.test-chip { position: relative; font-size: 13px; color: var(--orange); }
.test-chip summary { list-style: none; display: inline-flex; align-items: center; gap: 5px; padding: 4px 10px; border-radius: 999px; background: rgba(255, 149, 0, .14); font-weight: 600; cursor: pointer; }
.test-chip summary::-webkit-details-marker { display: none; }
.test-chip-body { position: absolute; right: 0; top: calc(100% + 6px); z-index: 20; width: min(82vw, 320px); padding: 10px 12px; border-radius: 14px; background: rgba(255, 244, 229, .97); box-shadow: 0 8px 24px rgba(0, 0, 0, .12); color: var(--label); font-weight: 400; }
.test-chip-body p { margin: 0 0 6px; font-weight: 600; }
.test-chip-body ul { margin: 0; padding-left: 18px; }
.test-chip-body li { margin: 4px 0; line-height: 1.4; }

/* Flash messages float in at the top and fade away (the page script removes them). */
.flash.toast {
  position: fixed;
  z-index: 30;
  left: 50%;
  top: calc(env(safe-area-inset-top) + 12px);
  translate: -50% 0;
  width: min(92vw, 460px);
  margin: 0;
  padding: 12px 16px;
  border-radius: 16px;
  color: var(--label);
  background: rgba(255, 255, 255, .72);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  backdrop-filter: blur(20px) saturate(180%);
  box-shadow: var(--hairline), 0 12px 32px rgba(0, 0, 0, .14);
  animation: toast-in 380ms var(--spring-bouncy) backwards;
  transition: opacity 300ms ease, translate 300ms ease;
}
.flash.toast.leaving { opacity: 0; translate: -50% -12px; }
@keyframes toast-in { from { translate: -50% -24px; } }

/* A folded form: the summary is a button; the body opens under it. */
.disclosure { width: 100%; }
.disclosure > summary { list-style: none; cursor: pointer; }
.disclosure > summary::-webkit-details-marker { display: none; }
.disclosure > summary .chevron { transition: rotate 200ms ease; }
.disclosure[open] > summary .chevron { rotate: 180deg; }
.disclosure-body { margin-top: 10px; padding: 12px; border-radius: 16px; background: rgba(127, 127, 127, .07); }
.disclosure-body .stack { margin: 0; }
.button-row > .disclosure { width: auto; flex: 1 1 100%; }
.button-row > .disclosure:not([open]) { flex: 0 0 auto; }

/* Sign-up choice: two tiles, one open at a time (details name="choice"). */
details.choice > summary { list-style: none; display: flex; align-items: center; gap: 12px; cursor: pointer; }
details.choice > summary::-webkit-details-marker { display: none; }
details.choice > summary > span { flex: 1; display: flex; flex-direction: column; gap: 2px; font-size: 17px; }
details.choice > summary > .icon:first-child { flex: none; width: 28px; height: 28px; }
details.choice[open] > summary { margin-bottom: 10px; }
details.choice[open] > summary .chevron { rotate: 180deg; }
details.choice .chevron { transition: rotate 200ms ease; color: var(--secondary); }

/* Admin section jump links. */
.chips { display: flex; gap: 8px; overflow-x: auto; padding: 2px 4px 4px; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.chips::-webkit-scrollbar { display: none; }
.chip { flex: none; padding: 7px 14px; border-radius: 999px; font-size: 14px; font-weight: 600; text-decoration: none; color: var(--label); background: rgba(127, 127, 127, .12); }
.chip.warn { color: var(--orange); background: rgba(255, 149, 0, .16); }
/* Admin pages: the current one reads as tinted glass, like the open control in the nav. */
.admin-tabs { margin: 0 0 14px; }
.chip.on { color: var(--blue); background: rgba(0, 122, 255, .12); box-shadow: inset 0 0 0 1px rgba(0, 122, 255, .24); }
.chip-count { display: inline-block; margin-left: 6px; min-width: 20px; padding: 1px 6px; border-radius: 999px; font-size: 12px; text-align: center; color: #fff; background: var(--orange); }
.stack-cards { display: flex; flex-direction: column; gap: 14px; }
/* The privacy checkbox on sign-in and invite forms. */
.agree { display: flex; align-items: flex-start; gap: 10px; font-size: 14px; font-weight: 400; color: var(--secondary); cursor: pointer; }
.agree input { flex: none; width: 20px; height: 20px; margin: 1px 0 0; padding: 0; accent-color: var(--blue); box-shadow: none; }
.agree a, .landing-foot a, .page-foot a { color: var(--blue); }
.page-foot { margin: 0; text-align: center; font-size: 13px; color: var(--secondary); }
@container page (min-width: 820px) { .landing .page-foot { grid-column: 1 / -1; } }
/* Long-form text (the privacy page). */
.prose h2 { margin: 22px 0 6px; font-size: 18px; }
.prose h3 { margin: 16px 0 4px; font-size: 16px; }
.prose p, .prose li { line-height: 1.55; }
.prose ul { padding-left: 20px; margin: 6px 0; }
.prose li { margin: 6px 0; }
/* Admins only: something they have to fix, on every page until it's fixed. */
.admin-alert { display: flex; gap: 10px; align-items: flex-start; padding: 12px 14px; border-radius: 16px; font-size: 14px; text-decoration: none; color: var(--red); background: rgba(255, 59, 48, .10); box-shadow: inset 0 0 0 1px rgba(255, 59, 48, .35); }
.admin-alert .icon { flex: none; margin-top: 1px; }
.admin-alert strong { font-weight: 600; }
/* Gate tab: a slim glass banner linking to the shortcut page. */
.shortcut-callout { position: relative; z-index: 0; display: grid; grid-template-columns: 40px minmax(0, 1fr) auto; gap: 12px; align-items: center; padding: 12px 14px; border-radius: 18px; color: var(--label); text-decoration: none; }
.shortcut-callout::before { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; pointer-events: none; background: rgba(255, 255, 255, .55); -webkit-backdrop-filter: blur(24px) saturate(180%); backdrop-filter: blur(24px) saturate(180%); box-shadow: 0 0 0 .5px rgba(0, 0, 0, .10), inset 0 0 0 1px rgba(255, 255, 255, .45), 0 4px 16px rgba(0, 0, 0, .08); }
.shortcut-callout-icon { display: grid; place-items: center; width: 40px; height: 40px; border-radius: 12px; color: var(--blue); background: rgba(0, 122, 255, .12); }
.shortcut-callout-text { display: flex; flex-direction: column; min-width: 0; }
.shortcut-callout-text strong { font-weight: 600; }
.shortcut-callout-text small { font-size: 13px; color: var(--secondary); }
.shortcut-callout-chevron { color: var(--secondary); }
@media (prefers-color-scheme: dark) { .shortcut-callout::before { background: rgba(44, 44, 46, .55); box-shadow: 0 0 0 .5px rgba(255, 255, 255, .14), inset 0 0 0 1px rgba(255, 255, 255, .06), 0 4px 16px rgba(0, 0, 0, .3); } }
/* Signed-out landing: the mark and one line, the sign-in card, three short points. */
/* Signed out, the page fills the screen so the landing can sit in the middle of it. */
body:not(.has-controls) .page { min-height: 100dvh; }
.landing { width: 100%; max-width: 460px; margin: clamp(8px, 6vh, 64px) auto 0; display: flex; flex-direction: column; gap: 20px; }
.landing-hero { display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; }
.landing-mark { display: grid; place-items: center; width: 84px; height: 84px; margin-bottom: 8px; border-radius: 26px; color: #fff; background: var(--blue); box-shadow: 0 8px 24px rgba(0, 0, 0, .12); }
.landing-hero h1 { margin: 0; font-size: 34px; letter-spacing: -.02em; }
.landing-tag { margin: 0; font-size: 18px; color: var(--secondary); }
.landing-card h2 { margin: 0 0 2px; font-size: 20px; }
.landing-points { list-style: none; margin: 0; padding: 0 8px; display: flex; flex-direction: column; gap: 14px; }
.landing-points li { display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 10px; align-items: start; font-size: 15px; color: var(--secondary); }
.landing-points .icon { color: var(--blue); margin-top: 1px; }
.landing-points strong { color: var(--label); font-weight: 600; }
/* Room to spare (tablets, laptops): the pitch on the left, the sign-in card on the right. */
@container page (min-width: 820px) {
  .landing {
    max-width: 1040px;
    margin-block: auto; /* centred in the page's height (below) */
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(360px, 440px);
    grid-template-areas: "hero card" "points card";
    column-gap: clamp(32px, 6cqi, 80px);
    row-gap: 28px;
    align-items: center;
  }
  .landing-hero { grid-area: hero; align-self: end; align-items: flex-start; text-align: left; }
  .landing-hero h1 { font-size: 52px; }
  .landing-tag { font-size: 22px; }
  .landing-card { grid-area: card; }
  .landing-points { grid-area: points; align-self: start; padding: 0; gap: 16px; }
  .landing-points li { font-size: 16px; }
}
.shortcut-version { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin: 6px 0 10px; }
.shortcut-version p { margin: 0; }
[id] { scroll-margin-top: 16px; }
.card.attention::before { background: rgba(255, 248, 235, .8); }

.block { display: block; }
.btn.danger { color: var(--red); }
.btn .chevron { margin-left: 2px; opacity: .7; }

h1 { font-size: 24px; line-height: 1.2; margin: 0 0 8px; }
h2 { font-size: 17px; margin: 0 0 8px; }
p { margin: 0 0 10px; }
a { color: var(--blue); }
small { display: block; font-size: 13px; }
.muted { color: var(--secondary); }
.error { color: var(--red); font-weight: 500; }

/* Panel glass, drawn on ::before so the card is never a backdrop-filter ancestor of anything that scrolls. */
.card {
  position: relative;
  z-index: 0;
  padding: 18px;
  border-radius: 22px;
}
.card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  pointer-events: none;
  background: rgba(255, 255, 255, .55);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  backdrop-filter: blur(24px) saturate(180%);
  box-shadow: var(--hairline), 0 12px 40px rgba(0, 0, 0, .10);
}
.card.warn::before { background: rgba(255, 244, 229, .75); }

.test-banner, .flash {
  margin: 0;
  padding: 10px 14px;
  border-radius: 14px;
  font-size: 14px;
}
.test-banner { background: rgba(255, 149, 0, .14); color: var(--orange); }
.flash { background: rgba(0, 122, 255, .10); color: var(--blue); }

.dev-link { margin: 14px 0; padding: 12px; border-radius: 14px; background: rgba(255, 149, 0, .10); }

/* Forms */
.stack { display: flex; flex-direction: column; gap: 8px; margin: 12px 0 4px; }
label { font-size: 14px; font-weight: 600; color: var(--secondary); }
input {
  font: inherit;
  font-size: 16px; /* 16px or iOS Safari zooms on focus */
  padding: 12px 14px;
  border-radius: 12px;
  border: 0;
  background: rgba(255, 255, 255, .8);
  box-shadow: 0 0 0 .5px rgba(0, 0, 0, .14);
  color: var(--label);
  width: 100%;
}
input:focus { outline: none; box-shadow: 0 0 0 2px rgba(0, 122, 255, .5); }
/* iOS Safari gives date pickers their own minimum width and centres the text, so they spill out of narrow
   cards. Take the native look off, let them shrink, and line the value up on the left like other fields. */
input[type="date"], input[type="datetime-local"] {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  min-width: 0;
  max-width: 100%;
  min-height: 48px;
  text-align: left;
}
input::-webkit-date-and-time-value { text-align: left; }
/* Long emails break onto the next line instead of running into the next column. */
.log-row > *, .list li > span, .page-head p { min-width: 0; overflow-wrap: anywhere; }

/* Buttons: regular glass, tinted when primary. */
.btn, .glass-btn, .gate-button {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font: inherit;
  font-size: 16px;
  font-weight: 600;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  color: var(--label);
  text-decoration: none;
  cursor: pointer;
  background: rgba(255, 255, 255, .55);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
  backdrop-filter: blur(16px) saturate(180%);
  box-shadow: var(--hairline), 0 4px 16px rgba(0, 0, 0, .06);
}
.btn.primary {
  color: var(--blue);
  background: linear-gradient(rgba(0, 122, 255, .10), rgba(0, 122, 255, .10)), rgba(255, 255, 255, .55);
  box-shadow: inset 0 0 0 1px rgba(0, 122, 255, .22), 0 4px 16px rgba(0, 0, 0, .06);
}
.btn.small { font-size: 14px; padding: 7px 12px; white-space: nowrap; }
.link-btn { font: inherit; font-size: 13px; color: var(--red); background: none; border: 0; padding: 0 0 0 6px; cursor: pointer; }
form.inline { display: inline; }

/* Gate */
.gate { container-type: inline-size; display: flex; flex-direction: column; align-items: center; gap: 18px; padding: 12px 0 4px; }
.device-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 600;
}
.device-status.online { color: var(--green); background: rgba(52, 199, 89, .14); }
.device-status.offline { color: var(--secondary); background: rgba(0, 0, 0, .06); }
.device-status.demo { color: var(--orange); background: rgba(255, 149, 0, .14); }
.device-status.unknown { color: var(--orange); background: rgba(255, 149, 0, .12); }

.gate-button {
  position: relative;
  z-index: 0;
  width: min(72cqi, 320px);
  aspect-ratio: 1;
  border-radius: 50%;
  border: 0;
  font: inherit;
  color: var(--label);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  cursor: pointer;
  background: transparent;
}
.gate-button::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  pointer-events: none;
  background: rgba(255, 255, 255, .45);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
  backdrop-filter: blur(16px) saturate(180%);
  box-shadow: var(--hairline), 0 10px 36px rgba(0, 0, 0, .10);
}
.gate-label { font-size: 20px; font-weight: 600; }
.gate-button.is-sending { color: var(--blue); }
.gate-button.is-sending::before {
  background: linear-gradient(rgba(0, 122, 255, .10), rgba(0, 122, 255, .10)), rgba(255, 255, 255, .55);
  box-shadow: inset 0 0 0 1px rgba(0, 122, 255, .22), 0 10px 36px rgba(0, 0, 0, .10);
}
/* ── Gate button animation ──────────────────────────────────────────────────
   idle: a soft halo breathes behind the button.
   is-sending: a light ring spins around the edge.
   is-sent / is-demo: the door swings open, the button pops, three shockwave rings burst outward (green, or
   orange for a demo).
   is-failed: a short shake. Only transform, scale, rotate and opacity animate. */
.gate-stage { position: relative; display: grid; place-items: center; }
.gate-halo, .gate-burst { position: absolute; inset: 0; margin: auto; width: min(72cqi, 320px); aspect-ratio: 1; border-radius: 50%; pointer-events: none; }
.center-card .gate-halo, .center-card .gate-burst { width: min(72cqi, 300px); }
.gate-halo {
  background: radial-gradient(closest-side, rgba(0, 122, 255, .22), rgba(0, 122, 255, .08) 60%, transparent 72%);
  scale: 1.18;
  animation: gate-breathe 3.6s ease-in-out infinite;
}
@keyframes gate-breathe {
  0%, 100% { scale: 1.12; opacity: .55; }
  50% { scale: 1.26; opacity: 1; }
}
.gate-stage.is-sent .gate-halo { background: radial-gradient(closest-side, rgba(52, 199, 89, .3), rgba(52, 199, 89, .1) 60%, transparent 72%); }
.gate-stage.is-demo .gate-halo { background: radial-gradient(closest-side, rgba(255, 149, 0, .3), rgba(255, 149, 0, .1) 60%, transparent 72%); }

/* Spinning ring while sending: a bright arc on a conic gradient, masked to a thin ring at the button's edge. */
.gate-ring {
  position: absolute;
  inset: -7px;
  border-radius: 50%;
  background: conic-gradient(from 0deg, transparent 0 55%, rgba(0, 122, 255, .15) 70%, var(--blue) 92%, rgba(255, 255, 255, .95) 100%);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 5px), #000 calc(100% - 4px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 5px), #000 calc(100% - 4px));
  opacity: 0;
  transition: opacity 200ms ease;
  pointer-events: none;
}
.gate-button.is-sending .gate-ring { opacity: 1; animation: gate-spin .85s linear infinite; }
@keyframes gate-spin { to { rotate: 1turn; } }

/* The door swings open (a 3D turn on its hinge side) and settles back. */
.gate-door { display: grid; place-items: center; perspective: 260px; }
.gate-icon { transform-origin: 28% 50%; }
.gate-button.is-sent .gate-icon, .gate-button.is-demo .gate-icon { animation: gate-door-swing 1.4s cubic-bezier(.2, .8, .2, 1) both; }
@keyframes gate-door-swing {
  0% { transform: rotateY(0deg); }
  35% { transform: rotateY(-62deg) scale(1.08); }
  70% { transform: rotateY(-62deg) scale(1.08); }
  100% { transform: rotateY(0deg); }
}
.gate-button.is-sending .gate-icon { animation: gate-nudge 1s ease-in-out infinite; }
@keyframes gate-nudge { 50% { transform: rotateY(-18deg); } }

/* The button pops on success. */
.gate-button.is-sent, .gate-button.is-demo { animation: gate-pop 520ms var(--spring-bouncy) backwards; }
@keyframes gate-pop { from { scale: .92; } to { scale: 1; } }
.gate-button.is-sent { color: var(--green); }
.gate-button.is-demo { color: var(--orange); }
.gate-button.is-sent::before { background: linear-gradient(rgba(52, 199, 89, .14), rgba(52, 199, 89, .14)), rgba(255, 255, 255, .55); box-shadow: inset 0 0 0 1px rgba(52, 199, 89, .3), 0 10px 36px rgba(0, 0, 0, .10); }
.gate-button.is-demo::before { background: linear-gradient(rgba(255, 149, 0, .14), rgba(255, 149, 0, .14)), rgba(255, 255, 255, .55); box-shadow: inset 0 0 0 1px rgba(255, 149, 0, .3), 0 10px 36px rgba(0, 0, 0, .10); }

/* Three shockwave rings, one after another. */
.gate-burst i {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 3px solid var(--green);
  opacity: 0;
}
.gate-stage.is-demo .gate-burst i { border-color: var(--orange); }
.gate-stage.is-sent .gate-burst i, .gate-stage.is-demo .gate-burst i { animation: gate-shockwave 1.25s cubic-bezier(.15, .7, .3, 1) both; }
.gate-stage.is-sent .gate-burst i:nth-child(2), .gate-stage.is-demo .gate-burst i:nth-child(2) { animation-delay: 140ms; }
.gate-stage.is-sent .gate-burst i:nth-child(3), .gate-stage.is-demo .gate-burst i:nth-child(3) { animation-delay: 280ms; }
@keyframes gate-shockwave {
  0% { scale: .96; opacity: .85; border-width: 4px; }
  100% { scale: 1.75; opacity: 0; border-width: 1px; }
}

/* A short shake when it didn't work. */
.gate-button.is-failed { animation: gate-shake 480ms cubic-bezier(.36, .07, .19, .97) both; }
@keyframes gate-shake {
  15%, 85% { translate: -3px 0; }
  30%, 70% { translate: 6px 0; }
  45%, 55% { translate: -8px 0; }
}
.gate-button:disabled { cursor: default; }

.gate-message { min-height: 1.5em; margin: 0; text-align: center; font-weight: 500; }
.gate-message.ok { color: var(--green); }
.gate-message.bad { color: var(--red); }
.gate-message.demo { color: var(--orange); max-width: 34ch; }

.notice {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  padding: 10px 12px;
  border-radius: 12px;
  font-size: 15px;
  color: var(--orange);
  background: rgba(255, 149, 0, .12);
}
.notice .icon { flex: none; margin-top: 2px; }

/* iPhone shortcut */
.connected { display: flex; gap: 8px; align-items: flex-start; color: var(--label); }
.connected .icon { flex: none; margin-top: 3px; color: var(--green); }
.shortcut-note { margin: 8px 0 0; font-weight: 500; min-height: 0; }
.shortcut-note:empty { display: none; }
.shortcut-note.waiting { color: var(--blue); }
.shortcut-note.bad { color: var(--red); }
.update { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; margin-bottom: 10px; }
.card.compact .notice { margin-top: 8px; }

/* ── Gate log: three tidy lines beside an icon in narrow containers, a table in wide ones ───── */
.log { display: flex; flex-direction: column; }
.log-row {
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr) auto;
  grid-template-areas: "icon person result" "icon detail ago" "icon meta meta";
  column-gap: 12px;
  row-gap: 2px;
  align-items: center;
  padding: 11px 0;
  border-top: .5px solid rgba(0, 0, 0, .08);
  font-size: 15px;
}
.log-row:nth-child(2) { border-top: 0; }
.log-head { display: none; }
.log-icon { grid-area: icon; align-self: start; display: grid; place-items: center; width: 36px; height: 36px; border-radius: 50%; color: var(--secondary); background: rgba(127, 127, 127, .12); }
.log-icon.ok { color: var(--green); background: rgba(52, 199, 89, .14); }
.log-icon.demo { color: var(--orange); background: rgba(255, 149, 0, .14); }
.log-person { grid-area: person; min-width: 0; }
.log-person strong { font-weight: 600; display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.log-person small { display: none; }
.log-result { grid-area: result; justify-self: end; }
.log-detail, .log-meta { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; color: var(--secondary); }
.log-detail { grid-area: detail; }
.log-meta { grid-area: meta; font-size: 12px; font-variant-numeric: tabular-nums; }
.log-ago { grid-area: ago; justify-self: end; font-size: 12px; color: var(--secondary); white-space: nowrap; }
.log-when, .log-unit, .log-from, .log-ip { display: none; }
.log-from .icon { vertical-align: -2px; }
@media (prefers-color-scheme: dark) { .log-row { border-top-color: rgba(255, 255, 255, .1); } }
@container (min-width: 780px) {
  .log-row {
    grid-template-columns: 10.5rem minmax(0, 1.3fr) minmax(0, .6fr) 9rem minmax(0, 1.3fr) 9rem;
    grid-template-areas: "when person unit result from ip";
    padding: 10px 4px;
  }
  .log-icon, .log-ago, .log-detail, .log-meta { display: none; }
  .log-when, .log-unit, .log-from, .log-ip { display: block; min-width: 0; }
  .log-when { grid-area: when; font-size: 14px; }
  .log-unit { grid-area: unit; }
  .log-from { grid-area: from; font-size: 13px; }
  .log-ip { grid-area: ip; font-size: 13px; font-variant-numeric: tabular-nums; }
  .log-result { justify-self: start; }
  .log-person small { display: block; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .log-head { display: grid; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: var(--secondary); padding-top: 0; }
  .log-head > span { display: block; }
  .log-row:nth-child(2) { border-top: .5px solid rgba(0, 0, 0, .08); }
}
.pill { display: inline-block; font-size: 12px; font-weight: 600; padding: 3px 9px; border-radius: 999px; white-space: nowrap; }
.pill.ok { color: var(--green); background: rgba(52, 199, 89, .14); }
.pill.demo { color: var(--orange); background: rgba(255, 149, 0, .14); }
.pill.refused { color: var(--secondary); background: rgba(127, 127, 127, .14); }
.pill.failed { color: var(--red); background: rgba(255, 59, 48, .12); }

/* Selects match the inputs (16px, or iOS zooms on focus). */
select {
  font: inherit;
  font-size: 16px;
  padding: 12px 14px;
  border-radius: 12px;
  border: 0;
  background: rgba(255, 255, 255, .8);
  box-shadow: 0 0 0 .5px rgba(0, 0, 0, .14);
  color: var(--label);
  width: 100%;
}
.field-pair { display: grid; gap: 8px; grid-template-columns: minmax(0, 1fr); }
@container (min-width: 420px) { .field-pair { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.field-pair > div { display: flex; flex-direction: column; gap: 8px; }
.list-title { margin-top: 16px; }
.link-field { margin: 10px 0; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 16px; }
.row-actions { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.badges { display: inline-flex; gap: 6px; }
.badge.host { color: rgb(255, 56, 92); background: rgba(255, 56, 92, .12); }
.center-card { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 10px; container-type: inline-size; }
.center-card .gate-button { width: min(72cqi, 300px); }
.small { font-size: 13px; }

.inline-form { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.inline-label { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; }
.inline-label input { width: auto; padding: 6px 8px; }

/* Free access on the Gate tab: one slim line, green, orange in the last days and once it has ended. */
.free-strip { display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 6px 6px 6px 14px; border-radius: 999px; font-size: 14px; color: var(--label); background: rgba(52, 199, 89, .12); box-shadow: inset 0 0 0 1px rgba(52, 199, 89, .28); }
.free-strip > .icon { flex: none; color: var(--green); }
.free-strip > span { flex: 1; min-width: 0; }
.free-strip strong { font-weight: 600; }
.free-strip form { margin: 0; }
.free-strip.soon, .free-strip.ended { background: rgba(255, 149, 0, .12); box-shadow: inset 0 0 0 1px rgba(255, 149, 0, .3); }
.free-strip.soon > .icon, .free-strip.ended > .icon { color: var(--orange); }

.choice-head { grid-column: 1 / -1; padding: 4px 4px 0; }
.choice-head h1 { margin-bottom: 4px; }
.choice h2 { display: flex; align-items: center; gap: 8px; }
.choice.host h2 .icon { color: rgb(255, 56, 92); }
.choice h2 .icon { color: var(--blue); }

textarea.message-field {
  font: inherit;
  font-size: 16px;
  width: 100%;
  padding: 12px 14px;
  border-radius: 12px;
  border: 0;
  background: rgba(255, 255, 255, .8);
  box-shadow: 0 0 0 .5px rgba(0, 0, 0, .14);
  color: var(--label);
  resize: vertical;
  margin: 6px 0 10px;
}
input.digits { font-size: 28px; letter-spacing: .4em; text-align: center; max-width: 220px; align-self: center; }
.stay-check { align-items: center; width: 100%; }
.card h2 .icon { vertical-align: -3px; }

[data-live-log].stale { opacity: .6; }

/* Admin unit cards */
.unit-card .list li { font-size: 14px; }
.unit-card .button-row { margin-top: 10px; }
.steps { margin: 10px 0 0; padding-left: 20px; display: flex; flex-direction: column; gap: 14px; }
.steps li { padding-left: 4px; }
.steps li > span { display: block; margin-bottom: 8px; }
.button-row { display: flex; flex-wrap: wrap; gap: 8px; }
.center { text-align: center; }
.center .icon { vertical-align: -3px; }

/* Lists */
.list { list-style: none; margin: 0; padding: 0; }
.list li {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  border-top: .5px solid rgba(0, 0, 0, .08);
  font-size: 15px;
}
.list li:first-child { border-top: 0; }
/* In a narrow card, a row's right side (time, result, a button) drops under its main text. */
@container (max-width: 400px) {
  .list li { flex-wrap: wrap; }
  .list li > span:last-child.muted.right { flex-basis: 100%; text-align: left; }
  .list li > span:last-child.right br { display: none; }
}
.list li > span:last-child.muted { text-align: right; font-size: 13px; }
.unit-row { align-items: flex-start !important; }
.row-actions { display: flex; flex-direction: column; gap: 6px; align-items: flex-end; }
/* Gate tab's Recent list: an icon for where the press came from, who, and the result with how long ago. */
.recent { list-style: none; margin: 4px 0 0; padding: 0; }
.recent li { display: grid; grid-template-columns: 36px minmax(0, 1fr) auto; gap: 12px; align-items: center; padding: 10px 0; border-top: .5px solid rgba(0, 0, 0, .08); }
.recent li:first-child { border-top: 0; }
.recent-icon { display: grid; place-items: center; width: 36px; height: 36px; border-radius: 50%; color: var(--secondary); background: rgba(127, 127, 127, .12); }
.recent-icon.ok { color: var(--green); background: rgba(52, 199, 89, .14); }
.recent-icon.demo { color: var(--orange); background: rgba(255, 149, 0, .14); }
.recent-main { display: flex; flex-direction: column; min-width: 0; }
.recent-main strong { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.recent-main small { font-size: 13px; color: var(--secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.recent-side { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
.recent-side time { font-size: 12px; color: var(--secondary); white-space: nowrap; }
@media (prefers-color-scheme: dark) { .recent li { border-top-color: rgba(255, 255, 255, .1); } }
/* A People row with an Edit button: tapping it opens the name field under the row. */
.list li:has(> .row-edit) { align-items: flex-start; }
.row-edit { flex: 1; min-width: 0; }
.row-edit > summary { display: flex; align-items: center; justify-content: space-between; gap: 10px; list-style: none; cursor: pointer; }
.row-edit > summary::-webkit-details-marker { display: none; }
.row-edit > summary > span:first-child { min-width: 0; overflow-wrap: anywhere; }
.row-edit[open] > summary .btn { color: var(--blue); background: rgba(0, 122, 255, .12); }
.row-edit .stack { margin-top: 10px; }
.row-edit .stack + form, .row-edit .invite-toggle + form { margin-top: 10px; }
.row-edit .invite-toggle { margin-top: 12px; padding-top: 12px; border-top: .5px solid rgba(127, 127, 127, .2); }
.row-edit .invite-toggle p { margin: 0 0 8px; font-size: 13px; }
.badge { font-size: 12px; font-weight: 600; padding: 2px 8px; border-radius: 999px; vertical-align: 1px; }
.badge.pending { color: var(--orange); background: rgba(255, 149, 0, .14); }
.badge.approved { color: var(--green); background: rgba(52, 199, 89, .14); }
.badge.suspended { color: var(--red); background: rgba(255, 59, 48, .12); }

/* Floating controls: separate glass capsules inset from the bottom edge, not a bar. */
.floating-controls {
  position: fixed;
  left: 50%;
  bottom: calc(env(safe-area-inset-bottom) + 14px);
  translate: -50% 0;
  display: flex;
  gap: 10px;
  z-index: 10;
}
.floating-controls .glass-btn { min-width: 0; flex: 1 1 0; }
.floating-controls { max-width: calc(100vw - 24px); }
.glass-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-width: 68px;
  height: 56px;
  padding: 0 14px;
  border-radius: 999px;
  color: var(--label);
  text-decoration: none;
  font-size: 11px;
  font-weight: 600;
  background: rgba(255, 255, 255, .40);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
  backdrop-filter: blur(16px) saturate(180%);
  box-shadow: var(--hairline), 0 4px 16px rgba(0, 0, 0, .08);
}
.glass-btn.is-active {
  color: var(--blue);
  background: linear-gradient(rgba(0, 122, 255, .10), rgba(0, 122, 255, .10)), rgba(255, 255, 255, .55);
  box-shadow: inset 0 0 0 1px rgba(0, 122, 255, .22), 0 4px 16px rgba(0, 0, 0, .08);
}

/* Press feedback (classes set by app.js from pointer events; :active doesn't fire on iOS taps). */
.press-bounce { transition: scale 100ms var(--press-ease); }
.press-bounce.is-pressed { scale: .9; will-change: transform; }
.glass-btn.press-bounce.is-pressed, .btn.small.press-bounce.is-pressed { scale: .86; }
.gate-button.press-bounce.is-pressed { scale: .94; }
.press-bounce.is-released { animation: press-release 420ms var(--spring-bouncy) backwards; will-change: transform; }
@keyframes press-release { from { scale: .9; } to { scale: 1; } }
@supports not (animation-timing-function: linear(0, 1)) {
  @keyframes press-release { 0% { scale: .9; } 40% { scale: 1.045; } 70% { scale: .982; } 100% { scale: 1; } }
}

@media (prefers-reduced-motion: reduce) {
  .press-bounce, .press-bounce.is-pressed { transition: opacity 100ms; scale: 1; }
  .press-bounce.is-pressed { opacity: .6; }
  .press-bounce.is-released { animation: none; }
  .gate-button.is-sending .gate-icon { animation: none; }
  .gate-halo, .gate-button.is-sending .gate-ring, .gate-button .gate-icon, .gate-burst i, .gate-button.is-failed, .gate-button.is-sent, .gate-button.is-demo { animation: none !important; }
  .gate-button.is-sending .gate-ring { rotate: 45deg; }
}

@media (prefers-reduced-transparency: reduce) {
  .card::before, .gate-button::before, .glass-btn, .btn {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    background-color: rgba(255, 255, 255, .96);
  }
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .card::before, .gate-button::before, .glass-btn, .btn { background-color: #fff; }
}

/* Wider screens: the controls float top-right instead of over the content's bottom. */
@media (min-width: 900px) {
  body.has-controls .page { padding-bottom: 32px; padding-top: 88px; }
  .floating-controls { left: auto; right: 24px; top: 20px; bottom: auto; translate: none; }
  /* Only signed-in pages float the header beside the controls; the sign-in page keeps it in the flow. */
  body.has-controls .site-header { justify-content: flex-start; position: absolute; top: calc(env(safe-area-inset-top) + 30px); }
  .test-chip-body { right: auto; left: 0; }
}

/* Dark mode: follows the phone's setting. Same flat glass, darker tint, iOS dark system colors. */
@media (prefers-color-scheme: dark) {
  :root {
    --label: rgb(242, 242, 247);
    --secondary: rgb(152, 152, 159);
    --blue: rgb(10, 132, 255);
    --green: rgb(48, 209, 88);
    --red: rgb(255, 69, 58);
    --orange: rgb(255, 159, 10);
    --hairline: 0 0 0 .5px rgba(255, 255, 255, .14), inset 0 0 0 1px rgba(255, 255, 255, .06);
  }
  html { background: #0b0d12; }
  body {
    background:
      radial-gradient(60rem 40rem at 10% -10%, rgba(10, 132, 255, .22), transparent 60%),
      radial-gradient(50rem 40rem at 110% 20%, rgba(48, 209, 88, .14), transparent 60%),
      radial-gradient(40rem 30rem at 50% 110%, rgba(255, 159, 10, .12), transparent 60%),
      #0b0d12;
    background-attachment: fixed;
  }
  .card::before {
    background: rgba(44, 44, 46, .55);
    box-shadow: var(--hairline), 0 12px 40px rgba(0, 0, 0, .45);
  }
  .card.warn::before { background: rgba(80, 52, 10, .55); }
  .btn, .glass-btn { background: rgba(58, 58, 60, .55); box-shadow: var(--hairline), 0 4px 16px rgba(0, 0, 0, .35); }
  .btn.primary, .glass-btn.is-active {
    background: linear-gradient(rgba(10, 132, 255, .18), rgba(10, 132, 255, .18)), rgba(44, 44, 46, .6);
    box-shadow: inset 0 0 0 1px rgba(10, 132, 255, .35), 0 4px 16px rgba(0, 0, 0, .35);
  }
  .gate-button::before { background: rgba(58, 58, 60, .5); box-shadow: var(--hairline), 0 10px 36px rgba(0, 0, 0, .45); }
  .gate-button.is-sending::before {
    background: linear-gradient(rgba(10, 132, 255, .18), rgba(10, 132, 255, .18)), rgba(44, 44, 46, .6);
    box-shadow: inset 0 0 0 1px rgba(10, 132, 255, .35), 0 10px 36px rgba(0, 0, 0, .45);
  }
  input, select, textarea.message-field { background: rgba(255, 255, 255, .08); box-shadow: 0 0 0 .5px rgba(255, 255, 255, .16); }
  .badge.host { background: rgba(255, 56, 92, .18); }
  input::placeholder { color: rgba(235, 235, 245, .35); }
  .list li { border-top-color: rgba(255, 255, 255, .10); }
  .flash.toast { background: rgba(44, 44, 46, .72); }
  .test-chip-body { background: rgba(60, 44, 20, .97); }
  .card.attention::before { background: rgba(70, 50, 20, .55); }
  .log-row, .log-row:nth-child(2) { border-top-color: rgba(255, 255, 255, .10); }
  .device-status.demo, .pill.demo { background: rgba(255, 159, 10, .16); }
  .pill.ok { background: rgba(48, 209, 88, .16); }
  .pill.failed { background: rgba(255, 69, 58, .18); }
  .device-status.offline { background: rgba(255, 255, 255, .08); }
  .test-banner, .notice, .dev-link { background: rgba(255, 159, 10, .16); }
  .flash { background: rgba(10, 132, 255, .16); }
  .device-status.online, .badge.approved { background: rgba(48, 209, 88, .16); }
  .badge.pending { background: rgba(255, 159, 10, .18); }
  .badge.suspended { background: rgba(255, 69, 58, .18); }
}

@media (prefers-color-scheme: dark) and (prefers-reduced-transparency: reduce) {
  .card::before, .gate-button::before, .glass-btn, .btn { background-color: rgba(28, 28, 30, .96); }
}
@media (prefers-color-scheme: dark) {
  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .card::before, .gate-button::before, .glass-btn, .btn { background-color: #1c1c1e; }
  }
}

@media (prefers-color-scheme: dark) {
  .gate-button.is-sent::before { background: linear-gradient(rgba(48, 209, 88, .2), rgba(48, 209, 88, .2)), rgba(44, 44, 46, .6); }
  .gate-button.is-demo::before { background: linear-gradient(rgba(255, 159, 10, .2), rgba(255, 159, 10, .2)), rgba(44, 44, 46, .6); }
  .gate-halo { background: radial-gradient(closest-side, rgba(10, 132, 255, .3), rgba(10, 132, 255, .1) 60%, transparent 72%); }
}
