/* SOLO Panel design tokens.
   Palette: deep navy/slate surface with a single teal signal color
   (status of inbounds/clients is the thing an admin scans for first,
   so it gets the one saturated accent; everything else stays quiet).
   Corner radii follow an Apple HIG-style scale: capsule (fully round)
   for primary actions and pill chips, a refined ~14px for secondary/
   tertiary controls and inputs, and a softer ~20px for cards/modals
   so containers read as concentric with the controls inside them.
   `corner-shape: squircle` is layered on top of `border-radius` as a
   progressive enhancement -- it's a newly proposed CSS property that
   renders Apple's continuous (superellipse) corner curve in browsers
   that support it, and is silently ignored (falling back to the
   plain circular-arc radius) everywhere else. */
:root {
  --bg: #0a0f1a;
  --surface: #111a2c;
  --surface-alt: #182437;
  --surface-glass: rgba(17, 26, 44, 0.78);
  --border: #24314a;
  --border-soft: rgba(231, 236, 246, 0.08);
  --text: #e7ecf6;
  --text-muted: #8a99b8;
  --accent: #33d9c4;
  --accent-strong: #1bb8a4;
  --danger: #e5626a;
  --warning: #e8b34a;
  --radius: 8px;
  --radius-sm: 10px;
  --radius-md: 14px;
  --radius-lg: 20px;
  --radius-capsule: 999px;
  --shadow-sm: 0 1px 2px rgba(2, 4, 8, 0.5), 0 1px 1px rgba(2, 4, 8, 0.3);
  --shadow-md: 0 12px 28px rgba(2, 4, 8, 0.45);
  --shadow-lg: 0 24px 60px rgba(2, 4, 8, 0.55);
  --font-display: "Roboto", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --font-body: "Roboto", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --font-mono: ui-monospace, "SFMono-Regular", Menlo, monospace;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.5;
  overflow-x: hidden;
}

a {
  color: var(--accent);
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 28px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  flex-wrap: wrap;
  gap: 10px;
}

.brand {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 20px;
  letter-spacing: 0.02em;
  color: var(--text);
}
.brand span {
  color: var(--accent);
}
.brand-center {
  text-decoration: none;
}
.brand-center:hover {
  text-decoration: none;
  opacity: 0.85;
}

.brand-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.brand-version {
  font-family: var(--font-body);
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 2px;
}

.topbar-side {
  flex: 1;
  display: flex;
  align-items: center;
}
.topbar-side.topbar-user {
  justify-content: flex-end;
  flex-wrap: wrap;
}

.topbar-user {
  color: var(--text-muted);
  font-size: 14px;
  gap: 16px;
}

/* Icon + label buttons (e.g. Change Password) -- icon stays a fixed
   size regardless of .btn's own responsive padding/font-size changes
   across breakpoints, so it never scales oddly relative to the text.
   `.btn.btn-icon` (two classes) intentionally outranks the plain
   `.btn` rule below on specificity, since `.btn` also sets its own
   `display` and is defined later in this file -- without the extra
   specificity here, source order would let `.btn`'s display win and
   the icon/label would fall back to plain inline flow instead of a
   flex row. */
.btn.btn-icon {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.btn-icon-svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

/* GitHub repo link (topbar, left side) -- same circular icon-button
   look as .profile-trigger on the right, so the topbar reads as
   balanced. */
.github-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-capsule);
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--text);
  transition:
    border-color 0.15s ease,
    transform 0.1s ease;
}
.github-link:hover,
.github-link:focus-visible {
  border-color: var(--accent);
  outline: none;
  text-decoration: none;
}
.github-link:active {
  transform: scale(0.95);
}
.github-link-svg {
  width: 20px;
  height: 20px;
}

/* Profile menu (topbar) -- single avatar-style icon button that opens
   a GitHub-style dropdown with Change Password / Sign out, replacing
   the two separate always-visible topbar buttons. */
