/* ===== interaction / touch polish ===== */

:root{
  --ui-target:44px;
}

/* Последний слой не должен уменьшать accessibility hit areas. */
.period,
nav.tabs button,
.date-calendar-title,
.date-calendar-nav,
.date-day,
.date-today,
.month-today,
.month-option,
.date-jump-month,
.picker-toolbar-btn,
.lnk,
.tariff-history-actions button,
.tariff-inline-close{
  min-height:var(--ui-target);
}

.nav > button,
.date-calendar-nav{
  width:var(--ui-target);
  height:var(--ui-target);
  min-width:var(--ui-target);
}

nav.tabs{
  min-height:52px;
}

nav.tabs button{
  min-height:44px;
}

.date-calendar-head{
  grid-template-columns:44px minmax(0,1fr) 44px;
}

.date-calendar-title{
  padding-right:10px;
  padding-left:10px;
  white-space:nowrap;
}

.date-day{
  height:44px;
}

.date-today,
.month-today{
  height:44px;
}

.date-jump-month,
.month-option{
  min-height:44px;
}

/* Маленькая иконка удаления остаётся визуально компактной, hit area — нет. */
.payout-record{
  grid-template-columns:minmax(0,1fr) auto 44px;
}

.payout-record > button{
  width:44px;
  height:44px;
  display:grid;
  place-items:center;
}

.tariff-history-actions button,
.tariff-inline-close{
  min-height:44px;
}

/* Заголовок picker не может заходить под Отмена / Готово. */
.picker-toolbar{
  min-height:44px;
  height:44px;
}

.picker-toolbar-btn{
  position:relative;
  z-index:2;
  min-width:clamp(58px,18vw,72px);
  padding-right:4px;
  padding-left:4px;
}

.picker-toolbar-title{
  left:clamp(76px,21vw,84px);
  right:clamp(76px,21vw,84px);
  width:auto;
  max-width:none;
  transform:translateY(-50%);
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
  text-align:center;
}

/* Sheet toolbar использует такой же безопасный центральный диапазон. */
.shead{
  grid-template-columns:minmax(58px,1fr) minmax(0,auto) minmax(58px,1fr);
  column-gap:6px;
}

.shead .ttl{
  max-width:min(44vw,320px);
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
}

.shead .lnk{
  min-width:0;
  display:inline-flex;
  align-items:center;
}

/*
  Защита от горизонтального переполнения на узких и складных экранах.

  main сюда не входит: её ширину задаёт мера контента, а max-width:100%
  из этого слоя перебивала её как более позднее правило той же
  специфичности. Раздел «Смены» из-за этого растягивался на всю ширину
  монитора, пока остальные разделы держались своей меры. Содержимое main
  не переполняет её и без этого: у неё overflow-x:hidden.
*/
html,
body,
header,
.bottom-controls{
  max-width:100%;
}

header{
  padding-left:calc(var(--ui-gutter,16px) + env(safe-area-inset-left));
  padding-right:calc(var(--ui-gutter,16px) + env(safe-area-inset-right));
}

main{
  padding-left:calc(var(--ui-gutter,16px) + env(safe-area-inset-left));
  padding-right:calc(var(--ui-gutter,16px) + env(safe-area-inset-right));
  scroll-padding-top:calc(92px + env(safe-area-inset-top));
  scroll-padding-bottom:calc(92px + env(safe-area-inset-bottom));
}

.bottom-controls{
  padding-left:calc(8px + env(safe-area-inset-left));
  padding-right:calc(8px + env(safe-area-inset-right));
}

nav.tabs{
  width:min(100%,520px);
  max-width:100%;
}

/*
  Все разделы одной ширины.

  Раньше плитка растягивалась под длину слова, и панель перестраивалась
  от раздела к разделу: «Управление» шире «Итогов», активная подсветка
  каждый раз другого размера. Основа ноль и равный рост делят панель
  поровну на любой ширине — и в пилюле на телефоне, и в нижнем баре на
  мониторе.

  Ширину вкладок решает только это правило: файл подключается последним
  из тех, что их описывают, и прежние min-width из platform.css сюда уже
  не доходят.
*/
nav.tabs button{
  flex:1 1 0;
  min-width:0;
  overflow:hidden;
  text-overflow:ellipsis;
}

.sheet,
.point-picker,
.month-picker,
.date-picker{
  max-height:min(
    calc(
      var(--app-viewport-height,100dvh) -
      env(safe-area-inset-top) -
      6px
    ),
    calc(
      100dvh -
      env(safe-area-inset-top) -
      6px
    )
  );
}

.sbody,
.point-list{
  min-height:0;
  overscroll-behavior:contain;
}

