/* Sesam: shared by the user app (body.app) and the admin app (body.admin). */

@font-face {
  font-family: "Young Serif";
  src: url("fonts/young-serif.woff2") format("woff2");  /* relative: also works under /sesam/ in the simulator */
  font-display: swap;
}

/* --- Tokens ------------------------------------------------------------------ */
:root {
  color-scheme: light dark;
  --bg: #f5f5f2;
  --fg: #16181c;
  --muted: #5d636b;
  --line: #dcdcd5;
  --card: #ffffff;
  --accent: #1f6f4a;
  --accent-ink: #ffffff;   /* text on accent */
  --err: #b3261e;
  --warn: #8a5a00;
  --display: "Young Serif", Georgia, "Times New Roman", serif;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, "Cascadia Mono", "SF Mono", Consolas, monospace;
  --radius: 18px;
  --shadow: 0 1px 0 rgb(0 0 0 / 0.03), 0 12px 32px -20px rgb(0 0 0 / 0.35);
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #14171c;
    --fg: #ecece8;
    --muted: #9aa0a8;
    --line: #2f343d;
    --card: #1e2229;
    --accent: #3fb07a;
    --accent-ink: #08130d;  /* white on this green is too low contrast */
    --err: #ff8a80;
    --warn: #e3b341;
    --shadow: 0 1px 0 rgb(255 255 255 / 0.03), 0 12px 32px -20px rgb(0 0 0 / 0.8);
  }
}

/* --- Base --------------------------------------------------------------------- */
* { box-sizing: border-box; }
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; background: var(--bg); }
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 17px/1.5 var(--sans);
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior-y: none;
}
main {
  max-width: 28rem;
  margin: 0 auto;
  padding: calc(1.25rem + var(--safe-top)) calc(1rem + var(--safe-right))
           calc(2rem + var(--safe-bottom)) calc(1rem + var(--safe-left));
}
h1, h2 { font-family: var(--display); font-weight: 400; font-synthesis: none; letter-spacing: -0.01em; }
p { margin: 0 0 0.75rem; }
.hint { color: var(--muted); }
.hint.small { font-size: 0.875rem; margin: 0.5rem 0 0; }
.center { text-align: center; }
.mono { font-family: var(--mono); font-size: 0.85em; }
.meta { color: var(--muted); font-size: 0.875rem; }
.small { font-size: 0.875rem; }
.push { margin-left: auto; }
.nowrap { white-space: nowrap; }
.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