.profile-menu {
  position: relative;
  z-index: 160;
}
/* Dims and softly blurs the rest of the page while the profile
   dropdown is open, so the open menu reads as the focused thing on
   screen (same idea as the QR/password modal backdrop, but lighter --
   this isn't a blocking modal, just a menu). */
.profile-menu-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(4, 7, 13, 0.35);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  z-index: 140;
}
.profile-menu-overlay.open {
  display: block;
}
.profile-trigger {
  position: relative;
  z-index: 150;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border-radius: var(--radius-capsule);
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--text);
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    transform 0.1s ease;
}
.profile-trigger:hover,
.profile-trigger:focus-visible {
  border-color: var(--accent);
  outline: none;
}
.profile-trigger:active {
  transform: scale(0.95);
}
.profile-trigger-svg {
  width: 22px;
  height: 22px;
}
.profile-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 200px;
  background: var(--surface-glass);
  backdrop-filter: blur(24px) saturate(160%);
  -webkit-backdrop-filter: blur(24px) saturate(160%);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  corner-shape: squircle;
  box-shadow: var(--shadow-lg);
  padding: 6px;
  z-index: 150;
  transform-origin: top right;
  opacity: 0;
  transform: scale(0.95) translateY(-4px);
  pointer-events: none;
  transition:
    opacity 0.12s ease,
    transform 0.12s ease;
}
.profile-dropdown.open {
  opacity: 1;
  transform: scale(1) translateY(0);
  pointer-events: auto;
}

/* Reused by .calendar-day-selected below -- same opacity+scale motion
   as this dropdown's own open transition. */
@keyframes select-pop {
  from {
    opacity: 0.7;
    transform: scale(0.95);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}
.profile-dropdown-form {
  margin: 0;
}
/* Same interactive-row look for both the plain <button> (Change
   Password) and the <button type="submit"> inside the logout <form>
   (Sign out), so the two menu items are visually identical. */
.profile-dropdown-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px 12px;
  border: none;
  background: transparent;
  color: var(--text);
  font-family: var(--font-body);
  font-size: 14px;
  text-align: left;
  border-radius: var(--radius);
  cursor: pointer;
  transition: background 0.12s ease;
}
.profile-dropdown-item:hover,
.profile-dropdown-item:focus-visible {
  background: var(--border-soft);
  outline: none;
}
.profile-dropdown-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  color: var(--text-muted);
}

.container {
  max-width: 980px;
  margin: 0 auto;
  padding: 32px 24px 64px;
}

h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: 600;
  margin: 0 0 16px;
}
h1 {
  font-size: 26px;
}
h2 {
  font-size: 19px;
}

.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 24px;
  flex-wrap: wrap;
  gap: 12px;
}

.card {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  corner-shape: squircle;
  box-shadow: var(--shadow-sm);
  padding: 24px;
  margin-bottom: 20px;
}

.mono {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text-muted);
}

.btn {
  display: inline-block;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 500;
  padding: 10px 18px;
  border-radius: var(--radius-md);
  corner-shape: squircle;
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--text);
  cursor: pointer;
  transition:
    background 0.15s ease,
    border-color 0.15s ease,
    box-shadow 0.15s ease,
    transform 0.1s ease;
  /* 44px is the standard minimum touch-target size -- applied at
     every screen size (not just mobile) since tablets and touch
     laptops need it too, and it doesn't hurt mouse-driven desktop use. */
  min-height: 44px;
}
.btn:hover {
  border-color: var(--accent);
  text-decoration: none;
}
.btn:active:not(:disabled) {
  transform: scale(0.97);
}
.btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.btn-accent {
  background: var(--accent);
  border-color: var(--accent);
  color: #06231f;
  font-weight: 600;
  border-radius: var(--radius-md);
  padding: 10px 26px;
  box-shadow: var(--shadow-sm);
}
.btn-accent:hover {
  background: var(--accent-strong);
  border-color: var(--accent-strong);
  box-shadow: var(--shadow-md);
}
.btn-accent:active:not(:disabled) {
  box-shadow: none;
}
.btn-small {
  padding: 5px 10px;
  font-size: 12px;
  min-height: 40px;
}

