/* ============================================================
   Design tokens — claro (por omissão) e escuro (prefers-color-scheme).
   Só os VALORES das variáveis mudam entre os dois blocos; nenhuma regra
   abaixo lê uma cor fixa fora daqui (à exceção dos overlays de crise —
   ver --crisis-bg mais abaixo, que é deliberadamente igual nos dois temas).
   Isto é o que torna o resto da folha "tema-agnóstico": escrever uma regra
   nova não obriga a pensar em claro/escuro à parte, só a usar a variável
   certa.
   ============================================================ */
:root {
  /* --- cor de marca: teal — decisão do dono, mantida entre temas --- */
  --teal: #0d9488;
  /* --teal-strong: variante para estados premidos/hover. Em claro é mais
     ESCURA (convenção normal de "carregar escurece"); em escuro teria de
     ser mais CLARA — escurecer ainda mais um acento sobre um fundo já
     quase preto torna-o ilegível. Por isso é redefinida no bloco escuro
     abaixo, não só copiada. */
  --teal-strong: #0b7d73;
  --teal-soft: rgba(13, 148, 136, 0.1);

  /* --- superfícies e texto --- */
  --bg: #f2f2f7;
  --card: #ffffff;
  --text: #1c1c1e;
  --muted: #6e6e73;
  --hairline: rgba(60, 60, 67, 0.29);
  --field-bg: #f2f2f7;
  --field-border: rgba(60, 60, 67, 0.18);
  --overlay-scrim: rgba(15, 23, 42, 0.45);
  --shadow-card: 0 1px 2px rgba(15, 23, 42, 0.06), 0 1px 1px rgba(15, 23, 42, 0.04);
  --tabbar-bg: rgba(255, 255, 255, 0.82);

  /* --- semântica (estado clínico/aviso) --- */
  --danger: #dc2626;
  --danger-bg-soft: #fee2e2;
  --warn: #d97706;
  --warn-bg-soft: #fef3c7;
  --success: #16a34a;
  --success-bg-soft: #dcfce7;
  --info: #075985;
  --info-bg-soft: #e0f2fe;
  --neutral-bg-soft: #e2e8f0;

  /* Overlays de crise (alarme, alerta de tensão fora do intervalo):
     DELIBERADAMENTE constantes entre claro/escuro — nunca redefinidas no
     bloco escuro abaixo. Um ecrã de emergência não deve mudar de
     intensidade consoante o tema do sistema; a previsibilidade importa
     mais aqui do que a consistência estética com o resto do ecrã. Mais
     escuro que o --danger de badges/texto (#dc2626) de propósito — pedido
     do brief ("mais sério e deliberado, nunca alarmista/brincalhão"); um
     vermelho mais profundo e menos saturado lê como mais grave do que um
     vermelho vivo. --crisis-bg-pulse é o pico da animação de
     alarm-pulse — a variação é subtil (dois tons próximos), a própria
     pulsação já chama a atenção sem precisar de um salto de cor gritante. */
  --crisis-bg: #b91c1c;
  --crisis-bg-pulse: #dc2626;

  /* --- peso: ver comentário original em weight-change--up/--down, mais
     abaixo — cores deliberadamente fora da paleta ok/perigo --- */
  --weight-up: #2563eb;
  --weight-down: #9333ea;

  /* --- gráfico (ApexCharts, público/js/bp-chart.js) — lidas com
     getComputedStyle no momento de desenhar, nunca fixas no JS, para que o
     gráfico acompanhe o tema em vigor no instante em que é desenhado.
     Cores de CLASSIFICAÇÃO clínica (bandas de risco, cor dos pontos) NÃO
     estão aqui — essas são fixas e iguais nos dois temas de propósito (ver
     BAND_COLORS em bp-chart.js): uma leitura de crise tem de ler vermelho
     tanto em claro como em escuro, nunca dependente do tema do telemóvel. */
  --chart-grid: #e7e7ea;
  --chart-text: #6e6e73;
  --chart-line-primary: #1c1c1e;
  --chart-tooltip-bg: #ffffff;

  /* --- forma e movimento --- */
  --radius-lg: 20px;
  --radius-md: 14px;
  --radius-sm: 10px;
  --transition-fast: 120ms ease;

  /* Altura de referência da bottom nav fixa (.tabbar), sem a faixa extra do
     home indicator (env(safe-area-inset-bottom), que soma-se à parte, onde
     for preciso) — usada em todos os sítios que têm de deixar espaço para
     ela nunca ficar por baixo do conteúdo (#content, .fab), para não haver
     dois números mágicos que podem divergir com o tempo. */
  --tabbar-h: 4.5rem;
}

@media (prefers-color-scheme: dark) {
  :root {
    --teal-strong: #14b8a6;
    --teal-soft: rgba(20, 184, 166, 0.16);

    /* Preto puro, não cinzento-escuro: a app é usada de noite (o dono tira
       leituras às 4h, notas reais com esse timestamp — brief), e os
       ecrãs OLED de iPhone poupam mais e brilham menos em preto puro do
       que em cinzento. --card fica um degrau acima (superfície "elevada",
       mesma relação semântica que já existia em claro entre --bg e
       --card) — é o que dá profundidade aos cartões sem precisar de
       sombra (uma sombra não se vê sobre preto; ver --shadow-card
       abaixo). */
    --bg: #000000;
    --card: #1c1c1e;
    --text: #f2f2f7;
    --muted: #98989d;
    --hairline: rgba(255, 255, 255, 0.15);
    --field-bg: #2c2c2e;
    --field-border: rgba(255, 255, 255, 0.14);
    --overlay-scrim: rgba(0, 0, 0, 0.6);
    /* Uma sombra a preto não tem contraste nenhum sobre um fundo já preto
       — em vez de a simular, o cartão ganha um contorno claro muito ténue
       (mesmo truque que apps nativas usam em modo escuro) para se separar
       visualmente do fundo. */
    --shadow-card: 0 0 0 1px rgba(255, 255, 255, 0.08);
    --tabbar-bg: rgba(28, 28, 30, 0.78);

    /* Vermelho/laranja/verde mais claros e saturados que o par claro — a
       mesma cor do modo claro (ex.: --danger #dc2626) sobre um cartão
       quase preto (--danger-bg-soft) não teria contraste suficiente para
       texto normal; isto não é só estética, é legibilidade. */
    --danger: #ff453a;
    --danger-bg-soft: rgba(255, 69, 58, 0.18);
    --warn: #ffb340;
    --warn-bg-soft: rgba(255, 179, 64, 0.16);
    --success: #32d74b;
    --success-bg-soft: rgba(50, 215, 75, 0.16);
    --info: #64d2ff;
    --info-bg-soft: rgba(100, 210, 255, 0.14);
    --neutral-bg-soft: #2c2c2e;

    --chart-grid: #2c2c2e;
    --chart-text: #98989d;
    --chart-line-primary: #f2f2f7;
    --chart-tooltip-bg: #1c1c1e;
  }
}