label { display: block; margin: 1rem 0 0.3rem; color: var(--muted); font-size: 0.9rem; }
input, select {
  width: 100%; padding: 0.7rem 0.8rem; margin-top: 0.3rem;
  font: inherit; font-size: max(16px, 1rem);  /* below 16px iOS zooms in on focus */
  color: var(--fg); background: var(--card);
  border: 1px solid var(--line); border-radius: 12px;
}
input::placeholder { color: var(--muted); opacity: 0.7; }
input:focus-visible, select:focus-visible {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
input[type="checkbox"] { width: auto; margin: 0; accent-color: var(--accent); }
select {
  -webkit-appearance: none; appearance: none; cursor: pointer;
  padding-right: 2.5rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%235d636b' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 0.9rem center; background-size: 12px 8px;
}
@media (prefers-color-scheme: dark) {
  select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%239aa0a8' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  }
}
:focus-visible { outline: 3px solid color-mix(in srgb, var(--accent) 50%, transparent); outline-offset: 2px; }

button {
  padding: 0.7rem 1.1rem;
  font: inherit; font-weight: 600;
  color: var(--accent-ink); background: var(--accent);
  border: 1px solid transparent; border-radius: 12px;
  cursor: pointer; touch-action: manipulation; -webkit-user-select: none; user-select: none;
  transition: transform 0.12s ease, background-color 0.2s ease, opacity 0.2s ease;
}
button:active:not(:disabled) { transform: scale(0.97); }
button:disabled { opacity: 0.5; cursor: default; }
button.primary { width: 100%; margin-top: 1.25rem; padding: 1rem; border-radius: 14px; font-size: 1.05rem; }
button.small { padding: 0.45rem 0.85rem; font-size: 0.875rem; font-weight: 500; border-radius: 10px; }
button.secondary { color: var(--fg); background: transparent; border-color: var(--line); }
button.danger { color: var(--err); background: transparent; border-color: currentColor; }
button.armed { color: #fff; background: var(--err); border-color: var(--err); }  /* second click confirms */

#status { min-height: 1.5em; margin: 1.25rem 0 0; text-align: center; }
#status.ok { color: var(--accent); }
#status.err { color: var(--err); }

.brand { display: flex; align-items: center; gap: 0.65rem; }
.brand .mark { width: 40px; height: 40px; border-radius: 11px; box-shadow: var(--shadow); }
.brand h1 { margin: 0; font-size: 2rem; line-height: 1; }
/* Company name under the wordmark: both apps, also before login */
.brand-text { display: flex; flex-direction: column; min-width: 0; }
.org-name {
  margin: 0.35rem 0 0; color: var(--muted);
  font: 600 0.72rem/1.2 var(--sans); letter-spacing: 0.14em; text-transform: uppercase;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.login .org-name { margin: -0.15rem 0 0.9rem; white-space: normal; }
.topbar .brand { min-width: 0; }

.panel, .card {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow);
}

/* <details> with a chevron instead of the browser's triangle */
.disclosure > summary { list-style: none; display: flex; align-items: center; gap: 0.5rem; cursor: pointer; font-weight: 600; }
.disclosure > summary::-webkit-details-marker { display: none; }
.disclosure > summary::after {
  content: ""; width: 0.5rem; height: 0.5rem; margin-left: auto;
  border: solid currentColor; border-width: 0 2px 2px 0; opacity: 0.5;
  transform: rotate(45deg) translate(-2px, -2px); transition: transform 0.2s ease;
}
.disclosure[open] > summary::after { transform: rotate(-135deg) translate(-2px, -2px); }

/* Install hint (both apps) */
.install {
  display: grid; grid-template-columns: auto 1fr; gap: 0.25rem 0.85rem; align-items: center;
  margin-top: 2rem; padding: 0.9rem 1rem;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow);
}
.install-icon { width: 44px; height: 44px; border-radius: 11px; }
.install p { margin: 0.15rem 0 0; color: var(--muted); font-size: 0.875rem; }
.install-actions { grid-column: 1 / -1; display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 0.5rem; }

/* --- User app ----------------------------------------------------------------- */
/* Only as tall as the content: stretched to 100dvh, phones scrolled by the few pixels their browser
   counts beyond what is visible (status and navigation bars) */
body.app main { padding-top: 0; display: flex; flex-direction: column; }

/* The header stays on top while the doors scroll under it, and gets smaller once they do (common.js
   sets .scrolled). Its place in the page keeps the same height, so the doors don't jump when it shrinks:
   what the padding and the wordmark lose (1.15 + 0.15 + 0.5 rem), the margin under it gains. */
body.app .brand {
  position: sticky; top: 0; z-index: 5;
  margin: 0 calc(-1rem - var(--safe-right)) 1.25rem calc(-1rem - var(--safe-left));
  padding: calc(1.75rem + var(--safe-top)) calc(1rem + var(--safe-right)) 0.75rem calc(1rem + var(--safe-left));
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
}
body.app .brand, body.app .brand .mark, body.app .brand h1 {
  transition: padding 0.2s ease, margin 0.2s ease, width 0.2s ease, height 0.2s ease, font-size 0.2s ease,
              box-shadow 0.2s ease;
}
body.app.scrolled .brand {
  padding-top: calc(0.6rem + var(--safe-top)); padding-bottom: 0.6rem; margin-bottom: 3.05rem;
  box-shadow: 0 1px 0 var(--line);
}
body.app.scrolled .brand .mark { width: 32px; height: 32px; border-radius: 9px; }
body.app.scrolled .brand h1 { font-size: 1.5rem; }
@media (prefers-reduced-motion: reduce) {
  body.app .brand, body.app .brand .mark, body.app .brand h1 { transition: none; }
}
body.app #status { margin-bottom: 1.5rem; }

.panel { padding: 1.25rem; margin-bottom: 1.5rem; }
.panel h2 { margin: 0 0 0.5rem; font-size: 1.6rem; line-height: 1.2; }

#door-list { display: grid; gap: 0.85rem; }
.door-wrap { animation: rise 0.5s cubic-bezier(0.2, 0.7, 0.2, 1) both; animation-delay: calc(var(--i, 0) * 70ms); }
button.door {
  position: relative; overflow: hidden;
  display: flex; align-items: center; gap: 1rem;
  width: 100%; min-height: 96px; padding: 1rem 1.15rem;
  color: var(--fg); background: var(--card); text-align: left; font-weight: 400;
  border: 1px solid var(--line); border-radius: 24px; box-shadow: var(--shadow);
  transition: transform 0.12s ease, background-color 0.3s ease, border-color 0.3s ease, color 0.3s ease;
}
button.door:disabled { opacity: 1; }
.door-icon {
  flex: none; display: grid; place-items: center; width: 58px; height: 58px; border-radius: 50%;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 13%, transparent);
  transition: background-color 0.3s ease, color 0.3s ease;
}
.door-text { display: flex; flex-direction: column; min-width: 0; }
.door-name { font: 1.55rem/1.15 var(--display); font-synthesis: none; overflow-wrap: anywhere; }
.door-sub { margin-top: 0.2rem; color: var(--muted); font-size: 0.9rem; }