/* Tertiary buttons -- lowest visual weight, for dismissive actions
   that sit beside a stronger primary/secondary action (modal Cancel/
   Close buttons). No border or fill at rest, unlike .btn's own
   filled-gray secondary look; a soft tinted background only appears
   on hover/press, which is the native Apple pattern for a plain
   (borderless) button. */
.btn-tertiary {
  background: transparent;
  border-color: transparent;
  color: var(--text-muted);
  font-weight: 500;
}
.btn-tertiary:hover {
  background: var(--border-soft);
  border-color: transparent;
  color: var(--text);
}

/* "Apply Changes" (mode toggles) -- deliberately NOT a solid accent
   fill like .btn-accent or a selected .mode-toggle chip, since a
   solid-accent button sitting right under a row of solid-accent chips
   reads as "just another chip". Outlined instead: accent border/text
   on a transparent background, filling solid only on hover -- same
   accent color family, visually distinct shape. */
.btn-apply {
  background: transparent;
  border: 2px solid var(--accent);
  color: var(--accent);
  font-weight: 600;
  border-radius: var(--radius-md);
  padding: 9px 26px;
}
.btn-apply:active:not(:disabled) {
  background: var(--accent-strong);
  border-color: var(--accent-strong);
  color: #06231f;
}
.btn-apply:hover:not(:disabled) {
  background: var(--accent);
  border-color: var(--accent);
  color: #06231f;
}
.btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.btn:disabled:hover {
  background: transparent;
  border-color: var(--border);
  color: var(--text);
}
.btn-apply:disabled:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* Divider between the two subsections of the combined "Advanced:
   modes & limits" card. */
.section-divider {
  border: none;
  border-top: 1px solid var(--border);
  margin: 24px 0;
}

/* Full-width primary action buttons (Save Limits, Apply Changes) on
   mobile only -- a full-width tap target is the more standard mobile
   pattern; desktop/tablet keep their normal auto width. */
@media (max-width: 660px) {
  .btn-block {
    display: block;
    width: 100%;
    text-align: center;
  }
}

form.inline {
  display: inline;
}

label {
  display: block;
  font-size: 13px;
  color: var(--text-muted);
  margin: 14px 0 6px;
}
.sub-header-row {
  margin: 0 0.5rem 1rem;
  display: flex;
  justify-content: space-between;
  gap: 8px;
}
input[type="text"],
input[type="password"],
input[type="number"],
select {
  width: 100%;
  padding: 10px 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  corner-shape: squircle;
  color: var(--text);
  font-family: var(--font-body);
  transition: border-color 0.15s ease;
  /* Matches .date-trigger's own min-height so the End date button and
     Usage limit (GB) input line up at the same height side by side. */
  min-height: 44px;
  /* 16px, not smaller: any focused input under 16px makes iOS Safari
     auto-zoom the whole page, on a phone or a tablet -- applied at
     every screen size so it can never regress on any device. */
  font-size: 16px;
}
input:focus,
select:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* Hide the browser's default up/down spinner arrows on number inputs
   (Days / Usage limit (GB) fields) -- user-requested, purely visual. */
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
input[type="number"] {
  appearance: textfield;
  -moz-appearance: textfield;
}

/* Custom date-picker trigger (End date field) -- styled to match the
   plain text/number inputs above, since it visually needs to sit in
   the same form-row. */
.date-trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  corner-shape: squircle;
  color: var(--text);
  font-family: var(--font-body);
  font-size: 16px;
  text-align: left;
  cursor: pointer;
  min-height: 44px;
  transition: border-color 0.15s ease;
}
.date-trigger:hover,
.date-trigger:focus-visible {
  border-color: var(--accent);
  outline: none;
}
.date-trigger-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  color: var(--text-muted);
}

