/* ===== modais, definições e assistente =====
   É o último `<link>` da página. */

/* `.75rem` não é um degrau do Bootstrap. */
.modal-device-identity {
    gap: .75rem;
}

/* A chapa da fotografia é clara nos dois temas, porque as imagens vêm com fundo branco; não é
   `bg-body-tertiary` porque essa vira com o tema. */
.showcase-preview {
    min-height: 280px;
}

/* Só com fotografia: sem ela, o ícone de reserva, que é claro, desaparece na chapa clara. */
.showcase-preview:has(img) {
    background-color: #fff;
}

/* No escuro a chapa não muda de cor: baixa de brilho com a fotografia, para descerem juntos. */
[data-bs-theme="dark"] .showcase-preview {
    filter: brightness(.84);
}

.showcase-preview img {
    max-height: 260px;
}

/* Num telefone a chapa é uma tira: a maioria dos modelos não tem fotografia. */
@media (max-width: 767.98px) {
    .showcase-preview {
        min-height: 0;
    }

    .showcase-preview img {
        max-height: 104px;
    }
}

/* O fundo fica aqui: no escuro a chapa passa a branca, e um `bg-*` na marcação
   ganharia-lhe pelo `!important`. */
.modal-device-thumb {
    width: 40px;
    height: 40px;
    background: var(--bs-tertiary-bg);
}

.modal-device-thumb img,
.modal-device-thumb i {
    max-width: 26px;
    max-height: 26px;
}

.selected-device-preview {
    width: 72px;
    height: 72px;
    background: var(--bs-tertiary-bg);
}

.selected-device-preview img {
    max-width: 56px;
    max-height: 56px;
}

/* As chapas pequenas, pela mesma razão do `.showcase-preview`, e só onde há fotografia. */
[data-bs-theme="dark"] .modal-device-thumb:has(img),
[data-bs-theme="dark"] .selected-device-preview:has(img),
[data-bs-theme="dark"] .gateway-card-thumb:has(img),
[data-bs-theme="dark"] .wizard-card-thumb:has(img) {
    background: #fff;
    filter: brightness(.84);
}

[data-bs-theme="dark"] .wizard-card-thumb:has(img) {
    border-radius: .5rem;
}

.gateway-picker {
    grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
    max-height: 18rem;
}

/* Com «Todos» a lista não escolhe nada, e esconde-se; o `!important` vence o do `d-grid`. */
.proximity-alarm:has([data-config-field="devicesScope"][value="all"]:checked) .proximity-alarm-picker {
    display: none !important;
}

/* A linha toda da grelha: o Bootstrap não tem utilitário de `grid-column`. */
.gateway-picker-empty {
    grid-column: 1 / -1;
}

/* O estado vem do `shell.css`. O `.75rem` fica aqui por não ser degrau do Bootstrap. */
.gateway-card {
    gap: .75rem;
    padding-inline: .75rem;
    border-radius: .75rem;
}

.gateway-card:has(.gateway-card-check:disabled) {
    cursor: default;
    opacity: .65;
}

.gateway-card-thumb {
    width: 48px;
    height: 48px;
    background: var(--bs-tertiary-bg);
}

/* As fotografias dos modelos já vêm sobre branco; o tom só existe para dar superfície ao
   ícone que aparece quando não há fotografia. */
.gateway-card-thumb:has(img) {
    background: transparent;
}

.gateway-card-thumb img {
    max-width: 44px;
    max-height: 44px;
    mix-blend-mode: multiply;
}

.gateway-card-thumb-icon {
    width: 24px;
    height: 24px;
}

.gateway-card-model {
    font-size: var(--fs-sm);
}

/* A contagem de barras cheias diz a leitura tão bem como a cor, para se ler sem percepção
   de tom. O dBm exacto vive na tooltip. */
.signal-meter {
    gap: 2px;
    height: 1rem;
    cursor: help;
}