/* Movimento só para quem não pediu o contrário — em vez de desligar
   animações/transições numa query "reduce", elas só existem dentro desta
   query "no-preference". Mesmo efeito prático, mas sem depender de nenhuma
   regra ser corretamente "desfeita" mais abaixo no cascade (mais fácil de
   verificar: se não está aqui dentro, não anima, nunca). O pulsar do
   alarme (alarm-pulse) é a única exceção deliberada — ver o comentário
   junto de .alarm-overlay. */
@media (prefers-reduced-motion: no-preference) {
  .tab,
  .btn-secondary,
  .btn-danger,
  .btn-primary,
  .btn-google,
  .bp-chart-view-btn,
  .weight-chart-view-btn,
  .day-toggle,
  .fab {
    transition: transform var(--transition-fast), opacity var(--transition-fast), background-color var(--transition-fast), color var(--transition-fast), box-shadow var(--transition-fast);
  }
  .btn-secondary:active,
  .btn-danger:active,
  .btn-primary:active,
  .btn-google:active,
  .fab:active {
    transform: scale(0.97);
  }
  .med-form,
  .bp-form,
  .bp-settings-panel {
    transition: transform var(--transition-fast);
  }
}

* { box-sizing: border-box; margin: 0; }
/* Contenção horizontal na RAIZ, não só no body: no Safari do iOS o pan
   horizontal por gesto (o "scroll horizontal" reportado pelo dono) é
   dirigido pelo elemento <html>, não pelo <body> — um `overflow-x: hidden`
   só no body (como havia antes) não trava esse pan quando é a raiz a
   ficar mais larga que o ecrã (ex.: um filho `position: fixed` mal
   dimensionado, ou o próprio layout viewport dinâmico do Safari). Os dois
   niveis (html E body) levam a mesma rede de segurança, mais `max-width:
   100%`/`width: 100%` para nenhum dos dois poder alargar além do ecrã por
   um conteúdo descendente. */
html {
  /* clip, não hidden: `overflow-x: hidden` faz o `overflow-y` passar a `auto`,
     transformando o elemento num contentor de scroll — e no iOS Safari um
     `position: fixed` dentro de um contentor de scroll deixa de estar preso ao
     ecrã e passa a acompanhar o scroll (a .tabbar flutuava a meio da lista).
     `overflow: clip` corta o excesso horizontal SEM criar contentor de scroll.
     `hidden` fica como fallback para browsers sem suporte a `clip`. */
  overflow-x: hidden;
  overflow-x: clip;
  max-width: 100%;
  width: 100%;
}
body {
  font-family: -apple-system, system-ui, sans-serif;
  background: var(--bg); color: var(--text);
  min-height: 100dvh; display: flex; flex-direction: column;
  position: relative;
  max-width: 100%;
  width: 100%;
  padding-bottom: env(safe-area-inset-bottom);
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  /* overflow-wrap é herdado — isto cobre TODO texto livre (nome/dosagem/
     notas de medicamento, nota de uma medição de tensão), incluindo o que
     ainda não existe hoje, sem ter de listar cada classe uma a uma. A
     causa real do scroll horizontal (achado a testar com dados realistas:
     um nome de medicamento sem espaços) é esta — uma palavra sem espaços
     não tem nenhum ponto onde o browser a possa partir por omissão
     (word-break normal), por isso o texto ultrapassa a largura do ecrã em
     vez de quebrar linha. `break-word` só quebra quando a palavra não cabe
     de outra forma; nunca parte palavras curtas normais a meio.
     overflow-x:hidden no body, mais abaixo, é só uma rede de segurança —
     sozinho escondia o problema (o conteúdo ficava inacessível, não
     corrigido); a correção real é esta. */
  overflow-wrap: break-word;
  /* Rede de segurança, não a correção: qualquer largura que escape aos
     dois problemas reais já corrigidos (palavras sem quebra — ver
     overflow-wrap acima — e itens flex sem min-width:0 — ver .med-name e
     .history-item-name) fica cortada em vez de abrir uma barra de scroll
     horizontal na página.
     clip (não hidden): ver a nota em `html` acima — `hidden` no body tornava-o
     um contentor de scroll e a .tabbar fixa deixava de ficar presa ao fundo do
     ecrã no iOS. `hidden` fica como fallback antes do `clip`. */
  overflow-x: hidden;
  overflow-x: clip;
}

/* Foco visível discreto (teclado/leitor de ecrã) — mesma cor de marca em
   qualquer controlo focável, sem depender de cada regra abaixo o repetir. */
:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; }

.topbar {
  background: var(--teal); color: #fff;
  padding: calc(env(safe-area-inset-top) + 0.6rem) 1.1rem 0.7rem;
  display: flex; justify-content: space-between; align-items: center;
}
.topbar h1 { font-size: 1.3rem; font-weight: 700; letter-spacing: -0.01em; }
/* Agrupa ⓘ e Sair do lado direito da barra — só um wrapper de layout (gap
   entre os dois), sem estilo visual próprio nenhum; cada botão lá dentro
   continua com o seu próprio aspeto. */
.topbar-actions { display: flex; align-items: center; gap: 1rem; }
.topbar .logout {
  background: none; border: 0; padding: 0;
  font-family: inherit; color: #fff; opacity: 0.85;
  text-decoration: none; font-size: 0.9rem; cursor: pointer;
}
/* Botão ⓘ — mesmo tamanho de alvo tocável que qualquer outro botão da barra
   (min 2rem de lado visual, mas com padding a alargar a área real de toque
   sem crescer visualmente), cor herdada do texto branco da topbar, sem
   fundo próprio (consistente com .logout, ao lado). */