/* Keyhole and tick drawn in CSS so they follow currentColor */
.keyhole { position: relative; width: 16px; height: 24px; }
.keyhole::before, .keyhole::after { content: ""; position: absolute; left: 50%; background: currentColor; }
.keyhole::before { top: 0; width: 15px; height: 15px; margin-left: -7.5px; border-radius: 50%; }
.keyhole::after { top: 10px; width: 13px; height: 14px; margin-left: -6.5px; clip-path: polygon(28% 0, 72% 0, 100% 100%, 0 100%); border-radius: 0 0 2px 2px; }
.tick { display: none; width: 12px; height: 22px; margin-top: -4px; border: solid currentColor; border-width: 0 4px 4px 0; transform: rotate(45deg); }

.door[data-state="pending"] .door-icon { animation: pulse 1.2s ease-in-out infinite; }
.door[data-state="open"] { color: var(--accent-ink); background: var(--accent); border-color: var(--accent); }
.door[data-state="open"] .door-sub { color: inherit; opacity: 0.85; }
.door[data-state="open"] .door-icon { color: var(--accent-ink); background: color-mix(in srgb, var(--accent-ink) 16%, transparent); }
.door[data-state="open"] .keyhole { display: none; }
.door[data-state="open"] .tick { display: block; animation: pop 0.35s cubic-bezier(0.2, 0.9, 0.3, 1.4); }
.door[data-state="open"]::after {
  content: ""; position: absolute; left: 0; bottom: 0; width: 100%; height: 4px;
  background: currentColor; opacity: 0.35; transform-origin: left; animation: drain 4s linear forwards;
}
.door[data-state="denied"] { border-color: var(--err); animation: shake 0.4s ease; }
.door[data-state="denied"] .door-sub { color: var(--err); }
.door[data-state="denied"] .door-icon { color: var(--err); background: color-mix(in srgb, var(--err) 12%, transparent); }
#doors-hint { margin: 1.25rem 0 0; font-size: 0.9rem; }
#login .hint.small { margin-top: 1rem; text-align: center; }
/* "Hittar telefonen ingen passkey?": folded away, opened by itself after a cancelled login */
details.help { margin-top: 0.75rem; color: var(--muted); font-size: 0.875rem; text-align: left; }
details.help > summary { list-style: none; color: var(--accent); font-weight: 600; text-align: center; cursor: pointer; }
details.help > summary::-webkit-details-marker { display: none; }
details.help p { margin: 0.5rem 0 0; }

/* Who is signed in, with a quiet text-style logout */
.account {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 0 0.5rem;
  margin: 0; color: var(--muted); font-size: 0.875rem;
}
#me-name { color: var(--fg); font-weight: 600; }
button.link {
  min-height: 44px; padding: 0 0.25rem;
  color: var(--accent); background: none; border: 0; font-weight: 600;
  text-decoration: underline; text-underline-offset: 3px;
}

/* --- Admin app ---------------------------------------------------------------- */
body.admin main { max-width: 60rem; padding-bottom: calc(6rem + var(--safe-bottom)); }
body.admin.signed-in main { padding-top: 0; }  /* the header's own padding takes its place */
body.admin:not(.signed-in) .topbar { display: none; }

/* Sticky, and smaller once the page scrolls, like the user app's header (common.js sets .scrolled).
   It has a set height, so its place in the page stays the same whatever is tallest in it: what the
   header loses (1.1rem), the margin under it gains. Inside, 3rem fits the wordmark with the company
   name and the 44px buttons on phones; shrunk, 2.75rem still does. */
.topbar {
  position: sticky; top: 0; z-index: 5;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  height: calc(4.85rem + var(--safe-top));
  margin: 0 calc(-1rem - var(--safe-right)) 0.65rem calc(-1rem - var(--safe-left));
  padding: calc(1.25rem + var(--safe-top)) calc(1rem + var(--safe-right)) 0.6rem calc(1rem + var(--safe-left));
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
}
.topbar .brand .mark { width: 36px; height: 36px; border-radius: 10px; }
.topbar h1 { font-size: 1.6rem; white-space: nowrap; }
.topbar, .topbar .brand .mark, .topbar h1 {
  transition: height 0.2s ease, padding 0.2s ease, margin 0.2s ease, width 0.2s ease, font-size 0.2s ease,
              box-shadow 0.2s ease;
}
body.admin.scrolled .topbar {
  height: calc(3.75rem + var(--safe-top)); padding-top: calc(0.5rem + var(--safe-top)); padding-bottom: 0.5rem;
  margin-bottom: 1.75rem; box-shadow: 0 1px 0 var(--line);
}
body.admin.scrolled .topbar .brand .mark { width: 30px; height: 30px; border-radius: 8px; }
body.admin.scrolled .topbar h1 { font-size: 1.2rem; }
@media (prefers-reduced-motion: reduce) {
  .topbar, .topbar .brand .mark, .topbar h1 { transition: none; }
}
.topbar .sub {
  margin-left: 0.15rem; font: 600 0.7rem/1 var(--sans); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--muted); vertical-align: middle;
}
#session { display: flex; align-items: center; gap: 0.6rem; min-width: 0; color: var(--muted); }
#me { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 14rem; }
.avatar.small { width: 32px; height: 32px; font-size: 0.75rem; }
button.logout, button.lock-all { display: inline-flex; flex: none; align-items: center; gap: 0.4rem; white-space: nowrap; }
.logout svg, .lock-all svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/* While any door is locked down: under the header, on every tab */
.lockdown-bar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5rem 1rem;
  margin-bottom: 1.25rem; padding: 0.6rem 0.6rem 0.6rem 1rem; border-radius: 14px;
  color: var(--warn); background: color-mix(in srgb, var(--warn) 14%, transparent); font-weight: 600;
}
.lockdown-bar p { margin: 0; }