/* Custom calendar modal, opened from .date-trigger above. Reuses the
   existing .modal-backdrop/.modal-box pattern (same as the QR/confirm
   modals) so it's responsive for free -- no separate popover
   positioning logic to write or maintain. */
.calendar-box {
  max-width: 300px;
}
.calendar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}
.calendar-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 15px;
}
.calendar-nav-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--text);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    transform 0.1s ease;
}
.calendar-nav-btn:active:not(:disabled) {
  transform: scale(0.94);
}
.calendar-nav-btn:hover:not(:disabled) {
  border-color: var(--accent);
}
.calendar-nav-btn:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}
.calendar-weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  text-align: center;
  color: var(--text-muted);
  font-size: 12px;
  margin-bottom: 4px;
}
.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}
.calendar-day {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  background: transparent;
  color: var(--text);
  font-family: var(--font-body);
  font-size: 14px;
  cursor: pointer;
  transition:
    background 0.12s ease,
    border-color 0.12s ease,
    transform 0.1s ease;
}
.calendar-day:active:not(:disabled) {
  transform: scale(0.92);
}
.calendar-day:hover:not(:disabled) {
  border-color: var(--accent);
}
.calendar-day:disabled {
  color: var(--text-muted);
  opacity: 0.35;
  cursor: not-allowed;
}
.calendar-day-empty {
  visibility: hidden;
  cursor: default;
}
.calendar-day-today {
  border-color: var(--border);
  font-weight: 600;
}
.calendar-day-selected,
.calendar-day-selected:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: #06231f;
  font-weight: 600;
  animation: select-pop 0.12s ease;
}

.error {
  color: var(--danger);
  font-size: 14px;
  margin-bottom: 12px;
}
.muted {
  color: var(--text-muted);
  font-size: 13px;
}

.form-row {
  display: flex;
  gap: 12px;
  align-items: flex-end;
  flex-wrap: wrap;
}

.login-shell {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.login-card {
  width: 100%;
  max-width: 340px;
}

.link-box {
  display: flex;
  gap: 8px;
  align-items: center;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  corner-shape: squircle;
  padding: 8px 10px;
  margin-top: 6px;
  width: 100%;
  max-width: 100%;
}
.link-box code {
  flex: 1;
  min-width: 0;
  width: 100%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text);
  cursor: pointer;
}
.link-box .btn-small {
  flex-shrink: 0;
}
.qr-icon-btn {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 6px;
  line-height: 0;
  /* Same 44px minimum touch target as .btn, at every screen size. */
  min-width: 44px;
  min-height: 44px;
}
.qr-icon-btn svg {
  width: 18px;
  height: 18px;
  display: block;
}

.toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: var(--surface-glass);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid var(--border-soft);
  color: var(--text);
  padding: 10px 18px;
  border-radius: var(--radius-capsule);
  box-shadow: var(--shadow-md);
  font-size: 13px;
  opacity: 0;
  pointer-events: none;
  transition:
    opacity 0.2s ease,
    transform 0.2s ease;
  z-index: 200;
}
.toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* QR code modal */
.modal-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(4, 7, 13, 0.6);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 20px;
}
.modal-backdrop.open {
  display: flex;
}
.modal-box {
  background: var(--surface-glass);
  backdrop-filter: blur(24px) saturate(160%);
  -webkit-backdrop-filter: blur(24px) saturate(160%);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  corner-shape: squircle;
  box-shadow: var(--shadow-lg);
  padding: 24px;
  width: 100%;
  max-width: 320px;
  text-align: center;
  /* Same opacity+scale+translateY motion as the profile dropdown
     (`.profile-dropdown`/`.profile-dropdown.open` above) -- every
     popup in the panel opens with this one shared animation. */
  opacity: 0;
  transform: scale(0.95) translateY(-4px);
  transition:
    opacity 0.12s ease,
    transform 0.12s ease;
}
.modal-backdrop.open .modal-box {
  opacity: 1;
  transform: scale(1) translateY(0);
}
.modal-box h3 {
  margin-bottom: 4px;
}
.modal-qr {
  background: #fff;
  border-radius: var(--radius-md);
  padding: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 16px 0;
}
.modal-qr canvas,
.modal-qr img {
  display: block;
  max-width: 100%;
  height: auto;
}
.modal-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin-top: 20px;
}