.info-btn {
  background: none; border: 0; padding: 0.2rem 0.3rem;
  font-family: inherit; color: #fff; opacity: 0.9;
  font-size: 1.15rem; line-height: 1; cursor: pointer;
}
/* #content é a única zona com scroll vertical (a bottom nav é fixa ao
   ecrã, ver .tabbar abaixo) — a folga de baixo tem de chegar sempre ao
   fundo da bottom nav (--tabbar-h) MAIS a seguranca do home indicator num
   iPhone com notch, para que o último item de uma lista (ex.: a medição
   mais recente de tensão) nunca fique tapado atrás da bottom nav. Ponto
   único desta folga — antes disto cada ecrã tinha o seu próprio hack de
   margin-bottom (.meds-history, .bp-settings-link, ambos com 5rem
   avulsos), fácil de esquecer num ecrã novo (ex.: Peso, que não tinha
   nenhum). */
#content { flex: 1; padding: 1.1rem; padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom)); overflow-y: auto; }
.placeholder { color: var(--muted); text-align: center; margin-top: 3rem; line-height: 1.5; }

/* Fixa ao FUNDO DO ECRÃ (viewport), não ao fim do document flow: antes
   disto .tabbar era só o último filho do body (display:flex,
   flex-direction:column), por isso um ecrã com pouco conteúdo deixava a
   barra a meio do ecrã (a coluna flex termina onde o conteúdo termina, não
   no fim do ecrã) e um ecrã com muito conteúdo arrastava-a para fora de
   vista ao fazer scroll da página toda (dono: "os icons de baixo devem
   ficar sempre fixos colados ao fim do ecrã"). `100dvh` no body (não
   `100vh`) já lidava com a barra de endereço do Safari a aparecer/
   desaparecer; isto aqui é uma falha diferente — a posição da barra em si,
   não a altura do body.
   Fundo translúcido + desfoque (estilo barra de separadores do iOS) com
   fallback sólido: @supports garante que um browser sem backdrop-filter
   (ou com o suporte desligado) mostra a mesma --card sólida de sempre em
   vez de conteúdo a transparecer por baixo de texto ilegível. */
.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0;
  display: flex; border-top: 0.5px solid var(--hairline); background: var(--card);
  padding-bottom: env(safe-area-inset-bottom);
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .tabbar {
    background: var(--tabbar-bg);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    backdrop-filter: saturate(180%) blur(20px);
  }
}
.tab {
  flex: 1; padding: 0.55rem 0 0.4rem; border: 0; background: none;
  font-size: 1.35rem; color: var(--muted); cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
}
.tab span { font-size: 0.68rem; font-weight: 500; }
.tab.active { color: var(--teal); font-weight: 600; }