.login { max-width: 24rem; margin: 12vh auto 0; text-align: center; }
.login-mark { width: 88px; height: 88px; border-radius: 22px; box-shadow: var(--shadow); }
.login h2 { margin: 1rem 0 0.5rem; font-size: 2rem; }

.tabs {
  display: flex; gap: 0.25rem; padding: 0.25rem; margin-bottom: 1.25rem;
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
}
.tab {
  flex: 1; display: flex; align-items: center; justify-content: center; gap: 0.5rem;
  color: var(--muted); background: transparent; font-weight: 600;
}
.tab svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.tab[aria-selected="true"] { color: var(--accent-ink); background: var(--accent); }

.card { padding: 1rem 1.1rem; margin-bottom: 0.75rem; }
.form-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 0.75rem; }
label.check { display: flex; align-items: center; gap: 0.6rem; color: var(--fg); font-size: 1rem; }
.field-label { margin: 1rem 0 0.4rem; color: var(--muted); font-size: 0.9rem; }
.days { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.chip {
  display: inline-flex; align-items: center; gap: 0.4rem; margin: 0; padding: 0.45rem 0.8rem;
  color: var(--fg); font-size: 0.95rem; cursor: pointer;
  border: 1px solid var(--line); border-radius: 999px;
}
.chip:has(input:checked) { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }

/* User cards */
.row-head {
  display: flex; align-items: center; gap: 0.75rem; width: 100%; padding: 0;
  color: var(--fg); background: none; border: 0; font-weight: 400; text-align: left;
}
.row-head::after {
  content: ""; flex: none; width: 0.5rem; height: 0.5rem; margin-left: 0.25rem;
  border: solid var(--muted); border-width: 0 2px 2px 0; transform: rotate(-45deg); transition: transform 0.2s ease;
}
.row-head[aria-expanded="true"]::after { transform: rotate(45deg); }
.avatar {
  flex: none; display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent);
  font: 600 0.9rem/1 var(--sans); letter-spacing: 0.02em;
}
.who { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.name { font-weight: 600; overflow-wrap: anywhere; }
.card.inactive .name, .card.inactive .avatar { opacity: 0.55; }
.badge {
  flex: none; padding: 0.15rem 0.55rem; border-radius: 999px; font-size: 0.75rem; font-weight: 600;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 15%, transparent);
}
.badge.warn { color: var(--warn); background: color-mix(in srgb, var(--warn) 18%, transparent); }
.warn-text { margin: 0.5rem 0 0; color: var(--warn); font-size: 0.9rem; }
.meta.warn-meta { color: var(--warn); }

.user-body { margin-top: 1rem; border-top: 1px solid var(--line); }
.user-body h3 {
  margin: 1.4rem 0 0.4rem; color: var(--muted);
  font-size: 0.7rem; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase;
}
.items { list-style: none; margin: 0; padding: 0; }
.items li { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; padding: 0.65rem 0; border-bottom: 1px solid var(--line); }
.items li > div:first-child { flex: 1 1 12rem; min-width: 0; }
.item-title { overflow-wrap: anywhere; }
.item-actions { display: flex; gap: 0.5rem; }
.actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.75rem; }
/* Inline rename: the field on its own row, Spara/Avbryt below; the card's other actions hide meanwhile */
.rename { display: grid; gap: 0.6rem; flex: 1 1 100%; width: 100%; }
.rename input { margin: 0; }
.rename-actions { display: flex; gap: 0.5rem; }
.door-card:has(form.rename) > .actions { display: none; }

