/* Admin UI: additions to Pico CSS v2 (SPEC 10.3). Mobile first. Two
   breakpoints: 768px (the top navigation instead of the bottom tab bar, the
   compact 40px controls instead of the 44px touch targets) and 1024px (tables
   instead of cards, two columns of a card instead of one). */

:root {
  --vpn-touch: 44px;
  --vpn-gap: 1rem;
  --vpn-max: 1120px;
  --vpn-tabbar: 56px;
  --vpn-line: var(--pico-muted-border-color);
  --vpn-ok: #12694a;
  --vpn-ok-bg: rgba(18, 105, 74, 0.12);
  --vpn-warn: #8a5300;
  --vpn-warn-bg: rgba(138, 83, 0, 0.12);
  --vpn-err: #a82015;
  --vpn-err-bg: rgba(168, 32, 21, 0.12);
  --vpn-neutral: var(--pico-muted-color);
  --vpn-neutral-bg: rgba(128, 128, 128, 0.12);
  /* One base size on every width: Pico grows the root font up to 131% */
  --pico-font-size: 100%;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --vpn-ok: #63d39b;
    --vpn-ok-bg: rgba(99, 211, 155, 0.14);
    --vpn-warn: #e0a54a;
    --vpn-warn-bg: rgba(224, 165, 74, 0.14);
    --vpn-err: #ef8279;
    --vpn-err-bg: rgba(239, 130, 121, 0.14);
    --vpn-neutral-bg: rgba(160, 160, 160, 0.14);
  }
}
:root[data-theme="dark"] {
  --vpn-ok: #63d39b;
  --vpn-ok-bg: rgba(99, 211, 155, 0.14);
  --vpn-warn: #e0a54a;
  --vpn-warn-bg: rgba(224, 165, 74, 0.14);
  --vpn-err: #ef8279;
  --vpn-err-bg: rgba(239, 130, 121, 0.14);
  --vpn-neutral-bg: rgba(160, 160, 160, 0.14);
}

/* Desktop: a compact control scale (~40px); phones keep the 44px touch targets */
@media (min-width: 768px) {
  :root {
    --vpn-touch: 40px;
    --pico-form-element-spacing-vertical: 0.5rem;
    --pico-form-element-spacing-horizontal: 0.875rem;
  }
}

/* Typography and the page container */
.container { max-width: var(--vpn-max); padding-inline: 16px; }
@media (min-width: 768px) { .container { padding-inline: 24px; } }
h1 { --pico-font-size: 1.75rem; --pico-typography-spacing-top: 1.5rem; }
h2 { --pico-font-size: 1.25rem; --pico-typography-spacing-top: 1.5rem; }
h3 { --pico-font-size: 1.0625rem; --pico-typography-spacing-top: 1rem; }
h4, h5, h6 { --pico-font-size: 1rem; }
/* Pico never sizes small: a variable would do nothing and code inside it fell to 11.7px */
small { font-size: 0.875rem; }
hgroup > p { margin-bottom: 0; }
main > h1 + p.muted { font-size: 0.875rem; }
body > main { padding-block: var(--vpn-gap); }
article { margin-bottom: var(--vpn-gap); }
section { margin-bottom: var(--vpn-gap); }
p, ul, ol, form { margin-bottom: var(--vpn-gap); }
pre { overflow-x: auto; }
/* No overflow on inline code: a scroll container would sit on its own baseline */
code { overflow-wrap: anywhere; }

/* Top navigation: one row from 768px, only the brand on a phone */
.site-header { padding-block: 0.25rem; border-bottom: 1px solid var(--vpn-line); }
.site-nav,
.site-nav ul { flex-wrap: wrap; }
.site-nav a,
.site-nav button {
  min-height: var(--vpn-touch);
  display: inline-flex;
  align-items: center;
}
.site-nav a[aria-current="page"] { font-weight: 600; text-decoration: underline; }
.site-nav button { margin: 0; padding-block: 0; }
.site-nav .site-sections,
.site-nav .site-logout { display: none; }
@media (min-width: 768px) {
  .site-nav .site-sections {
    --pico-nav-element-spacing-horizontal: 0.75rem;
    display: flex;
    margin-inline: auto 0;
  }
  .site-nav .site-logout { display: flex; }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .site-nav .site-sections { --pico-nav-element-spacing-horizontal: 0.375rem; }
}
/* Ten sections and "Выйти" fit one row of the 1120px container; should they
   not, the sections wrap among themselves and "Выйти" stays in the first row */
@media (min-width: 1024px) {
  .site-nav .site-sections { --pico-nav-element-spacing-horizontal: 0.5rem; }
}
@media (min-width: 768px) {
  .site-nav { flex-wrap: nowrap; }
  .site-nav .site-sections { flex: 0 1 auto; justify-content: flex-end; }
  .site-nav .site-logout { flex: none; }
}

