/* Brand overrides for the FlexAdmin template.
   Loaded after flexadmin/css/main.css. Nothing here edits third-party files:
   the template exposes its whole palette as custom properties on :root, and
   even reads them back at runtime to colour ApexCharts. */

:root {
  /* Core palette — warm off-white page, white surfaces, graphite ink.
     Sampled from the client's logo: metal #74736E, highlight #C1C0BB. */
  --background-color: #f7f7f5;
  --surface-color: #ffffff;
  --default-color: #2b2a28;
  --heading-color: #171614;
  --accent-color: #3f3e39;
  --contrast-color: #ffffff;

  --muted-color: #6e6d67;
  --light-color: #9b9a93;

  --border-color: #e4e3de;
  --border-color-light: #f0efeb;
  --border-color-dark: #d2d1ca;

  /* Status colours double as the check-in traffic light, so they are the only
     saturated hues in the interface — the rest of the UI stays neutral on
     purpose, to keep the signal readable at a glance. */
  --success-color: #16a34a;
  --success-color-light: #dcfce7;
  --warning-color: #ca8a04;
  --warning-color-light: #fef9c3;
  --danger-color: #dc2626;
  --danger-color-light: #fee2e2;
  /* Info carries no domain meaning here; kept neutral so it never competes
     with the traffic light. */
  --info-color: #3f3e39;
  --info-color-light: #edece8;

  --header-bg: rgba(255, 255, 255, 0.92);
  --header-shadow: 0 1px 0 rgb(23 22 20 / 0.06);

  --sidebar-bg: #ffffff;
  --sidebar-border: #e4e3de;
  --sidebar-color: #2b2a28;
  --sidebar-muted-color: #6e6d67;
  --sidebar-hover-bg: rgb(63 62 57 / 0.06);
  --sidebar-active-bg: #3f3e39;
  --sidebar-active-color: #ffffff;

  --table-header-bg: #f4f3f0;
  --table-hover-bg: #f7f7f5;
  --table-stripe-bg: #fbfbfa;

  --input-focus-ring: rgb(63 62 57 / 0.18);
}

/* Domain tokens: the traffic light is a single rule (rating 1-2 red, 3 yellow,
   4-5 green) and every surface that renders it — calendar cells, badges,
   charts — resolves the colour through these names. */
:root {
  --status-green: var(--success-color);
  --status-green-soft: var(--success-color-light);
  --status-yellow: var(--warning-color);
  --status-yellow-soft: var(--warning-color-light);
  --status-red: var(--danger-color);
  --status-red-soft: var(--danger-color-light);
  --status-empty: #e4e3de;
  --status-empty-soft: #f4f3f0;
}

.status-green {
  color: var(--status-green);
  background-color: var(--status-green-soft);
}

.status-yellow {
  color: var(--status-yellow);
  background-color: var(--status-yellow-soft);
}

.status-red {
  color: var(--status-red);
  background-color: var(--status-red-soft);
}

.status-empty {
  color: var(--light-color);
  background-color: var(--status-empty-soft);
}

/* Logout has to be a POST — as a GET, any page could sign a patient out with an
   <img src="/sair/">. That turns the template's logout links into buttons, and
   these classes were written assuming an anchor. */
button.user-menu-logout,
button.sidebar-footer-action {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  cursor: pointer;
}

button.user-menu-logout {
  width: 100%;
}

/* Falls back to initials when a user has no photo. Width, height and radius
   come from whichever FlexAdmin avatar class the caller passes in. */
.tv-avatar-initials {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--info-color-light);
  color: var(--accent-color);
  font-family: var(--heading-font);
  font-size: 0.78em;
  font-weight: 600;
  letter-spacing: 0.02em;
  overflow: hidden;
}

/* ---------------------------------------------------------------------------
   Patient app shell. FlexAdmin has no mobile chrome, so this is ours.
   --------------------------------------------------------------------------- */

.tv-app {
  background: var(--background-color);
  min-height: 100svh;
}

.tv-appbar {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 1030;
  height: var(--header-height);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-sm);
  padding: 0 var(--spacing-md);
  background: var(--header-bg);
  -webkit-backdrop-filter: saturate(140%) blur(8px);
  backdrop-filter: saturate(140%) blur(8px);
  border-bottom: 1px solid var(--header-border);
}

.tv-appbar-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-sm);
  min-width: 0;
  font-family: var(--heading-font);
  font-weight: 600;
  color: var(--heading-color);
}

.tv-appbar-brand img {
  height: 26px;
  width: auto;
}

.tv-appbar-brand span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tv-appbar-actions {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs);
}

/* The avatar is the way into the account menu. The tab bar is the daily flow,
   and reading your own record or editing your data is not a daily act. */
.tv-appbar-profile {
  display: inline-flex;
  line-height: 0;
  /* It is a <button> so the dropdown can own it; everything a button brings
     with it has to go, or the avatar sits inside a grey pill. */
  padding: 0;
  border: 0;
  background: none;
}

/* Bootstrap's own dropdown-item styling assumes an <a> or a lone <button>; the
   logout button is wrapped in its form, so the form must not become a row. */
.tv-appbar-menu .dropdown-menu form {
  margin: 0;
}

.tv-appbar-menu .dropdown-item {
  width: 100%;
  text-align: left;
}

.tv-app-main {
  /* Bottom padding clears the tab bar plus the iPhone home indicator. */
  padding: calc(var(--header-height) + var(--spacing-md)) var(--spacing-md)
    calc(72px + var(--spacing-lg) + env(safe-area-inset-bottom));
  max-width: 640px;
  margin-inline: auto;
}

.tv-tabbar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 1030;
  display: flex;
  justify-content: space-around;
  gap: var(--spacing-xs);
  padding: var(--spacing-xs) var(--spacing-sm) calc(var(--spacing-xs) + env(safe-area-inset-bottom));
  background: var(--surface-color);
  border-top: 1px solid var(--border-color);
}

.tv-tab {
  flex: 1;
  max-width: 120px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: var(--spacing-xs) 0;
  border-radius: var(--radius-md);
  text-decoration: none;
  color: var(--muted-color);
  font-size: 0.7rem;
  font-weight: 600;
  /* Keeps the whole tab a comfortable touch target on small phones. */
  min-height: 56px;
  justify-content: center;
}

.tv-tab i {
  font-size: 1.35rem;
  line-height: 1;
}

/* Mesmo com cinco abas o rótulo mais largo ("Histórico") chega perto da
   largura do item em telas de 320 px. Cortar com reticências é preferível a
   deixar o texto vazar por cima da aba vizinha — e nenhum rótulo depende da
   última letra. */
.tv-tab span {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tv-tab.active {
  color: var(--accent-color);
  background: var(--sidebar-hover-bg);
}

/* ---------------------------------------------------------------------------
   Check-in screen.
   --------------------------------------------------------------------------- */

.tv-ratings {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--spacing-xs);
}

/* Off-screen rather than display:none, so the radio still takes keyboard focus
   and screen readers still announce the group. */
.tv-rating-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.tv-rating-label {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 78px;
  padding: var(--spacing-sm) 2px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  color: var(--muted-color);
  text-align: center;
  cursor: pointer;
}

.tv-rating-label i {
  font-size: 1.6rem;
  line-height: 1;
}

.tv-rating-label span {
  font-size: 0.62rem;
  font-weight: 600;
}

.tv-rating-input:focus-visible + .tv-rating-label {
  outline: 3px solid var(--input-focus-ring);
}

/* The chosen face lights up in its own traffic-light colour: the patient sees
   the classification, not just the selection. */
.tv-rating-input:checked + .tv-rating-label[data-status="green"] {
  color: var(--status-green);
  border-color: var(--status-green);
  background: var(--status-green-soft);
}

.tv-rating-input:checked + .tv-rating-label[data-status="yellow"] {
  color: var(--status-yellow);
  border-color: var(--status-yellow);
  background: var(--status-yellow-soft);
}

.tv-rating-input:checked + .tv-rating-label[data-status="red"] {
  color: var(--status-red);
  border-color: var(--status-red);
  background: var(--status-red-soft);
}

.tv-question {
  padding: var(--spacing-sm) 0;
  border-bottom: 1px solid var(--border-color-light);
}

.tv-question:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}

/* Pending is the strong state: it is what the patient still has to read.
   Answered recedes to the old default look, so the list fades as it fills. */
.tv-question-name {
  display: block;
  margin-bottom: 6px;
  font-size: 1rem;
  font-weight: 600;
  color: var(--heading-color);
}

.tv-question.is-set .tv-question-name {
  font-size: 0.9rem;
  font-weight: 400;
  color: inherit;
}

/* Quebra de linha, sempre. Sem isso a faixa é obrigada a caber numa linha só,
   e com a fonte ampliada do celular (Android/iOS "texto grande") as opções
   eram espremidas até o texto vazar da caixa e escrever por cima da vizinha —
   reproduzido em 320px com a fonte a 22px, em "Inchaço / retenção de líquido"
   e em "Por que saiu do plano?". */
.tv-question-options {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* A base é o piso: as opções crescem para dividir a linha, mas não encolhem
   abaixo dela — quando não couberem, descem. `min-width: 0` fazia o oposto:
   removia exatamente a proteção do flexbox contra encolher além do conteúdo. */
.tv-question-option {
  position: relative;
  flex: 1 1 5rem;
}

/* Escala 0–5: seis opções de um caractere cabem numa linha só, e a base de
   5rem quebraria a régua em duas. */
.tv-question[data-answer="SCALE"] .tv-question-option {
  flex-basis: 2rem;
}

/* The input stays in the DOM and keeps working without CSS; it is the label
   that gets painted. Clipped rather than display:none so it remains reachable
   by the keyboard and by screen readers. */
.tv-question-option input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.tv-question-option label {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  /* `min-height`, nunca `height`: a caixa cresce com o texto em vez de deixá-lo
     transbordar por cima e por baixo, que era como um rótulo de duas linhas
     escrevia sobre a pergunta seguinte. 44px é o alvo mínimo de toque do iOS —
     os 40px antigos já ficavam abaixo dele. */
  min-height: 44px;
  padding: 6px 8px;
  line-height: 1.25;
  /* Última defesa: rótulo com uma palavra mais larga que a caixa
     ("específico") quebra dentro dela em vez de vazar. */
  overflow-wrap: anywhere;
  hyphens: auto;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  background: var(--surface-color);
  color: var(--heading-color);
  font-size: 0.9rem;
  cursor: pointer;
}

.tv-question-option input:checked + label {
  border-color: var(--accent-color);
  background: var(--accent-color);
  color: #fff;
  font-weight: 600;
}

.tv-question-option input:focus-visible + label {
  outline: 2px solid var(--accent-color);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
   History calendar.
   --------------------------------------------------------------------------- */

.tv-calendar {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}

.tv-calendar-weekday {
  padding-bottom: 4px;
  color: var(--muted-color);
  font-size: 0.68rem;
  font-weight: 700;
  text-align: center;
}

.tv-calendar-day {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1;
  border-radius: var(--radius-sm);
  font-size: 0.8rem;
  font-weight: 600;
}

.tv-calendar-day.is-blank {
  background: none;
}

.tv-calendar-day.is-future {
  opacity: 0.35;
}

/* An editable day is a link. The thin ring marks the one case worth a tap —
   a day still open with nothing recorded — and steps aside for `is-today`,
   which already draws its own, stronger ring. */
a.tv-calendar-day {
  color: inherit;
  text-decoration: none;
}

a.tv-calendar-day.status-empty:not(.is-today) {
  box-shadow: inset 0 0 0 1px var(--accent-color);
}

.tv-calendar-day.is-today {
  box-shadow: inset 0 0 0 2px var(--accent-color);
}

.tv-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-sm);
  margin-top: var(--spacing-md);
  color: var(--muted-color);
  font-size: 0.72rem;
}