/* An open user card: one section at a time (Dörrar / Enheter / Konto) */
.seg {
  display: flex; gap: 0.25rem; margin: 1rem 0 0.25rem; padding: 0.25rem;
  background: color-mix(in srgb, var(--fg) 6%, transparent); border-radius: 12px;
}
.seg button {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
  padding: 0.55rem 0.4rem; color: var(--muted); background: transparent; border-radius: 9px;
  font-size: 0.9rem; font-weight: 600;
}
.seg button[aria-selected="true"] { color: var(--fg); background: var(--card); box-shadow: 0 1px 3px rgb(0 0 0 / 0.18); }
.count {
  min-width: 1.4rem; padding: 0.1rem 0.4rem; border-radius: 999px; text-align: center;
  color: var(--muted); background: color-mix(in srgb, var(--fg) 9%, transparent);
  font: 600 0.72rem/1.2 var(--sans); letter-spacing: 0;
}
.seg button[aria-selected="true"] .count { color: var(--accent); background: color-mix(in srgb, var(--accent) 16%, transparent); }
.user-section { padding-top: 0.6rem; }

/* Door access as cards: the door, the week as seven dots, the time window. The card is the button. */
.rule-list { list-style: none; display: grid; gap: 0.6rem; margin: 0.4rem 0 0; padding: 0; }
button.rule-card {
  position: relative; display: flex; flex-direction: column; align-items: stretch; gap: 0.55rem;
  width: 100%; padding: 0.95rem 2.6rem 0.95rem 1rem;
  color: var(--fg); background: color-mix(in srgb, var(--fg) 3%, var(--card)); text-align: left; font-weight: 400;
  border: 1px solid var(--line); border-radius: 16px;
  transition: border-color 0.2s ease, transform 0.12s ease;
}
button.rule-card:hover { border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); }
.rule-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.15rem 0.75rem; }
.rule-door { font: 1.25rem/1.2 var(--display); font-synthesis: none; overflow-wrap: anywhere; }
.rule-time { font-weight: 600; font-variant-numeric: tabular-nums; }
.rule-card .chev {
  position: absolute; top: 50%; right: 1.15rem; width: 0.55rem; height: 0.55rem; margin-top: -0.28rem;
  border: solid var(--muted); border-width: 2px 2px 0 0; transform: rotate(45deg);
}
.week { display: inline-flex; gap: 4px; }
.week span {
  display: grid; place-items: center; width: 1.5rem; height: 1.5rem; border-radius: 50%;
  color: var(--muted); border: 1px solid var(--line); font: 600 0.68rem/1 var(--sans);
}
.week span.on { color: var(--accent-ink); background: var(--accent); border-color: var(--accent); }
button.add-rule {
  width: 100%; margin-top: 0.6rem; padding: 0.85rem; color: var(--accent); background: transparent;
  border: 1.5px dashed color-mix(in srgb, var(--accent) 55%, var(--line)); border-radius: 16px;
}

/* The rule editor: a dialog, and a sheet sliding up from the bottom on phones */
dialog.sheet {
  width: min(34rem, calc(100% - 2rem)); max-width: none; max-height: min(88dvh, 52rem); margin: auto; padding: 0;
  overflow: hidden; color: var(--fg); background: var(--card);
  border: 1px solid var(--line); border-radius: 20px; box-shadow: 0 24px 60px rgb(0 0 0 / 0.35);
}
dialog.sheet::backdrop { background: rgb(8 10 12 / 0.55); }
.sheet-body { display: flex; flex-direction: column; max-height: inherit; }
.sheet-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; padding: 1.1rem 1.25rem 0.5rem; }
.sheet-head h2 { margin: 0; font-size: 1.45rem; line-height: 1.2; }
.sheet-head .meta { margin: 0.25rem 0 0; }
.sheet-scroll { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 0 1.25rem 1.1rem; }
.sheet-scroll > label:first-child { margin-top: 0.5rem; }
.sheet-foot {
  display: flex; flex-wrap: wrap; gap: 0.5rem;
  padding: 0.8rem 1.25rem calc(0.8rem + var(--safe-bottom)); border-top: 1px solid var(--line);
}
.sheet-error { flex: 1 0 100%; margin: 0 0 0.2rem; color: var(--err); font-weight: 600; }
.presets { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; }
.times { display: grid; grid-template-columns: 1fr 1fr; gap: 0 0.75rem; margin-top: 0.4rem; }
.times .field-label { display: block; margin: 0.5rem 0 0.3rem; }
.time-pick { display: flex; align-items: center; gap: 0.3rem; font-weight: 600; }
.time-pick select { flex: 1; min-width: 0; margin: 0; padding-right: 1.9rem; background-position: right 0.65rem center; font-variant-numeric: tabular-nums; }
.window-summary {
  margin: 0.85rem 0 0; padding: 0.65rem 0.85rem; border-radius: 12px; font-size: 0.92rem;
  background: color-mix(in srgb, var(--accent) 11%, transparent);
}
.more { margin-top: 1.1rem; }
.more > summary { color: var(--accent); font-size: 0.95rem; }