/* Bottom tab bar of a phone; hidden from 768px */
.tabbar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 20;
  display: flex;
  align-items: stretch;
  min-height: var(--vpn-tabbar);
  padding-bottom: env(safe-area-inset-bottom);
  background: var(--pico-card-background-color);
  border-top: 1px solid var(--vpn-line);
}
.tabbar > a,
.tabbar > details > summary {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  min-height: var(--vpn-tabbar);
  white-space: nowrap;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  padding: 0.25rem;
  font-size: 0.8125rem;
  line-height: 1.1;
  text-align: center;
  text-decoration: none;
  color: var(--pico-secondary);
}
/* Pico gives details and an open summary a bottom margin: inside the bar it
   lifts the item and leaves a 23px target */
.tabbar > details { flex: 1 1 auto; min-width: 0; display: flex; margin: 0; }
.tabbar > details > summary { list-style: none; cursor: pointer; }
.tabbar > details > summary::marker,
.tabbar > details > summary::-webkit-details-marker { display: none; content: ""; }
.tabbar > details > summary::after { display: none; }
.tabbar a[aria-current="page"],
.tabbar > details:has(a[aria-current="page"]) > summary:not([role]) { color: var(--pico-primary); font-weight: 600; }
@media (max-width: 359px) {
  .tabbar > a,
  .tabbar > details > summary { font-size: 0.75rem; }
}
.tabbar-menu {
  position: absolute;
  right: 0.5rem;
  bottom: calc(100% + 0.25rem);
  min-width: 12rem;
  padding: 0.5rem;
  background: var(--pico-card-background-color);
  border: 1px solid var(--vpn-line);
  border-radius: var(--pico-border-radius);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
}
.tabbar-menu a,
.tabbar-menu button {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: var(--vpn-touch);
  margin: 0;
  text-decoration: none;
}
.tabbar-menu form { margin: 0; }
@media (min-width: 768px) { .tabbar { display: none; } }
/* Pico pads body > main: a plain main selector loses and the bar hides the end of the page */
@media (max-width: 767px) {
  body:has(> .tabbar) > main { padding-bottom: calc(var(--vpn-tabbar) + env(safe-area-inset-bottom) + var(--vpn-gap)); }
  .site-nav li { padding-block: 0.25rem; }
}

/* One column on phones and tablets, two from 1024px: a column of a 768px
   screen is too narrow for a card with fields and buttons */
.cols {
  display: grid;
  grid-template-columns: 1fr;
  column-gap: calc(var(--pico-spacing) * 2);
}
@media (min-width: 1024px) {
  .cols {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
.cols > * { min-width: 0; }

/* Touch targets */
button,
[role="button"],
select,
input:not([type="checkbox"], [type="radio"]) {
  min-height: var(--vpn-touch);
}
/* A button next to a field keeps its own width: Pico shares the group between
   the field and the button and wraps a long label */
[role="group"] > button,
[role="group"] > [type="button"],
[role="group"] > [type="submit"] { flex: 0 0 auto; width: auto; white-space: nowrap; }
@media (max-width: 479px) {
  /* Pico pads a button of a group by 2rem: on a phone the field beside it
     shrinks to a few letters */
  [role="group"] > button,
  [role="group"] > [type="button"],
  [role="group"] > [type="submit"] { --pico-form-element-spacing-horizontal: 0.875rem; }
  .copy-field [role="group"] > .copy-button { min-width: 0; }
  /* A long label and a field do not share a row of a phone */
  #user-connections [role="group"],
  .connection-profiles [role="group"],
  .ordered-list [role="group"] { flex-wrap: wrap; gap: 0.5rem; }
  #user-connections [role="group"] > *,
  .connection-profiles [role="group"] > *,
  .ordered-list [role="group"] > * { flex: 1 1 100%; margin-left: 0; border-radius: var(--pico-border-radius) !important; }
  /* The label of an ordered row takes the line, its buttons the next one */
  .ordered-list li > .ordered-label { flex: 1 1 calc(100% - 3rem); }
  .ordered-list li { justify-content: flex-end; margin-bottom: 0.5rem; }
  /* Buttons of one row share it in equal parts instead of stacking by the
     width of their labels */
  .device-card .row-actions > .inline-form { flex: 1 1 auto; }
  .device-card .row-actions > .inline-form > button,
  .danger-item > .inline-form > button,
  .invite-actions > button { width: 100%; }
  .danger-item > .inline-form { flex: 1 1 100%; }
  .copy-textarea .copy-button { align-self: stretch; }
  .danger-zone .row-actions .inline-form,
  .danger-zone .row-actions button { width: 100%; }
}
label:has(> input[type="checkbox"]) {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: var(--vpn-touch);
  margin-bottom: 0;
}

/* Buttons: primary (Pico default), quiet, dangerous */
/* Pico styles [type="submit"].secondary and .outline with two classes worth of
   specificity: the :not() below keeps these rules above them. */
button.secondary:not(.btn-danger),
button.outline:not(.btn-danger),
button.secondary.outline:not(.btn-danger),
button.copy-button,
[role="button"].secondary:not(.btn-danger),
[role="button"].outline:not(.btn-danger) {
  --pico-background-color: transparent;
  --pico-border-color: var(--vpn-line);
  --pico-color: var(--pico-contrast);
  --pico-box-shadow: none;
}
button.secondary:not(.btn-danger):is(:hover, :focus, :active),
button.outline:not(.btn-danger):is(:hover, :focus, :active),
button.secondary.outline:not(.btn-danger):is(:hover, :focus, :active),
button.copy-button:is(:hover, :focus, :active),
[role="button"].secondary:not(.btn-danger):is(:hover, :focus, :active),
[role="button"].outline:not(.btn-danger):is(:hover, :focus, :active) {
  --pico-background-color: var(--vpn-neutral-bg);
  --pico-border-color: var(--pico-primary);
  --pico-color: var(--pico-contrast);
}
button.btn-danger:not(.primary),
[role="button"].btn-danger:not(.primary) {
  --pico-background-color: transparent;
  --pico-border-color: var(--vpn-err);
  --pico-color: var(--vpn-err);
  --pico-box-shadow: none;
}
button.btn-danger:not(.primary):is(:hover, :focus, :active),
[role="button"].btn-danger:not(.primary):is(:hover, :focus, :active) {
  --pico-background-color: var(--vpn-err-bg);
  --pico-border-color: var(--vpn-err);
  --pico-color: var(--vpn-err);
}
/* A submit button of a card form is as wide as its label on a desktop, not
   the whole column */
@media (min-width: 768px) {
  main form:not(.inline-form, [role="search"]) > button[type="submit"] { width: auto; min-width: 12rem; }
}

/* Buttons in rows and small forms */
.inline-form { display: inline-block; margin: 0; }
.inline-form button,
.row-actions button,
.row-actions [role="button"] { width: auto; margin-bottom: 0; }
.row-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  margin-bottom: var(--vpn-gap);
}
.row-actions > .inline-form:has(.btn-danger) { margin-inline-start: auto; }
.table-scroll .row-actions { margin-bottom: 0; }
/* Rare and dangerous actions of a row (reissue and delete a device, detach a
   template): the summary is a button, and the forms open on their own line
   under the row's buttons instead of widening the row */
details.row-confirm { display: inline-block; margin: 0; vertical-align: middle; }
details.row-confirm > summary[role="button"] { display: inline-block; width: auto; text-align: center; line-height: var(--pico-line-height); }
details.row-confirm > summary::after { display: none; }
details.row-confirm > summary::-webkit-details-marker { display: none; }
details.row-confirm[open] { flex-basis: 100%; }
details.row-confirm > form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  margin: 0.5rem 0 0;
  white-space: normal;
}
details.row-confirm > form > p { flex-basis: 100%; margin: 0; }
details.row-confirm > form > button { width: auto; margin: 0; }
.icon-button { min-width: var(--vpn-touch); padding-inline: 0.5rem; }