/* A barra apagada; as cheias levam `opacity-100` na marcação. */
.signal-meter-bar {
    width: 3px;
    border-radius: 1px;
    background-color: currentColor;
    opacity: .2;
}

/* Seco, húmido e molhado é uma escala do domínio e não um `info`/`warning`/`danger`. Em
   tokens para o azul da barra e o do número não poderem divergir. */
:root {
    --moisture-dry: #cbd5e1;
    --moisture-damp: #93c5fd;
    --moisture-wet: #3b82f6;
    --moisture-damp-text: #1d4ed8;
    --moisture-wet-text: #1e3a8a;
}

/* No escuro a escala inverte de direcção mas não de sentido: mais forte continua a ser mais
   molhado. O seco sobe um degrau acima do fundo da barra, senão lê-se como cheio. */
[data-bs-theme="dark"] {
    --moisture-dry: #2c3850;
    --moisture-damp: #3b82f6;
    --moisture-wet: #93c5fd;
    --moisture-damp-text: #60a5fa;
    --moisture-wet-text: #93c5fd;
}

/* A configuração que o aparelho reporta: uma linha por definição, nome à esquerda. */
.reported-settings {
    font-size: var(--fs-sm);
}

.reported-setting {
    padding: .2rem 0;
    border-top: 1px solid var(--bs-border-color-translucent);
}

.reported-setting:first-child {
    border-top: 0;
}

/* A faixa do dia: uma coluna por dose marcada, na ordem das horas, em partes iguais e a
   embrulhar quando não cabem; por isso o cartão pede a linha inteira. */
.dose-strip {
    grid-template-columns: repeat(auto-fit, minmax(5rem, 1fr));
    gap: .4rem;
}

.dose {
    border-radius: .4rem;
    padding: .5rem .4rem;
    background: var(--bs-tertiary-bg);
    color: var(--bs-secondary-color);
}

.dose-slot {
    font-size: var(--fs-label);
    line-height: 1.2;
    min-height: 1.1em;
    opacity: .75;
}

.dose-hour {
    font-size: var(--fs-sm);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    line-height: 1.3;
}

.dose-state { font-size: var(--fs-label); line-height: 1.2; }

/* Uma dose sem nada marcado é o fundo: o que se procura na faixa é o que destoa dele. */
.dose--taken {
    background: var(--bs-success-bg-subtle);
    color: var(--bs-success-text-emphasis);
}

.dose--pending {
    background: var(--bs-warning-bg-subtle);
    color: var(--bs-warning-text-emphasis);
}

.dose--missed {
    background: var(--bs-danger-bg-subtle);
    color: var(--bs-danger-text-emphasis);
}

/* Os lugares por marcar não são uma dose, e por isso não têm fundo: são um contorno. */
.dose--free {
    background: transparent;
    border: 1px dashed var(--bs-border-color);
}

.diaper-strip {
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: .35rem;
}

.diaper-channel {
    gap: .2rem;
}

/* A cor é do estado do canal: as duas variantes abaixo trocam-na. */
.diaper-channel-value {
    font-size: var(--fs-sm);
    color: var(--bs-secondary-color);
}

.diaper-channel-value--damp {
    color: var(--moisture-damp-text);
}

.diaper-channel-value--wet {
    color: var(--moisture-wet-text);
}

.diaper-channel-track {
    height: 64px;
    border-radius: .35rem;
    background: var(--bs-tertiary-bg);
}

/* O limiar de "precisa de muda", para se ver quais as barras que o passaram. */
.diaper-channel-track::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: var(--diaper-threshold, 50%);
    border-top: 1px dashed var(--bs-border-color);
    opacity: .9;
    pointer-events: none;
}

/* Sem `min-height`: um canal seco a 0 não pinta nada, senão a faixa vazia parece húmida. */
.diaper-channel-fill {
    border-radius: .35rem .35rem 0 0;
    background: var(--moisture-dry);
    transition: height .2s ease-in-out;
}