.tv-legend span {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.tv-legend-dot {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: var(--radius-full);
  /* Colour arrives through the status- class; only the fill differs. */
  background: currentColor;
}

.tv-face {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: var(--radius-full);
  font-size: 1.15rem;
}

/* ---------------------------------------------------------------------------
   Habit editor (panel).
   --------------------------------------------------------------------------- */

.tv-habit-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  padding: 4px 0;
}

.tv-habit-row form {
  margin: 0;
}

.tv-habit-row > form:first-child {
  flex: 1 1 auto;
  min-width: 0;
}

.tv-habit-actions {
  display: flex;
  flex: 0 0 auto;
  gap: 2px;
}

/* A retired habit stays on the screen — it is how the nutritionist brings it
   back — but reads as switched off. */
.tv-habit-row.is-retired input {
  color: var(--light-color);
  text-decoration: line-through;
}

/* The consent text is long on purpose: it scrolls inside the card instead of
   pushing the password fields off the screen. */
.tv-terms {
  max-height: 11rem;
  margin-bottom: var(--spacing-md);
  overflow-y: auto;
  padding: var(--spacing-md);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  background: var(--background-color);
  color: var(--muted-color);
  font-size: 0.8rem;
}

.tv-terms p:last-child {
  margin-bottom: 0;
}

/* The ranking bars open the patient record. Without a pointer they read as a
   plain chart and nobody discovers the link. */
#tv-panel-ranking .apexcharts-bar-area {
  cursor: pointer;
}

/* Splash */
/* Opening splash — the vectorized V mark (templates/pwa/_splash_trace.svg)
   draws itself as construction lines, then the finished artwork
   (splash-art.svg) fades in over it: the mark's grey texture stack, whose
   holes are the runes and the leaf. The wordmark left the splash with the
   name and the CRN (client request, 2026-09-04) — "Team Viana" is written as
   text by the shells, not by the artwork. Hidden until the inline script in
   pwa/_splash.html adds .tv-splash-play, so a no-JS client is never trapped
   behind the overlay. */
.tv-splash {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: none;
  align-items: center;
  justify-content: center;
  background: #fff;
}

/* The stage sizes the inline lines SVG; the artwork <img> is stretched over
   it. Both files carry the same computed viewBox, so the overlay is exact. */
.tv-splash-stage {
  position: relative;
  width: min(60vw, 240px);
}

.tv-splash-stage svg {
  display: block;
  width: 100%;
  height: auto;
}

.tv-splash-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
}

.tv-trace {
  fill: none;
  stroke: #777670;
  stroke-width: 4;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}

.tv-splash-play {
  display: flex;
  animation: tv-splash-out 0.4s ease 1.4s forwards;
}

.tv-splash-play .tv-splash-stage {
  animation: tv-splash-settle 1.2s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

/* Choreography: the V and the wheat draw themselves; at 1s the artwork fades
   in over the lines as they fade out. The overlay leaves at 1.4s.
   pathLength="1" normalizes the path, so the dash offset runs 1 -> 0
   regardless of contour length. */
.tv-splash-play .tv-trace-mark {
  animation:
    tv-splash-draw 0.8s ease-in-out forwards,
    tv-splash-lines-out 0.4s ease 1s forwards;
}

.tv-splash-play .tv-splash-art {
  animation: tv-splash-art-in 0.4s ease 1s forwards;
}

@keyframes tv-splash-draw {
  to { stroke-dashoffset: 0; }
}

@keyframes tv-splash-lines-out {
  to { stroke-opacity: 0; }
}

@keyframes tv-splash-art-in {
  to { opacity: 1; }
}

@keyframes tv-splash-settle {
  from { transform: scale(0.94); }
  to { transform: scale(1); }
}

@keyframes tv-splash-out {
  to {
    opacity: 0;
    visibility: hidden;
  }
}

@media (prefers-reduced-motion: reduce) {
  .tv-trace {
    stroke-opacity: 0;
  }
  .tv-splash-art {
    opacity: 1;
  }
  .tv-splash-play .tv-splash-stage,
  .tv-splash-play .tv-trace,
  .tv-splash-play .tv-splash-art {
    animation: none;
  }
  .tv-splash-play {
    animation: tv-splash-out 0.3s ease 0.5s forwards;
  }
}

/* Conquista — o modal de parabéns e a prévia da arte que vai para o story. */
.tv-celebration-kicker {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-weight: 700;
  color: var(--muted-color);
  margin-bottom: 0.25rem;
}

.tv-celebration-art {
  width: 100%;
  max-width: 260px;
  height: auto;
  border-radius: 12px;
  border: 1px solid var(--border-color);
  box-shadow: 0 8px 20px rgb(23 22 20 / 0.1);
}

/* Foto de perfil — o avatar é o controle, e o distintivo de câmera é o que
   sinaliza isso. O botão zera o estilo nativo para não desenhar moldura em
   volta da foto. */
.tv-photo-trigger {
  position: relative;
  padding: 0;
  border: 0;
  background: none;
  border-radius: 50%;
  line-height: 0;
  cursor: pointer;
  flex-shrink: 0;
}

.tv-photo-trigger:focus-visible {
  outline: 3px solid var(--input-focus-ring);
  outline-offset: 2px;
}

.tv-photo-badge {
  position: absolute;
  right: -2px;
  bottom: -2px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--accent-color);
  color: var(--contrast-color);
  border: 2px solid var(--surface-color);
  display: grid;
  place-items: center;
  font-size: 0.7rem;
  line-height: 1;
}

.tv-photo-large {
  width: 100%;
  max-width: 260px;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 50%;
  border: 1px solid var(--border-color);
  margin-inline: auto;
}

/* As iniciais herdam o mesmo círculo, mas precisam centralizar o texto que a
   imagem não tem. */
span.tv-photo-large {
  display: grid;
  place-items: center;
  font-family: "Sora", system-ui, sans-serif;
  font-size: 3.5rem;
  font-weight: 600;
}

/* ---------------------------------------------------------------------------
   Anthropometry — the body plate and the measurement panel.

   The plate is meant to read as an anatomy atlas sheet: hairline graphite,
   transparent fills, dotted leader lines out to the margin. Colour arrives
   only on the region being asked about, and the accent is the same graphite
   the rest of the panel uses — a body measurement carries no verdict, so
   nothing here is allowed to look like a score.

   The two figures are traced from `brand/anthro/` and the rules below are what
   colour them; the drawing itself lives in `templates/clinical/_body_map.html`,
   which is also where the reason for each choice here is written down.

   Font sizes inside the SVG are in user units, which the viewBox scales with
   the card: they are not the rem scale and are not meant to match it.
   --------------------------------------------------------------------------- */

.tv-anthro-plate {
  display: grid;
  gap: var(--spacing-md);
}

.tv-anthro-sheet {
  display: block;
  width: 100%;
  height: auto;
  /* Nothing on the plate is text worth selecting, and a drag to reach a
     region would otherwise highlight every label on the way. */
  user-select: none;
}

.tv-anthro-frame {
  fill: none;
  stroke: var(--border-color);
  stroke-width: 1.5;
}

/* The three drawing layers of `brand/anthro/`, from the outline down to the
   faintest hint. Two things they all obey:

   1. **The properties are declared on the group, never on the shapes.** Half
      the frontal figure is a `<use>` reflection, and CSS class rules do not
      match inside a `<use>` shadow tree — only inherited values reach it. A
      selector written as `.tv-anthro-figure path` would paint the drawn half
      and leave the mirrored one at the initial black.
   2. **The hue is the brand's, the fallback is the artwork's.** The source
      files are hardcoded to #23262a/#4b5158/#6a7076; the tokens are the same
      graphite family, and the fallback keeps the plate readable if a token is
      ever renamed out from under it.

   Stroke widths are the source files' own (2.3/1.2/1), which is what makes the
   plate look like the drawing and not like a re-inking of it. */