/* Busy state: htmx sets .htmx-request on the element issuing the request */
.htmx-request button,
button.htmx-request,
form.htmx-request button { opacity: 0.6; cursor: progress; }
.htmx-indicator { opacity: 0; }
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator { opacity: 1; transition: opacity 200ms ease-in; }

/* Flash messages: a toast above the tab bar, bottom right on a desktop */
.flash-area {
  position: fixed;
  left: 50%;
  bottom: calc(var(--vpn-tabbar) + env(safe-area-inset-bottom) + 0.75rem);
  z-index: 30;
  width: max-content;
  max-width: min(32rem, calc(100vw - 2rem));
  transform: translateX(-50%);
}
.flash-area:empty { display: none; }
/* On phones the toast sits at the top: at the bottom it covered the fields
   and the submit button of the form the admin had just sent */
@media (max-width: 767px) {
  .flash-area { top: calc(env(safe-area-inset-top) + 0.5rem); bottom: auto; }
}
@media (min-width: 768px) {
  .flash-area { left: auto; right: 1.5rem; bottom: 1.5rem; transform: none; }
}
/* .flash is also used for notes and form errors inside the page flow */
.flash {
  margin-bottom: var(--vpn-gap);
  padding: 0.75rem 1rem;
  border-radius: var(--pico-border-radius);
  border-left: 4px solid currentColor;
  background: var(--vpn-neutral-bg);
}
.flash-area .flash {
  margin-bottom: 0;
  background: var(--pico-card-background-color);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
}
.flash-success { color: var(--vpn-ok); }
.flash-error { color: var(--vpn-err); }
.flash-info { color: var(--pico-primary); }
.flash-warn { color: var(--vpn-warn); }
.flash a { margin-left: 0.5rem; }
small.field-error,
p.field-error {
  display: block;
  margin-top: -0.5rem;
  margin-bottom: var(--vpn-gap);
  color: var(--vpn-err);
}
.muted { color: var(--pico-muted-color); }

/* Status chips */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  height: 24px;
  padding: 0 0.5rem;
  border-radius: 999px;
  background: var(--vpn-neutral-bg);
  color: var(--vpn-neutral);
  font-size: 0.8125rem;
  line-height: 1;
  white-space: nowrap;
  vertical-align: middle;
}
.badge::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.badge-on { background: var(--vpn-ok-bg); color: var(--vpn-ok); }
.badge-warn { background: var(--vpn-warn-bg); color: var(--vpn-warn); }
.badge-err,
.badge-off { background: var(--vpn-err-bg); color: var(--vpn-err); }
.count-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  margin-left: 0.25rem;
  padding: 0 0.375rem;
  border-radius: 999px;
  background: var(--vpn-warn-bg);
  color: var(--vpn-warn);
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1;
}