.row,
.sh,
.manage-row,
.seg,
.seg button{
  min-width:0;
}

/*
  Ограничение ширины написано для строки «подпись — значение», где значение
  лежит прямо в .row и делит её ширину с подписью. Вложенные стопки значений
  (например .payout-summary-right) образуют собственный блок шириной по
  содержимому, и там 58% отмеряются уже от него: «15 000 ₽» обрезалось до
  «15 0…» рядом с более широкой подписью состояния. Поэтому правило
  относится только к прямому значению строки.
*/
.row > .v{
  max-width:58%;
  overflow:hidden;
  text-overflow:ellipsis;
}

/* Один motion-contract для мыши, touch и pen. */
.nav > button:not(:disabled),
.period.clickable,
nav.tabs button,
.seg button,
.sh,
.manage-row,
.manage-back,
.manage-add,
.btn,
.point-row,
.employee-point,
.point-option,
.date-day,
.month-option,
.date-jump-month,
.date-calendar-nav,
.date-calendar-title,
.date-today,
.month-today,
.picker-toolbar-btn,
.lnk,
.payout-summary,
.payout-record > button,
.tariff-history-actions button,
.tariff-inline-close,
.app-confirm-btn{
  transition:
    transform var(--ui-fast) var(--ui-ease),
    background-color var(--ui-base) ease,
    border-color var(--ui-base) ease,
    color var(--ui-base) ease,
    opacity var(--ui-base) ease,
    box-shadow var(--ui-base) ease;
}

/*
  Сами состояния нажатия (мышь и касание) — в motion-reference.css, одним
  набором по видам элементов. Здесь их больше нет: прежний слой задавал
  всем одно сжатие и целиком перекрывался следующим файлом.
*/

/* Compact phones, включая узкие cover-screen складных устройств. */
@media (max-width:420px){
  :root{
    --ui-gutter:12px;
  }

  .date-day{
    height:44px;
  }

  .picker-toolbar-btn{
    font-size:13px;
  }

  .picker-toolbar-title{
    font-size:clamp(9px,2.7vw,10px);
    letter-spacing:.12em;
  }

  .row,
  .sh,
  .manage-row{
    gap:10px;
  }

  .row > .v{
    max-width:55%;
  }

  .seg button{
    padding-right:3px;
    padding-left:3px;
    font-size:clamp(10px,3vw,12px);
  }
}

/* На узком телефоне календарь использует реальную ширину sheet, а не сжимает 7 колонок. */
@media (max-width:370px){
  .date-weekdays,
  .date-grid{
    width:calc(100% + 28px);
    max-width:none;
    margin-right:-14px;
    margin-left:-14px;
    column-gap:0;
  }

  .tab-label-full{
    display:none;
  }

  .tab-label-short{
    display:inline;
  }

  nav.tabs button{
    padding-right:5px;
    padding-left:5px;
    font-size:11.5px;
  }

  .sh{
    gap:8px;
    padding-right:10px;
    padding-left:10px;
  }

  .sh .day{
    width:30px;
  }

  .sh .p{
    font-size:13.5px;
  }

  .sh .meta{
    font-size:10.5px;
  }

  .sh .amt{
    max-width:32%;
    overflow:hidden;
    font-size:13.5px;
    text-overflow:ellipsis;
  }
}

@media (max-width:319px){
  :root{
    --ui-gutter:10px;
  }

  nav.tabs{
    min-height:50px;
    padding:3px;
  }

  nav.tabs button{
    min-height:44px;
    padding-right:3px;
    padding-left:3px;
    font-size:10.5px;
  }

  .picker-toolbar-title,
  .shead .ttl{
    letter-spacing:.08em;
  }

  .shead{
    padding-right:10px;
    padding-left:10px;
  }

  .lnk{
    font-size:13px;
  }

  .row,
  .sh,
  .manage-row{
    padding-right:10px;
    padding-left:10px;
  }
}

/* Большие телефоны и раскрытые foldables используют доступную ширину, не превращаясь в desktop. */
@media (min-width:521px) and (max-width:899px){
  :root{
    --ui-gutter:20px;
  }

  header .nav,
  main{
    width:100%;
    max-width:760px;
    margin-right:auto;
    margin-left:auto;
  }

  nav.tabs{
    width:min(100%,560px);
  }

  .sheet,
  .point-picker{
    width:min(calc(100% - 24px),760px);
    max-width:760px;
    margin-right:auto;
    margin-left:auto;
  }
}