.diaper-channel-fill--damp {
    background: var(--moisture-damp);
}

.diaper-channel-fill--wet {
    background: var(--moisture-wet);
}

.diaper-channel-index {
    font-size: var(--fs-label);
    color: var(--bs-secondary-color);
}

/* A barra é navy nos dois temas, por isso a versão escura do logótipo serve sempre. */
.navbar-brand img {
    height: 30px;
}

.dashboard-notifications-menu {
    width: min(24rem, calc(100vw - 2rem));
}

/* Num ecrã estreito o menu sairia pela esquerda, e dentro de uma navbar o Bootstrap não chama
   o Popper: quem o trava é o CSS. */
@media (max-width: 575.98px) {
    /* Dois nomes de classe para empatar com o `[data-bs-popper]` do Bootstrap, que é quem
       põe o `top: 100%` e o `right: 0` desta posição estática. */
    .dropdown-menu.dashboard-notifications-menu {
        position: fixed;
        top: var(--navbar-height, 3.5rem);
        left: 1rem;
        right: 1rem;
        width: auto;
    }
}

.dashboard-notifications-list {
    max-height: min(28rem, calc(100vh - 8rem));
}

/* O mesmo tecto de leitura do ecrã principal: o modal continua de ecrã inteiro, e é o conteúdo
   que para. Ver o `--content-max` no `base.css`. */
#settingsModal .modal-body>.settings-modal-shell {
    max-width: var(--content-max);
    margin-inline: auto;
}

/* Quem rola é o corpo do diálogo, e por isso a altura resolvida é dele: a régua e a barra de
   gravar colam-se contra esta caixa, que mede o mesmo em todos os separadores. */
#settingsModal .modal-body {
    height: clamp(26rem, 68vh, 46rem);
}

/* Abaixo de lg o diálogo é o ecrã inteiro, e quem manda na altura é ele. */
@media (max-width: 991.98px) {
    #settingsModal .modal-body {
        height: auto;
    }
}

/* No modal do dispositivo quem rola é a coluna do conteúdo, e não o corpo. */
.device-modal-content {
    min-height: 0;
    overflow-y: auto;
}

/* Com o menu ao lado, a coluna do conteúdo mede a altura toda da linha. */
@media (min-width: 992px) {
    .device-modal-content {
        height: 100%;
    }
}

/* Abaixo disso o menu passa para cima do conteúdo, que fica com a altura que sobra, para não
   acabar por baixo do rodapé. */
@media (max-width: 991.98px) {
    .device-modal-shell>.row {
        flex-direction: column;
        flex-wrap: nowrap;
    }

    .device-modal-content {
        flex: 1 1 auto;
    }
}

/* Abaixo do `modal-fullscreen-lg-down` o diálogo é o ecrã todo, e o tecto de leitura
   deixa de fazer sentido. */
@media (max-width: 991.98px) {
    #settingsModal .modal-body {
        max-height: none;
    }
}

/* A contagem de cada secção no menu das definições. No separador activo o fundo é do próprio
   branco a 20%, para não abrir um terceiro tom dentro do navy. */
.settings-nav-count {
    min-width: 1.5rem;
    background: var(--bs-tertiary-bg);
    color: var(--bs-secondary-color);
    font-size: var(--fs-label);
}

.nav-pills .nav-link.active .settings-nav-count {
    background: rgba(var(--brand-on-rgb), .2);
    color: var(--brand-on);
}

/* Abaixo do ecrã médio a régua deita-se numa tira de uma linha que desliza, como a
   `.capability-section-nav`. */
@media (max-width: 767.98px) {
    .modal-side-nav {
        align-items: center;
        padding-bottom: .375rem;
        border-bottom: 1px solid var(--bs-border-color);
        overflow-x: auto;
        scrollbar-width: none;
        scroll-snap-type: x proximity;
    }

    .modal-side-nav::-webkit-scrollbar {
        display: none;
    }

    /* Cada separador com a largura do seu texto, e a encaixar: meia pastilha ao fundo é o
       que diz que há mais para o lado. */
    .modal-side-nav .nav-link {
        flex: none;
        white-space: nowrap;
        scroll-snap-align: start;
    }
}