/* Tables: a table from 1024px, cards below (the lists of users and nodes
   have seven columns and do not fit a tablet) */
.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin-bottom: var(--vpn-gap);
}
.table-scroll table { margin-bottom: 0; }
.table-scroll th,
.table-scroll td { vertical-align: middle; overflow-wrap: break-word; }
.table-scroll td:has(> code),
.table-scroll td:has(> .copy-field) { overflow-wrap: anywhere; }
.table-scroll td > small { vertical-align: middle; }
/* A profile name moves to the next line whole instead of breaking at its hyphen */
.table-scroll td[data-label="Профили"] > span { display: inline-block; }
@media (min-width: 1024px) {
  .table-scroll td[data-label="Профили"] > span { white-space: nowrap; }
}
.table-scroll .row-actions > .inline-form:has(.btn-danger) { margin-inline-start: 0; }
tbody:has(> tr:not(.empty-row)) > tr.empty-row { display: none; }
.num { text-align: right; font-variant-numeric: tabular-nums; }
tr.subtotal td { font-weight: 600; }
@media (min-width: 1024px) and (max-width: 1199px) {
  .table-scroll th,
  .table-scroll td { padding-inline: 0.5rem; }
}
@media (min-width: 1200px) {
  .table-scroll th,
  .table-scroll td { padding-inline: 0.75rem; }
  .table-scroll thead th { white-space: nowrap; }
}
@media (min-width: 1024px) {
  .table-scroll td { max-width: 24rem; }
  .table-scroll td.num,
  .table-scroll th.num,
  .table-scroll td:has(> time),
  .table-scroll td:has(.badge),
  .table-scroll td:has(.row-actions) { white-space: nowrap; }
  .table-scroll td:has(.row-actions) { max-width: none; width: 1%; }
  .table-scroll td[data-label="Профили"] { min-width: 10rem; }
  .table-scroll .row-actions { flex-wrap: nowrap; }
  .table-scroll .row-actions:has(> details[open]) { flex-wrap: wrap; }
  /* Devices have up to seven columns and three buttons: when the screen is
     too narrow, two status badges stack and the buttons wrap instead of the
     row running past the edge of the page */
  .device-table td:has(.badge),
  .device-table td:has(.row-actions) { white-space: normal; }
  .device-table td:has(.row-actions) { width: auto; }
  .device-table .row-actions { flex-wrap: wrap; }
  .device-table td .badge { margin-block: 2px; }
  .table-scroll .row-actions button,
  .table-scroll .row-actions [role="button"] {
    min-height: 36px;
    padding: 0.25rem 0.625rem;
    font-size: 0.875rem;
  }
}
@media (max-width: 1023px) {
  .table-scroll { overflow-x: visible; }
  .table-scroll table,
  .table-scroll tbody,
  .table-scroll tfoot,
  .table-scroll tr,
  .table-scroll td,
  .table-scroll th[scope="row"] { display: block; }
  .table-scroll thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .table-scroll table.striped { --pico-table-row-stripped-background-color: transparent; }
  .table-scroll tbody > tr,
  .table-scroll tfoot > tr {
    margin-bottom: 0.75rem;
    padding: 0.75rem;
    border: 1px solid var(--vpn-line);
    border-radius: var(--pico-border-radius);
    background: none;
  }
  .table-scroll td,
  .table-scroll th[scope="row"] {
    padding: 0.125rem 0;
    border: 0;
    text-align: left;
  }
  .table-scroll td.num { text-align: left; }
  .table-scroll td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: 0.75rem;
    color: var(--pico-muted-color);
  }
  .table-scroll tbody > tr:not(.empty-row) > td:first-child { font-size: 1.0625rem; font-weight: 600; }
  .table-scroll tbody > tr > td:first-child::before { display: none; }
  .table-scroll td:has(.row-actions) { margin-top: 0.5rem; }
  .table-scroll td:has(.row-actions)::before { display: none; }
  .table-scroll .row-actions { flex-wrap: wrap; }
  /* The name is the only way into the card of the row */
  .table-scroll tbody > tr > td:first-child > a,
  .table-scroll td a:has(> .badge) { display: inline-flex; align-items: center; min-height: var(--vpn-touch); }
  /* Traffic: a day and a node on one line, the three numbers on the next */
  .user-traffic tbody > tr,
  .user-traffic tfoot > tr {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: 0.5rem;
    margin-bottom: 0.5rem;
    padding: 0.5rem 0.75rem;
  }
  .user-traffic tr > td:nth-child(2):not(.num) { grid-column: span 2; }
  .user-traffic tfoot th[scope="row"] { grid-column: 1 / -1; font-weight: 600; }
  .user-traffic tbody > tr > td:first-child { font-size: 1rem; }
  .user-traffic td.num::before { color: var(--pico-muted-color); font-size: 0.75rem; }
  .user-traffic td.num:nth-last-child(3)::before { content: "↑ "; }
  .user-traffic td.num:nth-last-child(2)::before { content: "↓ "; }
  .user-traffic td.num:nth-last-child(1)::before { content: "всего "; }
}
@media (max-width: 359px) {
  /* Three columns of 68px break a date inside: the day and the node, the two
     directions, then the total on a line of its own */
  .user-traffic tbody > tr,
  .user-traffic tfoot > tr { grid-template-columns: max-content minmax(0, 1fr); }
  .user-traffic tr > td:first-child { white-space: nowrap; }
  .user-traffic tr > td:nth-child(2):not(.num) { grid-column: auto; }
  .user-traffic td.num:last-child { grid-column: 1 / -1; }
}
@media (min-width: 600px) and (max-width: 1023px) {
  /* Cards of a list in two or three columns on a tablet */
  .table-scroll table:not(.audit-table) > tbody:not(:has(> tr.subtotal, > tr > td:first-child > time)) {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
    gap: 0.75rem;
  }
  .table-scroll table:not(.audit-table) > tbody:not(:has(> tr.subtotal, > tr > td:first-child > time)) > tr { margin-bottom: 0; }
}