.tv-anthro-figure {
  fill: none;
  stroke: var(--default-color, #23262a);
  stroke-width: 2.3;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tv-anthro-detail {
  fill: none;
  stroke: var(--muted-color, #4b5158);
  stroke-width: 1.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tv-anthro-hint {
  fill: none;
  stroke: var(--light-color, #6a7076);
  stroke-width: 1;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.55;
}

/* The contact shadow. Barely there on purpose: any more and it reads as a
   second measurement band lying at the figure's feet. */
.tv-anthro-ground {
  fill: var(--default-color, #23262a);
  stroke: none;
  opacity: 0.055;
}

.tv-anthro-crop {
  stroke: var(--border-color-dark);
  stroke-width: 1.8;
  stroke-dasharray: 10 9;
}

.tv-anthro-leader {
  stroke: var(--border-color-dark);
  stroke-width: 1.5;
  stroke-dasharray: 3 6;
}

.tv-anthro-caption,
.tv-anthro-name,
.tv-anthro-footnote,
.tv-anthro-side-mark,
.tv-anthro-label-value {
  font-family: var(--default-font);
}

/* Both sheets are 760 user units wide and render at the card's width, so a
   user unit is 760/500 smaller than it was on the previous plates: every size
   below is the old one times 1.52, which is what keeps the type at the size it
   was drawn to be read at. Changing one sheet's viewBox without the other
   silently rescales the labels on both. */
.tv-anthro-caption {
  fill: var(--light-color);
  font-size: 20px;
  font-weight: 600;
  letter-spacing: 0.18em;
}

.tv-anthro-name {
  fill: var(--muted-color);
  font-size: 20px;
  letter-spacing: 0.03em;
}

.tv-anthro-label-value {
  fill: var(--heading-color);
  font-size: 29px;
  font-weight: 600;
}

/* A measurement that was not taken still gets its line on the plate: the
   dash says "not measured", which a missing label would not. */
.tv-anthro-label-value.is-empty {
  fill: var(--light-color);
  font-weight: 500;
}

.tv-anthro-side-mark {
  fill: var(--muted-color);
  font-size: 21px;
  font-weight: 700;
  letter-spacing: 0.04em;
}

.tv-anthro-footnote {
  fill: var(--light-color);
  font-size: 20px;
}

.tv-anthro-region {
  cursor: pointer;
}

/* The hit area is a good deal larger than the band it wraps: the bands are
   12-28 units tall inside a 1160-unit sheet, which is a finger-width of
   nothing on a laptop trackpad. */
.tv-anthro-hit {
  fill: transparent;
  stroke: none;
}

.tv-anthro-band {
  fill: transparent;
  stroke: var(--muted-color);
  stroke-width: 2.1;
  transition:
    stroke 120ms ease,
    stroke-width 120ms ease,
    fill 120ms ease;
}

/* Measured in the open assessment — applied by anthropometry.js, so the plate
   without a script shows the quiet version of every band and still reads. */
.tv-anthro-region.is-filled .tv-anthro-band {
  stroke: var(--heading-color);
  stroke-width: 3;
}

.tv-anthro-region:hover .tv-anthro-band {
  fill: var(--info-color-light);
  stroke: var(--accent-color);
}

.tv-anthro-region.is-active .tv-anthro-band {
  fill: var(--info-color-light);
  stroke: var(--accent-color);
  stroke-width: 4;
}

.tv-anthro-region:focus {
  outline: none;
}

/* The ring token is a halo colour — `rgb(63 62 57 / 0.18)` is about 1.35:1 on
   the white sheet, and WCAG 2.2 asks 3:1 of a focus indicator. Everywhere else
   in this file it is layered *over* a solid border (`outline: 3px solid` sits
   on top of the input's own edge); here there is no edge underneath, so the
   ring has to be the solid colour itself. */
.tv-anthro-region:focus-visible .tv-anthro-hit {
  stroke: var(--input-focus-border);
  stroke-width: 4.5;
}

/* The selected region's own leader and label come forward with it, so the
   answer in the panel is visibly the line the eye is on. */
.tv-anthro-callouts [data-callout].is-active .tv-anthro-leader {
  stroke: var(--accent-color);
  stroke-dasharray: none;
}

.tv-anthro-callouts [data-callout].is-active .tv-anthro-name {
  fill: var(--heading-color);
}

/* --- Overview, panel and photo slots ------------------------------------- */

.tv-anthro-metric {
  padding: var(--spacing-sm) 0;
}

.tv-anthro-metric-label {
  display: block;
  color: var(--muted-color);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
}

.tv-anthro-value {
  font-family: var(--heading-font);
  font-size: 1.35rem;
  font-weight: 600;
  color: var(--heading-color);
  line-height: 1.3;
}

.tv-anthro-value.is-empty {
  color: var(--light-color);
  font-weight: 500;
}

.tv-anthro-unit {
  font-family: var(--default-font);
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--muted-color);
}

/* Deltas are stated, never judged: a centimetre off a thigh is not good news
   or bad news until the nutritionist says which. Hence one neutral colour
   for both directions — the sign carries the whole meaning. */
.tv-anthro-delta {
  font-family: var(--heading-font);
  font-weight: 600;
  color: var(--heading-color);
}

.tv-anthro-history {
  max-height: 13rem;
  overflow-y: auto;
}

.tv-anthro-history li {
  display: flex;
  justify-content: space-between;
  gap: var(--spacing-md);
  padding: 0.3rem 0;
  border-bottom: 1px solid var(--border-color-light);
  font-size: 0.85rem;
}

.tv-anthro-history li:last-child {
  border-bottom: 0;
}

.tv-anthro-slot {
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--background-color);
}

.tv-anthro-slot-empty {
  border-style: dashed;
}

.tv-anthro-thumb {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
}

/* The empty slot keeps the filled one's proportion, so a half-photographed
   assessment does not turn the row into a staircase. */
.tv-anthro-slot-body {
  display: grid;
  place-items: center;
  gap: var(--spacing-xs);
  aspect-ratio: 3 / 4;
  padding: var(--spacing-sm);
  text-align: center;
}

.tv-anthro-slot-caption {
  padding: var(--spacing-xs) var(--spacing-sm);
  border-top: 1px solid var(--border-color);
  background: var(--surface-color);
  font-size: 0.78rem;
}

.tv-anthro-row.is-open {
  background: var(--table-hover-bg);
}

/* --- Comparison mode ------------------------------------------------------
   The evolution table is one reading per line, not two tables side by side:
   the pair lives in a single cell, the arrow carries the direction, and only
   the final value takes the ink — it is the one the eye is looking for. The Δ
   keeps the neutral `.tv-anthro-delta` treatment of the panel, for the same
   reason: the sign is the whole statement. */

.tv-anthro-evo-pair {
  white-space: nowrap;
  color: var(--muted-color);
}

.tv-anthro-evo-final {
  color: var(--heading-color);
  font-weight: 600;
}

.tv-anthro-evo-arrow {
  padding: 0 0.15rem;
  color: var(--light-color);
}

/* FlexAdmin's sidebar rule (.nav-item > .nav-link.active, main.css:2619)
   bleeds its dark gradient into every Bootstrap nav; nav-underline's own
   rule then recolors the text to --accent-color — which the brand overrides
   to graphite, leaving graphite on graphite. The underline IS the active
   marker here, so the pill background has no business existing. */
.nav-underline .nav-item > .nav-link.active {
  background: transparent;
  box-shadow: none;
}

/* On the form the plate is a control, not an illustration: it has to still be
   on screen when the nutritionist reaches the calf fields, two thousand
   pixels down. Only from lg up — below that the plate sits after the form and
   sticking it would pin it to the bottom of the page. */
@media (min-width: 992px) {
  .tv-anthro-sticky {
    position: sticky;
    top: calc(var(--header-height) + var(--spacing-md));
  }
}

@media (prefers-reduced-motion: reduce) {
  .tv-anthro-band {
    transition: none;
  }
}

/* --- Lista de compras -----------------------------------------------------
   Comprado é riscado, nunca removido: a linha continua legível para quem
   quiser conferir o que já pegou. "Ocultar comprados" é uma classe no
   contêiner — o CSS já sabe quais linhas estão marcadas, então o JS não
   percorre a lista para esconder nada. */

.tv-shopping-done .tv-shopping-name {
  color: var(--muted-color);
  text-decoration: line-through;
}

.tv-shopping-hiding .tv-shopping-done {
  display: none;
}

/* --- Meu plano: a refeição mais próxima do horário atual -------------------
   Aplicado por `my-plan.js`, no relógio do próprio aparelho — nunca pelo
   servidor. Tratamento clínico, não de julgamento: nada da paleta de
   status (verde/amarelo/vermelho) entra aqui. */

.tv-meal-now {
  box-shadow: inset 3px 0 0 0 var(--accent-color);
  background-color: rgb(63 62 57 / 0.04);
}

.tv-meal-now-chip {
  display: inline-flex;
  align-items: center;
  margin-left: 0.4rem;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  background: var(--accent-color);
  color: var(--contrast-color);
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  vertical-align: middle;
}

/* Impressão: a lista é o único documento do app que alguém leva ao mercado em
   papel. Some com o cromo das duas cascas (app bar, tab bar, header, sidebar,
   rodapé) e com os controles marcados `tv-no-print` — botão impresso é tinta
   gasta. Vale para qualquer tela: nenhuma delas quer imprimir o menu. */
@media print {
  .tv-appbar,
  .tv-tabbar,
  .header,
  .sidebar,
  .sidebar-overlay,
  .footer,
  .back-to-top,
  .page-header-actions,
  .tv-no-print {
    display: none !important;
  }

  .tv-app-main,
  .main,
  .main-content {
    margin: 0 !important;
    padding: 0 !important;
  }

  .card {
    border: 0;
    box-shadow: none;
  }
}

/* ---------------------------------------------------------------------------
   Agenda (painel). Uma grade CSS própria, sem biblioteca de calendário: a
   posição e a altura de cada atendimento chegam prontas de `schedule/reports.py`
   como linha e span, então o navegador só desenha o que o servidor já decidiu.

   `--tv-agenda-row` é só a altura de uma linha; quantas linhas cada coisa ocupa
   é `ROW_MINUTES` no Python. Mudar a altura aqui apenas estica a semana —
   nenhum alinhamento depende deste valor.
   --------------------------------------------------------------------------- */

/* No `:root` e não no `.tv-agenda` porque a legenda é irmã da grade, não filha:
   o mesmo cinza tem de sair de um lugar só, senão o quadradinho da legenda passa
   a mentir sobre a faixa que ele explica. */
:root {
  --tv-agenda-off-bg: rgb(23 22 20 / 0.045);
}

.tv-agenda {
  --tv-agenda-row: 5px;
  --tv-agenda-gutter: 3.25rem;
  min-width: 46rem;
}

/* A semana não cabe num telefone em pé, e espremer sete colunas até caberem
   deixaria os blocos ilegíveis. Rolar horizontalmente é a resposta honesta. */
.tv-agenda-scroll {
  overflow-x: auto;
}

.tv-agenda-head,
.tv-agenda-body {
  display: grid;
  grid-template-columns: var(--tv-agenda-gutter) repeat(7, minmax(0, 1fr));
}

.tv-agenda-head {
  /* No `position: sticky` here: `.tv-agenda-scroll` only ever scrolls
     horizontally, so there is no vertical scrollport for it to stick within. */
  background: var(--surface-color);
  border-bottom: 1px solid var(--border-color);
}

.tv-agenda-head-day {
  padding: var(--spacing-xs) 4px;
  border-left: 1px solid var(--border-color-light);
  color: var(--default-color);
  text-align: center;
  text-decoration: none;
}

.tv-agenda-head-day:hover {
  background: var(--table-hover-bg);
}

.tv-agenda-head-weekday {
  display: block;
  color: var(--muted-color);
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.tv-agenda-head-date {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
}

.tv-agenda-head-day.is-today {
  box-shadow: inset 0 -2px 0 var(--accent-color);
}

.tv-agenda-body {
  position: relative;
  /* `grid-template-rows` vem inline: só o servidor sabe quantas horas a semana
     precisa mostrar. */
}

/* Colunas dos dias, desenhadas como linhas verticais em vez de elementos —
   uma borda por coluna evita sete divs vazias por dia. */
.tv-agenda-body::before {
  content: "";
  grid-column: 2 / -1;
  grid-row: 1 / -1;
  background-image: repeating-linear-gradient(
    to right,
    var(--border-color-light) 0 1px,
    transparent 1px calc(100% / 7)
  );
}

/* A etiqueta e o fio da hora não ocupam linha: encostam no topo da sua e ficam
   com altura zero, senão a hora de fechamento criaria uma faixa extra. */
.tv-agenda-hour {
  grid-column: 1;
  align-self: start;
  height: 0;
  margin-top: -0.5em;
  padding-right: var(--spacing-xs);
  color: var(--muted-color);
  font-size: 0.7rem;
  text-align: right;
}

.tv-agenda-line {
  grid-column: 2 / -1;
  align-self: start;
  height: 0;
  border-top: 1px solid var(--border-color-light);
}

/* Fora do horário habitual. Um cinza levíssimo: é contexto, não alerta — o
   nutricionista pode marcar aqui e às vezes marca. */
.tv-agenda-off {
  z-index: 0;
  /* Translúcido de propósito: os fios das horas e das colunas continuam
     visíveis por baixo, e uma faixa opaca apagaria a régua justamente onde ela
     é mais necessária, que é para ver quanto do dia está fora. */
  background: var(--tv-agenda-off-bg);
}

/* O quadrado livre é o gesto principal da tela, e por isso é discreto até o
   ponteiro chegar: uma grade coberta de cruzes competiria com os atendimentos,
   que são o que se lê. */
.tv-agenda-slot {
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  color: var(--light-color);
  font-size: 0.75rem;
  text-decoration: none;
  opacity: 0;
}

.tv-agenda-slot:hover,
.tv-agenda-slot:focus-visible {
  background: var(--info-color-light);
  color: var(--accent-color);
  opacity: 1;
}

/* Sem ponteiro não há hover, e um alvo de toque invisível não existe. No
   telefone as cruzes ficam fracas mas presentes — no desktop continuam fora do
   caminho, porque lá o que se lê são os atendimentos. */
@media (hover: none) {
  .tv-agenda-slot {
    opacity: 0.3;
  }
}

.tv-agenda-item {
  z-index: 2;
  overflow: hidden;
  margin: 0 2px;
  padding: 2px 6px;
  border: 1px solid var(--border-color-dark);
  border-left: 3px solid var(--accent-color);
  border-radius: var(--radius-sm);
  background: var(--surface-color);
  color: var(--default-color);
  font-size: 0.72rem;
  line-height: 1.15;
  text-decoration: none;
}

.tv-agenda-item:hover {
  background: var(--info-color-light);
  color: var(--heading-color);
}

.tv-agenda-item-time {
  display: block;
  color: var(--muted-color);
  font-variant-numeric: tabular-nums;
}

.tv-agenda-item-name {
  display: block;
  font-weight: 600;
}

/* As situações se distinguem por peso e traço, não por cor: as cores saturadas
   desta interface são o semáforo do check-in, e um atendimento não é uma nota. */
.tv-agenda-item[data-status="CONFIRMED"] {
  border-left-width: 5px;
}

.tv-agenda-item[data-status="DONE"] {
  border-left-color: var(--light-color);
  background: var(--background-color);
  color: var(--muted-color);
}

.tv-agenda-item[data-status="NO_SHOW"] {
  border-style: dashed;
  color: var(--muted-color);
}

.tv-agenda-legend-off {
  background: var(--tv-agenda-off-bg);
  box-shadow: inset 0 0 0 1px var(--border-color-dark);
}

.tv-agenda-legend-booked {
  background: var(--surface-color);
  box-shadow: inset 0 0 0 1px var(--border-color-dark), inset 3px 0 0 var(--accent-color);
}

/* --- Mês: carga por dia, não horários ------------------------------------- */

.tv-agenda-month {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}

.tv-agenda-month-day {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  aspect-ratio: 1;
  border-radius: var(--radius-sm);
  background: var(--background-color);
  color: var(--default-color);
  font-size: 0.8rem;
  text-decoration: none;
}

.tv-agenda-month-day.is-blank {
  background: none;
}

.tv-agenda-month-day.is-booked {
  background: var(--info-color-light);
  font-weight: 600;
}

.tv-agenda-month-day.is-today {
  box-shadow: inset 0 0 0 2px var(--accent-color);
}

a.tv-agenda-month-day:hover {
  background: var(--table-hover-bg);
}

.tv-agenda-month-count {
  padding: 0 6px;
  border-radius: var(--radius-full);
  background: var(--accent-color);
  color: var(--contrast-color);
  font-size: 0.68rem;
  font-weight: 700;
}

/* --- Horários habituais ---------------------------------------------------- */

.tv-hours-block {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 4px 2px 8px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-full);
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   Metas nutricionais — o trilho do cálculo.

   Quatro etapas numeradas numa coluna de 54px, ligadas por um filete vertical,
   e entre cada par de cartões um conector que diz qual número desce. O
   encadeamento é a assinatura da tela: em vez de setas por toda parte, a
   geometria do trilho já responde "o que vem de onde".

   Escopo fechado. Tudo aqui vive sob `.tv-metas`, com os tokens do handoff
   como custom properties do próprio wrapper: a fonte Archivo, a paleta de
   pergaminho e os raios não vazam para o resto do painel, que continua com o
   FlexAdmin. Um upgrade do template não toca nesta tela, e esta tela não
   redefine nada de `:root`.

   As medidas estão em px de propósito. O handoff é hi-fi — cores,
   espaçamentos e escala tipográfica são finais, e convertê-los para rem os
   amarraria ao tamanho de fonte do navegador, que não foi a régua com que
   foram desenhados.

   Nenhuma cor com significado sozinha. Déficit, superávit, excesso e diferença
   são palavra e número; o chip verde/âmbar da barra e o selo "Meta atingida"
   carregam ícone e frase, e a barra de macros usa três tons do mesmo grafite,
   porque uma distribuição não é um placar (item 37).
   --------------------------------------------------------------------------- */

.tv-metas {
  /* Tokens do handoff, seção "Design tokens". */
  --tv-page: #f6f5f1;
  --tv-surface: #fff;
  --tv-surface-soft: #f4f2ec;
  --tv-text: #1c1a16;
  --tv-text-2: #55514a;
  --tv-muted: #8b8578;
  --tv-faint: #b3ada0;
  --tv-border: #e4e1d8;
  --tv-border-input: #d6d2c6;
  --tv-border-subtle: #eeebe2;
  --tv-border-soft: #e8e5db;
  --tv-border-derived: #cfcabd;
  --tv-rail: #d9d5ca;
  --tv-derived-text: #938d80;
  --tv-ok: #2f7d5c;
  --tv-ok-bg: #e7f1ea;
  --tv-warn: #8a6d1f;
  --tv-warn-bg: #f5ecd9;
  --tv-macro-p: #1c1a16;
  --tv-macro-c: #6f6a61;
  --tv-macro-g: #b3ada0;
  --tv-r-sm: 8px;
  --tv-r-md: 10px;
  --tv-r-lg: 12px;
  --tv-r-pill: 999px;

  max-width: 1200px;
  border: 1px solid var(--tv-border);
  border-radius: var(--tv-r-lg);
  background: var(--tv-page);
  color: var(--tv-text);
  font-family: "Archivo", system-ui, -apple-system, sans-serif;
  font-size: 14px;
  line-height: 1.45;
}

.tv-metas p {
  margin: 0;
}

.tv-metas b {
  font-weight: 700;
}

/* Todo número da tela é tabular: colunas que mudam enquanto se digita não
   podem dançar de largura. */
.tv-metas [data-out],
.tv-metas [data-carry],
.tv-metas .tv-metas-num,
.tv-metas input {
  font-variant-numeric: tabular-nums;
}

.tv-metas-link {
  color: var(--tv-text-2);
  font-size: 12.5px;
  text-decoration: underline;
}

.tv-metas-link:hover {
  color: var(--tv-text);
}

/* --- Barra fixa ------------------------------------------------------------ */

/* `top` é a altura do header do FlexAdmin, que é `position: fixed`: com o
   `top: 0` literal do handoff a barra deslizaria para debaixo dele e ficaria
   ilegível justamente quando começasse a servir. */
.tv-metas-bar {
  position: sticky;
  top: var(--header-height, 0px);
  z-index: 3;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 10px 26px;
  border-bottom: 1px solid var(--tv-border);
  border-radius: var(--tv-r-lg) var(--tv-r-lg) 0 0;
  background: var(--tv-surface);
  font-size: 12px;
}

/* Os chips rolam dentro da própria faixa em vez de empurrar a página. Com a
   sidebar do FlexAdmin aberta a barra fica bem mais estreita que a janela, e a
   sequência inteira não cabe: sem isto ela transbordava e o que sumia na borda
   direita era justamente o [Salvar metas]. `min-width: 0` é o que permite ao
   item de flex encolher abaixo do próprio conteúdo — sem ele o `overflow` não
   tem o que fazer.

   A regra não está numa media query de propósito: o que aperta é a largura do
   **container**, e uma media query mede o viewport. O mesmo vale para a linha
   da fórmula e para a tabela dos macros abaixo. */
.tv-metas-chips {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  gap: 8px;
  min-width: 0;
  overflow-x: auto;
}

.tv-metas-chip {
  display: flex;
  flex: 0 0 auto;
  align-items: baseline;
  gap: 7px;
  padding: 5px 11px;
  border-radius: var(--tv-r-pill);
  background: var(--tv-page);
  color: var(--tv-text);
  text-decoration: none;
  transition: background-color 140ms ease, color 140ms ease;
}

.tv-metas-chip:hover,
.tv-metas-chip.is-active {
  background: var(--tv-text);
  color: var(--tv-page);
}

.tv-metas-chip-num {
  font-size: 10.5px;
  font-weight: 700;
}

/* O rótulo do chip é o cinza do handoff para texto de barra, um degrau acima
   do secundário dos cartões: na pílula clara ele fica ao lado do valor em 700
   e precisa recuar sem sumir. */
.tv-metas-chip-label {
  color: #6e6a60;
}

.tv-metas-chip:hover .tv-metas-chip-label,
.tv-metas-chip.is-active .tv-metas-chip-label {
  color: inherit;
  opacity: 0.75;
}

.tv-metas-chip-value {
  font-weight: 700;
}

.tv-metas-chip-arrow {
  color: var(--tv-faint);
}

.tv-metas-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  padding: 4px 11px;
  border-radius: var(--tv-r-pill);
  background: var(--tv-page);
  color: var(--tv-muted);
  font-size: 11.5px;
  font-weight: 700;
}

.tv-metas-status.is-ok {
  background: var(--tv-ok-bg);
  color: var(--tv-ok);
}

.tv-metas-status.is-off {
  background: var(--tv-warn-bg);
  color: var(--tv-warn);
}

/* O salvar fica encostado à direita da barra, e é o último a ceder espaço:
   quando a linha não comporta tudo, a barra quebra e ele desce inteiro em vez
   de ser cortado. */
.tv-metas-bar-actions {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 12px;
  margin-left: auto;
}

.tv-metas-saved {
  color: var(--tv-muted);
  font-size: 11.5px;
}

/* O microtexto vira aviso quando o script marca o formulário como sujo. */
.tv-metas-saved.is-dirty {
  color: var(--tv-warn);
}

.tv-metas-save {
  padding: 9px 18px;
  border: 0;
  border-radius: var(--tv-r-pill);
  background: var(--tv-text);
  color: var(--tv-page);
  font-size: 13.5px;
  font-weight: 600;
  transition: background-color 140ms ease;
}

.tv-metas-save:hover {
  background: #33302a;
}

/* --- Trilho ---------------------------------------------------------------- */

.tv-metas-rail {
  padding: 24px 26px 28px;
}

.tv-metas-row {
  display: grid;
  grid-template-columns: 54px 1fr;
}

.tv-metas-track {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.tv-metas-dot {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border: 1.5px solid var(--tv-text);
  border-radius: 50%;
  background: var(--tv-surface);
  font-size: 13px;
  font-weight: 700;
}

.tv-metas-line {
  flex: 1;
  width: 1px;
  margin-top: 6px;
  background: var(--tv-rail);
}

/* A etapa 4 fecha o trilho: nada desce dela. */
.tv-metas-row-last .tv-metas-line {
  display: none;
}

.tv-metas-connector {
  padding: 9px 2px;
  color: var(--tv-muted);
  font-size: 12px;
}

.tv-metas-connector b {
  color: var(--tv-text-2);
}

/* --- Cartões --------------------------------------------------------------- */

.tv-metas-card,
.tv-metas-check {
  padding: 20px 22px;
  border: 1px solid var(--tv-border);
  border-radius: var(--tv-r-lg);
  background: var(--tv-surface);
}

.tv-metas-check {
  margin-top: 24px;
}

.tv-metas-card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.tv-metas-title {
  margin: 0;
  font-family: inherit;
  font-size: 17px;
  font-weight: 700;
  color: var(--tv-text);
}

.tv-metas-sub {
  margin-top: 2px;
  color: var(--tv-muted);
  font-size: 12.5px;
}

.tv-metas-label {
  display: block;
  margin-bottom: 6px;
  color: var(--tv-muted);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.tv-metas-label-spaced {
  margin-top: 14px;
}

.tv-metas-foot {
  color: var(--tv-muted);
  font-size: 12px;
}

.tv-metas-foot b {
  color: var(--tv-text-2);
}

.tv-metas-micro {
  color: var(--tv-muted);
  font-size: 11.5px;
}

.tv-metas-empty {
  margin-top: 16px;
  padding: 14px 16px;
  border: 1px dashed var(--tv-border-derived);
  border-radius: var(--tv-r-md);
  color: var(--tv-text-2);
  font-size: 13px;
}

/* --- Campos ---------------------------------------------------------------- */

/* O widget chega do Django com as classes do Bootstrap; o que segue é a
   tradução delas para os tokens desta tela, e não uma segunda folha de
   estilo de formulário. */
.tv-metas input.form-control,
.tv-metas select.form-select,
.tv-metas textarea.form-control,
.tv-metas .tv-metas-select,
.tv-metas .tv-metas-input {
  width: 100%;
  box-sizing: border-box;
  padding: 9px 12px;
  border: 1px solid var(--tv-border-input);
  border-radius: var(--tv-r-sm);
  background: var(--tv-surface);
  color: var(--tv-text);
  font-family: inherit;
  font-size: 14.5px;
  line-height: 1.3;
  transition: border-color 140ms ease, box-shadow 140ms ease;
}

.tv-metas input.form-control:focus,
.tv-metas select.form-select:focus,
.tv-metas textarea.form-control:focus,
.tv-metas .tv-metas-select:focus,
.tv-metas .tv-metas-input:focus {
  border-color: var(--tv-text);
  box-shadow: 0 0 0 3px rgba(28, 26, 22, 0.08);
  outline: 0;
}

.tv-metas select.form-select,
.tv-metas .tv-metas-select {
  font-weight: 600;
}

.tv-metas input.form-control:disabled,
.tv-metas input.form-control[disabled] {
  background: var(--tv-surface-soft);
  color: var(--tv-derived-text);
}

/* --- Etapa 1: a fórmula ---------------------------------------------------- */

/* Quebra quando não couber, e nunca antes: com espaço, os quatro blocos e os
   três operadores ficam na linha única do mock. O que estourava para fora do
   cartão era o bloco do GET quando a coluna do conteúdo encolhia — a base de
   160px é o ponto em que o bloco deixa de ser legível e passa a valer mais
   descer do que espremer. */
.tv-metas-formula {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 10px;
  margin-top: 16px;
}

.tv-metas-block {
  flex: 1 1 160px;
  padding: 11px 14px;
  border: 1px solid var(--tv-border-soft);
  border-radius: var(--tv-r-md);
}

/* Só a rotina é editável: a borda mais escura é o que diz isso antes do
   clique. */
.tv-metas-block.is-editable {
  border-color: var(--tv-border-input);
}

/* Sem borda, o bloco escuro precisa de mais respiro lateral que os claros para
   o número de 26px não encostar no fundo (handoff: 11px 16px). */
.tv-metas-block.is-result {
  flex: 1.15 1 180px;
  padding: 11px 16px;
  border: 0;
  background: var(--tv-text);
  color: var(--tv-page);
}

.tv-metas-block .tv-metas-label {
  margin-bottom: 0;
}

.tv-metas-block.is-result .tv-metas-label {
  color: #b8b2a6;
}

.tv-metas-block-value {
  margin-top: 2px;
  font-size: 20px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.tv-metas-block-unit {
  font-size: 11.5px;
  font-weight: 500;
  color: var(--tv-muted);
}

.tv-metas-block-figure {
  margin-top: 1px;
  font-size: 26px;
  font-weight: 800;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

.tv-metas-block-note {
  margin-top: 2px;
  color: var(--tv-muted);
  font-size: 11.5px;
}

.tv-metas-block.is-result .tv-metas-block-note {
  color: #b8b2a6;
}

/* O select da rotina é o controle, e o número acima dele é o termo que a
   multiplicação usa: um diz o porquê ("Pesado — trabalho braçal"), o outro
   entra na conta. */
.tv-metas-block select.form-select {
  margin-top: 4px;
  padding: 5px 8px;
  font-size: 11.5px;
  font-weight: 500;
}

.tv-metas-op {
  align-self: center;
  color: var(--tv-muted);
  font-size: 17px;
}

/* --- Etapa 2: estratégia --------------------------------------------------- */

.tv-metas-strategy {
  display: grid;
  grid-template-columns: 1fr 1fr 1.15fr;
  gap: 22px;
  margin-top: 16px;
}

.tv-metas-context {
  color: var(--tv-text-2);
  font-size: 12.5px;
  line-height: 1.5;
}

/* O segmented, aqui e no carboidrato. Nos dois casos o que decide é um
   controle nativo por baixo — o select de objetivo (revelado pelo script) ou
   os rádios de `carbs_mode` — e a caixa é só a cara dele. */
.tv-metas-seg {
  display: flex;
  overflow: hidden;
  border: 1px solid var(--tv-border-input);
  border-radius: var(--tv-r-sm);
  font-size: 12.5px;
  font-weight: 600;
  text-align: center;
}

.tv-metas-seg-cell {
  flex: 1;
  padding: 9px 6px;
  border: 0;
  background: var(--tv-surface);
  color: var(--tv-muted);
  font: inherit;
  transition: background-color 140ms ease, color 140ms ease;
}

.tv-metas-seg-cell + .tv-metas-seg-cell {
  border-left: 1px solid var(--tv-border);
}

.tv-metas-seg-cell:hover {
  color: var(--tv-text);
}

/* O anel de foco vai para dentro, como o dos rádios do carboidrato: a caixa do
   segmented tem `overflow: hidden`, e um `outline` normal seria cortado
   justamente nas duas células das pontas. */
.tv-metas-seg-cell:focus-visible {
  box-shadow: inset 0 0 0 2px var(--tv-text);
  outline: 0;
}

.tv-metas-seg-cell[aria-pressed="true"] {
  background: var(--tv-text);
  color: var(--tv-page);
}

/* Os rádios continuam existindo e continuam focáveis — só saem da pintura.
   `display: none` os tiraria da ordem de tabulação e o modo do carboidrato
   viraria um controle que só o mouse alcança. */
.tv-metas-seg-radio {
  flex: 1;
  display: flex;
  position: relative;
}

.tv-metas-seg-radio + .tv-metas-seg-radio {
  border-left: 1px solid var(--tv-border);
}

.tv-metas-seg-radio input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.tv-metas-seg-radio label {
  flex: 1;
  padding: 6px 4px;
  color: var(--tv-muted);
  transition: background-color 140ms ease, color 140ms ease;
}

.tv-metas-seg-radio input:checked + label {
  background: var(--tv-text);
  color: var(--tv-page);
}

.tv-metas-seg-radio input:focus-visible + label {
  box-shadow: inset 0 0 0 2px var(--tv-text);
}

.tv-metas-seg-sm {
  font-size: 11px;
}

.tv-metas-pct {
  margin-top: 12px;
}

.tv-metas-pct-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.tv-metas-pct-row input.form-control {
  width: 64px;
  padding: 9px 11px;
  font-size: 15px;
  font-weight: 700;
  text-align: right;
}

.tv-metas-pct-mark {
  font-size: 14px;
  font-weight: 600;
}

.tv-metas-quickpick {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}

.tv-metas-pill {
  padding: 4px 10px;
  border: 1px solid var(--tv-border-input);
  border-radius: var(--tv-r-pill);
  background: var(--tv-surface);
  color: var(--tv-text);
  font-family: inherit;
  font-size: 11.5px;
  font-weight: 600;
  transition: border-color 140ms ease;
}

.tv-metas-pill:hover {
  border-color: #b8b2a6;
}

/* O painel de resultado: o único lugar da tela onde a meta aparece grande. */
.tv-metas-panel {
  align-self: start;
  padding: 14px 16px;
  border: 1px solid var(--tv-border);
  border-radius: var(--tv-r-md);
  background: var(--tv-page);
}

.tv-metas-panel-line {
  color: var(--tv-muted);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

/* A classe que `targets.js` cria ao reescrever a linha da fórmula. Ela sai do
   script, então precisa existir aqui — e é neutra de propósito: o sinal
   (U+2212 ou +) é quem diz a direção. */
.tv-metas-panel-line .tv-targets-op {
  color: var(--tv-text);
  font-weight: 700;
}

.tv-metas-panel-figure {
  margin-top: 4px;
  font-size: 32px;
  font-weight: 800;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.tv-metas-panel-input {
  margin-top: 4px;
}

.tv-metas-panel-input input.form-control {
  padding: 4px 10px;
  font-size: 32px;
  font-weight: 800;
  line-height: 1.1;
  text-align: right;
}

.tv-metas-panel-unit {
  margin-top: 4px;
  color: var(--tv-text-2);
  font-size: 12px;
}

.tv-metas-manual {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
  color: var(--tv-text-2);
  font-size: 12px;
}

/* Botão fantasma: o mesmo desenho para "usar valor calculado", "+ Adicionar do
   catálogo" e o submit do catálogo — três ações secundárias, um só peso. */
.tv-metas-ghost {
  display: inline-block;
  padding: 6px 14px;
  border: 1px dashed #c9c4b6;
  border-radius: var(--tv-r-pill);
  background: transparent;
  color: var(--tv-text-2);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 140ms ease, color 140ms ease;
}

.tv-metas-ghost:hover {
  border-color: #b8b2a6;
  color: var(--tv-text);
}

/* --- Etapa 3: macronutrientes ---------------------------------------------- */

.tv-metas-table {
  margin-top: 4px;
}

/* As duas colunas de texto e a de resultado encolhem antes de a linha empurrar
   o cartão para fora; as dos campos ficam nos 110px porque abrigam um input de
   86px. Com `1fr` puro a coluna do resultado tem mínimo de conteúdo, e é o que
   fazia a tabela mandar a página inteira para o lado numa coluna estreita. */
.tv-metas-tr {
  display: grid;
  grid-template-columns: minmax(0, 150px) minmax(0, 190px) 110px 110px minmax(0, 1fr);
  gap: 0 14px;
  align-items: center;
  padding: 12px 0;
  border-top: 1px solid var(--tv-border-subtle);
}

.tv-metas-th {
  padding: 14px 0 8px;
  border-top: 0;
  color: var(--tv-muted);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.tv-metas-macro-name {
  display: block;
  font-size: 15px;
  font-weight: 700;
}

.tv-metas-macro-sub {
  display: block;
  color: var(--tv-muted);
  font-size: 11px;
}

.tv-metas-dash {
  color: var(--tv-faint);
  font-size: 12px;
}

/* Cabeçalho da coluna Resultado: a coluna inteira é alinhada à direita, e o
   rótulo tem de acompanhar. */
.tv-metas-right {
  text-align: right;
}

/* Os erros de um par g/kg ⇄ gramas atravessam o grid inteiro: como sexta
   célula eles cairiam na coluna de 150px do nome do macro. */
.tv-metas-tr-errors {
  grid-column: 1 / -1;
}

.tv-metas-cell.tv-metas-dash {
  text-align: right;
  padding-right: 24px;
}

.tv-metas-field input.form-control {
  width: 86px;
  padding: 8px 11px;
  font-weight: 700;
  text-align: right;
}

/* O campo derivado: o que o servidor vai reescrever. Tracejado e esmaecido —
   legível, e claramente não a linha em que se digita. O `[readonly]` recebe o
   mesmo tratamento porque é assim que `targets.js` marca o par do carboidrato
   fora do modo em vigor. */
.tv-metas-derived input.form-control,
.tv-metas-field input.form-control[readonly] {
  border: 1px dashed var(--tv-border-derived);
  background: var(--tv-surface-soft);
  color: var(--tv-derived-text);
  font-weight: 600;
}

.tv-metas-result {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  /* Sem isto o `minmax(0, 1fr)` da coluna não vale nada: o mínimo automático de
     um item de grid é o conteúdo dele, e a minibarra de 110px sozinha já
     empurraria a linha para fora. */
  min-width: 0;
  font-size: 15px;
  font-weight: 700;
}

.tv-metas-result-unit {
  margin-left: -6px;
}

.tv-metas-result-pct {
  color: var(--tv-muted);
  font-size: 12.5px;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}

.tv-metas-result-note {
  color: var(--tv-muted);
  font-size: 12px;
  font-weight: 400;
}

.tv-metas-mini {
  display: block;
  width: 110px;
  height: 6px;
  overflow: hidden;
  border-radius: 3px;
  background: #edeae2;
}

.tv-metas-mini-fill {
  display: block;
  max-width: 100%;
  height: 6px;
  background: var(--tv-text);
  transition: width 250ms ease;
}

.tv-metas-over {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin-top: 12px;
  padding: 8px 12px;
  border-left: 2px solid var(--tv-text);
  background: var(--tv-surface-soft);
  font-size: 12.5px;
}

.tv-metas-split {
  margin-top: 14px;
}

.tv-metas-stack {
  display: flex;
  height: 26px;
  overflow: hidden;
  border-radius: var(--tv-r-sm);
  background: #edeae2;
}

.tv-metas-stack-part {
  display: flex;
  align-items: center;
  overflow: hidden;
  padding-left: 10px;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
  transition: width 250ms ease;
}

.tv-metas-stack-protein {
  background: var(--tv-macro-p);
  color: var(--tv-page);
}

.tv-metas-stack-carbs {
  background: var(--tv-macro-c);
  color: var(--tv-page);
}

.tv-metas-stack-fat {
  background: var(--tv-macro-g);
  color: var(--tv-text);
}

.tv-metas-close {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 10px;
}

.tv-metas-close-line {
  color: var(--tv-text-2);
  font-size: 13px;
}

.tv-metas-close-chip {
  color: var(--tv-text-2);
  font-size: 12.5px;
}

/* `targets.js` monta o selo com as classes do Bootstrap, e o servidor
   renderiza a mesma marcação: a regra abaixo dá a esse par a cara do handoff
   sem que a tela mude de aparência no primeiro toque de tecla. */
.tv-metas .badge.bg-success-subtle {
  padding: 5px 12px;
  border-radius: var(--tv-r-pill);
  background: var(--tv-ok-bg) !important;
  color: var(--tv-ok) !important;
  font-size: 12px;
  font-weight: 700;
}

/* --- Etapa 4: resumo ------------------------------------------------------- */

.tv-metas-dl {
  margin: 12px 0 0;
}

.tv-metas-dl-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 0 18px;
  align-items: baseline;
  padding: 11px 0;
  border-top: 1px solid var(--tv-border-subtle);
}

.tv-metas-dl-row dt {
  font-size: 14px;
  font-weight: 600;
}

.tv-metas-dl-row dd {
  margin: 0;
}

.tv-metas-dl-eq {
  color: var(--tv-muted);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

.tv-metas-dl-value {
  min-width: 120px;
  text-align: right;
  font-size: 15px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.tv-metas-tag {
  margin-left: 6px;
  padding: 2px 8px;
  border: 1px solid var(--tv-border);
  border-radius: var(--tv-r-pill);
  color: var(--tv-muted);
  font-size: 10.5px;
  font-weight: 600;
}

.tv-metas-x {
  margin-left: 6px;
  padding: 0 2px;
  border: 0;
  background: none;
  color: var(--tv-faint);
  font-size: 12px;
  transition: color 140ms ease;
}

.tv-metas-x:hover {
  color: var(--tv-text);
}

.tv-metas-extra-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-top: 12px;
  margin-top: 2px;
  border-top: 1px solid var(--tv-border-subtle);
}

.tv-metas-add {
  margin-left: auto;
}

.tv-metas-add summary {
  display: inline-block;
  list-style: none;
}

.tv-metas-add summary::-webkit-details-marker {
  display: none;
}

.tv-metas-add-fields {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  margin-top: 12px;
}

.tv-metas-add-fields > div {
  flex: 1 1 180px;
}

.tv-metas-inputs {
  display: grid;
  grid-template-columns: 170px 1fr;
  gap: 16px;
  margin-top: 18px;
}

.tv-metas-inputs input.form-control {
  font-size: 15px;
  font-weight: 700;
}

.tv-metas-inputs textarea.form-control {
  font-size: 14px;
  font-weight: 400;
}

.tv-metas-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-top: 18px;
}

/* --- Conferência: meta x plano publicado ----------------------------------- */

.tv-metas-mirror {
  margin: 12px 0 0;
  color: var(--tv-text-2);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.tv-metas-mirror th,
.tv-metas-mirror td {
  padding: 10px 8px;
  border-color: var(--tv-border-subtle);
}

.tv-metas-mirror thead th {
  color: var(--tv-muted);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.tv-metas-mirror th[scope="row"] {
  color: var(--tv-text);
  font-weight: 600;
}

/* A banda de cor do espelho continua sendo `status-green/red/yellow`, que
   `brand.css` define lá em cima com as cores do painel. Aqui ela só ganha a
   forma de pill desta tela — trocar as cores faria a conferência discordar de
   toda a outra tela que usa a mesma classe. */
.tv-metas-delta {
  font-weight: 700;
}

.tv-metas-delta.status-green,
.tv-metas-delta.status-yellow,
.tv-metas-delta.status-red {
  border-radius: var(--tv-r-sm);
  text-align: center;
}

/* --- Telas estreitas ------------------------------------------------------- */

@media (max-width: 991.98px) {
  .tv-metas-strategy {
    grid-template-columns: 1fr;
  }

  .tv-metas-tr {
    grid-template-columns: 1fr 1fr;
    gap: 8px 14px;
  }

  .tv-metas-th {
    display: none;
  }

  .tv-metas-result {
    grid-column: 1 / -1;
    justify-content: flex-start;
  }

  .tv-metas-inputs {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 767.98px) {
  .tv-metas-rail {
    padding: 16px 12px 20px;
  }

  .tv-metas-row {
    grid-template-columns: 30px 1fr;
  }

  .tv-metas-card,
  .tv-metas-check {
    padding: 16px 14px;
  }

  .tv-metas-bar {
    padding: 10px 12px;
  }
}

/* ---------------------------------------------------------------------------
   Plano alimentar — o quadro vivo do editor.

   Duas colunas: as refeições à esquerda, o painel de nutrientes à direita, com
   a barra de contexto e a barra de dias por cima das duas. Handoff em
   `docs/superpowers/specs/2026-08-11-plano-editor-handoff/`.

   Escopo fechado, como em `.tv-metas`. Tudo aqui vive sob `.tv-plano`, com os
   tokens do handoff como custom properties do próprio wrapper: a fonte
   Schibsted Grotesk, a paleta de pergaminho e os raios não vazam para o resto
   do painel, que continua com o FlexAdmin, e esta tela não redefine nada de
   `:root`. Um upgrade do template não toca aqui.

   As três cores de macro NÃO estão nesta folha. Chegam como
   `--tv-macro-protein`/`-carbs`/`-fat` no atributo `style` do wrapper, vindas
   de `apps/mealplans/donut.py` — que é quem precisa dos valores para decidir a
   tinta de contraste do rótulo de cada fatia. Uma segunda cópia aqui seria a
   cópia que diverge.

   As medidas estão em px de propósito: o handoff é hi-fi e foi desenhado nessa
   régua; converter para rem as amarraria ao tamanho de fonte do navegador, que
   não foi a régua usada.

   Nenhuma cor com significado sozinha. Todo chip de estado carrega glifo e
   palavra ("✓ na meta", "▲ faltam 60"), o marcador de dado incompleto é a
   palavra "piso", e o dia em conflito tem `title` além da borda âmbar.
   --------------------------------------------------------------------------- */

/* Os campos do picker de alimento (`mealplans/_picker.html`). Distribuídos
   pela largura do CONTÊINER e não pela da janela: `col-md-*` responde ao
   viewport, e o mesmo picker é incluído no corpo do `<details>` de
   substituição (~346px) e na faixa larga de adicionar alimento. No estreito
   o `col-md-2` da quantidade media 33px, 20 deles de padding — "100"
   aparecia recortado como "10".

   As bases em `rem` são o que decide a quebra: quando a soma não cabe, o
   botão desce, depois a quantidade, e busca e medida ficam na primeira linha
   com o espaço todo. `min-width` na quantidade é o piso que o defeito exige —
   sem ele o shrink a levaria de volta a um dígito.

   Fora do escopo `.tv-plano` de propósito: o picker também é renderizado pelo
   editor de receitas, que não tem o wrapper. Nada aqui lê `--tv-*`. */
.tv-picker-fields {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: flex-start;
}

.tv-picker-search {
  position: relative;
  flex: 5 1 11rem;
}

.tv-picker-portion {
  flex: 2 1 7rem;
}

.tv-picker-qty {
  flex: 1 1 5rem;
  min-width: 5rem;
}

.tv-picker-add {
  flex: 0 0 auto;
}

/* O quadro de comparação entre dois alimentos mora FORA do `.tv-plano` — é um
   modal do Bootstrap, um só na página, e os tokens do board são declarados no
   wrapper de propósito. Por isso a única regra própria dele é uma largura:
   tudo o mais é Bootstrap. */
.tv-compare-grams {
  width: 9rem;
}

.tv-plano,
.tv-plano-pill {
  /* Tokens do handoff, seção "Design tokens". */
  --tv-page: #f6f5f1;
  --tv-surface: #fff;
  --tv-band: #edeae2;
  --tv-text: #1c1a16;
  --tv-text-2: #55514a;
  --tv-muted: #8b8578;
  --tv-faint: #b3ada0;
  --tv-border: #e4e1d8;
  --tv-border-input: #d6d2c6;
  --tv-border-subtle: #eeebe2;
  --tv-border-dashed: #c9c4b6;
  --tv-border-hover: #b8b2a6;
  --tv-ok: #2f7d5c;
  --tv-ok-bg: #e7f1ea;
  --tv-warn: #8a6d1f;
  --tv-warn-bg: #f5ecd9;
  --tv-danger: #a8503c;
  --tv-r-sm: 8px;
  --tv-r-md: 12px;
  --tv-r-pill: 999px;

  font-family: "Schibsted Grotesk", system-ui, -apple-system, sans-serif;
}

.tv-plano {
  max-width: 1200px;
  border: 1px solid var(--tv-border);
  border-radius: var(--tv-r-md);
  background: var(--tv-page);
  color: var(--tv-text);
  font-size: 13px;
  line-height: 1.4;
}

/* Todo número desta tela é tabular: uma coluna que muda a cada edição não pode
   dançar de largura enquanto se digita. */
.tv-plano,
.tv-plano input {
  font-variant-numeric: tabular-nums;
}

.tv-plano p {
  margin: 0;
}

.tv-plano b {
  font-weight: 700;
}

.tv-plano a {
  color: inherit;
  text-decoration: underline;
}

/* O marcador nativo do `<details>` sai em toda parte: cada summary desta tela
   desenha a própria affordance — o caret da refeição, o chip de ação, o botão
   tracejado dos nutrientes. */
.tv-plano summary {
  list-style: none;
  cursor: pointer;
}

.tv-plano summary::-webkit-details-marker {
  display: none;
}

.tv-plano :focus-visible {
  border-color: var(--tv-text);
  outline: none;
  box-shadow: 0 0 0 3px rgba(28, 26, 22, 0.08);
}

/* --- Pílulas do cabeçalho da página -----------------------------------------

   Ficam no `page_actions` do layout do painel, fora do wrapper — por isso
   declaram os tokens no mesmo bloco que ele, em vez de carregarem uma segunda
   paleta só delas. */

.tv-plano-pill {
  padding: 8px 16px;
  border: 1px solid var(--tv-border-input);
  border-radius: var(--tv-r-pill);
  background: var(--tv-surface);
  color: var(--tv-text-2);
  font-size: 13px;
  font-weight: 600;
  transition: border-color 140ms ease, background-color 140ms ease;
}

.tv-plano-pill:hover {
  border-color: var(--tv-border-hover);
}

.tv-plano-pill-solid {
  padding: 9px 18px;
  border-color: var(--tv-text);
  background: var(--tv-text);
  color: var(--tv-page);
  font-size: 13.5px;
}

.tv-plano-pill-solid:hover {
  border-color: #33302a;
  background: #33302a;
}

/* --- Barra de contexto ------------------------------------------------------ */

.tv-plano-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 10px 26px;
  border-bottom: 1px solid var(--tv-border);
  border-radius: var(--tv-r-md) var(--tv-r-md) 0 0;
  background: var(--tv-surface);
  font-size: 12px;
}

.tv-plano-version {
  padding: 4px 12px;
  border: 1px solid var(--tv-border-input);
  border-radius: var(--tv-r-pill);
  font-size: 12.5px;
  font-weight: 700;
  text-decoration: none;
}

.tv-plano-tag {
  padding: 3px 10px;
  border-radius: var(--tv-r-pill);
  background: var(--tv-warn-bg);
  color: var(--tv-warn);
  font-size: 11px;
  font-weight: 700;
}

.tv-plano-tag-published {
  background: var(--tv-ok-bg);
  color: var(--tv-ok);
}

.tv-plano-tag-superseded,
.tv-plano-tag-archived {
  background: var(--tv-band);
  color: var(--tv-text-2);
}

.tv-plano-saved {
  color: var(--tv-muted);
}

.tv-plano-goals {
  margin-left: auto;
  padding: 4px 12px;
  border: 1px solid var(--tv-border);
  border-radius: var(--tv-r-pill);
  font-size: 11.5px;
}

.tv-plano-ghost {
  padding: 5px 13px;
  border: 1px solid var(--tv-border-input);
  border-radius: var(--tv-r-pill);
  background: var(--tv-surface);
  color: var(--tv-text-2);
  font-size: 12px;
  font-weight: 600;
  text-decoration: none;
  transition: border-color 140ms ease;
}

.tv-plano-ghost:hover {
  border-color: var(--tv-border-hover);
}

/* --- Barra de dias ---------------------------------------------------------- */

.tv-plano-days {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 10px 26px;
  border-bottom: 1px solid var(--tv-border);
  background: var(--tv-surface);
}

.tv-plano-days-label {
  color: var(--tv-muted);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.tv-plano-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* O chip É o checkbox: o input sai de vista, mas continua sendo ele que o
   clique alterna, que o teclado alcança e que o POST envia. */
.tv-plano-chip {
  position: relative;
  display: inline-flex;
  justify-content: center;
  min-width: 38px;
  padding: 6px 10px;
  border: 1px solid var(--tv-border-input);
  border-radius: var(--tv-r-pill);
  color: var(--tv-muted);
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 140ms ease, color 140ms ease;
}

.tv-plano-chip input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

/* `is-on` vem do servidor e é o que de fato pinta o dia ativo; o `:has()` fica
   como reforço para quem alternar o chip sem recarregar. Depender só dele
   deixaria os sete dias idênticos num navegador sem `:has()`. */
.tv-plano-chip.is-on,
.tv-plano-chip:has(input:checked) {
  border-color: var(--tv-text);
  background: var(--tv-text);
  color: var(--tv-page);
  font-weight: 700;
}

/* Conflito: o dia já é de outro plano publicado. No rascunho é aviso (a
   reclamação só acontece ao publicar); no publicado é o que muda agora. */
.tv-plano-chip.is-conflict {
  border-color: var(--tv-warn);
}

.tv-plano-chip:has(input:focus-visible) {
  box-shadow: 0 0 0 3px rgba(28, 26, 22, 0.08);
}

/* A mesma faixa sem formulário, nas versões que não estão no ar. */
.tv-plano-days-static {
  color: var(--tv-muted);
}

.tv-plano-days-sum {
  color: var(--tv-text-2);
  font-size: 12px;
  font-weight: 700;
}

.tv-plano-days-note {
  flex: 1 1 240px;
  margin-left: auto;
  color: var(--tv-muted);
  font-size: 11.5px;
  text-align: right;
}

/* --- Corpo ------------------------------------------------------------------ */

.tv-plano-body {
  display: grid;
  grid-template-columns: 1fr 340px;
  gap: 14px;
  align-items: start;
  padding: 22px 26px 26px;
}

.tv-plano-meals,
.tv-plano-rail {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}

/* --- Cartão de refeição ----------------------------------------------------- */

.tv-plano-meal {
  position: relative;
  padding: 16px 20px;
  border: 1px solid var(--tv-border);
  border-radius: var(--tv-r-md);
  background: var(--tv-surface);
}

.tv-plano-meal-head {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Espaço para os três botões de ação, que sobrepõem esta linha justamente por
   não poderem morar dentro do summary. Só com o cartão aberto: fechado eles
   não estão no DOM, e a reserva viraria um talho em branco à direita da prévia,
   que é a linha que mais precisa da largura. */
.tv-plano-meal[open] > .tv-plano-meal-head {
  padding-right: 190px;
}

.tv-plano-caret {
  color: var(--tv-faint);
  font-size: 11px;
  transition: transform 140ms ease;
}

.tv-plano-meal[open] > .tv-plano-meal-head .tv-plano-caret {
  transform: rotate(90deg);
}

.tv-plano-meal-name {
  font-size: 13.5px;
  font-weight: 800;
  letter-spacing: 0.05em;
}

.tv-plano-time {
  padding: 3px 9px;
  border: 1px solid var(--tv-border-input);
  border-radius: var(--tv-r-sm);
  font-size: 12px;
  font-weight: 700;
}

/* Aberto, a pílula estática sai e o campo entra no lugar dela. São dois
   elementos porque o campo não pode morar dentro do `<summary>` — o clique que
   o focaria fecharia o cartão — e a prévia fechada precisa do rótulo. */
.tv-plano-meal[open] > .tv-plano-meal-head .tv-plano-time {
  display: none;
}

.tv-plano-time-form {
  display: flex;
  gap: 4px;
}

.tv-plano-time-input {
  width: 88px;
  padding: 3px 8px;
  border: 1px solid var(--tv-border-input);
  border-radius: var(--tv-r-sm);
  background: var(--tv-surface);
  color: inherit;
  font: inherit;
  font-size: 12px;
  font-weight: 700;
}

/* `min-width: 0` é o que deixa a prévia encolher abaixo do próprio conteúdo:
   sem ele o `text-overflow` não tem o que fazer e a lista de itens empurra os
   totais compactos para fora do cartão. */
.tv-plano-peek {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  color: var(--tv-muted);
  font-size: 12px;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.tv-plano-peek-totals {
  display: flex;
  flex: 0 0 auto;
  gap: 10px;
  color: var(--tv-text-2);
  font-size: 12px;
}

/* Aberto, a prévia sai: os mesmos números estão no rodapé e os mesmos nomes
   estão nas linhas. */
.tv-plano-meal[open] > .tv-plano-meal-head .tv-plano-peek,
.tv-plano-meal[open] > .tv-plano-meal-head .tv-plano-peek-totals {
  display: none;
}

.tv-plano-meal-actions {
  position: absolute;
  top: 14px;
  right: 20px;
  display: flex;
  gap: 6px;
}

.tv-plano-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border: 1px solid var(--tv-border);
  border-radius: var(--tv-r-sm);
  background: var(--tv-surface);
  color: var(--tv-text-2);
  font-size: 12px;
  transition: border-color 140ms ease;
}

.tv-plano-icon:hover {
  border-color: var(--tv-border-hover);
}

.tv-plano-icon-danger {
  color: var(--tv-danger);
}

/* Excluir em duas etapas, sem `confirm()` e sem script: o ✕ é o summary de um
   `<details>`, e o botão que de fato posta só existe no DOM depois de ele
   abrir. */
.tv-plano-confirm {
  position: relative;
}

.tv-plano-confirm form {
  position: absolute;
  top: 30px;
  right: 0;
  z-index: 4;
}

.tv-plano-danger {
  padding: 7px 12px;
  border: 1px solid var(--tv-danger);
  border-radius: var(--tv-r-sm);
  background: var(--tv-danger);
  color: #fff;
  font-size: 11.5px;
  font-weight: 700;
  white-space: nowrap;
}

/* --- Linha de alimento ------------------------------------------------------ */

.tv-plano-item {
  display: grid;
  grid-template-columns: 1fr 76px 96px 26px;
  gap: 12px;
  align-items: center;
  padding: 11px 0;
  border-top: 1px solid var(--tv-border-subtle);
}

.tv-plano-items > .tv-plano-item:first-child {
  border-top: 0;
}

/* A coluna de ordem só existe enquanto o plano é rascunho, e por isso a
   largura extra é marcada no CONTÊINER e não na linha: a linha carrega
   `class="tv-plano-item"` literal, que os testes de ganchos contam, e uma
   classe modificadora ali mudaria a string que eles procuram. */
.tv-plano-items[data-ordered] > .tv-plano-item {
  grid-template-columns: 20px 1fr 76px 96px 26px;
}

.tv-plano-order {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  /* O bloco inteiro é a alça de arraste (`plan-editor.js` liga o `draggable`
     aqui), então o cursor precisa dizer isso antes do gesto. */
  cursor: grab;
}

.tv-plano-order:active {
  cursor: grabbing;
}

.tv-plano-icon-mini {
  width: 18px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--tv-faint);
  font-size: 11px;
  line-height: 1.1;
  transition: color 140ms ease;
}

.tv-plano-icon-mini:hover:not(:disabled) {
  color: var(--tv-text-2);
}

.tv-plano-icon-mini:disabled {
  opacity: 0.35;
}

/* A linha sendo arrastada e o alvo onde ela cairia. `outline` e não `border`
   de propósito: a linha já tem `border-top`, e trocá-la deslocaria as
   vizinhas em 1px a cada passagem do ponteiro. */
.tv-plano-item.is-dragging {
  opacity: 0.4;
}

.tv-plano-item.is-drop-before {
  box-shadow: inset 0 2px 0 0 var(--tv-text-2);
}

.tv-plano-item.is-drop-after {
  box-shadow: inset 0 -2px 0 0 var(--tv-text-2);
}

.tv-plano-item-main {
  min-width: 0;
}

.tv-plano-item-name {
  overflow: hidden;
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.tv-plano-badge {
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: var(--tv-r-pill);
  background: var(--tv-band);
  font-size: 10.5px;
  font-weight: 600;
}

.tv-plano-item-detail {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 2px;
  color: var(--tv-muted);
  font-size: 11.5px;
}

.tv-plano-portion {
  margin-right: 4px;
}

.tv-plano-actchip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 9px;
  border: 1px solid var(--tv-border);
  border-radius: var(--tv-r-pill);
  color: var(--tv-text-2);
  font-size: 10.5px;
  font-weight: 600;
  transition: border-color 140ms ease;
}

.tv-plano-actchip:hover {
  border-color: var(--tv-border-hover);
}

.tv-plano-glyph {
  color: var(--tv-text);
  font-size: 11.5px;
}

/* Aberto, o painel toma a linha inteira da célula: um `<details>` não tem como
   deixar o corpo em outro ponto do grid que não junto do próprio summary. */
.tv-plano-drop[open] {
  flex: 1 1 100%;
}

.tv-plano-drop-body {
  margin-top: 8px;
  padding: 10px 12px;
  border-radius: var(--tv-r-sm);
  background: var(--tv-page);
}

/* A rolagem horizontal é SÓ do painel de equivalentes, que carrega uma tabela
   de sete colunas. No painel do picker ela seria um estrago: `overflow-x: auto`
   faz o `overflow-y` computar `auto` junto, e a lista de resultados da busca é
   `position: absolute` com 16rem de altura dentro dele — ela seria recortada
   pela própria caixa que a mostra. */
.tv-plano-drop[data-equivalents] .tv-plano-drop-body {
  overflow-x: auto;
}

.tv-plano-drop-title {
  margin-bottom: 6px;
  color: var(--tv-text-2);
  font-size: 11.5px;
  font-weight: 700;
}

.tv-plano-item-kcal {
  color: var(--tv-muted);
  font-size: 10.5px;
  text-align: right;
}

.tv-plano-item-kcal b {
  color: var(--tv-text);
  font-size: 14px;
}

.tv-plano-qty {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* 64px, não os 44 do handoff: com 44 o spinner nativo do type="number" cobre
   o segundo dígito ("150" lia "15"). O spinner sai — os números são digitados,
   nunca clicados — e a coluna de 96px absorve a diferença. */
.tv-plano-qty input {
  width: 64px;
  padding: 6px 8px;
  border: 1px solid var(--tv-border-input);
  border-radius: var(--tv-r-sm);
  font-size: 13px;
  font-weight: 700;
  text-align: right;
  appearance: textfield;
  -moz-appearance: textfield;
}

.tv-plano-qty input::-webkit-inner-spin-button,
.tv-plano-qty input::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.tv-plano-unit {
  color: var(--tv-muted);
  font-size: 11px;
}

.tv-plano-remove {
  border: 0;
  background: none;
  color: var(--tv-faint);
  font-size: 13px;
  transition: color 140ms ease;
}

.tv-plano-remove:hover {
  color: var(--tv-danger);
}

/* A substituição autorizada, aninhada sob a linha que ela substitui. Não entra
   em total nenhum — é o que o paciente come no LUGAR do item. */
.tv-plano-sub {
  display: flex;
  grid-column: 1 / -1;
  align-items: center;
  gap: 8px;
  margin-left: 14px;
  padding: 6px 10px;
  border-radius: var(--tv-r-sm);
  background: var(--tv-page);
  font-size: 12px;
}

.tv-plano-sub > span:nth-child(2) {
  flex: 1 1 auto;
}

.tv-plano-empty,
.tv-plano-hint {
  color: var(--tv-muted);
  font-size: 11.5px;
}

/* A recusa do servidor a um salvamento, escrita ao lado do controle que a
   provocou. É a única marcação que `plan-editor.js` cria — o resto da tela vem
   pronto do servidor —, e entra como IRMÃ do form: dentro de `.tv-plano-item`
   ela ocuparia uma célula de 96px da grade, e `grid-column` a põe na linha
   inteira, do mesmo jeito que a substituição já faz. Sem script a recusa
   continua chegando por `messages`, com a página recarregada. */
.tv-plano-error {
  grid-column: 1 / -1;
  margin-top: 4px;
  color: var(--tv-danger);
  font-size: 11.5px;
}

/* A tabela de macros por alimento (`_meal_table.html`). O scroll horizontal é
   do wrapper e não da tabela: sete colunas não cabem na coluna esquerda do
   board em telas estreitas, e deixar a página inteira rolar de lado seria o
   defeito que `overflow-x` existe para evitar. `overflow-y` fica em `visible`
   por omissão — declarar `hidden` aqui recortaria os `title` nativos. */
.tv-plano-macros {
  margin-top: 12px;
  overflow-x: auto;
}

.tv-plano-macros table {
  width: 100%;
  border-collapse: collapse;
  font-size: 11.5px;
}

/* Só a primeira coluna quebra linha. Um nome de alimento da TACO tem seis
   palavras ("Ovo, de galinha, inteiro, cozido"), e mantê-lo numa linha só
   empurraria os números para fora da tela — que é justamente o que a coluna
   de números não pode fazer, porque quebrar "12,5" ao meio é ilegível. */
.tv-plano-macros td,
.tv-plano-macros th {
  white-space: nowrap;
}

.tv-plano-macros tbody th {
  min-width: 9rem;
  white-space: normal;
}

.tv-plano-macros th,
.tv-plano-macros td {
  padding: 5px 8px;
  border-bottom: 1px solid var(--tv-border-subtle);
  text-align: left;
  font-weight: 400;
}

.tv-plano-macros thead th {
  color: var(--tv-muted);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* A unidade é informação de cabeçalho, não de célula: repeti-la em cada linha
   encheria a coluna de "g" e empurraria os números para fora da tela. */
.tv-plano-macros-unit {
  text-transform: none;
  letter-spacing: 0;
}

.tv-plano-macros-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.tv-plano-macros-none {
  color: var(--tv-muted);
}

.tv-plano-macros tfoot th,
.tv-plano-macros tfoot td {
  border-bottom: 0;
  border-top: 1px solid var(--tv-border);
  color: var(--tv-text-2);
}

.tv-plano-add {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--tv-border-subtle);
}

.tv-plano-meal-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 12px;
  padding: 8px 12px;
  border-radius: var(--tv-r-sm);
  background: var(--tv-page);
  color: var(--tv-text-2);
  font-size: 12px;
}

.tv-plano-part {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.tv-plano-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
}

.tv-plano-note {
  margin-top: 8px;
  color: var(--tv-muted);
  font-size: 11.5px;
}

.tv-plano-newmeal {
  padding: 13px;
  border: 1px dashed var(--tv-border-dashed);
  border-radius: var(--tv-r-md);
  color: var(--tv-text-2);
  font-size: 13px;
  font-weight: 600;
  text-align: center;
}

.tv-plano-newmeal-fields {
  display: flex;
  gap: 8px;
  margin-top: 12px;
  text-align: left;
}

.tv-plano-newmeal-fields input[type="text"] {
  flex: 1 1 auto;
  min-width: 0;
}

/* --- Rail -------------------------------------------------------------------- */

.tv-plano-card {
  padding: 18px 20px;
  border: 1px solid var(--tv-border);
  border-radius: var(--tv-r-md);
  background: var(--tv-surface);
}

.tv-plano-card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 10px;
}

.tv-plano-card-head h3 {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
}

.tv-plano-card-head span {
  color: var(--tv-muted);
  font-size: 11.5px;
}

.tv-plano-card-foot {
  margin-top: 10px;
  text-align: right;
}

.tv-plano-guidance {
  color: var(--tv-text-2);
}

/* 160px, não os 150 do handoff: o anel engrossou (stroke 18) a pedido do
   dono, e sem os 10px a mais o miolo encostaria em "de 5501 kcal · 51%". */
.tv-plano-donut-wrap {
  position: relative;
  width: 160px;
  height: 160px;
  margin: 4px auto 0;
}

.tv-plano-donut {
  width: 100%;
  height: 100%;
}

.tv-plano-donut-track {
  stroke: var(--tv-band);
}

/* A transição é sobre o dasharray porque é ele que muda quando a quantidade de
   um item muda: a fatia cresce, não pisca. */
.tv-plano-arc {
  transition: stroke-dasharray 250ms ease;
}

.tv-plano-arc-label {
  font-size: 8.5px;
  font-weight: 700;
}

.tv-plano-donut-centre {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.tv-plano-donut-centre b {
  font-size: 21px;
  font-weight: 800;
}

.tv-plano-donut-centre span {
  color: var(--tv-muted);
  font-size: 8.5px;
}

.tv-plano-track {
  height: 6px;
  margin-top: 14px;
  border-radius: 3px;
  background: var(--tv-band);
}

.tv-plano-fill {
  height: 100%;
  border-radius: 3px;
  background: var(--tv-text);
  transition: width 250ms ease;
}

.tv-plano-legend {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  margin-top: 6px;
  color: var(--tv-muted);
  font-size: 10.5px;
}

.tv-plano-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px;
  align-items: center;
  padding: 10px 0;
  border-top: 1px solid var(--tv-border-subtle);
}

/* Um respiro entre a barra de energia e a primeira linha de macro. Escrito
   como irmão adjacente e não como `:first-of-type`: as linhas não são os
   primeiros `div` do cartão — o cabeçalho e o donut vêm antes —, e o seletor
   ingênuo não casaria com nada. */
.tv-plano-legend + .tv-plano-row,
.tv-plano-hint + .tv-plano-row {
  margin-top: 6px;
}

.tv-plano-row-name {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  font-weight: 700;
}

.tv-plano-row-plain {
  color: var(--tv-text-2);
}

.tv-plano-row-sub {
  color: var(--tv-muted);
  font-size: 11.5px;
}

.tv-plano-row-sub b {
  color: var(--tv-text);
  font-size: 13px;
}

.tv-plano-state {
  padding: 3px 9px;
  border-radius: var(--tv-r-pill);
  font-size: 10.5px;
  font-weight: 700;
  white-space: nowrap;
}

.tv-plano-state.is-on {
  background: var(--tv-ok-bg);
  color: var(--tv-ok);
}

.tv-plano-state.is-off {
  background: var(--tv-warn-bg);
  color: var(--tv-warn);
}

/* A nota única de dado incompleto. Substituiu quatro renderizações do mesmo
   fato — o aviso que se repete é o aviso que ninguém lê. */
.tv-plano-warn {
  margin-top: 12px;
  padding: 8px 11px;
  border-radius: var(--tv-r-sm);
  background: var(--tv-warn-bg);
  color: var(--tv-warn);
  font-size: 11.5px;
}

.tv-plano-foot {
  margin-top: 12px;
  color: var(--tv-muted);
  font-size: 11.5px;
}

.tv-plano-micro {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  padding: 7px 0;
  border-top: 1px solid var(--tv-border-subtle);
  font-size: 12.5px;
}

.tv-plano-card-head + .tv-plano-micro {
  border-top: 0;
}

.tv-plano-floor {
  margin-left: 3px;
  color: var(--tv-warn);
}

.tv-plano-more > summary {
  margin-top: 10px;
  padding: 8px;
  border: 1px dashed var(--tv-border-dashed);
  border-radius: var(--tv-r-pill);
  color: var(--tv-text-2);
  font-size: 12px;
  text-align: center;
}

/* --- Campos e o picker do FlexAdmin dentro do quadro -------------------------

   `_picker.html` é markup compartilhado com o editor de receitas e continua com
   as classes do Bootstrap — o contrato dele com `plan-editor.js` está nos
   `data-*`, não nas classes. Aqui ele só recebe a régua desta tela. */

.tv-plano .form-control,
.tv-plano .form-select,
.tv-plano-newmeal-fields input {
  padding: 7px 10px;
  border: 1px solid var(--tv-border-input);
  border-radius: var(--tv-r-sm);
  background: var(--tv-surface);
  color: var(--tv-text);
  font-family: inherit;
  font-size: 13px;
}

.tv-plano textarea.form-control {
  width: 100%;
  line-height: 1.45;
}

.tv-plano .tv-food-picker {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 8px;
  margin-top: 0;
}

.tv-plano .tv-food-picker > .row {
  flex: 1 1 320px;
  margin: 0;
}

.tv-plano .tv-food-picker .mb-2 {
  margin-bottom: 0;
}

/* O segmentado Alimento|Receita nos tons do handoff: ativo em grafite. */
.tv-plano .tv-food-picker .btn-light {
  border: 1px solid var(--tv-border-input);
  background: var(--tv-surface);
  color: var(--tv-text-2);
  font-size: 12.5px;
  font-weight: 600;
}

.tv-plano .tv-food-picker .btn-check:checked + .btn-light {
  border-color: var(--tv-text);
  background: var(--tv-text);
  color: var(--tv-page);
}

.tv-plano .tv-food-picker .btn-primary {
  border-color: var(--tv-text);
  border-radius: var(--tv-r-pill);
  background: var(--tv-text);
  color: var(--tv-page);
}

.tv-plano .list-group-item {
  border-color: var(--tv-border-subtle);
  font-size: 12.5px;
}

/* --- Estreito ----------------------------------------------------------------

   O que aperta é a largura do CONTAINER — a sidebar do FlexAdmin abre e fecha —
   e uma media query mede o viewport. Por isso os limites são generosos. */

@media (max-width: 1199.98px) {
  .tv-plano-body {
    grid-template-columns: 1fr;
  }

  .tv-plano-goals,
  .tv-plano-days-note {
    margin-left: 0;
    text-align: left;
  }
}

@media (max-width: 767.98px) {
  .tv-plano-bar,
  .tv-plano-days,
  .tv-plano-body {
    padding-right: 14px;
    padding-left: 14px;
  }

  .tv-plano-meal {
    padding: 14px;
  }

  .tv-plano-meal-head {
    flex-wrap: wrap;
  }

  .tv-plano-meal[open] > .tv-plano-meal-head {
    padding-right: 186px;
  }

  .tv-plano-item {
    grid-template-columns: 1fr 70px 26px;
  }

  .tv-plano-items[data-ordered] > .tv-plano-item {
    grid-template-columns: 20px 1fr 70px 26px;
  }

  .tv-plano-qty {
    grid-column: 1 / -1;
  }
}