/* Pending invites at the top of Användare: dashed, because they aren't users yet */
.section-title {
  display: flex; align-items: center; gap: 0.5rem; margin: 1.5rem 0 0.6rem;
  color: var(--muted); font: 600 0.72rem/1.2 var(--sans); letter-spacing: 0.12em; text-transform: uppercase;
}
/* Om Sesam: version, commit, build time */
.push-what { margin-top: 0; }
.push-state { margin: 0.75rem 0 0; font-weight: 600; }
#push-actions:empty { display: none; }
.about { display: grid; grid-template-columns: auto 1fr; gap: 0.4rem 1.25rem; margin: 0; }
.about dt { color: var(--muted); }
.about dd { margin: 0; overflow-wrap: anywhere; }
.pending-list { list-style: none; display: grid; gap: 0.5rem; margin: 0; padding: 0; }
.pending-list li {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem; padding: 0.75rem 0.9rem;
  border: 1.5px dashed color-mix(in srgb, var(--accent) 40%, var(--line)); border-radius: 16px;
}
.avatar.pending { background: transparent; border: 1.5px dashed color-mix(in srgb, var(--accent) 60%, transparent); }
.pending-list .badge { margin-left: 0.45rem; vertical-align: 0.1em; }
.badge.kind { color: var(--muted); background: transparent; box-shadow: inset 0 0 0 1px var(--line); }
/* A new device: a phone outline instead of initials */
.avatar.device::before {
  content: ""; width: 0.8rem; height: 1.25rem; border: 2px solid currentColor; border-radius: 4px;
  background: linear-gradient(currentColor, currentColor) center bottom 2px / 0.35rem 2px no-repeat;
}
.pending-list .who { min-width: 10rem; }  /* the buttons wrap below the name on a narrow phone */
.pending-actions { display: flex; gap: 0.4rem; margin-left: auto; }
#pending-result .invite-box { margin-bottom: 0.75rem; }
/* Door access chosen in the invite form */
.inv-doors { min-width: 0; margin: 1.25rem 0 0; padding: 0; border: 0; }
.inv-doors legend { padding: 0; color: var(--fg); font-weight: 600; }
.inv-doors label { margin-top: 0.6rem; }
.profile button[type="submit"] { margin-top: 0.75rem; }

/* Doors */
.door-card .row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; }
/* A live status change (connection, door contact) while the Dörrar tab is open */
.door-card.changed { animation: door-changed 1.6s ease-out; }
@keyframes door-changed {
  from { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 60%, transparent), var(--shadow); }
  to { box-shadow: 0 0 0 3px transparent, var(--shadow); }
}
.door-title { font: 1.3rem/1.2 var(--display); font-weight: 400; }
.dot { display: inline-flex; align-items: center; gap: 0.4rem; color: var(--muted); font-size: 0.875rem; }
.dot::before { content: ""; width: 0.55rem; height: 0.55rem; border-radius: 50%; background: var(--muted); }
.dot.online::before { background: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 25%, transparent); }
.dot.offline::before { background: var(--err); }

/* Invites */
.invite-box {
  display: flex; align-items: flex-start; gap: 1rem; margin-top: 0.75rem; padding: 0.85rem;
  border-radius: 14px; background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.invite-box { flex-wrap: wrap; }
.invite-box > div { flex: 1; min-width: 0; }
.invite-box > .invite-head { flex: 1 0 100%; display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; }
.invite-title { display: flex; align-items: center; gap: 0.7rem; min-width: 0; }
.invite-title .meta { margin-top: 0.1rem; }
.ok-mark { position: relative; flex: none; width: 2rem; height: 2rem; border-radius: 50%; background: var(--accent); }
.ok-mark::after {
  content: ""; position: absolute; left: 0.7rem; top: 0.42rem; width: 0.45rem; height: 0.85rem;
  border: solid var(--accent-ink); border-width: 0 3px 3px 0; transform: rotate(45deg);
}
.invite-box .close, .sheet .close {
  flex: none; display: grid; place-items: center;
  width: 36px; height: 36px; padding: 0; border-radius: 50%;
  color: var(--fg); background: var(--card); border-color: var(--line); font: 400 1.4rem/1 var(--sans);
}
.invite-box p { margin: 0 0 0.5rem; font-size: 0.9rem; }
.qr { flex: none; width: 11rem; height: 11rem; border-radius: 10px; background: #fff; image-rendering: pixelated; }
.copy-row { display: flex; gap: 0.5rem; }
.copy-row input { flex: 1; min-width: 0; margin: 0; padding: 0.5rem 0.6rem; }

/* Audit log */
.toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-bottom: 0.75rem; }
.toolbar select { width: auto; min-width: 11rem; margin: 0; padding-top: 0.45rem; padding-bottom: 0.45rem; }
.toolbar select, .toolbar button { min-height: 42px; }
#audit-verify { margin-left: auto; }
#audit-verify-result { margin: 0 0 0.75rem; }
#audit-verify-result:empty { display: none; }
#audit-verify-result.ok { color: var(--accent); }
#audit-verify-result.err { color: var(--err); font-weight: 600; }
.table-wrap { overflow-x: auto; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); }
table { width: 100%; border-collapse: collapse; font-size: 0.9rem; font-variant-numeric: tabular-nums; }
th, td { padding: 0.6rem 0.75rem; text-align: left; vertical-align: top; border-bottom: 1px solid var(--line); }
th { color: var(--muted); font-size: 0.7rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; }
tbody tr:last-child td { border-bottom: 0; }
.pill { padding: 0.12rem 0.5rem; border-radius: 999px; font-size: 0.75rem; font-weight: 600; white-space: nowrap; }
.pill.ok { color: var(--accent); background: color-mix(in srgb, var(--accent) 15%, transparent); }
.pill.denied { color: var(--err); background: color-mix(in srgb, var(--err) 15%, transparent); }
.pill.info { color: var(--muted); background: color-mix(in srgb, var(--muted) 15%, transparent); }
.pill.alert { color: var(--warn); background: color-mix(in srgb, var(--warn) 18%, transparent); }
.c-event .note { display: block; font-size: 0.8rem; }