/* Copy fields, QR code, ordered lists, empty states */
.copy-field { margin-bottom: var(--vpn-gap); }
.copy-field textarea,
.copy-field input,
textarea.code {
  font-family: var(--pico-font-family-monospace);
  font-size: 0.875em;
  overflow-wrap: anywhere;
}
.copy-field textarea { margin-bottom: 0.25rem; }
.copy-textarea { display: flex; flex-direction: column; align-items: flex-end; }
.copy-textarea textarea { width: 100%; }
.copy-button {
  min-width: 9.5rem;
  margin-bottom: 0;
  white-space: nowrap;
}
.qr img {
  display: block;
  width: 100%;
  max-width: 18rem;
  background: #fff;
  border-radius: var(--pico-border-radius);
}
.order-badge {
  margin-left: auto;
  min-width: 1.5rem;
  text-align: center;
  font-weight: 600;
  color: var(--pico-primary);
}
.ordered-list ol { padding-left: 0; list-style: none; counter-reset: ordered; }
.ordered-list li::before {
  counter-increment: ordered;
  content: counter(ordered) ".";
  min-width: 1.25rem;
  color: var(--pico-muted-color);
}
.ordered-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}
.ordered-list .ordered-label { flex: 1 1 8rem; }
.empty-state {
  padding: 1rem;
  border: 1px dashed var(--vpn-line);
  border-radius: var(--pico-border-radius);
  text-align: center;
  margin-bottom: var(--vpn-gap);
}
.empty-state p { margin-bottom: 0; }
.empty-state p + p { margin-top: 0.75rem; }
.empty-state [role="button"] { width: auto; }

/* Collapsed help */
details.help { margin-bottom: var(--vpn-gap); }
details.help > summary,
details.more > summary { color: var(--pico-muted-color); }
details.help > summary,
details.more > summary,
.device-card details > summary,
.node-card section details > summary { font-size: 0.9375rem; }
/* Pico mutes and spaces a help text only after a field: after a switch it is ours */
label:has(> input[type="checkbox"]) + small:not(.field-error) {
  display: block;
  margin-bottom: var(--vpn-gap);
  color: var(--pico-muted-color);
}
small + details.help { margin-top: 0.5rem; }
details.help p:last-child { margin-bottom: 0; }

/* Login */
.login-card { max-width: 24rem; margin: 10vh auto 0; }
.login-card h1 { --pico-font-size: 1.5rem; margin-bottom: 0.25rem; }

/* Device cards (user card, pending devices): one column, a grid from 768px */
.device-cards { display: grid; grid-template-columns: 1fr; gap: var(--vpn-gap); margin-bottom: var(--vpn-gap); }
@media (min-width: 768px) { .device-cards { grid-template-columns: repeat(auto-fill, minmax(min(22rem, 100%), 1fr)); } }
.device-card { margin: 0; }
.device-card > header { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; justify-content: space-between; }
.device-card details { margin-bottom: 0; }
.device-card details[open] { margin-bottom: 0.5rem; }
/* Both actions of a device are dangerous: no lone button at the far right */
.device-card .row-actions > .inline-form:has(.btn-danger) { margin-inline-start: 0; }
.device-facts, .device-details { font-size: 0.9em; }
.device-details { padding-left: 1.25rem; }
.device-settings [role="group"] { max-width: 20rem; }
.device-settings small { display: block; margin-bottom: 0.75rem; }

/* Cards of a node, a profile and a connection (UX-2b): a header with chips and
   one quiet action, collapsed panels for the rest, a danger zone at the bottom */