/* ===== assistente de adicionar dispositivo ===== */

/* Os cinco traços da barra: finos, à mesma largura, e a cor diz quais já ficaram para trás. */
.wizard-progress > * {
    height: .25rem;
}

/* A migalha: cinco nomes em linha e sem fundo; o peso e a cor distinguem o passo dado, o
   actual e o que falta. */
.wizard-trail {
    min-height: 1.9rem;
}

.wizard-trail .wizard-badge {
    max-width: 14rem;
    padding: .2rem .4rem;
    font-size: var(--fs-sm);
    border: 1px solid transparent;
    background: transparent;
    animation: wizard-badge-in .32s cubic-bezier(.2, .8, .3, 1) both;
}

/* A cor vem das utilidades do Bootstrap na marcação, e o nome do passo acompanha-a. */
.wizard-trail .wizard-badge-key {
    color: inherit;
}

.wizard-trail .wizard-badge-value {
    min-width: 0;
}

.wizard-trail button.wizard-badge {
    cursor: pointer;
}

.wizard-trail button.wizard-badge:hover,
.wizard-trail button.wizard-badge:focus-visible {
    border-color: var(--bs-primary-border-subtle);
    background: var(--bs-primary-bg-subtle);
}

.wizard-trail .wizard-trail-sep {
    font-size: var(--fs-sm);
}

/* A pastilha da classificação de um aparelho que já existe: o valor no corpo pequeno da
   plataforma, que é o tamanho das outras etiquetas do modal. */
.classification-pill {
    font-size: var(--fs-sm);
}

@keyframes wizard-badge-in {
    from { opacity: 0; transform: translateY(-4px) scale(.96); }
    to { opacity: 1; transform: none; }
}

/* A pergunta activa à esquerda, a imagem do modelo à direita quando já se sabe qual é. */
.wizard-stage {
    grid-template-columns: minmax(0, 1fr) 13rem;
}

.wizard-stage:has(.wizard-art.d-none) {
    grid-template-columns: minmax(0, 1fr);
}

@media (max-width: 41.75rem) {
    .wizard-stage { grid-template-columns: minmax(0, 1fr); }
}