/* New events in the open log (admin.js, tr.fresh): they slide in, in the accent fading out over 4 s,
   with an accent edge on the left. The cells carry it here; on phones the card does (below). */
@keyframes fresh-in { from { opacity: 0; transform: translateY(-0.5rem); } }
@keyframes fresh-tint { from { background-color: color-mix(in srgb, var(--accent) 14%, var(--card)); } }
@keyframes fresh-edge { from { box-shadow: inset 3px 0 0 var(--accent); } }
table.audit tr.fresh > td { animation: fresh-in 0.35s ease-out, fresh-tint 4s ease-out; }
table.audit tr.fresh > td:first-child { animation: fresh-in 0.35s ease-out, fresh-tint 4s ease-out, fresh-edge 4s ease-in; }
@media (prefers-reduced-motion: reduce) {
  table.audit tr.fresh > td { animation: fresh-tint 4s ease-out; }
  table.audit tr.fresh > td:first-child { animation: fresh-tint 4s ease-out, fresh-edge 4s ease-in; }
}

/* "3 nya händelser": over the log while older events are being read, under the shrunken header */
button.new-events {
  position: fixed; z-index: 6; left: 50%; top: calc(3.75rem + var(--safe-top) + 0.6rem);
  display: inline-flex; align-items: center; gap: 0.4rem; min-height: 40px; padding: 0.45rem 1rem;
  font-size: 0.875rem; border-radius: 999px; box-shadow: 0 8px 24px -6px rgb(0 0 0 / 0.35);
  transform: translateX(-50%); animation: new-events-in 0.25s ease-out;
}
button.new-events:active:not(:disabled) { transform: translateX(-50%) scale(0.97); }
.new-events svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
@keyframes new-events-in { from { opacity: 0; transform: translate(-50%, -0.5rem); } }
@media (pointer: coarse) { button.new-events { min-height: 44px; } }
@media (prefers-reduced-motion: reduce) { button.new-events { animation: none; } }
.contact { display: inline-flex; align-items: center; gap: 0.4rem; margin: 0.4rem 0 0; font-weight: 600; font-size: 0.9rem; }
.contact::before { content: ""; width: 0.7rem; height: 0.9rem; border: 2px solid currentColor; border-radius: 2px; }
.contact.closed { color: var(--accent); }
.contact.open { color: var(--warn); }
.contact.open::before { border-left-width: 6px; }
.contact .meta { font-weight: 400; }
#audit-more { margin-top: 0.75rem; }

/* Toast */
body.admin #status {
  position: fixed; left: 50%; bottom: calc(1rem + var(--safe-bottom)); z-index: 20; transform: translateX(-50%);
  min-height: 0; max-width: calc(100% - 2rem); margin: 0; padding: 0.7rem 1.1rem;
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 8px 28px rgb(0 0 0 / 0.2);
}
body.admin #status:empty { display: none; }