/* Health status badges (docs/product-vision.md rule 10). Small text
   pill next to each inbound's label on the dashboard. */
.health-badge {
  display: inline-block;
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 2px 8px;
  border-radius: var(--radius-capsule);
  border: 1px solid var(--border);
  vertical-align: middle;
}
.health-healthy {
  color: var(--accent);
  border-color: var(--accent);
}
.health-degraded {
  color: var(--warning);
  border-color: var(--warning);
}
.health-unavailable {
  color: var(--danger);
  border-color: var(--danger);
}
.health-unknown {
  color: var(--text-muted);
}

/* Label + inline icon button, side by side (e.g. "Usage limit (GB)"
   + its reset icon) -- same flex/space-between idea as .sub-header-row
   above, reused here since a plain <label> is display:block. */
.field-label-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

/* Small borderless icon-only button sitting inline with a label
   (e.g. the "reset usage" icon next to Usage limit (GB)) -- quieter
   than .qr-icon-btn's bordered/filled look, since this sits next to
   plain text rather than inside a .link-box. */
.icon-btn-inline {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
  border: none;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  line-height: 0;
  border-radius: var(--radius);
  transition:
    color 0.15s ease,
    background 0.15s ease,
    transform 0.1s ease;
}
.icon-btn-inline:hover,
.icon-btn-inline:focus-visible {
  color: var(--accent);
  background: var(--border-soft);
  outline: none;
}
.icon-btn-inline:active {
  transform: scale(0.92);
}
.icon-btn-inline svg {
  width: 18px;
  height: 18px;
  display: block;
}

/* Danger confirm button (e.g. "Reset usage" modal's Yes) -- same
   outlined-fills-on-hover treatment as .btn-apply, but in the danger
   color family, so a destructive Yes reads as clearly different from
   the plain .btn-tertiary Cancel/No sitting next to it. */
.btn-danger {
  background: transparent;
  border: 2px solid var(--danger);
  color: var(--danger);
  font-weight: 600;
  border-radius: var(--radius-md);
  padding: 9px 26px;
}
.btn-danger:hover {
  background: var(--danger);
  border-color: var(--danger);
  color: #2a0a0c;
}
.btn-danger:active:not(:disabled) {
  background: #c94850;
  border-color: #c94850;
  color: #2a0a0c;
}

/* Danger-bordered info card (persistent-storage warning, modes-save
   error) -- was a repeated inline style on two cards in dashboard.ejs. */
.card-danger {
  border-color: var(--danger);
}

/* Two cards side by side (dashboard's Location + Subscription URL
   cards) -- stacks to full-width cards on narrow screens via the
   `flex-direction: column` override below. No flex-wrap here: with
   flex-direction switched to column at <=660px, flex-wrap: wrap
   would wrap overflowing items into a second *column* instead of
   stacking them in one column, pushing the second card off-screen. */
.two-col {
  display: flex;
  gap: 20px;
  margin-bottom: 20px;
}
.two-col > .card {
  flex: 1;
  min-width: 220px;
  margin-bottom: 0;
}

/* Subscription Panel endpoint cards (one per generated connection) --
   was a repeated inline style block per <details> in subscription.ejs.
   Hover/focus border shifts to the accent color so the cards read as
   tappable, matching the hover treatment already used on .btn/.mode-toggle. */