.card-head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: start;
  justify-content: space-between;
}
.card-head hgroup { margin-bottom: 0; }
/* A name of 64 letters without a space must wrap, not widen the card */
.card-head > hgroup,
.user-head > hgroup,
.device-card > header > *,
.ordered-label { min-width: 0; overflow-wrap: anywhere; }
.card-head .chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  margin: 0.25rem 0;
}
.card-head .row-actions { margin-bottom: 0; }
.user-card h2,
.node-card h2,
.profile-card h2,
.connection-card h2 { --pico-font-size: 1.0625rem; --pico-typography-spacing-top: 1rem; }
.sr-title,
.users-filter label,
.app-panel .sub-instruction-title,
details.help > label[for$="-client-settings"] {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
details.panel,
details.sub-other {
  border: 1px solid var(--vpn-line);
  border-radius: var(--pico-border-radius);
  padding: 0.5rem 0.75rem;
  margin-bottom: 0.75rem;
}
/* A summary is a row to tap: as tall as a button, its text on the left and
   the chevron pinned to the right, so a long title wraps without pushing the
   chevron to a line of its own (Pico floats it and sets line-height 1rem) */
details.panel > summary,
details.sub-other > summary,
details.help > summary,
details.more > summary,
.device-card details > summary,
.node-card section details > summary {
  position: relative;
  display: flex;
  align-items: center;
  min-height: var(--vpn-touch);
  padding: 0.25rem 1.75rem 0.25rem 0;
  line-height: 1.25;
}
details.panel > summary::after,
details.sub-other > summary::after,
details.help > summary::after,
details.more > summary::after,
.device-card details > summary::after,
.node-card section details > summary::after { position: absolute; right: 0; top: 50%; margin: -0.5rem 0 0; }
details.panel > summary,
details.sub-other > summary { font-size: 1.0625rem; font-weight: 600; }
/* Pico greys the summary of an open details with three classes worth of specificity */
details.panel > summary:not([role]):not(.x),
details.sub-other > summary:not([role]):not(.x) { color: var(--pico-color); }
details.panel.danger-zone > summary:not([role]):not(.x) { color: var(--vpn-err); }
details.panel[open] > summary,
details.sub-other[open] > summary { border-bottom: 1px solid var(--vpn-line); margin-bottom: 0.75rem; }
.device-card details[open] > summary,
.node-card section details[open] > summary { margin-bottom: 0.25rem; }
details.panel section:last-child,
details.panel form:last-child { margin-bottom: 0; }
.danger-zone {
  border: 1px solid var(--vpn-err);
  border-radius: var(--pico-border-radius);
  padding: 0.75rem;
}
.danger-zone h2 { margin-top: 0; color: var(--vpn-err); }
.danger-zone p:last-child { margin-bottom: 0; }
.danger-zone .row-actions { margin-bottom: 0.5rem; }
.danger-zone .row-actions > .inline-form:has(.btn-danger) { margin-inline-start: 0; }

/* Node parameters: label and value wrap instead of being cut off */
.node-facts { margin-bottom: var(--vpn-gap); }
.node-facts th[scope="row"],
.node-facts td {
  padding: 0.25rem 0.5rem 0.25rem 0;
  border-bottom: 1px solid var(--vpn-line);
  overflow-wrap: anywhere;
  text-align: left;
  vertical-align: top;
}
.node-facts th[scope="row"] { width: 14rem; font-weight: 400; color: var(--pico-muted-color); }
@media (max-width: 767px) {
  .node-facts tr,
  .node-facts th[scope="row"],
  .node-facts td { display: block; }
  .node-facts th[scope="row"] { width: auto; border-bottom: 0; padding-bottom: 0; }
}
.copy-inline {
  font-size: 0.8125rem;
  display: inline-block;
  width: auto;
  min-width: 0;
  min-height: 0;
  margin: 0 0 0 0.5rem;
  padding: 0.125rem 0.5rem;
  line-height: 1.4;
  vertical-align: baseline;
}
.node-facts th[scope="row"],
.node-facts td { line-height: 1.8; }
/* A small button with a finger-sized hit area */
.copy-inline { position: relative; }
.copy-inline::before { content: ""; position: absolute; inset: -8px -4px; }
@media (min-width: 768px) {
  /* A wrapped button starts at the left edge of its value */
  .node-facts .copy-inline { margin-left: 0; }
  .node-facts td > :has(+ .copy-inline) { margin-right: 0.5rem; }
}
@media (max-width: 359px) {
  .node-reports pre > code { padding: 0.5rem; }
}
@media (max-width: 767px) {
  .node-facts td:has(> .copy-inline) { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 0.5rem; }
  .node-facts .copy-inline { margin-left: 0; }
  /* Safari zooms the page when a focused field has text under 16px */
  .copy-field textarea,
  .copy-field input,
  textarea.code,
  textarea#user-instruction { font-size: 1rem; }
  #node-base-config { max-height: 50vh; }
  /* Three nested insets leave 215px of a 320px screen */
  .user-card,
  .node-card,
  .profile-card,
  .connection-card { --pico-block-spacing-horizontal: 0.75rem; }
  details.panel,
  details.sub-other { padding-inline: 0.5rem; }
}
.link-list { padding-left: 1.25rem; }
.connection-card textarea.code { min-height: 10rem; }
.connection-mode p,
.connection-notes p { font-size: 0.9375rem; }
.link-list li { margin-bottom: 0.25rem; }

/* Journal: day groups, the human label of an action, details on their own row */
.filter-chips ul {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  padding: 0;
  margin-bottom: 0.75rem;
  list-style: none;
}
.filter-chips li { padding: 0; }
/* Pico gives nav links negative margins (chips would overlap) and shifts the
   lists of a nav to the left of the page edge */
.filter-chips a { margin: 0; }
nav.filter-chips ul { margin-inline: 0; }
.chip-link {
  display: inline-flex;
  align-items: center;
  min-height: 36px;
  padding: 0 0.625rem;
  border: 1px solid var(--vpn-line);
  border-radius: 999px;
  font-size: 0.875rem;
  text-decoration: none;
  color: var(--pico-contrast);
}
.chip-link[aria-current] { background: var(--vpn-neutral-bg); font-weight: 600; }
.audit-table .audit-day th {
  padding-top: 1rem;
  border-bottom: 1px solid var(--vpn-line);
  color: var(--pico-muted-color);
  font-size: 0.875rem;
  text-align: left;
}
.audit-action { font-weight: 600; }
.audit-table .audit-details td { padding-top: 0; color: var(--pico-muted-color); }
@media (min-width: 1024px) {
  /* Pico stripes every odd row and counts the day and details rows: the
     zebra flipped at every day. Entries are tinted, the rest is plain */
  .audit-table tbody > tr.audit-day,
  .audit-table tbody > tr.audit-details { --pico-table-row-stripped-background-color: transparent; }
  .audit-table tbody > tr:not(.audit-day, .audit-details) > td { background-color: var(--pico-table-row-stripped-background-color); }
  .audit-table tbody > tr:has(+ tr.audit-details) > td { border-bottom: 0; }
  .audit-table .audit-details td { max-width: none; overflow-wrap: anywhere; }
  /* The action cell holds a label, a code and a badge: it must wrap, or the
     badge runs into the next column */
  .audit-table td:has(.badge) { white-space: normal; }
}
@media (max-width: 767px) {
  .chip-link { min-height: var(--vpn-touch); }
  /* Six chips took four rows of a phone: one row that scrolls sideways */
  nav.filter-chips ul { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; margin-inline: -16px; padding-inline: 16px; }
  .filter-chips li { flex: 0 0 auto; }
}
@media (min-width: 768px) and (max-width: 1023px) {
  /* A journal entry of a tablet is a row inside its card, not four stacked pairs */
  .table-scroll .audit-table tbody > tr[id^="audit-row-"] {
    display: grid;
    grid-template-columns: 4.5rem minmax(6rem, 9rem) minmax(0, 1fr) minmax(0, 14rem);
    column-gap: 0.75rem;
    align-items: start;
  }
}
@media (max-width: 1023px) {
  .node-reports pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  /* A day is a heading between the cards, not a card; an entry and its
     details are one card */
  .table-scroll tbody > tr.audit-day { margin: 0.75rem 0 0.25rem; padding: 0; border: 0; }
  .table-scroll .audit-day th { display: block; padding: 0; border: 0; background: none; }
  .table-scroll tbody > tr:has(+ tr.audit-details) {
    margin-bottom: 0;
    padding-bottom: 0.25rem;
    border-bottom: 0;
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
  }
  .table-scroll tbody > tr.audit-details {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
    border-top-left-radius: 0;
    border-top-right-radius: 0;
  }
  .table-scroll tbody > tr.audit-details > td:first-child { font-size: 0.9375rem; font-weight: 400; }
}

/* User card (UX-2a): the header with the single quiet action, the facts line,
   the collapsed panels and the danger zone at the bottom. */
.pending-context { font-size: 0.9em; color: var(--pico-muted-color); }
.user-head { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: flex-start; justify-content: space-between; }
.user-head hgroup { margin-bottom: 0; }
.user-head-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: flex-start; }
.user-head-actions > details { margin-bottom: 0; }
.user-head-actions > details > summary { min-height: var(--vpn-touch); display: flex; align-items: center; }
.user-facts { color: var(--pico-muted-color); font-size: 0.9em; margin-bottom: var(--vpn-gap); }
details.panel.danger-zone { border-color: var(--vpn-err); }
.danger-item { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 0.75rem; }
.danger-item p { margin: 0; flex: 1 1 18rem; }
@media (min-width: 768px) {
  /* One column of buttons, so the explanations start at one line */
  .danger-item > .inline-form { flex: 0 0 15rem; }
  .danger-item > .inline-form > button { width: 100%; }
}
.invite-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.5rem; }
.user-connection small { display: block; margin-bottom: var(--vpn-gap); }
.user-connection [role="group"] { margin-bottom: 0.25rem; }