/* Um ou vários: os dois cartões do último passo do assistente, lado a lado. */
.wizard-mode {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.wizard-bulk-list {
    max-height: 18rem;
}

/* Num ecrã estreito o SIM desce para a linha de baixo do identificador. */
.wizard-bulk-sim {
    flex: 0 1 16rem;
}

.wizard-ask {
    display: flex;
    flex-direction: column;
    gap: 1.1rem;
    animation: wizard-ask-in .26s ease both;
}

@keyframes wizard-ask-in {
    from { opacity: 0; transform: translateY(5px); }
    to { opacity: 1; transform: none; }
}

/* O `display` fica aqui: o `d-none` que a esconde é do mesmo peso que um `d-flex` e um
   utilitário do Bootstrap ganharia-lhe. */
.wizard-art {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 11rem;
    animation: wizard-art-in .48s cubic-bezier(.2, .7, .3, 1) both .1s;
}

.wizard-art img {
    max-height: 7rem;
}

.wizard-art .wizard-art-name {
    font-size: var(--fs-sm);
}

.wizard-art .wizard-art-sub {
    font-size: var(--fs-label);
}

@keyframes wizard-art-in {
    from { opacity: 0; transform: translateY(6px) scale(.985); }
    to { opacity: 1; transform: none; }
}

/* A grelha de escolhas em cards, partilhada pelo tipo de dispositivo e pelo modelo: um
   leva ícone, o outro leva a fotografia, e o resto da forma é o mesmo. */
.wizard-card-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

@media (max-width: 34rem) {
    .wizard-card-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* O estado vem do `shell.css`. O `.selected` só o modal de edição o usa: no assistente,
   responder colapsa a pergunta numa badge. */
.wizard-card {
    padding: .9rem .7rem;
}

.wizard-card-icon {
    font-size: var(--fs-xl);
}

/* A miniatura tem altura fixa para os cards de uma linha ficarem alinhados mesmo com
   fotografias de proporções diferentes. */
.wizard-card-thumb {
    height: 3.75rem;
}

.wizard-card-thumb img {
    max-height: 100%;
}

.wizard-card-label {
    font-size: var(--fs-sm);
}

/* O modelo interno, ou a contagem de modelos de um tipo. */
.wizard-card-sub {
    font-size: var(--fs-label);
}

/* ===== pastilha de estado ===== */

/* A pastilha é o `badge` do Bootstrap, montada no `components/state-badge.js`; sobra aqui o
   ponto. O rótulo diz sempre o estado, para a leitura não depender da cor. */
.state-badge-dot {
    width: 6px;
    height: 6px;
    background: currentcolor;
}

@media (prefers-reduced-motion: reduce) {
    .wizard-trail .wizard-badge,
    .wizard-ask,
    .wizard-art {
        animation: none;
    }
}

/* ===== catálogo de capacidades ===== */

/* A tira das secções cola ao topo enquanto a lista corre por baixo, e cada pastilha aponta
   para o `id` da sua secção. */
/* Uma linha só, que desliza quando não cabe, sem barra à vista e com encaixe: uma pastilha
   meio cortada sozinha lê-se como «há mais para o lado». */
.capability-section-nav {
    gap: .375rem;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    scroll-snap-type: x proximity;
}

.capability-section-nav::-webkit-scrollbar {
    display: none;
}

.capability-section-nav > * {
    scroll-snap-align: start;
}

/* A borda e o fundo ficam aqui: os estados abaixo trocam-nos, e um utilitário traz
   `!important` e ganharia-lhes. */
.capability-section-chip {
    gap: .375rem;
    padding: .3125rem .6875rem;
    color: var(--bs-body-color);
    font-size: var(--fs-sm);
    font-weight: 560;
}

.capability-section-chip .count {
    font-weight: 600;
}

.capability-section-chip.selected .count {
    color: var(--bs-primary);
}

.capability-filter-row {
    grid-template-columns: 1fr;
}

/* Os dois filtros lado a lado só a partir do `lg`: abaixo disso, com a régua das secções ao
   lado, os mosaicos ficam estreitos demais. */
@media (min-width: 992px) {
    .capability-filter-row {
        grid-template-columns: 7fr 5fr;
    }
}

/* A secção é um destino de scroll, e o desvio é a altura da tira, para o cabeçalho não
   ficar debaixo dela ao chegar. */
.capability-catalog-section {
    scroll-margin-top: 3.25rem;
}

/* Uma linha por capacidade: o ícone que a capacidade já tem nos cartões de pedido, o nome, e
   os factos. Nada leva largura fixa. */
.capability-row {
    grid-template-columns: 1.4rem minmax(0, 1fr) auto;
    align-items: center;
    gap: .625rem;
    padding: .4375rem .75rem;
}

/* O alinhamento e a quebra viram no telefone, mais abaixo. */
.capability-facts {
    font-size: var(--fs-sm);
    text-align: right;
    white-space: nowrap;
}

/* Existe para o tipo de dispositivo, mas o fornecedor escolhido não a declara. Fica
   apagada e no fundo afundado: é contexto, e não uma linha que se possa accionar. */
.capability-row.is-unsupported {
    opacity: .42;
    background: var(--bs-tertiary-bg);
}

@media (max-width: 575.98px) {
    .capability-row {
        grid-template-columns: 1.4rem minmax(0, 1fr);
        align-items: start;
    }

    .capability-facts {
        grid-column: 2;
        text-align: left;
        white-space: normal;
    }
}