.endpoint-card {
  margin-top: 18px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  corner-shape: squircle;
  padding: 18px;
  transition:
    border-color 0.15s ease,
    box-shadow 0.15s ease;
}
.endpoint-card:hover {
  border-color: var(--accent);
  box-shadow: var(--shadow-sm);
}

/* Responsive: narrow viewports (phones) */
@media (max-width: 660px) {
  .container {
    padding: 20px 14px 48px;
  }
  .topbar {
    padding: 14px 16px;
  }
  h1 {
    font-size: 22px;
  }

  .page-header {
    flex-direction: column;
    align-items: flex-start;
  }

  /* Cards, the location flag, and small buttons are sized for a
     desktop pointer and don't scale with text -- once a card goes
     full-width on a stacked mobile layout they read as visually tiny
     and are also below a comfortable touch-target size. Bump them up
     for phones only; desktop/tablet sizing is unchanged. */
  .card {
    padding: 20px;
  }
  .location-flag {
    width: 30px;
    height: auto;
  }
  .qr-icon-btn {
    padding: 12px;
  }
  .qr-icon-btn svg {
    width: 22px;
    height: 22px;
  }
  .btn {
    padding: 13px 22px;
    font-size: 15px;
  }
  .btn-small {
    padding: 8px 14px;
    font-size: 13px;
  }

  /* Change Password button (topbar): the full text label doesn't fit
     the topbar's shrunk flex column on narrow screens (topbar-side
     has flex:1, so its content area is much narrower than the full
     viewport once the centered brand takes the middle) -- collapse it
     to an icon-only square button, same footprint as .qr-icon-btn,
     matching the Log out button's own compact size. The label stays
     in the DOM (sr-only, not display:none) so it's still announced by
     screen readers and still provides the button's accessible name. */
  .btn-icon-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
  .btn-icon {
    padding: 10px;
    min-width: 44px;
    justify-content: center;
  }
  .mode-toggle {
    padding: 10px 16px;
  }

  /* Force the Location/Subscription URL row to stack on phones via an
     explicit rule instead of relying on flex-wrap's own min-width
     math (which depends on the browser correctly reporting a narrow
     layout viewport -- not reliable across every device/browser
     configuration). */
  .two-col {
    flex-direction: column;
  }
}

/* Accessibility: visible keyboard-focus indicator for elements made
   focusable via tabindex (copyable code/link elements) and any
   ARIA button, matching the same accent color already used for
   mouse-hover/input focus states above. */
[role="button"] {
  cursor: pointer;
}
.link-box code:focus-visible,
[role="button"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Technical-details rows on the Subscription Web Panel (endpoint
   cards' Core/Protocol/Transport/Security/Status breakdown, vision
   rules 16/31). Flex-based instead of a <table> so it never needs
   horizontal scroll on a phone -- label and value sit inline on wide
   screens, and everything (including the explanation) wraps onto its
   own line as the viewport narrows. */
.detail-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}
.detail-row:last-child {
  border-bottom: none;
}
.detail-label {
  flex: 0 0 100px;
  color: var(--text-muted);
  font-size: 13px;
}
.detail-value {
  flex: 1 1 140px;
  min-width: 0;
}
.detail-explain {
  flex: 1 1 100%;
  color: var(--text-muted);
  font-size: 12px;
}

@media (max-width: 480px) {
  .detail-label {
    flex-basis: 100%;
  }

  /* Small phones: reclaim horizontal space -- the 660px breakpoint
     above already tightens .container's own padding, this tightens
     the modal sitting inside it. (.card itself is NOT re-tightened
     here: the 660px breakpoint just above intentionally bumped its
     padding up for touch/visual sizing, and since most real phones
     are under 480px wide, a smaller override here would silently
     undo that fix for almost every device it was meant to help.) */
  .modal-box {
    padding: 18px;
  }
}

