/* Visible feedback: a press, an action still in progress, a page or dialog appearing. */
:root{--ui-accent:#285c8e;--ui-progress:#2f7fd0}
html[data-crew-mode=dark]{--ui-accent:#8ec1ef;--ui-progress:#8ec1ef}
button,.nav-button,[role="button"],select,summary,input[type="checkbox"],input[type="radio"]{transition:transform .12s cubic-bezier(.2,.8,.2,1),background-color .15s ease,border-color .15s ease,color .15s ease,box-shadow .15s ease,opacity .15s ease;-webkit-tap-highlight-color:transparent}
button:not(:disabled):active,[role="button"]:active,summary:active{transform:translateY(1px) scale(.97)}
select:not(:disabled):active{transform:scale(.985)}
button:focus-visible,select:focus-visible,input:focus-visible,summary:focus-visible,[role="button"]:focus-visible{outline:2px solid var(--ui-accent);outline-offset:2px}
/* Keep label metrics stable when the active route changes on the mobile strip. */
@media (max-width:800px){:root:not([data-crew-mode=accessible]) .sidebar .nav-button{font-weight:750}}
:where(.ui-pending){position:relative}
.ui-pending{cursor:progress;opacity:.85}
.ui-pending::after{content:"";position:absolute;right:4px;top:4px;width:14px;height:14px;box-sizing:border-box;pointer-events:none;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:spin .7s linear infinite}
.ui-progress{position:fixed;top:0;left:0;height:3px;width:100%;transform:scaleX(0);transform-origin:left;background:var(--ui-progress);box-shadow:0 0 10px var(--ui-progress);border-radius:0 3px 3px 0;z-index:10000;opacity:0;pointer-events:none;transition:opacity .25s ease}
.ui-progress.is-active{opacity:1}
.ui-progress.is-finishing{transition:transform .18s ease-out,opacity .25s ease}
.ui-pending.nav-button::after,.ui-pending[data-route]::after{content:none}
/* Refresh buttons: the button's own arrows turn while the data loads. */
.is-refreshing svg{animation:ui-refresh-spin .8s linear infinite;transform-origin:50% 50%}
.is-refreshing,.is-refreshed{cursor:default}
@keyframes ui-refresh-spin{to{transform:rotate(360deg)}}
tr.saving td{animation:ui-saving .9s ease-in-out infinite alternate}
/* A dialog arrives solid and slides up a little: fading the light panel in over the page read as a white flash,
   and the old scale made its edges creep sideways. Only the backdrop fades. */
dialog[open]{animation:ui-dialog-in .18s cubic-bezier(.22,.61,.36,1)}
dialog[open]::backdrop{animation:ui-fade-in .18s ease}
/* Long lists in dialogs (the summary «Открыть список», up to ~300 people): only rows on screen are laid out, so the
   dialog opens at once instead of after half a second. */
.summary-person{content-visibility:auto;contain-intrinsic-size:auto 112px}
.toast{transition:opacity .2s ease,transform .2s ease}
@keyframes ui-saving{from{opacity:1}to{opacity:.55}}
@keyframes ui-dialog-in{from{transform:translateY(10px)}to{transform:none}}
@keyframes ui-fade-in{from{opacity:0}to{opacity:1}}
@media (prefers-reduced-motion:reduce){
  button,.nav-button,[role="button"],select,summary,input[type="checkbox"],input[type="radio"]{transition:none}
  button:not(:disabled):active,[role="button"]:active,summary:active,select:not(:disabled):active{transform:none}
  tr.saving td,dialog[open],dialog[open]::backdrop{animation:none}
  .ui-pending::after{animation-duration:1.6s}
  .ui-progress,.ui-progress.is-finishing{transition:none}
  .is-refreshing svg{animation:none}
}

/* Icon feedback leaves ::after available for the existing 44px hit area. */
.ui-pending-icon{cursor:progress}
.ui-pending-icon svg{animation:ui-pending-pulse .7s ease-in-out infinite alternate}
@keyframes ui-pending-pulse{from{opacity:1}to{opacity:.35}}
.ui-refresh-icon{width:1em;height:1em;flex-shrink:0;vertical-align:middle;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;margin-inline-end:.35em}
@media (prefers-reduced-motion:reduce){.ui-pending-icon svg{animation:none;opacity:.55}}