/* Dashboard (UX-3a): the summary tiles, the attention list and the short
   event feed of the overview at GET /. */
.tiles {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.5rem;
  margin-bottom: var(--vpn-gap);
}
@media (max-width: 599px) {
  /* The traffic tile holds two numbers: it takes the row; without it an odd
     last tile does */
  .tiles { grid-auto-flow: dense; }
  .tiles > .tile:has(.traffic),
  .tiles:not(:has(.traffic)) > .tile:last-child:nth-child(odd) { grid-column: 1 / -1; }
}
@media (min-width: 600px) and (max-width: 1023px) {
  /* Five tiles as three and two without a hole */
  .tiles { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .tile { grid-column: span 2; }
  .tile:nth-child(n+4):nth-last-child(-n+2) { grid-column: span 3; }
}
@media (min-width: 1024px) {
  .tiles { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}
.tile {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-height: var(--vpn-touch);
  padding: 0.75rem;
  border: 1px solid var(--vpn-line);
  border-radius: var(--pico-border-radius);
  background: var(--pico-card-background-color);
  color: inherit;
  text-decoration: none;
}
.tile-label { font-size: 0.875rem; color: var(--pico-muted-color); }
.tile-value { font-size: 1.25rem; font-weight: 600; line-height: 1.2; overflow-wrap: anywhere; }
.tile-value .traffic { font-size: 1.0625rem; }
.tile-warn { border-color: var(--vpn-warn); background: var(--vpn-warn-bg); }
.tile-err { border-color: var(--vpn-err); background: var(--vpn-err-bg); }
.attention-list,
.event-list { list-style: none; padding: 0; }
.attention-list > li,
.event-list > li {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  align-items: baseline;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--vpn-line);
}
@media (max-width: 767px) {
  /* The time is a line above every event, whatever the length of its name */
  .event-list > li > time { flex: 1 1 100%; font-size: 0.875rem; color: var(--pico-muted-color); }
}
.attention-text { flex: 1 1 14rem; }
.event-entity { flex: 1 1 12rem; }

/* Users filter and diagnostics (UX-3b): the search row of the users list, the
   state chips of the current filter and the "Почему не работает" block. */
.users-filter {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  margin-bottom: 0.75rem;
}
.users-filter input[type="search"] { flex: 1 1 12rem; margin: 0; }
.users-filter select { flex: 1 1 9rem; max-width: 14rem; margin: 0; }
/* Pico rounds a search form into a pill and squares the inner corners */
#users-filter,
#users-filter > * { --pico-border-radius: 0.25rem; }
#users-filter > * { border-radius: var(--pico-border-radius); margin-left: 0; }
.users-filter button { flex: 0 0 auto; width: auto; margin: 0; }
@media (max-width: 479px) {
  /* The search takes the row, the order and the button share the next one */
  .users-filter input[type="search"] { flex: 1 1 100%; }
  .users-filter select { max-width: none; }
}
.user-problems { margin-bottom: var(--vpn-gap); }
.user-problems h2 { margin-bottom: 0.5rem; }
.user-problem {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  padding: 0.5rem 0.75rem;
  margin-bottom: 0.5rem;
  border-left: 4px solid var(--vpn-warn);
  border-radius: var(--pico-border-radius);
  background: var(--vpn-warn-bg);
}
.user-problem p { margin: 0; flex: 1 1 18rem; }
.user-problem-err { border-left-color: var(--vpn-err); background: var(--vpn-err-bg); }
.server-fresh { margin: -0.5rem 0 1.5rem; }

/* Subscription: one panel per application, one open at a time */
.app-panel .qr { margin-bottom: 0.5rem; }
.qr-app { color: var(--vpn-warn); }

/* Separate links of the subscription: a panel like the application ones, its
   fields in compact rows with small labels; the deep links are quiet text
   links, not buttons */
.sub-other label,
.sub-happ label {
  margin-bottom: 0.25rem;
  font-size: 0.875rem;
  color: var(--pico-muted-color);
}
.sub-other .copy-field,
.sub-happ .copy-field { margin-bottom: 0.75rem; }
.sub-other > p { margin-bottom: 0.75rem; }
.sub-other .sub-instruction-title { --pico-font-size: 0.9375rem; margin: 1rem 0 0.25rem; }
.sub-other > p:has(> [role="button"]) { margin: 0.5rem 0 0; }
.sub-other > p > [role="button"].outline:not(.btn-danger) {
  display: block;
  min-height: 0;
  padding: 0.75rem 0;
  border: 0;
  font-size: 0.875rem;
  text-align: left;
  text-decoration: underline;
  --pico-color: var(--pico-primary);
  --pico-background-color: transparent;
}
.sub-other > p > [role="button"].outline:not(.btn-danger)::after {
  content: " — открыть на этом устройстве";
  display: inline-block;
  margin-left: 0.25rem;
  color: var(--pico-muted-color);
}
textarea#user-instruction {
  font-family: inherit;
  font-size: 0.9375rem;
  line-height: 1.5;
}