/* Smallest common phones (320-359px, e.g. iPhone SE/older Android) --
   the 660px/480px breakpoints above already technically apply at this
   width, but were never specifically tuned for it: container/card
   padding eats a larger share of a 320px screen than a 400px+ one, so
   tighten it a bit further here on top of (not instead of) the rules
   above. Element sizing (.location-flag, .qr-icon-btn, .btn-small,
   .card padding bump) from the 660px breakpoint is left as-is --
   those are about touch-target/visual size, not available width, and
   apply equally well at 320px. */
@media (max-width: 359px) {
  .container {
    padding: 16px 10px 40px;
  }
  .card {
    padding: 16px;
  }
  .two-col {
    gap: 14px;
  }
  .form-row {
    gap: 8px;
  }
}

/* Corner notification popups (replaces alert() for validation/
   success messages e.g. "Password changed successfully.") -- stacked
   top-right, each with a close (X) button and colored left border by
   type. Auto-dismiss after a few seconds, or closed manually. */
.notification-container {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 300;
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: min(340px, calc(100vw - 40px));
}
.notification {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  background: var(--surface-glass);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid var(--accent);
  border-radius: var(--radius-md);
  corner-shape: squircle;
  padding: 12px 14px;
  box-shadow: var(--shadow-md);
  opacity: 0;
  transform: translateX(16px);
  transition:
    opacity 0.2s ease,
    transform 0.2s ease;
}
.notification.show {
  opacity: 1;
  transform: translateX(0);
}
.notification-error {
  border-color: var(--danger);
}
.notification-message {
  flex: 1;
  font-size: 14px;
  color: var(--text);
  line-height: 1.4;
}
.notification-close {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border: none;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
}
.notification-close:hover {
  color: var(--text);
}
.notification-close svg {
  width: 16px;
  height: 16px;
}

/* Step list used inside warning/info cards (e.g. the persistent-
   storage setup steps) -- numbered, roomy, with inline <code> pills
   for keyboard shortcuts so the steps stay easy to scan. */
.step-list {
  margin: 8px 0 12px;
  padding-left: 22px;
  color: var(--text);
}
.step-list li {
  margin-bottom: 8px;
  line-height: 1.5;
}
.step-list li:last-child {
  margin-bottom: 0;
}
.step-list code {
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 6px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text);
}

/* Per-mode enable/disable options (Advanced: modes section), styled
   as clickable chips/pills rather than plain checkboxes -- the whole
   chip is the click target (native <label> behavior), and its
   background switches to the existing accent color when selected
   (same color pairing .btn-accent already uses) instead of relying on
   a small checkbox square. One dimension (core/protocol/transport/
   alpn/fingerprint) at a time, chips wrapping naturally on narrow
   screens instead of a rigid grid. */
.mode-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 10px;
  margin-bottom: 8px;
}
.mode-toggle {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 16px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--text);
  font-size: 14px;
  margin: 0;
  cursor: pointer;
  user-select: none;
  transition:
    background 0.15s ease,
    border-color 0.15s ease,
    color 0.15s ease,
    transform 0.1s ease;
  /* Same 44px minimum touch target as .btn, at every screen size. */
  min-height: 44px;
}
.mode-toggle:active {
  transform: scale(0.97);
}
.mode-toggle:hover {
  border-color: var(--accent);
}
.mode-toggle.selected {
  background: var(--accent);
  border-color: var(--accent);
  color: #06231f;
  font-weight: 600;
}
/* The real checkbox stays in the DOM (form submission, native
   label-click toggling, keyboard Tab/Space) but is visually hidden --
   sr-only, not display:none, so it's still focusable and readable by
   screen readers. */
.mode-toggle input[type="checkbox"] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
/* Visible keyboard-focus indicator on the chip itself, since the
   checkbox that actually receives focus is hidden -- same accent
   outline already used for focus-visible elsewhere in this file. */
.mode-toggle:has(input:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