/* Низкие landscape-экраны: панели остаются доступными и не съедают рабочую область. */
@media (orientation:landscape) and (max-height:520px){
  header{
    padding-top:calc(6px + env(safe-area-inset-top));
    padding-bottom:6px;
  }

  main{
    padding-top:calc(64px + env(safe-area-inset-top));
    padding-bottom:calc(78px + env(safe-area-inset-bottom));
    scroll-padding-top:calc(68px + env(safe-area-inset-top));
    scroll-padding-bottom:calc(74px + env(safe-area-inset-bottom));
  }

  .bottom-controls{
    bottom:calc(4px + env(safe-area-inset-bottom));
  }

  nav.tabs{
    min-height:48px;
  }

  .sheet,
  .point-picker,
  .month-picker,
  .date-picker{
    max-height:min(
      calc(
        var(--app-viewport-height,100dvh) -
        env(safe-area-inset-top) -
        4px
      ),
      calc(
        100dvh -
        env(safe-area-inset-top) -
        4px
      )
    );
  }

  .grab{
    margin-top:5px;
  }
}

@media (prefers-reduced-motion:reduce){
  .nav > button,
  .period,
  nav.tabs button,
  .seg button,
  .sh,
  .manage-row,
  .manage-back,
  .manage-add,
  .btn,
  .point-row,
  .employee-point,
  .point-option,
  .date-day,
  .month-option,
  .date-jump-month,
  .date-calendar-nav,
  .date-calendar-title,
  .date-today,
  .month-today,
  .picker-toolbar-btn,
  .lnk,
  .payout-summary,
  .payout-record > button,
  .tariff-history-actions button,
  .tariff-inline-close,
  .app-confirm-btn{
    transition-duration:.001ms !important;
  }
}

/* Нижняя навигация является частью viewport, а не плавающим островом над контентом. */
:root{
  --bottom-tabs-height:52px;
  --bottom-dock-gap:6px;

  /*
    Отступ панели от нижней системной зоны телефона.

    iOS отдаёт окно приложению двумя разными способами, и панель обязана
    вставать одинаково в обоих. Если окно доходит до нижнего края экрана,
    полоса Home Indicator лежит внутри него и приходит через
    env(safe-area-inset-bottom). Если окно уже обрезано по безопасной
    области, та же полоса лежит за его нижней границей, а env даёт ноль.

    Поэтому запас под панелью — это системная зона плюс собственный зазор,
    а не «системная зона или зазор, что больше». Прежнее
    max(8px,env(safe-area-inset-bottom)) в первом случае прижимало панель
    вплотную к полосе Home Indicator, во втором оставляло над ней 8px, и
    одна и та же панель стояла на экране по-разному. Со сложением она в
    обоих случаях стоит на --bottom-dock-clearance выше системной зоны.

    Сам зазор взят у iOS: плавающая панель Safari стоит на 2px выше зоны
    Home Indicator, нижняя кнопка системного приложения такой же высоты
    52px — на 4px (замерено на iPhone 17 Pro Max, iOS 26.5). Берём меньшее
    из двух: панель разделов и так самая нижняя полоса приложения, и лишняя
    высота здесь отнимается у списка над ней.
  */
  --bottom-dock-clearance:2px;
  --bottom-dock-safe:calc(
    env(safe-area-inset-bottom) +
    var(--bottom-dock-clearance)
  );

  --bottom-dock-space:calc(
    var(--bottom-tabs-height) +
    var(--bottom-dock-gap) +
    var(--bottom-dock-safe)
  );
  --app-shell-height:100dvh;
}

.bottom-controls{
  bottom:0;
  min-height:var(--bottom-dock-space);
  padding:
    var(--bottom-dock-gap)
    calc(8px + env(safe-area-inset-right))
    var(--bottom-dock-safe)
    calc(8px + env(safe-area-inset-left));
  align-items:flex-start;
  background:var(--bg);
}

/*
  Под указателем мыши нижней системной зоны нет: под панелью остаётся
  только край окна, и зазор до него задаётся дизайном, а не телефоном.
*/
@media (hover:hover) and (pointer:fine){
  :root{
    --bottom-dock-clearance:10px;
  }
}