.login-body { justify-content: center; align-items: center; background: var(--teal); }
.login-card {
  background: var(--card); border-radius: var(--radius-lg); padding: 2.6rem 2.2rem;
  text-align: center; width: min(90vw, 340px);
  box-shadow: 0 20px 45px rgba(0, 0, 0, 0.22);
}
.login-logo { font-size: 3rem; color: var(--teal); }
.login-card h1 { font-size: 1.5rem; font-weight: 700; margin-top: 0.3rem; }
.login-card p { color: var(--muted); margin: 0.5rem 0 1.6rem; }
.btn {
  display: inline-block; padding: 0.85rem 1.5rem; border-radius: var(--radius-md);
  text-decoration: none; font-weight: 600;
}
.btn-google { background: var(--teal); color: #fff; }
.btn-google:active { background: var(--teal-strong); }

/* --- notificações (topo do separador Medicamentos) ---
   Sem `display` próprio de propósito — como .missed-banner/.error-banner
   logo abaixo, fica em block por omissão, e assim não precisa da guarda
   :not([hidden]) que tests/css-hidden-guard.test.js exige de qualquer
   regra que defina display para uma classe também usada num elemento
   [hidden] (ver esse ficheiro para o porquê). */
.notify-card {
  background: var(--card); border-radius: var(--radius-lg); padding: 0.95rem 1rem;
  margin-bottom: 0.9rem; box-shadow: var(--shadow-card);
}
.notify-text { color: var(--muted); font-size: 0.88rem; line-height: 1.4; margin: 0; }
.notify-btn { margin-top: 0.7rem; }
/* Estado "ativas": card discreto, sem caixa — o dono não deve ser
   lembrado disto sempre que abre a app, só confirmar de relance que está
   tudo bem (ver brief: "não incomodar depois de ligado"). */
.notify-card--ok { background: none; box-shadow: none; padding: 0 0 0.2rem; }
.notify-card--ok .notify-text { color: var(--success); font-weight: 600; font-size: 0.85rem; }
.notify-card--denied .notify-text { color: var(--warn); }

/* --- medicamentos --- */

.error-banner {
  background: var(--danger-bg-soft); color: var(--danger); border: 0;
  border-radius: var(--radius-sm); padding: 0.75rem 0.95rem; margin-bottom: 0.9rem;
  font-size: 0.9rem; line-height: 1.4;
}

.meds-list { list-style: none; display: flex; flex-direction: column; gap: 0.8rem; }

.med-card {
  background: var(--card); border-radius: var(--radius-lg); padding: 1.1rem;
  box-shadow: var(--shadow-card);
}
.med-card.med-inactive { opacity: 0.55; }

.med-card-header { display: flex; align-items: center; gap: 0.5rem; }
/* min-width: 0 anula o "auto" por omissão dos itens flex (que nunca
   encolhe abaixo do conteúdo mínimo): sem isto, um nome de medicamento sem
   espaços força .med-card-header — e por arrasto .med-card, .meds-list,
   #content — a alargar em vez de deixar o texto quebrar (ver overflow-wrap
   no body, acima, que é o que realmente quebra a palavra depois disto). */
.med-name { font-weight: 700; font-size: 1.08rem; flex: 1; min-width: 0; letter-spacing: -0.01em; }
.med-badge {
  font-size: 0.7rem; color: var(--muted); background: var(--neutral-bg-soft);
  border-radius: 999px; padding: 0.2rem 0.6rem; font-weight: 600;
}
.med-dosage { color: var(--text); margin-top: 0.3rem; }
.med-schedules { color: var(--teal); font-size: 0.9rem; margin-top: 0.3rem; font-weight: 500; }
/* pre-wrap preserva as quebras de linha que o dono escreveu de propósito
   (textarea multi-linha) — sem isto, uma nota em duas linhas colapsava
   numa só. overflow-wrap: anywhere ao lado, não só o break-word herdado
   do body, porque pre-wrap por si só só quebra em espaços; uma nota sem
   nenhum (ex.: um URL comprido colado) continua sem um ponto de quebra
   nenhum sem isto — o mesmo defeito de scroll horizontal que motivou o
   overflow-wrap do body, só que dentro de um bloco que já preserva
   espaços em branco. */
.med-notes { color: var(--muted); font-size: 0.9rem; margin-top: 0.3rem; white-space: pre-wrap; overflow-wrap: anywhere; }

.med-card-actions { display: flex; gap: 0.6rem; margin-top: 0.9rem; }

.btn-secondary, .btn-danger, .btn-primary {
  border: 0; border-radius: var(--radius-md); padding: 0.65rem 1rem;
  font-family: inherit; font-size: 0.92rem; font-weight: 600; cursor: pointer;
  min-height: 2.75rem;
}
.btn-secondary { background: var(--neutral-bg-soft); color: var(--text); }
.btn-danger { background: var(--danger-bg-soft); color: var(--danger); }
.btn-primary { background: var(--teal); color: #fff; }
.btn-primary:active { background: var(--teal-strong); }

.fab {
  position: fixed; right: 1.2rem; bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 0.6rem);
  width: 3.5rem; height: 3.5rem; border-radius: 50%; border: 0;
  background: var(--teal); color: #fff; font-size: 1.8rem; line-height: 1;
  box-shadow: 0 8px 20px rgba(13, 148, 136, 0.4); cursor: pointer;
}

.form-backdrop {
  position: fixed; inset: 0; background: var(--overlay-scrim);
  align-items: flex-end; z-index: 10;
}
.form-backdrop:not([hidden]) { display: flex; }
.med-form, .bp-form, .bp-settings-panel {
  background: var(--card); width: 100%; max-height: 90vh; overflow-y: auto;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  padding: 1.6rem 1.3rem calc(1.3rem + env(safe-area-inset-bottom));
  display: flex; flex-direction: column; gap: 0.95rem;
  position: relative;
}
/* Pega de arrasto decorativa (padrão de folha modal do iOS) — puramente
   visual (::before, sem markup novo nenhum): esta folha não é de facto
   arrastável, é só o sinal visual de "isto é uma folha", consistente com o
   resto do sistema. */
.med-form::before, .bp-form::before, .bp-settings-panel::before {
  content: ''; position: absolute; top: 0.55rem; left: 50%;
  transform: translateX(-50%); width: 2.5rem; height: 4px;
  border-radius: 999px; background: var(--hairline);
}
.med-form h2, .bp-form h2, .bp-settings-panel h2 { font-size: 1.2rem; font-weight: 700; margin-top: 0.4rem; }

.field { flex-direction: column; gap: 0.35rem; font-size: 0.85rem; font-weight: 600; color: var(--muted); }
.field:not([hidden]) { display: flex; }
.field input[type="text"], .field input[type="time"], .field input[type="number"],
.field input[type="datetime-local"], .field input[type="date"], .field textarea {
  font: inherit; font-weight: 400; padding: 0.7rem 0.8rem; border: 1px solid var(--field-border);
  border-radius: var(--radius-sm); color: var(--text); background: var(--field-bg);
}
.field textarea { resize: vertical; }
.field-checkbox { flex-direction: row; align-items: center; gap: 0.5rem; }
.field-checkbox input { width: 1.2rem; height: 1.2rem; accent-color: var(--teal); }

/* min-width: 0 — achado real ao auditar #med-form a 320px: um <fieldset>
   tem, na folha de estilos por omissão do browser, `min-width:
   min-content` (o mesmo comportamento problemático que motivou min-width:0
   em .med-name/.history-item-name/.bp-summary, mas aqui vem do PRÓPRIO
   elemento HTML, não de ser item de uma flex row) — mesmo com
   `border: 0; padding: 0` a limpar a aparência, esse min-width por omissão
   sobrevive e recusa encolher o fieldset abaixo do seu conteúdo mínimo,
   mesmo dentro de uma coluna flex já limitada a 100% da largura do
   formulário. Sem isto, #med-form tinha scrollWidth 6px maior que
   clientWidth a 320px — mascarado pela rede de segurança overflow-x:hidden
   do body/html (nunca visível como scroll), mas era exatamente o mesmo
   tipo de overflow interno silencioso que .alarm-med-name tinha (ver esse
   comentário) — só detetado a auditar scrollWidth de cada elemento, não
   só do documento. */
.schedules-field { border: 0; padding: 0; min-width: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.schedules-field legend { font-size: 0.85rem; font-weight: 600; color: var(--muted); padding: 0; }

.schedule-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
  background: var(--bg); border-radius: var(--radius-sm); padding: 0.65rem;
}
.schedule-time { font: inherit; padding: 0.5rem; border: 1px solid var(--field-border); border-radius: 8px; background: var(--field-bg); color: var(--text); }

.day-toggles { display: flex; gap: 0.3rem; }
.day-toggle {
  width: 2.1rem; height: 2.1rem; border-radius: 50%; border: 1px solid var(--field-border);
  background: var(--field-bg); color: var(--muted); font-size: 0.8rem; font-weight: 600;
  cursor: pointer;
}
.day-toggle.on { background: var(--teal); border-color: var(--teal); color: #fff; }

.schedule-remove {
  border: 0; background: none; color: var(--danger); font-size: 0.85rem;
  cursor: pointer; padding: 0.3rem; font-weight: 600;
}

.form-actions { display: flex; gap: 0.6rem; justify-content: flex-end; margin-top: 0.4rem; }
.form-actions button { flex: 1; }

/* --- tomas falhadas --- */

.missed-banner {
  background: var(--danger-bg-soft); border: 0; border-radius: var(--radius-lg);
  padding: 0.9rem 0.95rem; margin-bottom: 0.9rem;
}
.missed-banner-title { color: var(--danger); font-weight: 700; margin-bottom: 0.6rem; }
.missed-list { list-style: none; display: flex; flex-direction: column; gap: 0.6rem; }
.missed-item { background: var(--card); border-radius: var(--radius-sm); padding: 0.65rem 0.75rem; box-shadow: var(--shadow-card); }
.missed-item-name { font-weight: 700; }
.missed-item-time { color: var(--muted); font-size: 0.85rem; margin: 0.15rem 0 0.6rem; }
.missed-item-actions { display: flex; gap: 0.5rem; }
.missed-item-actions button { flex: 1; min-height: 2.3rem; padding: 0.4rem; font-size: 0.8rem; }

/* --- histórico --- */

/* Sem margin-bottom próprio de propósito: a folga para a bottom nav fixa já
   vem de #content (padding-bottom: var(--tabbar-h) + safe-area) — um hack
   local aqui só duplicava essa folga, e um ecrã novo sem o mesmo hack
   (era o caso do ecrã de Peso antes desta correção) ficava sem proteção
   nenhuma. */
.meds-history { margin-top: 1.3rem; }
.meds-history summary {
  font-weight: 700; color: var(--teal); cursor: pointer; padding: 0.5rem 0; list-style: none;
  font-size: 0.9rem;
}
.meds-history summary::-webkit-details-marker { display: none; }
.history-empty { color: var(--muted); font-size: 0.85rem; padding: 0.4rem 0; }
.history-day { margin-top: 0.9rem; }
.history-day-label {
  font-size: 0.72rem; color: var(--muted); font-weight: 700; margin-bottom: 0.5rem;
  text-transform: uppercase; letter-spacing: 0.04em;
}
.history-list { list-style: none; display: flex; flex-direction: column; gap: 0.4rem; }
.history-item {
  display: flex; justify-content: space-between; align-items: center; gap: 0.5rem;
  background: var(--card); border-radius: var(--radius-sm); padding: 0.6rem 0.75rem; font-size: 0.9rem;
  box-shadow: var(--shadow-card);
}
.history-item-name { flex: 1; min-width: 0; }
.history-status { font-size: 0.75rem; font-weight: 700; padding: 0.2rem 0.6rem; border-radius: 999px; }
.history-status-taken { background: var(--success-bg-soft); color: var(--success); }
.history-status-taken_late { background: var(--warn-bg-soft); color: var(--warn); }
.history-status-missed { background: var(--danger-bg-soft); color: var(--danger); }
.history-status-dismissed { background: var(--neutral-bg-soft); color: var(--muted); }

/* --- alarme --- */

.alarm-overlay {
  position: fixed; inset: 0; z-index: 100;
  flex-direction: column; align-items: center; justify-content: center;
  padding: 2rem 1.5rem calc(2rem + env(safe-area-inset-bottom));
  text-align: center; color: #fff;
  background: var(--crisis-bg); /* fundo estático — a variante --missed cancela a animação abaixo */
}
.alarm-overlay:not([hidden]) { display: flex; }

/* O pulsar só corre para quem não pediu movimento reduzido (ver a query
   prefers-reduced-motion no topo do ficheiro) — sem animação, o alarme
   continua um vermelho sólido inconfundível, só sem o movimento. */
@media (prefers-reduced-motion: no-preference) {
  .alarm-overlay { animation: alarm-pulse 1.8s ease-in-out infinite; }
}

@keyframes alarm-pulse {
  0%, 100% { background: var(--crisis-bg); }
  50% { background: var(--crisis-bg-pulse); }
}

/* Toma já 'missed' (passou os 30 min sem confirmação, ver public/js/alarm.js):
   o dono está a olhar para o ecrã neste preciso momento — o alarme continua
   visível e exigindo ação, mas sem pulsar nem tocar; mais barulho não
   acrescenta informação nenhuma. */
.alarm-overlay--missed { animation: none; }

.alarm-time { font-size: 1.05rem; opacity: 0.85; margin-bottom: 0.5rem; font-weight: 500; }
/* max-width: 100% — achado real ao testar com um nome de medicamento sem
   espaços (o mesmo caso de .med-name/.history-item-name, ver comentário
   grande junto de .med-name em app.css), mas um MECANISMO DIFERENTE: este
   elemento não é filho de uma flex ROW (onde min-width:0 resolve, porque o
   item tenta encolher abaixo do "auto"), é filho direto de .alarm-overlay,
   uma flex COLUMN com align-items: center — nesse eixo cruzado, sem
   `stretch`, o browser dimensiona o item pelo seu tamanho de conteúdo
   máximo (max-content), IGNORANDO overflow-wrap: break-word (herdado do
   body) por completo: não há nenhuma largura disponível contra a qual
   quebrar. Confirmado num browser real — sem isto, um nome comprido não
   fazia scroll horizontal (o overflow-x: hidden do body/html escondia o
   excesso, ver comentário grande junto de html/body acima), ficava
   CORTADO e ILEGÍVEL dos dois lados, invisível ao teste automático de
   scrollWidth/clientWidth (que só vê o documento, não o elemento
   individual) — pior do que overflow, porque parecia "sem defeito
   nenhum" a esse teste. `max-width: 100%` dá ao item uma largura definida
   (100% do content-box de .alarm-overlay, já descontado o padding do
   overlay) para overflow-wrap ter contra o que quebrar. Mesmo raciocínio
   aplicado a .alarm-med-dosage (dosagem é texto livre do dono, maxlength
   200, tão sujeita a isto como o nome) e .alarm-error (mensagem de erro,
   por defesa). */
.alarm-med-name { font-size: 2.3rem; font-weight: 800; margin-bottom: 0.4rem; letter-spacing: -0.02em; max-width: 100%; }
.alarm-med-dosage { font-size: 1.3rem; opacity: 0.95; margin-bottom: 1.6rem; max-width: 100%; }
.alarm-hint { font-size: 0.85rem; opacity: 0.9; margin-bottom: 1rem; }
.alarm-error {
  background: rgba(0, 0, 0, 0.25); color: #fff; border-radius: var(--radius-sm);
  padding: 0.65rem 0.9rem; margin-bottom: 1rem; font-size: 0.9rem;
  max-width: 100%;
}
.alarm-actions { display: flex; gap: 0.8rem; width: 100%; max-width: 22rem; }
.alarm-btn {
  flex: 1; min-height: 3.4rem; border: 0; border-radius: var(--radius-md);
  font: inherit; font-size: 1.05rem; font-weight: 700; cursor: pointer;
}
.alarm-btn-take { background: #fff; color: var(--crisis-bg); }
.alarm-btn-dismiss { background: rgba(255, 255, 255, 0.15); color: #fff; border: 1px solid rgba(255, 255, 255, 0.6); }

/* --- tensão arterial --- */

.bp-record-btn { display: block; width: 100%; text-align: center; font-size: 1rem; padding: 1rem; margin-bottom: 1.1rem; }

.bp-latest { margin-bottom: 1.1rem; }

.bp-section-title {
  font-size: 0.75rem; color: var(--muted); margin-bottom: 0.7rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em;
}

.bp-ocr-row { margin-bottom: 0.6rem; }
.bp-ocr-row .btn-secondary { width: 100%; }

.bp-ocr-status {
  background: var(--info-bg-soft); color: var(--info); border: 0;
  border-radius: var(--radius-sm); padding: 0.65rem 0.85rem; margin-bottom: 0.85rem;
  font-size: 0.85rem;
}

/* Confiança baixa: mesma paleta "aviso" já usada em .bp-badge--aviso /
   .history-status-taken_late — troca de cor deliberada (não só o texto),
   para que "olhar duas vezes" seja visível de relance. */
.bp-ocr-status--baixa {
  background: var(--warn-bg-soft); color: var(--warn);
}

/* Sem o 5rem de margin-bottom que tinha antes, pela mesma razão que
   .meds-history acima: essa folga já vem centralizada em #content. */
.bp-settings-link {
  display: block; width: 100%; text-align: center; background: none; border: 0;
  color: var(--teal); font-family: inherit; font-size: 0.9rem; font-weight: 600;
  padding: 0.85rem 0; margin: 0.4rem 0; cursor: pointer;
}

.bp-list { list-style: none; display: flex; flex-direction: column; gap: 0.8rem; }
.bp-item {
  background: var(--card); border-radius: var(--radius-lg); padding: 1.1rem;
  box-shadow: var(--shadow-card);
  display: flex; justify-content: space-between; align-items: flex-start; gap: 0.6rem;
}
.bp-item-actions { flex-shrink: 0; }
.bp-item-actions .btn-danger { min-height: 2.3rem; padding: 0.4rem 0.75rem; font-size: 0.8rem; }

/* Cartão-resumo de uma medição (última medição em destaque, ou dentro de
   um item da lista): cor da borda esquerda e do badge seguem a severidade
   devolvida por classify()/classifyPulse() — nunca uma cor fixa, para que
   mudar um limiar nas Configurações mude visivelmente a cor na próxima
   vez que a mesma leitura for desenhada. */
.bp-summary {
  background: var(--card); border-radius: var(--radius-lg); padding: 1.1rem;
  border-left: 4px solid var(--muted); flex: 1; min-width: 0;
}
.bp-item .bp-summary { box-shadow: none; padding: 0; border-radius: 0; border-left: 0; }
.bp-latest .bp-summary { box-shadow: var(--shadow-card); }
.bp-summary--ok { border-left-color: var(--success); }
.bp-summary--aviso { border-left-color: var(--warn); }
.bp-summary--perigo { border-left-color: var(--danger); }

/* Número em destaque ("hero"): só dentro do cartão da ÚLTIMA medição
   (.bp-latest, partilhado por Tensão e Peso) — o mesmo .bp-values dentro
   de um item da lista (.bp-item) fica no tamanho normal, mais abaixo. Uma
   única classe, dois tamanhos consoante o contexto — sem precisar de uma
   classe "hero" à parte no HTML/JS. */
.bp-values { font-size: 1.2rem; font-weight: 700; letter-spacing: -0.01em; }
.bp-latest .bp-values { font-size: 2.3rem; font-weight: 800; letter-spacing: -0.02em; line-height: 1.15; }
.bp-time { color: var(--muted); font-size: 0.85rem; margin-top: 0.25rem; }
/* Mesmo raciocínio de .med-notes acima (pre-wrap + overflow-wrap: anywhere)
   — partilhada por tensão E peso (public/js/bp.js e public/js/weight.js,
   ambos atribuem esta classe às suas notas). */
.bp-note-text { color: var(--muted); font-size: 0.9rem; margin-top: 0.35rem; white-space: pre-wrap; overflow-wrap: anywhere; }

.bp-badge {
  display: inline-block; margin-top: 0.5rem; font-size: 0.8rem; font-weight: 700;
  padding: 0.25rem 0.65rem; border-radius: 999px;
}
.bp-badge--ok { background: var(--success-bg-soft); color: var(--success); }
.bp-badge--aviso { background: var(--warn-bg-soft); color: var(--warn); }
.bp-badge--perigo { background: var(--danger-bg-soft); color: var(--danger); }

/* --- gráfico (Fase 3 Task 3) --- */

.bp-chart-section { margin-bottom: 1.3rem; }
/* .weight-chart-views (Fase 4 Task 2) partilha este bloco via seletor
   combinado — mesmo visual, sem duplicar regras — reusa também
   .bp-chart-section acima e .bp-chart abaixo diretamente no markup do
   ecrã de Peso (public/index.html), sem precisar de classe própria.
   Estilo de "segmented control" do iOS: um trilho com padding, os botões
   sem fundo próprio, só o ativo ganha uma superfície + sombra — em vez de
   4 botões soltos com borda cada um. */
.bp-chart-views, .weight-chart-views {
  gap: 0.2rem; margin-bottom: 0.7rem; background: var(--field-bg);
  border-radius: var(--radius-sm); padding: 0.2rem;
}
/* [hidden] só ganha ao display do autor quando o seletor do autor também
   carrega :not([hidden]) — ver tests/css-hidden-guard.test.js e o histórico
   de 3 defeitos desta classe já apanhados neste projeto. */
.bp-chart-views:not([hidden]), .weight-chart-views:not([hidden]) { display: flex; }
.bp-chart-view-btn, .weight-chart-view-btn {
  flex: 1; padding: 0.45rem; border: 0; background: none;
  border-radius: calc(var(--radius-sm) - 0.2rem); font-size: 0.82rem; font-weight: 600;
  color: var(--muted); cursor: pointer;
}
.bp-chart-view-btn.active, .weight-chart-view-btn.active { background: var(--card); color: var(--text); box-shadow: var(--shadow-card); }

/* --- navegação de período (‹ rótulo ›) ---
   Uma classe só (.chart-nav*), partilhada por tensão E peso via navId
   diferente por instância — mesmo padrão de <div id="weight-chart"
   class="bp-chart"> logo abaixo (reusar a classe diretamente em vez de
   duplicar bp-chart-nav-*/weight-chart-nav-*, que aqui não fazia falta:
   ambos os contentores têm o mesmo navId só para o JS os distinguir, nunca
   precisam de estilos diferentes). Escondido por omissão na vista "Total"
   (sem período nenhum para navegar) e enquanto não há medições — por isso
   carrega [hidden] no HTML e por isso a regra de `display` abaixo precisa
   de :not([hidden]) (ver tests/css-hidden-guard.test.js). */
.chart-nav { align-items: center; justify-content: space-between; gap: 0.6rem; margin-bottom: 0.6rem; }
.chart-nav:not([hidden]) { display: flex; }
/* min-width: 0 pela mesma razão de .med-name/.history-item-name (ver
   comentário grande junto de .med-name, acima): item flex entre dois
   botões de largura fixa (‹/›) — sem isto, um rótulo de período mais
   longo (ex.: a variante de semana que atravessa fronteira de ano, "29
   dez 2025 – 4 jan 2026") podia forçar .chart-nav, e por arrasto o ecrã,
   a alargar em vez de o texto quebrar dentro do espaço disponível. */
.chart-nav-label { flex: 1; min-width: 0; text-align: center; font-size: 0.88rem; font-weight: 600; color: var(--text); }
.chart-nav-prev, .chart-nav-next {
  flex: none; width: 2.2rem; height: 2.2rem; border: 0; border-radius: 999px;
  background: var(--field-bg); color: var(--text); font-size: 1.1rem; line-height: 1;
  cursor: pointer;
}
/* Desativado nas duas pontas do intervalo de dados (o dono não pode
   "vaguear" para um período infinito e sempre vazio, ver bp-chart.js) —
   opacidade + cursor bastam; não há nada de crítico escondido só por CSS
   aqui, a navegação real já é bloqueada em JS (navigate() em bp-chart.js). */
.chart-nav-prev:disabled, .chart-nav-next:disabled { opacity: 0.35; cursor: default; }

/* --- intervalo de datas da vista "Total" (pedido do dono: "permite
   escolher uma data de início e outra de fim") ---
   Mesma classe partilhada por tensão E peso (bp-chart-range/weight-chart-
   range, via config.rangeId em bp-chart.js) — o mesmo padrão de
   .chart-nav* acima. Só visível na vista "Total" (escondido nas outras 3,
   que têm .chart-nav em vez disto) — por isso carrega [hidden] no HTML e
   a regra de `display` abaixo precisa de :not([hidden])
   (tests/css-hidden-guard.test.js).
   `flex-wrap: wrap` + `.chart-range-field { flex: 1 1 130px }`: a 320px os
   dois campos (rótulo + <input type="date">) cabem lado a lado (2×130px +
   gap < 320px, com a margem do cartão); num ecrã ainda mais estreito que
   este projeto não precisa de suportar, quebravam para duas linhas em vez
   de forçar scroll horizontal — nunca uma largura fixa em pixels que
   pudesse ultrapassar o cartão. .field já dá a cada campo o layout coluna
   rótulo/input (reaproveitado, ver .field acima) — só o `flex-wrap` do
   contentor e o `flex-basis` de cada campo são específicos daqui. */
.chart-range { gap: 0.6rem; margin-bottom: 0.6rem; flex-wrap: wrap; }
.chart-range:not([hidden]) { display: flex; }
.chart-range-field { flex: 1 1 130px; min-width: 0; }
/* `color-scheme: light dark` (não um valor fixo): sem isto o Safari/iOS
   desenha o <input type="date"> nativo (texto, cursor, ícone) sempre no
   estilo claro, mesmo com --field-bg escuro por trás — um "recorte"
   branco sobre um cartão escuro. Com isto, o próprio motor do browser
   escolhe claro/escuro consoante prefers-color-scheme, tal como o resto
   do tema desta app — nunca uma segunda paleta escrita à mão para um
   controlo nativo que o browser já sabe pintar sozinho. */
.chart-range-field input[type="date"] { color-scheme: light dark; }
/* max-width: 100% + overflow: hidden: o ApexCharts escreve larguras em
   pixel absolutas no SVG a partir da largura MEDIDA deste contentor
   (getBoundingClientRect, no momento do render/resize) — em qualquer
   instante entre essa medição e o próximo redesenho (troca de vista,
   resize da janela, fonte real do telemóvel a medir diferente da
   emulação), o SVG pode ficar momentaneamente mais largo do que o
   contentor. Sem isto, esse excesso empurrava a página toda para os
   lados; com isto, fica sempre recortado ao tamanho do cartão, nunca
   larga o ecrã. */
.bp-chart {
  background: var(--card); border-radius: var(--radius-lg); padding: 0.6rem 0.4rem;
  box-shadow: var(--shadow-card); min-height: 4rem;
  max-width: 100%; overflow: hidden;
}
.bp-chart-empty { margin: 0; padding: 1.5rem 0.5rem; }
/* .bp-chart-detail reutiliza .bp-summary/.bp-summary--<severidade> (já
   definidos acima) via className atribuído em bp-chart.js — sem `display`
   próprio aqui de propósito: um <div> é `display: block` por omissão do
   browser, por isso `[hidden]` funciona sozinho, sem precisar de
   :not([hidden]) (essa guarda só é necessária quando uma regra do autor
   fixa um display diferente de block/none). */
.bp-chart-detail { margin-top: 0.9rem; }
.bp-chart-detail-close {
  margin-top: 0.6rem; background: none; border: 0; color: var(--muted);
  font-size: 0.85rem; text-decoration: underline; cursor: pointer; padding: 0;
}

/* Ecrã de alerta de perigo — mesmo padrão do .alarm-overlay (sobreposição
   fixa a ecrã inteiro, guardada com :not([hidden])), mas sem a animação
   pulsante: informativo, nunca alarmista (brief da Task 2). Só o botão de
   dispensa explícita ($('bp-danger-dismiss')) esconde isto. Mesmo
   --crisis-bg do alarme (não var(--danger)) — o mesmo raciocínio de
   "constante entre temas, mais grave que o vermelho de badges" aplica-se
   aqui tal como lá. */
.bp-danger-overlay {
  position: fixed; inset: 0; z-index: 150;
  flex-direction: column; align-items: center; justify-content: center;
  padding: 2rem 1.5rem calc(2rem + env(safe-area-inset-bottom));
  text-align: center; color: #fff; background: var(--crisis-bg);
}
.bp-danger-overlay:not([hidden]) { display: flex; }
/* max-width: 100% nos dois — mesmo raciocínio de .alarm-med-name acima
   (filhos diretos de uma flex COLUMN com align-items: center não têm
   largura definida contra a qual overflow-wrap possa quebrar). O texto
   atual destes dois é sempre controlado pela app (nunca entrada livre do
   dono), por isso o risco real é baixo — mas o custo de o prevenir aqui é
   zero, e é a mesma classe de defeito que já mordeu .alarm-med-name. */
.bp-danger-title { font-size: 1.5rem; font-weight: 700; margin-bottom: 1rem; max-width: 100%; }
.bp-danger-value { font-size: 2.1rem; font-weight: 800; margin-bottom: 1rem; letter-spacing: -0.02em; max-width: 100%; }
.bp-danger-message { font-size: 1.05rem; line-height: 1.5; margin-bottom: 2rem; max-width: 28rem; }
/* .alarm-btn tem `flex: 1` (pensado para o eixo horizontal de
   .alarm-actions, ver acima) — como este botão é filho direto de
   .bp-danger-overlay (eixo vertical, flex-direction: column), esse mesmo
   `flex: 1` fazia-o crescer a preencher a altura toda do ecrã em vez de
   ficar do tamanho do texto. `flex: none` neutraliza isso aqui. */
.bp-danger-overlay .alarm-btn { flex: none; width: 100%; max-width: 16rem; }
.bp-danger-overlay .alarm-btn-take { color: var(--crisis-bg); }

/* --- "Acerca de" (dedicatória) ---
   Mesmo padrão de sobreposição a ecrã inteiro que .bp-danger-overlay/
   .alarm-overlay já usam (position: fixed; inset: 0; guardado com
   :not([hidden]) — ver tests/css-hidden-guard.test.js). Fundo --teal (o
   mesmo da .topbar/.login-body) em vez do --crisis-bg do alarme/perigo: isto
   não é um aviso, é uma dedicatória — a cor de marca, não a de alerta, é o
   tom certo, e mantém-se igual em claro/escuro tal como a topbar já faz.
   z-index abaixo do alarme e do alerta de perigo (100/150, acima): se um
   lembrete de medicamento ou uma leitura de tensão fora do intervalo
   disparar enquanto esta folha está aberta, o mais urgente continua a
   ganhar — nunca o contrário. */
.info-overlay {
  position: fixed; inset: 0; z-index: 60;
  flex-direction: column; align-items: center; justify-content: center;
  padding: 2rem 1.5rem calc(2rem + env(safe-area-inset-bottom));
  text-align: center; color: #fff; background: var(--teal);
}
.info-overlay:not([hidden]) { display: flex; }
.info-close {
  position: absolute; top: calc(env(safe-area-inset-top) + 1rem); right: 1.3rem;
  background: none; border: 0; padding: 0.5rem 0.3rem;
  font-family: inherit; color: #fff; opacity: 0.9;
  text-decoration: underline; font-size: 0.9rem; cursor: pointer;
}
.info-content { max-width: 26rem; }
/* Dedicatória em letras grandes, propositadamente — não é texto miúdo, é o
   ponto central deste ecrã (pedido do dono: "em letras grandes"). Sem
   largura fixa (só max-width no pai), com overflow-wrap explícito — já
   herdado do body (ver esse comentário), mas repetido aqui para nunca
   depender só disso: mesmo uma palavra sem espaços nenhuns não empurra a
   largura além do ecrã a 320px. */
.info-credit {
  font-size: 1.5rem; font-weight: 700; line-height: 1.5;
  overflow-wrap: break-word; max-width: 100%;
}

/* --- configurações de limiares --- */

.bp-settings-status { color: var(--muted); font-size: 0.9rem; }
.bp-settings-fields { display: flex; flex-direction: column; gap: 0.85rem; }
.threshold-row { background: var(--bg); border-radius: var(--radius-sm); padding: 0.75rem; }
.threshold-row-title { font-weight: 700; font-size: 0.9rem; margin-bottom: 0.55rem; }
.threshold-row-fields { display: flex; gap: 0.6rem; }
.threshold-row-fields .field { flex: 1; }

/* --- peso (Fase 4 Task 2) --- */
/* Cartão de destaque, itens da lista e ações reutilizam .bp-summary/
   .bp-values/.bp-time/.bp-note-text/.bp-item/.bp-item-actions diretamente
   (public/js/weight.js) — esses estilos já são genéricos (um cartão com
   valor+data+nota), sem nada específico de tensão arterial, por isso não há
   CSS novo para eles aqui. Só a linha de variação (sem equivalente na
   Tensão) precisa de classes próprias. */
.weight-change { font-size: 0.9rem; font-weight: 700; margin-top: 0.35rem; }
.weight-change--up { color: var(--weight-up); }
.weight-change--down { color: var(--weight-down); }
.weight-change--same { color: var(--muted); font-weight: 600; }