/* --- Phones ---------------------------------------------------------------------- */
@media (max-width: 40rem) {
  body.admin main { padding-bottom: calc(7rem + var(--safe-bottom)); }
  .topbar h1 { font-size: 1.4rem; }
  #me, #me-avatar, .logout .label, .lock-all .label { display: none; }
  button.logout, button.lock-all { justify-content: center; width: 44px; height: 44px; padding: 0; }

  .toolbar { display: grid; grid-template-columns: 1fr 1fr; }
  .toolbar select { width: 100%; min-width: 0; }
  #audit-verify { margin-left: 0; white-space: nowrap; }

  /* Bottom tab bar within thumb reach */
  .tabs {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 10; margin: 0;
    padding: 0.35rem calc(0.5rem + var(--safe-right)) calc(0.35rem + var(--safe-bottom)) calc(0.5rem + var(--safe-left));
    border-width: 1px 0 0; border-radius: 0;
    background: color-mix(in srgb, var(--card) 88%, transparent);
    -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  }
  .tab { flex-direction: column; gap: 0.15rem; padding: 0.4rem 0; font-size: 0.75rem; font-weight: 600; }
  .tab svg { width: 24px; height: 24px; }
  .tab[aria-selected="true"] { color: var(--accent); background: transparent; }
  body.admin #status { bottom: calc(5.25rem + var(--safe-bottom)); }

  .grid2 { grid-template-columns: 1fr; }
  .invite-box { flex-direction: column; align-items: center; }
  .invite-box > .invite-head { flex: none; width: 100%; }
  .qr { width: 14rem; height: 14rem; }

  /* The rule editor as a bottom sheet, with a grabber like native sheets */
  dialog.sheet {
    width: 100%; max-height: 92dvh; margin: auto 0 0;
    border-width: 1px 0 0; border-radius: 22px 22px 0 0;
    animation: sheet-up 0.32s cubic-bezier(0.2, 0.8, 0.2, 1);
  }
  .sheet-body::before {
    content: ""; flex: none; align-self: center; width: 2.6rem; height: 4px; margin-top: 0.55rem;
    border-radius: 2px; background: var(--line);
  }
  .sheet-head { padding-top: 0.6rem; }
  .sheet-foot > button { flex: 1 1 auto; }
}
@keyframes sheet-up { from { transform: translateY(100%); } to { transform: none; } }

@media (max-width: 48rem) {
  /* Audit log as cards: the 7-column table is cramped below this width */
  .table-wrap { overflow: visible; background: none; border: 0; box-shadow: none; }
  table.audit thead { display: none; }
  table.audit, table.audit tbody { display: block; }
  table.audit tr {
    display: grid; grid-template-columns: 1fr auto; gap: 0.15rem 0.75rem; margin-bottom: 0.6rem; padding: 0.8rem 0.95rem;
    background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  }
  table.audit tr.empty { display: block; }
  table.audit td { display: block; padding: 0; border: 0; }
  table.audit td.none { display: none; }
  table.audit .c-event { grid-column: 1; grid-row: 1; font-weight: 600; }
  table.audit .c-outcome { grid-column: 2; grid-row: 1; }
  table.audit .c-time { grid-column: 1 / -1; color: var(--muted); font-size: 0.8rem; }
  table.audit .c-user, table.audit .c-door, table.audit .c-reason, table.audit .c-ip { grid-column: 1 / -1; font-size: 0.875rem; }
  table.audit td[data-label]:not(.c-event):not(.c-time)::before { content: attr(data-label) ": "; color: var(--muted); }
  table.audit .c-event .meta { font-weight: 400; }
  /* A new event's card carries the accent itself */
  table.audit tr.fresh { animation: fresh-in 0.35s ease-out, fresh-card 4s ease-out; }
  table.audit tr.fresh > td, table.audit tr.fresh > td:first-child { animation: none; }
  @media (prefers-reduced-motion: reduce) { table.audit tr.fresh { animation: fresh-card 4s ease-out; } }
}
@keyframes fresh-card {
  from {
    background-color: color-mix(in srgb, var(--accent) 12%, var(--card));
    border-color: color-mix(in srgb, var(--accent) 50%, var(--line));
    box-shadow: inset 3px 0 0 var(--accent);
  }
}

/* Comfortable touch targets on touch screens (Apple: 44pt, Android: 48dp) */
@media (pointer: coarse) {
  button.small, .toolbar select, .copy-row input { min-height: 44px; }
  .invite-box .close, .sheet .close { width: 44px; height: 44px; }
  .chip { min-height: 40px; }
  .seg button { min-height: 44px; }
}

/* --- Motion -------------------------------------------------------------------- */
@keyframes rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 35%, transparent); }
  50% { box-shadow: 0 0 0 10px color-mix(in srgb, var(--accent) 0%, transparent); }
}
@keyframes pop { from { transform: rotate(45deg) scale(0.4); opacity: 0; } to { transform: rotate(45deg) scale(1); opacity: 1; } }
@keyframes drain { from { transform: scaleX(1); } to { transform: scaleX(0); } }
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  20%, 60% { transform: translateX(-6px); }
  40%, 80% { transform: translateX(6px); }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition: none !important; }
  /* A colour fading out isn't motion: new rows in the log keep their highlight (without sliding in) */
  table.audit tr.fresh, table.audit tr.fresh > td { animation-duration: 4s !important; }
}