/* Project additions */
.qr svg { display: block; width: 100%; max-width: 16rem; height: auto; background: #fff; border-radius: var(--pico-border-radius); }
pre.nft { white-space: pre; font-size: 0.8125rem; }
.secret-once { border-left: 4px solid var(--vpn-warn); padding-left: 0.75rem; }
fieldset.checks label { min-height: var(--vpn-touch); }
.impact ul { margin-bottom: 0.5rem; }

/* Radio and checkbox choices with a description (MCP scopes): the input
   keeps its own column, the text wraps beside it */
label.choice { display: flex; align-items: flex-start; gap: 0.5rem; margin-bottom: 0.75rem; }
label.choice > input { flex: none; margin: 0.2em 0 0; }
label.choice > span { flex: 1 1 auto; min-width: 0; }
label.choice small { display: block; }

/* The overview block "Требует внимания" */
.attention { margin-bottom: var(--vpn-gap); }
/* No list indent: the badge already marks the items, and on a phone the
   indent squeezed the text into a narrow column */
.attention ul { margin-bottom: 0; padding-inline-start: 0; }
.attention li { list-style: none; margin-inline-start: 0; }
.attention-ok { color: var(--vpn-ok); }
/* Audit details: one change per line ("DNS клиентов: a → b") */
.audit-detail { display: block; }