/*
  На большом экране навигация перестаёт быть плавающим островом.

  Пилюля с собственным фоном, рамкой и тенью — форма для телефона, где
  панель висит над содержимым в зоне большого пальца. На мониторе она
  читалась как чужой мобильный элемент: узкая полоса по центру, ничем не
  связанная с колонкой контента. Здесь это нижний бар страницы: линия
  сверху отделяет его от содержимого, а вкладки выровнены по той же мере
  ширины, что и сам контент. Подсветка выбранной вкладки остаётся
  прежней — язык интерфейса не меняется.

  Геометрия панели при этом та же самая: высота по-прежнему
  --bottom-dock-space, поэтому расчёт высоты main не расходится с ней.
*/
@media (min-width:900px) and (hover:hover) and (pointer:fine){
  :root{
    --bottom-dock-gap:10px;
  }

  .bottom-controls{
    border-top:1px solid var(--line);
  }

  nav.tabs{
    width:min(100%,var(--desktop-content));
    max-width:var(--desktop-content);
    padding:0;
    gap:4px;

    border-color:transparent;
    background:transparent;
    box-shadow:none;

    backdrop-filter:none;
    -webkit-backdrop-filter:none;
  }

  /*
    Разделы делят бар поровну, а не занимают каждый по длине слова.
    Предел ширины держит плитки прежнего размера: без него на широком
    мониторе они растянулись бы в плиты на четверть экрана, а свободное
    место должно уходить по краям.
  */
  nav.tabs button{
    flex:1 1 0;
    min-width:0;
    max-width:132px;
    padding:0 18px;
  }
}

nav.tabs{
  height:var(--bottom-tabs-height);
  min-height:var(--bottom-tabs-height);
  border-radius:999px;
}

nav.tabs button{
  border-radius:999px;
}

/*
  Измеритель layout viewport (src/platform-shell.js).

  Растянут от верхней до нижней границы окна, поэтому его высота равна
  области, относительно которой движок раскладывает position:fixed. Оболочка
  и её нижняя панель должны доходить ровно до неё — в отличие от
  window.innerHeight, который в установленном приложении iOS сообщает ниже
  окна на верхнюю safe-area.
*/
.app-viewport-probe{
  position:fixed;
  top:0;
  bottom:0;
  left:0;

  width:0;

  visibility:hidden;
  pointer-events:none;
}

/* Скроллируемый экран физически заканчивается перед dock: строки не просвечивают под ним. */
html,
body{
  height:var(--app-shell-height);
  min-height:var(--app-shell-height);
}

main{
  height:calc(
    var(--app-shell-height) -
    var(--bottom-dock-space)
  );
  padding-bottom:16px;
  scroll-padding-bottom:16px;
}

main.shifts-layout{
  padding-bottom:0;
}

/* Поиск и фильтр смен используют одинаковую рабочую ширину и высоту. */
#shiftSearch{
  width:100%;
  min-width:0;
  min-height:28px;
  padding:0;
  border:0;
  outline:0;
  background:transparent;
  color:var(--ink);
  font:inherit;
}

#shiftSearch,
#shiftFilterOpen{
  box-sizing:border-box;
}

#shiftFilterOpen{
  width:100%;
  min-height:52px;
}

/* Модальные поверхности полностью отделяются от нижней навигации. */
body.sheet-open .bottom-controls,
body.point-picker-open .bottom-controls,
body.month-picker-open .bottom-controls,
body.date-picker-open .bottom-controls{
  opacity:0;
  visibility:hidden;
  pointer-events:none;
}

/*
  iOS standalone может сообщать visualViewport ниже фактического окна приложения.
  В PWA shell привязывается к полному layout viewport, а внутренние overlay по-прежнему
  используют visualViewport для клавиатуры и zoom.

  Layout viewport берётся измеренным (--app-window-height, src/platform-shell.js),
  а не через 100vh: в iOS 100vh — это высота окна без клавиатуры, она не
  уменьшается, пока клавиатура открыта. Оболочка тогда оказывалась выше окна,
  документ становился прокручиваемым, и нижняя панель, привязанная здесь к
  документу, уезжала вверх вместе с прокруткой. 100vh остаётся запасным
  значением до первого измерения.
*/
@media (display-mode:standalone){
  :root{
    --app-shell-height:var(--app-window-height,100vh);
  }

  html,
  body{
    height:var(--app-window-height,100vh);
    min-height:var(--app-window-height,100vh);
  }

  .bottom-controls{
    position:absolute;
    bottom:0;
  }

  .veil,
  .point-veil,
  .month-veil,
  .date-veil{
    position:absolute;
    top:0;
    right:0;
    bottom:auto;
    left:0;
    height:var(--app-window-height,100vh);
  }
}

@media (orientation:landscape) and (max-height:520px){
  :root{
    --bottom-tabs-height:48px;
    --bottom-dock-gap:4px;
  }

  .bottom-controls{
    bottom:0;
  }

  nav.tabs{
    height:var(--bottom-tabs-height);
    min-height:var(--bottom-tabs-height);
  }

  main{
    padding-bottom:12px;
    scroll-padding-bottom:12px;
  }

  main.shifts-layout{
    padding-bottom:0;
  }
}
