@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,400;1,600&display=swap");

/* ============================================================
   CONSTÂNCIA — Design System
   Habit tracker · crescimento / consistência · SaaS-premium
   Indigo brand · emerald heat · flame streak · light/dark
   ============================================================ */

:root {
  /* ---- Brand (indigo) ---- */
  --brand: #b45309;            /* âmbar-700: branco em cima passa AA (4.66) */
  --brand-strong: #92400e;     /* texto de marca sobre tint */
  --brand-fg: #ffffff;
  --brand-tint: rgba(180, 83, 9, 0.10);
  --brand-tint-strong: rgba(180, 83, 9, 0.18);

  /* ---- Accents ---- */
  --flame: #f59e0b;       /* streak / flame */
  --flame-strong: #f97316;
  --flame-tint: rgba(245, 158, 11, 0.14);

  /* ---- Heat ramp (emerald) — used by heatmap & "done" ---- */
  --heat-0: var(--surface-3);          /* nothing logged */
  --heat-1: #dcfce7;
  --heat-2: #86efac;
  --heat-3: #22c55e;
  --heat-4: #16a34a;
  --heat-5: #15803d;                   /* extra-deep for very strong days */
  --heat-skip: #cbd5e1;                /* pulado / skip */

  /* ---- Mood scale 1..5 (sad → great) ---- */
  --mood-1: #ef4444;
  --mood-2: #f97316;
  --mood-3: #eab308;
  --mood-4: #84cc16;
  --mood-5: #22c55e;

  /* ---- Typography ---- */
  --font: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --fs-display: 1.625rem;
  --fs-h1: 1.25rem;
  --fs-h2: 1rem;
  --fs-body: 0.875rem;
  --fs-sm: 0.8125rem;
  --fs-xs: 0.75rem;
  --fs-micro: 0.6875rem;

  /* ---- Radius ---- */
  --radius: 14px;
  --radius-sm: 10px;
  --radius-lg: 20px;
  --radius-pill: 999px;

  /* ---- Spacing / density ---- */
  --content-max: 1080px;
  --gap: 16px;

  /* ---- Status ---- */
  --ok: #16a34a;
  --ok-tint: rgba(22, 163, 74, 0.12);
  --warn: #d97706;
  --warn-tint: rgba(217, 119, 6, 0.14);
  --danger: #dc2626;
  --danger-tint: rgba(220, 38, 38, 0.12);
  --info: #2563eb;
  --info-tint: rgba(37, 99, 235, 0.12);
}

/* ---------- LIGHT ---------- */
:root,
[data-theme="light"] {
  color-scheme: light;
  --bg: #f5f6fb;
  --bg-grad-1: #f7f8fd;
  --bg-grad-2: #eef0f8;
  --surface: #ffffff;
  --surface-2: #f7f8fc;
  --surface-3: #eef0f6;
  --border: #e6e8f0;
  --border-strong: #d4d8e4;
  --text: #14161d;
  --text-2: #424859;
  --muted: #5c6376;
  --faint: #667085;    /* AA sobre fundo claro */
  --overlay: rgba(18, 22, 34, 0.42);

  --shadow-card: 0 1px 2px rgba(20, 22, 40, 0.05), 0 1px 1px rgba(20, 22, 40, 0.04);
  --shadow-card-hover: 0 8px 24px rgba(40, 38, 90, 0.10), 0 2px 6px rgba(20, 22, 40, 0.06);
  --shadow-pop: 0 16px 48px rgba(20, 18, 60, 0.18), 0 3px 10px rgba(20, 18, 60, 0.08);
  --shadow-brand: 0 6px 18px rgba(217, 119, 6, 0.30);
}

/* ---------- DARK ---------- */
[data-theme="dark"] {
  color-scheme: dark;
  --brand: #fbbf24;            /* âmbar-300: texto de marca legível no escuro */
  --brand-strong: #fcd34d;
  --brand-tint: rgba(251, 191, 36, 0.14);
  --brand-tint-strong: rgba(251, 191, 36, 0.24);

  --flame: #fbbf24;
  --flame-strong: #fb923c;
  --flame-tint: rgba(251, 191, 36, 0.16);

  --heat-1: #14532d;
  --heat-2: #166534;
  --heat-3: #22c55e;
  --heat-4: #4ade80;
  --heat-5: #86efac;
  --heat-skip: #3a4252;

  --mood-1: #f87171;
  --mood-2: #fb923c;
  --mood-3: #facc15;
  --mood-4: #a3e635;
  --mood-5: #4ade80;

  --bg: #0b0d13;
  --bg-grad-1: #0e1118;
  --bg-grad-2: #090b10;
  --surface: #14171f;
  --surface-2: #10131a;
  --surface-3: #1c212c;
  --border: #232936;
  --border-strong: #333a4a;
  --text: #e9ebf2;
  --text-2: #b7bdcc;
  --muted: #868fa0;
  --faint: #8b94a7;    /* AA sobre fundo escuro */
  --overlay: rgba(3, 5, 9, 0.64);

  --ok: #4ade80;
  --ok-tint: rgba(74, 222, 128, 0.14);
  --warn: #fbbf24;
  --warn-tint: rgba(251, 191, 36, 0.16);
  --danger: #f87171;
  --danger-tint: rgba(248, 113, 113, 0.16);
  --info: #60a5fa;
  --info-tint: rgba(96, 165, 250, 0.16);

  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.40);
  --shadow-card-hover: 0 8px 26px rgba(0, 0, 0, 0.55);
  --shadow-pop: 0 18px 54px rgba(0, 0, 0, 0.65);
  --shadow-brand: 0 6px 20px rgba(217, 119, 6, 0.42);
}

/* ============================================================
   Base
   ============================================================ */
* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: 1.5;
  color: var(--text);
  background: var(--bg);
  background-image: radial-gradient(130% 90% at 50% -12%, var(--bg-grad-1), var(--bg-grad-2));
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  letter-spacing: -0.006em;
  transition: background-color 0.25s ease, color 0.25s ease;
}
a { color: var(--brand); text-decoration: none; }
a:hover { color: var(--brand-strong); }
button { font-family: inherit; cursor: pointer; }
h1, h2, h3, h4 { margin: 0; letter-spacing: -0.02em; }
::selection { background: var(--brand-tint-strong); }

/* Scrollbars */
*::-webkit-scrollbar { height: 10px; width: 10px; }
*::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: var(--radius-pill);
  border: 3px solid transparent;
  background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover { background: var(--faint); background-clip: padding-box; }
*::-webkit-scrollbar-track { background: transparent; }

/* ============================================================
   Layout shell
   ============================================================ */
.tr-shell {
  min-height: 100%;
  display: flex;
  flex-direction: column;
}

/* ---------- Skip-link (WCAG 2.4.1) ----------
   Escondido fora da tela até o foco chegar (Tab); só então some visível no
   canto superior esquerdo, por cima de tudo (nav é z-index:40). Não afeta o
   layout sem foco — o gate de fidelidade compara pixels do estado normal. */
.tr-skip {
  position: absolute;
  left: -999px;
  top: -999px;
  z-index: 1100;
  padding: 10px 16px;
  background: var(--surface);
  color: var(--text);
  border: 2px solid var(--brand);
  border-radius: var(--radius-sm);
  font-weight: 700;
  text-decoration: none;
}
.tr-skip:focus {
  left: 12px;
  top: 12px;
}

/* ---------- Top nav ---------- */
.tr-nav {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 16px;
  /* height auto + wrap (gate 2026-09-09): a tira de links rolava por baixo do botão de
     tema/avatar e o centro dos últimos links ficava coberto (375 e 768). Agora os links
     quebram linha e a barra cresce — nada fica clipado. */
  height: auto;
  min-height: 60px;
  flex-wrap: wrap;
  padding: 0 20px;
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  backdrop-filter: saturate(1.4) blur(14px);
  border-bottom: 1px solid var(--border);
}
.tr-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: var(--text);
  padding: 4px 4px 4px 2px;
  border-radius: var(--radius-sm);
  flex: 0 0 auto;
  transition: opacity 0.15s;
}
.tr-brand:hover { color: var(--text); opacity: 0.9; }
.tr-brand-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px; height: 34px;
  border-radius: 11px;
  font-size: 1.125rem;
  color: #fff;
  background: linear-gradient(135deg, var(--brand) 0%, var(--brand-strong) 70%, var(--flame-strong) 165%);
  box-shadow: var(--shadow-brand);
  flex: 0 0 auto;
}
.tr-brand-word {
  font-weight: 800;
  font-size: 1.125rem;
  letter-spacing: -0.03em;
  /* 1.3, não 1: com line-height 1 a tinta do glifo saía 2px acima e 2px abaixo da
     caixa (gate 2026-09-09 — o fix anterior em fretz.css era no seletor errado) */
  line-height: 1.3;
}

.tr-nav-links {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 2px;
  min-width: 0;
  overflow: visible;
}
/* até 1360px os links são só ícone: 10 rótulos (o afinador do FB-0027 é o 10º) não cabem
   numa linha ao lado da marca e dos controles — a 1280 a barra quebrava em duas linhas
   (90 px) e empurrava o leitor de tablatura pra baixo da dobra numa janela de 720, onde o
   render preguiçoso do alphaTab não desenhava nada (gate v0.15.0). Era 1100 com 9 rótulos. */
@media (max-width: 1360px) {
  .tr-nav-link > span { display: none; }
  .tr-nav-link .bi { font-size: 1.0625rem; }
}
.tr-nav-links::-webkit-scrollbar { display: none; }
.tr-nav-link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-2);
  text-decoration: none;
  white-space: nowrap;
  border: none;
  background: transparent;
  position: relative;
  transition: background 0.15s, color 0.15s;
}
.tr-nav-link .bi { font-size: 0.9375rem; opacity: 0.85; }
.tr-nav-link:hover { color: var(--text); background: var(--surface-3); }
.tr-nav-link.active {
  color: var(--brand);
  background: var(--brand-tint);
}
.tr-nav-link.active .bi { opacity: 1; }
.tr-nav-spacer { flex: 1 1 auto; }

.tr-icon-btn {
  width: 36px; height: 36px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-2);
  font-size: 1.0625rem;
  flex: 0 0 auto;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.tr-icon-btn:hover { color: var(--text); background: var(--surface-3); }

/* ---------- Avatar ---------- */
.tr-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  /* tamanho em EM, não px: a 200% de fonte as iniciais (20px) vazavam do círculo de 24px
     (gate 2026-09-09, 108 células). 2.5em = 30px na base, e o círculo cresce junto. */
  width: 2.5em; height: 2.5em;
  border-radius: 50%;
  font-size: 0.75rem;
  font-weight: 700;
  color: #fff;
  /* sem letter-spacing: o .02em sobrava DEPOIS da última letra e a tinta das
     iniciais saía 3px do círculo (gate 2026-09-09, 24 células) */
  letter-spacing: 0;
  flex: 0 0 auto;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18);
}
.tr-avatar-sm { width: 2.4em; height: 2.4em; font-size: 0.625rem; }   /* 24px na base */
.tr-avatar-lg { width: 2.75em; height: 2.75em; font-size: 1rem; }    /* 44px na base */

/* ---------- User chip (dropdown) ---------- */
.tr-user {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 4px 10px 4px 4px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}
.tr-user:hover { border-color: var(--border-strong); background: var(--surface-2); }
.tr-user-name { font-size: var(--fs-sm); font-weight: 600; white-space: nowrap; }
.tr-user.dropdown-toggle::after { margin-left: 0; color: var(--muted); border-top-color: currentColor; }
.tr-level-chip {
  display: inline-flex; align-items: center;
  font-size: var(--fs-micro); font-weight: 800; letter-spacing: 0.02em;
  padding: 2px 7px; border-radius: var(--radius-pill);
  background: var(--flame-tint); color: var(--flame-strong);
  white-space: nowrap;
}

/* ---------- Content container ---------- */
.tr-content {
  width: 100%;
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 28px 24px 64px;
  flex: 1 1 auto;
}

/* ---------- Flash ---------- */
.tr-flash {
  width: 100%;
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 12px 24px 0;
}
.tr-flash:empty { display: none; }
.tr-flash .alert {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  box-shadow: var(--shadow-card);
}

/* ============================================================
   Page header
   ============================================================ */
.tr-page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 24px;
}
.tr-page-title {
  font-size: var(--fs-display);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.1;
  display: flex;
  align-items: center;
  gap: 11px;
  /* O título é uma FLEX de coisas que não encolhem (o nome da peça, o tipo, o
     selo "no tempo" com white-space: nowrap). Numa linha de 320 px com a fonte
     do usuário a 200%, o selo passava 2 px da borda e a PÁGINA ganhava rolagem
     lateral (WCAG 1.4.10) — 2 px que ninguém vê e todo mundo sente, porque o
     dedo arrasta a tela inteira de lado. Deixar quebrar linha resolve sem
     esconder nada, e o nome comprido quebra dentro da própria caixa. */
  flex-wrap: wrap;
  overflow-wrap: anywhere;
}
.tr-page-title .bi { color: var(--brand); font-size: 0.9em; }
.tr-page-sub {
  margin-top: 5px;
  font-size: var(--fs-sm);
  color: var(--muted);
}

/* ============================================================
   Cards & surfaces
   ============================================================ */
.tr-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  padding: 18px 20px;
  transition: box-shadow 0.18s, border-color 0.18s, transform 0.18s;
}
.tr-card-hover:hover {
  box-shadow: var(--shadow-card-hover);
  border-color: var(--border-strong);
  transform: translateY(-2px);
}
.tr-card-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
}
.tr-card-title {
  font-size: var(--fs-h2);
  font-weight: 700;
  letter-spacing: -0.015em;
  display: flex;
  align-items: center;
  gap: 8px;
}
.tr-card-title .bi { color: var(--brand); }
.tr-card-head .tr-card-actions { margin-left: auto; display: flex; align-items: center; gap: 6px; }

.tr-muted { color: var(--muted); }
.tr-faint { color: var(--faint); }

.tr-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--gap);
}

/* ---------- Stat block ---------- */
.tr-stat {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 16px 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
}
.tr-stat-num {
  font-size: 1.875rem;
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--text);
}
.tr-stat-num.brand { color: var(--brand); }
.tr-stat-num.flame { color: var(--flame-strong); }
.tr-stat-num.ok { color: var(--ok); }
.tr-stat-label {
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}

/* ============================================================
   Buttons (Bootstrap bridge + custom)
   ============================================================ */
.btn { font-weight: 600; border-radius: var(--radius-sm); }
.btn-brand {
  background: var(--brand);
  border: 1px solid var(--brand);
  color: var(--brand-fg);
  box-shadow: var(--shadow-brand);
  transition: filter 0.15s, transform 0.12s, box-shadow 0.15s;
}
.btn-brand:hover { background: var(--brand-strong); border-color: var(--brand-strong); color: var(--brand-fg); filter: brightness(1.02); }
.btn-brand:active { transform: translateY(1px); }
.btn-soft {
  background: var(--brand-tint);
  border: 1px solid transparent;
  color: var(--brand);
  transition: background 0.15s, color 0.15s;
}
.btn-soft:hover { background: var(--brand-tint-strong); color: var(--brand-strong); }
.btn-ghost {
  background: transparent;
  border: 1px solid var(--border-strong);
  color: var(--text-2);
}
.btn-ghost:hover { background: var(--surface-2); color: var(--text); border-color: var(--faint); }

/* ============================================================
   Habit / Today
   ============================================================ */
.tr-habit-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  transition: border-color 0.16s, box-shadow 0.16s, transform 0.16s;
}
.tr-habit-row:hover { border-color: var(--border-strong); box-shadow: var(--shadow-card-hover); }
.tr-habit-row.done { background: var(--surface-2); }
.tr-habit-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px;
  border-radius: 12px;
  font-size: 1.1875rem;
  color: #fff;
  flex: 0 0 auto;
  background: var(--brand);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16);
}
.tr-habit-body { flex: 1 1 auto; min-width: 0; }
.tr-habit-name {
  font-size: var(--fs-body);
  font-weight: 700;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tr-habit-row.done .tr-habit-name { color: var(--muted); }
.tr-habit-meta {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 3px;
  font-size: var(--fs-xs);
  color: var(--muted);
}

/* Big round check */
.tr-check {
  width: 40px; height: 40px;
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
  border: 2px solid var(--border-strong);
  background: var(--surface);
  color: var(--faint);
  font-size: 1.1875rem;
  transition: all 0.18s cubic-bezier(0.2, 0.8, 0.3, 1);
}
.tr-check:hover { border-color: var(--ok); color: var(--ok); transform: scale(1.06); }
.tr-check.done {
  background: var(--ok);
  border-color: var(--ok);
  color: #fff;
  box-shadow: 0 4px 12px var(--ok-tint);
}
.tr-check.done:hover { transform: scale(1.06); filter: brightness(1.04); }

/* Conic completion ring — drive with --pct (0..100) */
.tr-ring {
  --pct: 0;
  --size: 44px;
  --thick: 5px;
  width: var(--size); height: var(--size);
  flex: 0 0 auto;
  border-radius: 50%;
  display: inline-grid;
  place-items: center;
  background:
    conic-gradient(var(--brand) calc(var(--pct) * 1%), var(--surface-3) 0);
  -webkit-mask: none;
}
.tr-ring::before {
  content: "";
  position: relative;
  width: calc(var(--size) - var(--thick) * 2);
  height: calc(var(--size) - var(--thick) * 2);
  border-radius: 50%;
  background: var(--surface);
  grid-area: 1 / 1;
}
.tr-ring > * { grid-area: 1 / 1; z-index: 1; }
.tr-ring-label {
  font-size: var(--fs-micro);
  font-weight: 800;
  color: var(--text);
  letter-spacing: -0.02em;
}
.tr-ring.full { background: conic-gradient(var(--ok) 100%, var(--ok) 0); }

/* Streak / flame */
.tr-streak {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: var(--fs-sm);
  font-weight: 800;
  color: var(--flame-strong);
  background: var(--flame-tint);
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  letter-spacing: -0.01em;
}
.tr-flame {
  color: var(--flame-strong);
  font-size: 0.875rem;
  filter: drop-shadow(0 1px 2px rgba(249, 115, 22, 0.35));
}
.tr-streak.cold { color: var(--muted); background: var(--surface-3); }
.tr-streak.cold .tr-flame { color: var(--faint); filter: none; }

/* Week strip */
.tr-week-strip {
  display: flex;
  align-items: center;
  gap: 6px;
}
.tr-day-dot {
  display: inline-flex; flex-direction: column; align-items: center;
  gap: 4px;
  font-size: var(--fs-micro);
  font-weight: 700;
  color: var(--muted);
}
.tr-day-dot > .dot {
  width: 26px; height: 26px;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface-3);
  border: 1.5px solid transparent;
  color: var(--faint);
  font-size: 0.6875rem;
  transition: all 0.15s;
}
.tr-day-dot.done > .dot { background: var(--ok); color: #fff; }
.tr-day-dot.skip > .dot { background: repeating-linear-gradient(45deg, var(--heat-skip), var(--heat-skip) 3px, transparent 3px, transparent 6px); color: var(--muted); }
.tr-day-dot.today > .dot { border-color: var(--brand); color: var(--brand); box-shadow: 0 0 0 3px var(--brand-tint); }
.tr-day-dot.today.done > .dot { color: #fff; }
.tr-day-dot.future > .dot { opacity: 0.5; }

/* ============================================================
   Quantity (count/measure habits)
   ============================================================ */
.tr-qty {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.tr-qty-val { font-size: var(--fs-sm); font-weight: 700; white-space: nowrap; color: var(--text-2); }
.tr-qty-bar {
  --pct: 0;
  position: relative;
  flex: 1 1 auto;
  height: 8px;
  min-width: 60px;
  border-radius: var(--radius-pill);
  background: var(--surface-3);
  overflow: hidden;
}
.tr-qty-bar::after {
  content: "";
  position: absolute; inset: 0;
  width: calc(var(--pct) * 1%);
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--brand), var(--brand-strong));
  transition: width 0.4s cubic-bezier(0.2, 0.8, 0.3, 1);
}
.tr-qty-bar.full::after { background: linear-gradient(90deg, var(--ok), var(--heat-4)); }

/* ============================================================
   Heatmap (DOM grid — NOT canvas)
   ============================================================ */
.tr-heatmap {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: repeat(7, 1fr);
  gap: 4px;
  overflow-x: auto;
  padding: 2px;
}
.tr-heat-cell {
  width: 14px; height: 14px;
  border-radius: 4px;
  background: var(--heat-0);
  box-shadow: inset 0 0 0 1px rgba(20, 22, 40, 0.04);
  cursor: default;
  position: relative;
  transition: transform 0.12s, outline-color 0.12s;
}
[data-theme="dark"] .tr-heat-cell { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05); }
.tr-heat-cell:hover { transform: scale(1.25); outline: 2px solid var(--brand); outline-offset: 1px; z-index: 2; }
.tr-heat-cell[data-nivel="0"]  { background: var(--heat-0); }
.tr-heat-cell[data-nivel="1"]  { background: var(--heat-1); }
.tr-heat-cell[data-nivel="2"]  { background: var(--heat-2); }
.tr-heat-cell[data-nivel="3"]  { background: var(--heat-3); }
.tr-heat-cell[data-nivel="4"]  { background: var(--heat-4); }
.tr-heat-cell[data-nivel="5"]  { background: var(--heat-5); }
.tr-heat-cell[data-nivel="-1"] {
  background: repeating-linear-gradient(45deg, var(--heat-skip), var(--heat-skip) 2px, transparent 2px, transparent 4px);
  background-color: var(--surface-3);
}
/* hover tooltip affordance — page sets title="" or data-tip; we surface it via [data-tip] */
.tr-heat-cell[data-tip]:hover::after {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 7px);
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  background: var(--text);
  color: var(--surface);
  font-size: var(--fs-micro);
  font-weight: 600;
  padding: 4px 8px;
  border-radius: 6px;
  box-shadow: var(--shadow-pop);
  z-index: 50;
  pointer-events: none;
}
.tr-heatmap-legend {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-micro); color: var(--muted); font-weight: 600;
  margin-top: 8px;
}
.tr-heatmap-legend .tr-heat-cell { cursor: default; }

/* ============================================================
   Mood
   ============================================================ */
.tr-mood { display: inline-flex; align-items: center; gap: 8px; }
.tr-mood-opt {
  width: 38px; height: 38px;
  border-radius: 50%;
  border: 2px solid var(--border);
  background: var(--surface);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 1.1875rem;
  line-height: 1;
  color: var(--faint);
  transition: all 0.16s cubic-bezier(0.2, 0.8, 0.3, 1);
}
.tr-mood-opt[data-humor="1"] { --m: var(--mood-1); }
.tr-mood-opt[data-humor="2"] { --m: var(--mood-2); }
.tr-mood-opt[data-humor="3"] { --m: var(--mood-3); }
.tr-mood-opt[data-humor="4"] { --m: var(--mood-4); }
.tr-mood-opt[data-humor="5"] { --m: var(--mood-5); }
.tr-mood-opt:hover { border-color: var(--m); color: var(--m); transform: translateY(-2px); }
.tr-mood-opt.selected {
  border-color: var(--m);
  background: color-mix(in srgb, var(--m) 16%, var(--surface));
  color: var(--m);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--m) 22%, transparent);
}

/* ============================================================
   Achievements / badges
   ============================================================ */
.tr-badge {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 8px;
  padding: 18px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  transition: box-shadow 0.18s, transform 0.18s, border-color 0.18s;
}
.tr-badge:not(.locked):hover { box-shadow: var(--shadow-card-hover); transform: translateY(-3px); border-color: var(--border-strong); }
.tr-badge-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 56px; height: 56px;
  border-radius: 50%;
  font-size: 1.625rem;
  color: #fff;
  background: linear-gradient(135deg, var(--flame), var(--flame-strong));
  box-shadow: 0 6px 16px var(--flame-tint);
}
.tr-badge-name { font-size: var(--fs-sm); font-weight: 700; letter-spacing: -0.01em; }
.tr-badge-desc { font-size: var(--fs-xs); color: var(--muted); line-height: 1.4; }
.tr-badge-xp {
  font-size: var(--fs-micro); font-weight: 800; letter-spacing: 0.04em;
  color: var(--brand);
  background: var(--brand-tint);
  padding: 2px 8px;
  border-radius: var(--radius-pill);
}
.tr-badge.locked { opacity: 0.62; filter: saturate(0.25); }
.tr-badge.locked .tr-badge-icon { background: var(--surface-3); color: var(--faint); box-shadow: none; }
.tr-badge.locked .tr-badge-xp { background: var(--surface-3); color: var(--muted); }

/* ============================================================
   Progress / level
   ============================================================ */
.tr-level {
  display: flex;
  align-items: center;
  gap: 12px;
}
.tr-level-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 40px; height: 40px;
  padding: 0 10px;
  border-radius: 12px;
  font-size: var(--fs-h2);
  font-weight: 800;
  color: #fff;
  background: linear-gradient(135deg, var(--brand), var(--brand-strong));
  box-shadow: var(--shadow-brand);
  flex: 0 0 auto;
}
.tr-level-bar {
  --pct: 0;
  position: relative;
  flex: 1 1 auto;
  height: 10px;
  border-radius: var(--radius-pill);
  background: var(--surface-3);
  overflow: hidden;
}
.tr-level-bar::after {
  content: "";
  position: absolute; inset: 0;
  width: calc(var(--pct) * 1%);
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--brand), var(--flame));
  transition: width 0.5s cubic-bezier(0.2, 0.8, 0.3, 1);
}

/* Pills / chips / tags */
.tr-pill {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: var(--fs-xs); font-weight: 700;
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  background: var(--surface-3);
  color: var(--text-2);
  white-space: nowrap;
}
.tr-pill.brand { background: var(--brand-tint); color: var(--brand); }
.tr-pill.ok { background: var(--ok-tint); color: var(--ok); }
.tr-pill.warn { background: var(--warn-tint); color: var(--warn); }
.tr-pill.danger { background: var(--danger-tint); color: var(--danger); }
.tr-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-sm); font-weight: 600;
  padding: 5px 11px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text-2);
  transition: all 0.15s;
}
.tr-chip:hover { border-color: var(--faint); color: var(--text); }
.tr-chip.active { background: var(--brand-tint); border-color: var(--brand); color: var(--brand); }
.tr-tag {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: var(--fs-micro); font-weight: 700; letter-spacing: 0.02em;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  color: #fff;
  background: var(--brand);
  line-height: 1.4;
  white-space: nowrap;
}

/* Category dot */
.tr-cat-dot {
  display: inline-block;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--brand);
  flex: 0 0 auto;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.08);
}

/* ============================================================
   Empty state
   ============================================================ */
.tr-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 12px;
  padding: 56px 24px;
  color: var(--muted);
}
.tr-empty .tr-empty-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 72px; height: 72px;
  border-radius: 50%;
  background: var(--brand-tint);
  color: var(--brand);
  font-size: 2rem;
}
.tr-empty-title { font-size: var(--fs-h2); font-weight: 700; color: var(--text); }
.tr-empty p { margin: 0; max-width: 360px; line-height: 1.6; }

/* ============================================================
   Data table (chart fallback)
   ============================================================ */
.tr-data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}
.tr-data-table th, .tr-data-table td {
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  text-align: left;
}
.tr-data-table th {
  font-size: var(--fs-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.tr-data-table tbody tr:last-child td { border-bottom: none; }
/* visually hidden but present in DOM (for screen readers / test fallback) */
.tr-visually-data {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ============================================================
   Toasts
   ============================================================ */
.tr-toasts {
  position: fixed;
  right: 20px;
  /* acima do botão flutuante de feedback (concilio-feedback), senão o aviso
     nasce escondido atrás dele e a pessoa nunca lê o que o app disse */
  bottom: 84px;
  z-index: 1090;
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: min(380px, calc(100vw - 40px));
  pointer-events: none;
}
.tr-toast {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-pop);
  color: var(--text);
  font-size: var(--fs-sm);
  font-weight: 500;
  animation: tr-toast-in 0.24s cubic-bezier(0.2, 0.8, 0.3, 1);
}
.tr-toast.leaving { animation: tr-toast-out 0.2s ease forwards; }
.tr-toast-icon { color: var(--brand); font-size: 1.0625rem; flex: 0 0 auto; }
.tr-toast.success .tr-toast-icon { color: var(--ok); }
.tr-toast.warning .tr-toast-icon { color: var(--warn); }
.tr-toast.danger .tr-toast-icon { color: var(--danger); }
.tr-toast-msg { flex: 1 1 auto; min-width: 0; line-height: 1.4; }
.tr-toast-action {
  flex: 0 0 auto;
  border: none;
  background: var(--brand-tint);
  color: var(--brand);
  font: inherit;
  font-weight: 700;
  font-size: var(--fs-xs);
  padding: 5px 11px;
  border-radius: var(--radius-pill);
  transition: background 0.15s;
}
.tr-toast-action:hover { background: var(--brand-tint-strong); }
.tr-toast-close {
  flex: 0 0 auto;
  border: none; background: transparent;
  color: var(--faint); font-size: 1rem;
  line-height: 1; padding: 2px;
}
.tr-toast-close:hover { color: var(--text); }
@keyframes tr-toast-in { from { opacity: 0; transform: translateX(16px) scale(0.97); } to { opacity: 1; transform: none; } }
@keyframes tr-toast-out { to { opacity: 0; transform: translateX(16px) scale(0.97); } }

/* ============================================================
   Auth (public) layout
   ============================================================ */
.tr-auth-wrap {
  min-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 32px 18px;
  gap: 20px;
}
.tr-auth-brand {
  display: inline-flex; align-items: center; gap: 11px;
  font-size: 1.375rem; font-weight: 800; letter-spacing: -0.03em;
  color: var(--text);
}
.tr-auth-card {
  width: 100%;
  max-width: 410px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-pop);
  padding: 30px 30px 28px;
}
.tr-auth-card h1 {
  font-size: var(--fs-h1);
  font-weight: 800;
  margin-bottom: 6px;
}
.tr-auth-card .tr-auth-sub {
  color: var(--muted);
  font-size: var(--fs-sm);
  margin-bottom: 22px;
}
.tr-auth-foot {
  margin-top: 20px;
  text-align: center;
  font-size: var(--fs-sm);
  color: var(--muted);
}

/* error pages */
.tr-error-code {
  font-size: 4rem;
  font-weight: 800;
  letter-spacing: -0.04em;
  line-height: 1;
  background: linear-gradient(135deg, var(--brand), var(--flame-strong));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* ============================================================
   Bootstrap bridge (buttons / forms / dropdown / dark)
   ============================================================ */
.btn-primary {
  --bs-btn-bg: var(--brand); --bs-btn-border-color: var(--brand);
  --bs-btn-hover-bg: var(--brand-strong); --bs-btn-hover-border-color: var(--brand-strong);
  --bs-btn-active-bg: var(--brand-strong); --bs-btn-active-border-color: var(--brand-strong);
  --bs-btn-disabled-bg: var(--brand); --bs-btn-disabled-border-color: var(--brand);
}
.bg-primary { background-color: var(--brand) !important; }
.text-primary { color: var(--brand) !important; }
.btn-link { --bs-btn-color: var(--brand); --bs-btn-hover-color: var(--brand-strong); }
.form-control, .form-select {
  border-radius: var(--radius-sm);
  border-color: var(--border-strong);
  background: var(--surface);
  color: var(--text);
}
.form-control:focus, .form-select:focus, .form-check-input:focus {
  border-color: var(--brand); box-shadow: 0 0 0 0.2rem var(--brand-tint);
}
.form-check-input:checked { background-color: var(--brand); border-color: var(--brand); }
.form-label { font-size: var(--fs-sm); font-weight: 600; color: var(--text-2); }
.input-group-text { background: var(--surface-2); border-color: var(--border-strong); color: var(--muted); }

.dropdown-menu {
  --bs-dropdown-bg: var(--surface);
  --bs-dropdown-border-color: var(--border);
  --bs-dropdown-border-radius: var(--radius-sm);
  --bs-dropdown-link-hover-bg: var(--surface-2);
  --bs-dropdown-link-active-bg: var(--brand-tint);
  --bs-dropdown-link-active-color: var(--text);
  --bs-dropdown-link-color: var(--text-2);
  box-shadow: var(--shadow-pop);
  padding: 6px;
}
.dropdown-item { border-radius: var(--radius-sm); display: flex; align-items: center; gap: 9px; font-size: var(--fs-sm); }
.dropdown-item .bi { color: var(--muted); }
.dropdown-header { font-size: var(--fs-xs); color: var(--muted); }
.dropdown-divider { border-color: var(--border); }
.dropdown-logout { margin: 0; }
.dropdown-logout button { width: 100%; text-align: left; border: none; background: transparent; font: inherit; }

[data-bs-theme="dark"] .bg-light { background-color: var(--surface-3) !important; }
[data-bs-theme="dark"] .text-dark { color: var(--text) !important; }

/* ============================================================
   Responsive
   ============================================================ */
/* A SIDEBAR (>=900px) tem 100vh de altura e `.tr-nav-links` rola (overflow-y:auto) — com
   os 13 links + 4 cabeçalhos da leva 2026-09-16 (antes eram 10, sem Teoria/Exercício/Música)
   o conteúdo passou a medir 729px (1024x768) / 729px (1280x900, 3px de sobra só) contra os
   ~594/726px livres: Diário/Progresso/Admin ficam com a CAIXA fora da área visível do
   scroll, e o clique onde "deveriam" estar cai no botão de tema/avatar por baixo —
   elementFromPoint mede 1x1 (gate 2026-09-17, mesma classe do vício de 2026-09-09 na barra
   horizontal, agora no eixo vertical). Aperta o passo só onde a janela é baixa; >940px de
   altura mantém o espaçamento do design (fretz-ponte.css) intacto. */
@media (min-width: 900px) and (max-height: 940px) {
  .tr-nav .tr-nav-link { padding-top: 5px; padding-bottom: 5px; }
  .tr-nav .tr-nav-sec { padding-top: 5px; padding-bottom: 1px; }
  .tr-nav .tr-nav-links { gap: 0; }
}

/* Entre o wrap do celular (<=720px) e a sidebar (>=900px) a barra fica de UMA linha só
   (60px) com os 13 ícones + avatar — mas com os 3 painéis novos (Teoria/Exercício/Música)
   o nome do usuário ao lado do avatar empurrava a barra pra 90px (2 linhas, gate
   2026-09-17, medido a 768px). Some o nome e aperta o passo só nesta faixa estreita. */
@media (min-width: 721px) and (max-width: 899px) {
  .tr-user-name { display: none; }
  .tr-nav { gap: 8px; padding: 0 12px; }
  .tr-nav-links { gap: 0; }
  .tr-nav-link { padding: 8px 7px; }
}


/* O h1 do Hoje (dashboard.html) usava font-size:clamp(1.8rem,4.5vw,2.8rem) — o termo
   `vw` mede a LARGURA DA JANELA, não o `font-size` da raiz, então forçar
   html{font-size:200%} (a régua de fonte ampliada) não dobrava a letra: cresceu só
   x1.29–x1.67 em vez de ~x2, e a régua de "sem corte"/"sem rolagem" também caía a
   320/375px (gate 2026-09-17). Os 3 degraus abaixo reproduzem o MESMO tamanho que o
   clamp dava a 100% em cada viewport testado (320/375→1.8rem · 768→2.16rem ·
   1024/1280/1920→2.8rem) só que em rem puro — acompanha o zoom de fonte de verdade. */
.tr-hoje-h1 { font-size: 1.8rem; }
@media (min-width: 640px) { .tr-hoje-h1 { font-size: 2.16rem; } }
@media (min-width: 1000px) { .tr-hoje-h1 { font-size: 2.8rem; } }

/* Card "Streak de treino" (Hoje + os 3 painéis novos Teoria/Exercício/Música — mesma
   grade `auto 1fr auto` nos 4 templates): a pílula final ("1 dia" / "sem streak") herda
   `.tr-pill{white-space:nowrap}` e a coluna `auto` do grid não encolhe abaixo do texto
   inteiro — a 320px com fonte 200% a pílula (e a de "🎯 no tempo (…)" no card do plano,
   mesma classe) empurrava a grade 87px pra fora da janela (gate 2026-09-17). Só nesses
   dois lugares a pílula pode quebrar linha; em todo o resto do app continua nowrap. */
.tr-streak-grid .tr-pill,
.tr-habit-meta .tr-pill {
  white-space: normal;
  text-align: center;
}
/* a coluna `auto` do grid só encolhe até o CONTEÚDO — sem um teto explícito a pílula
   segue medida como se fosse uma linha só, mesmo com white-space:normal acima (o
   `auto` do grid não empurra pra baixo do max-content sozinho). O teto só entra
   ≤400px: é só aí (320/375 + fonte 200%) que "sem streak"/"🎯 no tempo (…)" estouram;
   em qualquer largura maior a pílula nunca chega perto de 60px mesmo a 200%. */
/* Duas correções do gate CHEIO de 2026-09-18, ambas neste teto:
   1. **Só a grade de streak.** O teto nasceu para "sem streak"/"🎯 no tempo (…)" do card
      Streak, mas pegava TODO `.tr-habit-meta` — que também é a linha de meta de `/pecas`,
      `/estudar`, `/baralhos` e `/admin`. Lá ele não resolvia nada e inchava a tela: o card
      de `/pecas` a 375px + fonte 200% passou de 309px (0.19.3, em produção) para 599px,
      porque cada pílula virava uma coluna de 60px com o texto quebrado em cinco linhas —
      e um card que não cabe na tela faz a régua de clique acertar a barra grudada.
   2. **Tinta dentro da pílula.** Teto SOZINHO só empurra a tinta pra fora: a palavra fica
      inteira e pinta além do fundo arredondado ("sem streak" saía 9px a 100% e 59px a
      200%). `overflow-wrap: anywhere` deixa a palavra quebrar DENTRO da pílula. */
/* O teto de 60px que existia aqui (17/09) segurava a rolagem lateral, mas cobrava caro:
   a palavra continuava inteira e PINTAVA FORA do fundo arredondado (gate CHEIO de 18/09:
   "sem streak" 9px fora a 100% e 59px a 200%) — e mandar quebrar em qualquer ponto
   transformava a pílula numa coluna de letras ("1 d i a", captura
   `dashboard__adapt-375-fonte200`). Media query em `em` não serve de corte aqui: `em` numa
   @media mede a fonte INICIAL do documento, não o zoom de fonte do usuário (`html{font-size}`),
   então a regra nunca dispararia. O que resolve é deixar o texto QUEBRAR onde o navegador
   sabe quebrar: sem teto em px, a linha inteira à disposição e `min-width:0` nos itens da
   grade (que é quem permite a coluna encolher). Medido: 0 pílula com tinta fora e 0px de
   excedente horizontal em Hoje/Teoria/Exercício/Música/Estudar/Baralhos × 320 e 375px ×
   fonte 100/200%. */

/* Residual de 26px de rolagem lateral no Hoje/Teoria/Exercício/Música a 320px +
   fonte 200% (gate 2026-09-17, item registrado pra investigar com régua de
   tinta). Duas causas, as duas só aparecem ≤400px:
   1. a coluna `auto` do NOME (hábito/tag: "Geral"/"Pentatônica"/…) é uma
      ÚNICA faixa compartilhada por TODAS as linhas da grade — o rótulo mais
      comprido entre elas (ex.: "Pentatônica" em Teoria) dita a largura da
      coluna pras OUTRAS linhas também, e a 320px+200% isso sozinho já
      empurrava a grade ~15-40px pra fora da janela. `min-width:0` no item da
      grade + teto no `.tr-habit-name` (com reticências) resolve a AUTORIA.
   2. mesmo com (1) corrigido, sobrava um residual que não batia em NENHUM
      elemento medido (nem por caixa, nem por nó de texto) — o próprio
      `.tr-streak-grid` reportava `scrollWidth` maior que `clientWidth` sem
      nenhum filho/neto cujo `getBoundingClientRect` passasse do próprio
      limite da grade (medido: filhos batem em 283px, grade tem 246px de
      largura — Chromium contando alguma extensão "fantasma" na área
      rolável do grid). Only reproduz nesta grade especificamente
      (4 linhas + divisor `grid-column:1/-1`); `overflow:hidden` na própria
      grade contém isso sem cortar NADA visível (a grade já cabia). */
@media (max-width: 400px) {
  .tr-streak-grid {
    overflow: hidden;
  }
  .tr-streak-grid > div:has(.tr-habit-name) {
    min-width: 0;
  }
  /* Nem reticências no nome, nem teto na pílula (ver o bloco acima): com `min-width:0`
     no item da grade, "Geral"/"Pentatônica" e "sem streak" quebram em duas linhas e
     cabem — a 200% o teto de 110px deixava o nome em "G…"/"Te…", que não é nome.
     A coluna do MEIO (as 7 barrinhas da semana, um `div` sem classe no template) ganha
     piso: liberada a encolher junto, ela ia a 0px a 200% e a semana sumia da tela. 56px
     é o que as 7 barras + os vãos precisam para continuarem lidas como semana. */
  .tr-streak-grid > * { min-width: 0; }
  .tr-streak-grid { grid-template-columns: auto minmax(56px, 1fr) auto !important; }
  .tr-streak-grid .tr-habit-name {
    /* `.tr-habit-name` global (linha 547) é nowrap + reticências; aqui o nome aparece
       INTEIRO — a 200% o teto de 110px deixava "Ge…"/"Te…", que não é nome. */
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    display: inline-block;
    vertical-align: bottom;
  }
  .tr-streak-grid .tr-pill { white-space: normal; }
}

/* Três colunas (nome · semana · pílula) não cabem em 375px quando o usuário amplia a
   fonte: alguma coisa tem que ceder. Cortar o nome esconde informação; quebrar a palavra
   dá "Ge-ral"/"Exer-cí-cio"; deixar tudo solto faz o nome pintar por cima das barrinhas
   (as três medidas em 18/09, com captura). O que fica limpo é a PÍLULA descer pra linha
   dela. O corte não pode ser em `@media`, onde `em` mede a fonte inicial e ignora o zoom
   do usuário — mas em `@container` o `em` é a fonte do PRÓPRIO container, então
   `18em` significa "a caixa tem menos de 18 letras de largura", que é exatamente a
   pergunta certa. A 375px/100% (≈21em) nada muda; a 200% (≈10,7em) a pílula desce. */
.tr-card:has(.tr-streak-grid) { container-type: inline-size; }
@container (max-width: 18em) {
  .tr-streak-grid { grid-template-columns: auto minmax(56px, 1fr) !important; }
  .tr-streak-grid .tr-pill {
    grid-column: 1 / -1;
    justify-self: start;
    max-width: 100%;
  }
}

@media (max-width: 720px) {
  /* A tira de links rolava POR BAIXO do botão de tema e do avatar: a 375px o centro de
     "Metrônomo" e "Diário" caía embaixo deles (gate 2026-09-09, elementFromPoint). Em vez
     de rolar escondido, os ícones QUEBRAM LINHA e a barra cresce — tudo visível e clicável. */
  .tr-nav { gap: 6px; padding: 0 12px; min-height: 56px; }
  /* no celular a tira de ícones ganha a SUA linha, abaixo da marca e dos controles */
  .tr-nav-links { order: 3; flex: 1 0 100%; justify-content: space-between; padding-bottom: 6px; }
  /* O passo apertou na leva 2026-09-16 (gate CHEIO 18/09): a barra é GRUDADA e, com os
     13 links (eram 10), media 265px a 375px + fonte 200% — um terço da tela — e passava
     a TAPAR o topo do 1º card depois de rolar até ele. Com 5px/6px ela volta a ~196px,
     abaixo dos 200px que a 0.19.3 já tinha em produção, ainda com os 13 links visíveis,
     nenhum com o centro coberto e zero de excedente horizontal (100/150/200%). O alvo
     de toque continua acima do piso: ícone de 20px + 10px de respiro = 30px. */
  .tr-nav-link { padding: 5px 6px; }
  .tr-user-name { display: none; }
  .tr-level-chip { display: none; }
  .tr-content { padding: 20px 16px 56px; }
  .tr-flash { padding: 10px 16px 0; }
  .tr-page-title { font-size: 1.375rem; }
}
@media (max-width: 420px) {
  .tr-brand-word { display: none; }
}

/* ============================================================
   Contenção de overflow horizontal (responsivo)
   Flex/grid items têm min-width:auto por padrão → não encolhem
   abaixo do conteúdo e estouram a viewport. Liberar o encolhimento
   faz o overflow-x:auto de heatmap/tabelas/faixa engatar de fato.
   ============================================================ */
.tr-card { min-width: 0; }
/* Enquanto a barra é GRUDADA (só no celular, <=899px), rolar até um card com
   `scrollIntoView` parava o topo dele DEBAixo da barra — quem clicasse no título logo
   depois acertava um link da nav (gate CHEIO 2026-09-18, `clique-titulo-375-light-f200`,
   com a barra em 186px e o título em y=173). `scroll-margin-top` é justamente o respiro
   que o navegador guarda ao rolar até o elemento; 190px cobre a barra no pior caso
   (fonte 200%) e não muda nada fora da rolagem. Na sidebar (>=900px) não existe barra
   no topo, então a regra não vale lá. */
@media (max-width: 899px) {
  .tr-card { scroll-margin-top: 190px; }
}
.tr-grid > * { min-width: 0; }
.tr-heatmap { max-width: 100%; }
.tr-week-strip { max-width: 100%; overflow-x: auto; scrollbar-width: thin; }
/* wrapper utilitário para tabelas largas (ex.: leaderboard de streaks) */
.tr-table-wrap { width: 100%; max-width: 100%; overflow-x: auto; }

@media (max-width: 720px) {
  /* numa linha estreita, a faixa de 7 dias quebra para a sua própria
     linha rolável em vez de empurrar a linha do hábito para fora */
  .tr-habit-row { flex-wrap: wrap; }
  .tr-week-strip { order: 10; width: 100%; }
  .tr-data-table { display: block; overflow-x: auto; white-space: nowrap; }
}

/* ---- Widget de feedback (lib concilio-feedback) -------------------------- */
/* O widget vem com paleta neutra e lê variáveis `--cfb-*`; aqui elas apontam para
   os tokens do app, então ele acompanha sozinho o tema claro e o escuro. A folha
   da lib vive numa @layer, então este bloco vence mesmo carregando antes. */
:root{
  /* --brand puro fica em 4.47:1 com branco, logo abaixo do piso AA (4.5). O tom
     forte (indigo-600) passa. Medido pelo gate em 19/08/2026. */
  --cfb-primaria:var(--brand-strong);
  --cfb-primaria-txt:var(--brand-fg);
  --cfb-fundo:var(--surface);
  --cfb-fundo-2:var(--surface-2);
  --cfb-texto:var(--text);
  --cfb-texto-2:var(--muted);
  --cfb-borda:var(--border);
  --cfb-perigo:var(--danger);
  --cfb-raio:var(--radius-sm);
}

/* No tema escuro a paleta desliza um degrau (--brand-strong vira #d97706) e o par
   com branco cai para 4.47:1, de novo abaixo do piso. O widget mantém o indigo-600
   nos dois temas: sobre a superfície escura ele continua legível, e o botão para de
   reprovar. A mesma dívida existe nos botões primários do PRÓPRIO app no escuro —
   registrada no docs/ROADMAP.md, não corrigida aqui. */
[data-theme="dark"]{ --cfb-primaria:#4f46e5; }

/* ============================================================
   Traste — componentes específicos (braço, estudo, metrônomo,
   player de trecho, leitor de tablatura)
   ============================================================ */

/* --- grids com contagem fixa em desktop --- */
.tr-grid-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); }
.tr-grid-3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); }

/* --- variantes de pill --- */
.tr-pill.pill-danger { background: color-mix(in srgb, #ef4444 14%, transparent); color: #dc2626; }
[data-theme="dark"] .tr-pill.pill-danger { color: #f87171; }
.tr-pill.pill-ok { background: color-mix(in srgb, #22c55e 14%, transparent); color: #16a34a; }
[data-theme="dark"] .tr-pill.pill-ok { color: #4ade80; }

/* --- auth --- */
.tr-auth-title { font-size: 1.625rem; font-weight: 800; letter-spacing: -0.02em; margin-bottom: 4px; }
.tr-auth-links { display: flex; justify-content: space-between; gap: 10px; margin-top: 14px; font-size: var(--fs-sm); }

/* --- cards da lista desativados --- */
.tr-card-inativo { opacity: 0.55; }
.tr-card-inativo td { text-decoration: none; }

/* --- braço da guitarra (SVG) --- */
.tr-braco-wrap { overflow-x: auto; }
.tr-braco-svg { width: 100%; max-width: 760px; height: auto; display: block; }
.tr-braco-editor .tr-braco-svg { max-width: 100%; }
/* --text-muted nunca existiu (o token é --muted): as cordas nasciam sem traço.
   Achado ao ler a captura do braço ao vivo (FB-0005). */
.tr-braco-corda { stroke: var(--muted); opacity: 0.75; }
.tr-braco-traste { stroke: var(--border-strong); stroke-width: 1.5; }
.tr-braco-pestana { stroke: var(--text); stroke-width: 5; }
.tr-braco-bola { fill: var(--brand); opacity: 0.92; }
.tr-braco-bola.tonica { fill: #dc2626; }
.tr-braco-rotulo { fill: #fff; font-size: 0.625rem; font-weight: 700; }
.tr-braco-numcasa { fill: var(--muted); font-size: 0.6875rem; }
.tr-braco-marca { fill: var(--border-strong); }
/* Tábua do braço (FB-0024, verso/leitor em SVG) — mistura discreta de âmbar
   com a superfície do tema: usa `--surface-2`/`--brand`, então clareia ou
   escurece sozinha nos dois temas, sem cor fixa nova. */
.tr-braco-tabua {
  fill: color-mix(in srgb, var(--surface-2) 88%, var(--brand) 10%);
  stroke: var(--border-strong);
  stroke-width: 1;
}

/* --- sessão de estudo --- */
.tr-estudo-card { max-width: 720px; margin: 0 auto; }
.tr-estudo-estado { display: flex; gap: 8px; margin-bottom: 10px; }
.tr-estudo-pergunta { font-size: 1.375rem; font-weight: 700; letter-spacing: -0.01em; margin: 6px 0 10px; }
.tr-estudo-resposta { font-size: 1.625rem; font-weight: 800; color: var(--brand); margin: 6px 0 10px; }
.tr-estudo-img { max-width: 100%; border-radius: 10px; margin: 8px 0; }
.tr-estudo-botoes { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.tr-estudo-botoes .btn { padding: 10px 6px; font-weight: 700; line-height: 1.15; }
.tr-estudo-botoes .tr-faint { font-weight: 500; font-size: 0.6875rem; }
@media (max-width: 560px) {
  .tr-estudo-botoes { grid-template-columns: repeat(2, 1fr); }
  .tr-estudo-pergunta { font-size: 1.1875rem; }
  .tr-estudo-resposta { font-size: 1.375rem; }
}

/* --- metrônomo --- */
.tr-met-card { display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 26px 18px; }
.tr-met-pulso-wrap { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.tr-met-pulso {
  width: 84px; height: 84px; border-radius: 50%;
  background: var(--surface-2); border: 3px solid var(--border-strong);
  transition: transform 0.05s ease;
}
.tr-met-pulso.pulso { animation: tr-pulso 0.22s ease; }
.tr-met-pulso.pulso-forte { animation: tr-pulso-forte 0.24s ease; }
@keyframes tr-pulso { 0% { transform: scale(1.16); background: var(--brand); } 100% { transform: scale(1); } }
@keyframes tr-pulso-forte { 0% { transform: scale(1.3); background: #dc2626; } 100% { transform: scale(1); } }
.tr-met-bpm { font-size: 1.875rem; font-weight: 800; letter-spacing: -0.03em; }
.tr-met-controles { display: flex; gap: 8px; align-items: center; justify-content: center; flex-wrap: wrap; }
.tr-met-controles #met-bpm { width: 110px; font-size: 1.125rem; font-weight: 700; }
#met-play.tocando { background: #dc2626; border-color: #dc2626; }

/* --- player de trecho (YouTube embutido) --- */
.tr-yt-player { position: relative; width: 100%; aspect-ratio: 16 / 9; border-radius: 12px; overflow: hidden; background: #000; }
.tr-yt-player iframe, .tr-yt-player > div, .tr-yt-player video { position: absolute; inset: 0; width: 100%; height: 100%; }
/* Instagram (/embed/ oficial): cartão vertical, sem controle de tempo (FB-0006) */
.tr-ig-player iframe { display: block; width: 100%; max-width: 440px; height: 640px; border: 0; border-radius: 12px; background: #fff; }
.tr-trecho-play { font-weight: 600; text-decoration: none; }
.tr-trecho-play.active { color: var(--brand); }

/* --- leitor de tablatura (alphaTab) --- */
/* isolation: o cursor do alphaTab nasce com z-index alto e vazava por cima da barra
   de navegação fixa quando a página rolava — o contexto próprio o prende aqui. */
.tr-leitor-tab { position: relative; isolation: isolate; max-height: 70vh; overflow-y: auto; overflow-x: auto; border: 1px solid var(--border); border-radius: 12px; background: #fff; }
[data-theme="dark"] .tr-leitor-tab { background: #f4f1ea; }  /* partitura legível: papel claro mesmo no escuro */
.tr-tab-controles .form-check-label { font-size: var(--fs-sm); }
.tr-tab-controles .tr-tab-bpm { width: 5.25rem; font-weight: 700; }
.tr-tab-loop input { width: 4rem; }
/* Cursor e seleção do alphaTab são <div> SEM estilo próprio: sem estas regras
   eles existem e são invisíveis — era o "não vejo a marcação do compasso" e o
   "selecionar o trecho não funciona" do FB-0009. Âmbar da marca sobre o papel. */
.at-cursor-bar { background: rgba(217, 119, 6, 0.16); }
.at-cursor-beat { background: rgba(217, 119, 6, 0.9); width: 3px; }
.at-selection div { background: rgba(37, 99, 235, 0.14); }
.at-highlight * { fill: #d97706; stroke: #d97706; }
/* Vista "só o braço": o alphaTab precisa da LARGURA do host pra diagramar, então a
   tablatura some por altura zero, nunca por display:none (que a faria re-renderizar). */
.tr-leitor-tab.tr-leitor-oculto { height: 0 !important; max-height: 0 !important; min-height: 0; padding: 0; border-width: 0; overflow: hidden !important; }
.tr-tab-braco { margin-bottom: 10px; }
/* FB-0010 — na vista "os dois" o braço ocupava 327 px de altura e empurrava a
   partitura pra fora da tela. Cabe em 22vh; o resto da tela é do papel. */
.tr-tab-braco .tr-braco-svg { max-width: 100%; max-height: 22vh; width: auto; display: block; margin: 0 auto; }
/* Braço ao vivo (FB-0005): a peça inteira em fantasma, o que já tocou meio aceso,
   o que está soando agora aceso de verdade. */
.tr-braco-bola.fantasma { opacity: 0.16; }
.tr-braco-bola.tocada { opacity: 0.5; }
.tr-braco-bola.ativa { fill: #2563eb; opacity: 1; stroke: #fff; stroke-width: 2; }

/* raia A — FB-0010/0011/0013/0019 */

/* FB-0013 — "os controles de tablatura e metrônomo devem estar integrados em uma
   coisa só". O bloco fica GRUDADO abaixo da barra: é o que se usa DURANTE o
   treino, e o leitor desconta a altura dele pra caber o papel na tela (FB-0010).
   Fundo OPACO de propósito: painel grudado com fundo translúcido deixa a
   partitura passar por trás e o texto vira ilegível ao rolar. */
.tr-comando {
  position: sticky;
  top: 68px;
  z-index: 30;
  padding: 14px 18px;
  background: var(--surface);
  box-shadow: var(--shadow-card-hover);
}
.tr-comando[data-estado="treinando"] {
  border-color: var(--brand);
  background:
    linear-gradient(var(--brand-tint), var(--brand-tint)),
    var(--surface);
}
.tr-comando-linha { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
/* A linha quebra, mas as TIRAS dentro dela não quebravam: com a fonte do usuário
   a 150%/200% num telefone, a tira do BPM (349 px numa linha de 305) e a do loop
   por compasso (495 px) passavam da tela — a página ganhava rolagem LATERAL e o
   campo "até" terminava em x=486 numa tela de 375 (WCAG 1.4.4 e 1.4.10).
   Quebrar linha aqui não esconde nada: é o mesmo comportamento do bloco. */
.tr-comando .tr-sessao-bpm,
.tr-comando .tr-tab-loop,
.tr-comando .btn-group { flex-wrap: wrap; }
.tr-comando .tr-tab-loop input,
.tr-comando .tr-sessao-bpm-num { min-width: 0; }
/* Alvo de toque de 24 px (WCAG 2.5.8, AA): a caixa do Bootstrap nasce com 1em
   (15 px na fonte do app). O mesmo piso que a tela de login já adota — ver
   `.tr-auth-card .form-check-input` mais abaixo. */
.tr-comando .form-check-input,
#video-controles .form-check-input { width: 24px; height: 24px; margin-top: 0; }
.tr-comando-linha + .tr-comando-linha {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}
.tr-comando-play { min-width: 128px; }
.tr-comando-campo { display: flex; flex-direction: column; gap: 2px; margin: 0; }
.tr-comando-campo select { width: auto; }
.tr-comando-volume { min-width: 170px; }
.tr-comando-plano { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px; font-size: var(--fs-sm); }
/* FB-0028 — a meta de andamento dentro do bloco de comando. Mesma altura de
   linha do resumo do plano (elas são vizinhas e não podem parecer dois blocos),
   e a barra ganha largura de verdade porque aqui ela é o alvo do que se está
   tocando, não um fato de rodapé. */
.tr-comando-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 10px;
  font-size: var(--fs-sm);
}
.tr-comando-meta-valor { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-weight: 700; }

/* FB-0030 — a fita de progresso por compasso: uma casinha por compasso da peça,
   preenchida de baixo pra cima na fração do BPM alvo. Casinha vazia é "ainda
   não treinado", não "ruim". As casinhas encolhem para caber (peça de 120
   compassos numa linha de 340 px dá 2 px cada), com um piso pra não sumirem. */
.tr-comando-compassos {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font-size: var(--fs-sm);
}
/* Meta e fita são o MESMO assunto (onde estou × onde quero chegar), então
   dividem a linha em vez de empilhar. Não é só estética: empilhadas, as duas
   somavam ~28 px ao bloco de comando e empurravam o começo da tablatura pra
   FORA da dobra numa janela de 1280×720 — o gate mediu o topo do papel em
   y=721, um pixel abaixo do fim da tela. Numa tela estreita elas voltam a
   empilhar sozinhas (flex-wrap), que aí sobra altura. */
.tr-comando-progresso {
  display: flex;
  align-items: center;
  gap: 8px 24px;
  flex-wrap: wrap;
  margin-top: 10px;
}
.tr-comando-progresso > * { margin-top: 0; }
.tr-fita {
  display: flex;
  align-items: flex-end;
  gap: 1px;
  height: 22px;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 6px);
  background: var(--surface-3);
  max-width: 100%;
  overflow-x: auto;
}
.tr-fita-casa {
  display: flex;
  align-items: flex-end;
  flex: 1 1 3px;
  min-width: 3px;
  height: 100%;
  background: var(--surface);
  border-radius: 1px;
}
.tr-fita-preenche {
  display: block;
  width: 100%;
  min-height: 0;
  background: var(--brand);
  border-radius: inherit;
}
.tr-fita-preenche.atingida { background: var(--ok); }
.tr-comando-meta .tr-meta-barra { width: 160px; margin-right: 0; }
@media (max-width: 480px) {
  /* numa tela estreita a barra some antes do número: quem informa é o texto */
  .tr-comando-meta .tr-meta-barra { width: 100%; }
}
.tr-comando-sessao { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px; }

/* FB-0011 — zoom da tablatura */
.tr-tab-zoom { display: inline-flex; align-items: center; gap: 6px; }
.tr-tab-zoom .btn { min-width: 34px; font-weight: 700; line-height: 1; }
.tr-tab-zoom-valor { min-width: 4ch; text-align: center; font-variant-numeric: tabular-nums; }

/* FB-0011 — "está cortando o título": o cabeçalho da partitura é HTML, e HTML
   QUEBRA LINHA. O alphaTab desenhava centralizado numa linha só e o título saía
   cortado pelos dois lados. */
.tr-tab-cabecalho { margin-bottom: 8px; text-align: center; overflow-wrap: anywhere; }
.tr-tab-titulo { font-size: 1.25rem; font-weight: 800; line-height: 1.25; }
.tr-tab-subtitulo { font-size: var(--fs-sm); color: var(--muted); }
.tr-tab-artista { color: var(--muted); }
.tr-tab-album, .tr-tab-credito { font-size: var(--fs-sm); color: var(--faint); }

@media (max-width: 720px) {
  /* grudado numa tela pequena come a tela inteira: no celular o bloco rola junto */
  .tr-comando { position: static; }
  .tr-comando-linha { gap: 10px; }
  .tr-comando-play { min-width: 0; }
}


/* raia B — FB-0014/0015/0016/0018 */
/* ============================================================
   /estudar virou "o que fazer HOJE" (FB-0018), o card de baralho
   ficou clicável inteiro (FB-0014) e o braço passou a 25 colunas
   (FB-0016). Só tokens já existentes — nenhuma cor nova.
   ============================================================ */

/* Título de seção solto (fora de card): a tela passou a ter três blocos
   distintos e "Hoje" precisa se separar de "Peças pra revisitar". */
.tr-secao-titulo {
  font-size: var(--fs-h2);
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: 24px 0 10px;
}
.tr-secao-titulo:first-of-type { margin-top: 4px; }

/* ---------- FB-0014: o card inteiro é o link ----------
   O <a> continua sendo o alvo real (foco, leitor de tela, menu de contexto);
   o ::after só ESTICA a área de clique dele por cima do card. Fazer o card
   virar <a> exigiria tirar o botão de dentro — e aninhar <a> em <a> é inválido. */
.tr-estudo-baralho { position: relative; }
.tr-link-total::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  z-index: 1;
}
/* O foco do teclado cai no <a>, que é pequeno perto do card; o anel no card
   inteiro é o que diz "é ISTO que o Enter abre". */
.tr-estudo-baralho:focus-within {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}
/* FB-0020: o card da PEÇA (/pecas) também é o link inteiro. Os chips de tag
   dentro dele têm destino próprio (filtrar), então sobem por cima da área
   esticada — senão o clique no chip cairia no ::after e abriria a peça. */
.tr-peca-card { position: relative; }
.tr-peca-card .tr-tag-chip { position: relative; z-index: 2; }
.tr-peca-card:focus-within {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}
.tr-estudo-baralho:hover { cursor: pointer; }

/* ---------- FB-0018: peças pra revisitar ---------- */
.tr-revisita-lista { list-style: none; margin: 0; padding: 0; }
.tr-revisita-item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 14px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}
.tr-revisita-item:last-child { border-bottom: 0; }
.tr-revisita-nome {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 220px;
  min-width: 0;
  font-weight: 700;
}
/* O piso de 24px da WCAG 2.5.8 (AA): o título é filho de um `display:flex`, então
   não vale a isenção "inline" da norma — e ele media 23,25px (line-height 1,55
   sobre 15px). `min-height` em vez de mexer no line-height: o texto fica onde
   está, só o ALVO cresce. Gate de usabilidade 0.14.0, frente B. */
.tr-revisita-nome a {
  color: var(--text);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  /* título sem espaço (200 chars de "A", teste adversarial) não quebrava e a PÁGINA rolava
     de lado a 375px — só apareceu com o banco cheio da suíte E2E inteira (2026-09-09) */
  min-width: 0;
  overflow-wrap: anywhere;
}
.tr-revisita-nome a:hover { color: var(--brand-strong); text-decoration: underline; }
.tr-revisita-dias { font-size: var(--fs-sm); color: var(--muted); white-space: nowrap; }
/* Vencida: o pill já diz, a cor do prazo é reforço — nunca a única pista. */
.tr-revisita-item.vencida .tr-revisita-dias { color: var(--danger); font-weight: 700; }
.tr-revisita-form {
  display: flex;
  /* O rótulo "revisar a cada" é `nowrap` e o select tem largura mínima: sem
     quebra de linha a linha não tem para onde ceder, e com o texto a 150% em
     375px o "Salvar" saía da janela (389px numa tela de 375; 452px a 200%),
     levando a página inteira a rolar de lado. Com `wrap` o rótulo fica numa
     linha e select+botão na seguinte. Gate de usabilidade 0.14.0, frente B. */
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-left: auto;
}
.tr-revisita-rotulo {
  font-size: var(--fs-xs);
  color: var(--muted);
  margin: 0;
  white-space: nowrap;
}
.tr-revisita-form .form-select { width: auto; min-width: 104px; }
/* Em tela estreita o controle vai pra linha de baixo inteira, em vez de
   espremer o título até quebrar letra a letra. */
@media (max-width: 560px) {
  .tr-revisita-form { margin-left: 0; flex: 1 1 100%; }
  /* O select cresce até um teto em vez de empurrar o "salvar" pra quina — no
     celular a quina inferior direita é do botão flutuante de feedback (fixo), e
     medido em 375px ele cobria ~37% do "salvar" de uma das peças enquanto se
     rolava. Com o teto, a linha termina antes da faixa do botão.
     O teto é em `rem`, não em px: a 200% (WCAG 1.4.4) os 140px absolutos
     cortavam "sem prazo" — que precisa de 159px — e o controle deixava de dizer
     o prazo que está valendo. Em rem o teto acompanha o texto e nunca corta;
     quem impede o "salvar" de ir pra quina agora é o `flex-wrap` do formulário.
     Gate de usabilidade 0.14.0, frente B. */
  .tr-revisita-form .form-select { flex: 0 1 auto; max-width: 9rem; }
}

/* Baralho em dia: fora do caminho, não fora do app. */
.tr-emdia {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 24px;
}
.tr-emdia-rotulo {
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--muted);
}
.tr-emdia .tr-chip { text-decoration: none; }

/* ---------- FB-0016: o braço completo (25 colunas) ---------- */
/* Card de braço usa a largura toda da coluna de conteúdo; com 720/820px a
   célula cairia abaixo do alvo de toque e a grade rolaria no desktop. */
.tr-estudo-card.tr-estudo-largo { max-width: 100%; }

/* O SVG do verso tem `max-width: 760px` (o tamanho certo pra uma janela de 4
   casas na lista de cards). Com o braço INTEIRO ali dentro, 760px espremia 24
   trastes: as bolinhas viravam pontos de 6px e o "R" da tônica ficava
   ilegível — e, pior, a resposta saía com um espaçamento de casas diferente do
   braço interativo logo acima, que é justamente o que se quer comparar.
   Medido na captura de 1280 (claro e escuro). */
.tr-estudo-largo .tr-braco-svg { max-width: 100%; min-width: 880px; }
/* ...e não pode ENCOLHER até sumir. O SVG tem `width: 100%` com aspecto travado:
   em 375px o braço inteiro cabia em 301px, e aí a bolinha virava um ponto de 4px
   e o "R" da tônica desaparecia — a resposta do card ficava ilegível (medido na
   captura de 375). Com o mínimo, quem rola é o `.tr-braco-wrap` (que já é
   `overflow-x: auto`), igual à grade da frente. Os rótulos DENTRO do SVG estão em
   unidades do viewBox, então crescem junto: o tamanho de 4 casas não serve pra 25. */
.tr-estudo-largo .tr-braco-rotulo { font-size: 0.875rem; }
.tr-estudo-largo .tr-braco-numcasa { font-size: 1rem; }

/* A FRENTE (`.tr-bb-quiz`) já reserva a faixa do botão flutuante de feedback em
   tela estreita. A REVELAÇÃO não reservava — e as duas grades ficavam com
   larguras diferentes: a frente mostrava até a casa 7, o verso até a 9, e a
   comparação "onde eu marquei × onde era" (que é o valor da revelação) deixava
   de bater coluna a coluna. Medido na captura de 375px. Mesma faixa, mesmo
   recorte, grades alinhadas. */
/* (remendo do botão flutuante de feedback removido: o widget não tem mais botão flutuante — FEEDBACK_SEM_BOTAO) */

/* (a regra `.tr-bb-grade.completo` que morava aqui saiu na revisão da FB-0046:
   `bbMontarGrade` só põe `completo` quando a janela começa na casa 0, e aí a
   grade também é `tem-pestana` — então `.tem-pestana.completo` (0,3,0) vencia
   SEMPRE. Colunas do braço inteiro: procure lá embaixo, em "Pestana".) */

/* ============================================================
   Traste — acessibilidade (gate de usabilidade 2026-08-20)
   ============================================================ */

/* Botão de marca: âmbar-escuro fixo nos DOIS temas (branco em cima = AA 4.66+) */
.btn-brand { background: #b45309; border-color: #b45309; color: #fff; }
.btn-brand:hover { background: #92400e; border-color: #92400e; color: #fff; }

/* Texto de marca sobre tint usa o tom forte (AA) */
.tr-nav-link.active, .tr-pill.brand, .tr-chip.active { color: var(--brand-strong); }

/* Tag: âmbar-escuro + branco no claro; âmbar-claro + texto escuro no escuro */
[data-theme="dark"] .tr-tag { background: var(--brand); color: #1f2937; }

/* Pills de estado com piso AA no tema claro */
.tr-pill.pill-danger { color: #b91c1c; }
[data-theme="dark"] .tr-pill.pill-danger { color: #f87171; }
.tr-pill.pill-ok { color: #15803d; }
[data-theme="dark"] .tr-pill.pill-ok { color: #4ade80; }
/* .warn e .ok existiam no CSS sem NENHUM uso — a primeira tela a usá-las (o selo
   "nunca tocada" da biblioteca, v0.6.0) reprovou no gate com 2.74. Ficam com o
   piso desde já, pra próxima feature não repetir a armadilha. */
.tr-pill.warn { color: #854d0e; }              /* 5.90 sobre o warn-tint composto */
[data-theme="dark"] .tr-pill.warn { color: var(--warn); }
.tr-pill.ok { color: #166534; }                /* 6.24 sobre o ok-tint composto */
[data-theme="dark"] .tr-pill.ok { color: var(--ok); }

/* Botão outline com contraste nos dois temas */
.btn-outline-secondary { color: #495057; border-color: #868e96; }
.btn-outline-secondary:hover { color: #fff; }
[data-theme="dark"] .btn-outline-secondary { color: #cbd5e1; border-color: #64748b; }
[data-theme="dark"] .btn-outline-secondary:hover { color: #0f172a; background: #cbd5e1; }

/* Título/célula gigante sem espaço quebra em vez de estourar o layout */
.tr-card-title, .tr-card-title a, .tr-habit-name, .tr-page-title, .tr-page-sub,
td, .tr-estudo-pergunta, .tr-estudo-resposta, .tr-muted, h1 {
  overflow-wrap: anywhere;
}
/* …e o CHIP é o mesmo caso: o nome da tag vem do usuário e pode ter os 40
   caracteres que o editor anuncia. Sem teto de largura, uma tag de 40 letras
   levava o chip a 508px numa janela de 375 com o texto a 150% (WCAG 1.4.4) e a
   página passava a rolar de lado. Gate de usabilidade 0.14.0, frente B. */
.tr-chip, .tr-chip-tag, .tr-tag-chip {
  max-width: 100%;
  overflow-wrap: anywhere;
}

/* Select dentro de cabeçalho de card nunca estoura o contêiner (mobile) */
.tr-card-head { flex-wrap: wrap; }
.tr-card-head .form-select { max-width: 100%; min-width: 0; }


/* Tag de peça: chip neutro + bolinha na cor da tag (contraste sempre AA) */
.tr-tag-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-xs); font-weight: 600;
  padding: 2px 10px; margin: 0 4px 4px 0;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text-2);
  text-decoration: none;
}
.tr-tag-chip:hover { border-color: var(--faint); color: var(--text); }
.tr-tag-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; flex: none; }
.tr-chip-tag { margin-right: 4px; }


/* ============================================================
   Meta de andamento (BPM alvo × atingido) — v0.4.0
   ============================================================ */
.tr-meta-linha { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.tr-meta-barra {
  display: inline-block;
  vertical-align: middle;
  width: 84px;
  height: 8px;
  margin-right: 8px;
  border-radius: var(--radius-pill);
  background: var(--surface-3);
  border: 1px solid var(--border);
  overflow: hidden;
}
.tr-meta-barra-larga { width: 100%; max-width: 340px; height: 12px; margin-right: 0; }
.tr-meta-preenche {
  display: block;
  height: 100%;
  background: var(--brand);
  border-radius: inherit;
}
.tr-meta-preenche.atingida { background: var(--ok); }
.tr-meta-valor { font-size: var(--fs-sm); font-weight: 700; }

/* Card que ocupa a linha inteira dentro de um tr-grid (tabela larga não pode
   ficar espremida em meia coluna com a outra metade vazia) */
.tr-span-total { grid-column: 1 / -1; }

/* Destaque do "onde focar" na tela de progresso */
.tr-foco { border-color: var(--brand); background: var(--brand-tint); }

/* ============================================================
   Sessão de estudo em tela grande — o card ancora no centro
   vertical em vez de ficar perdido no topo (⚠️ do gate 2026-08-20).
   ============================================================ */
@media (min-width: 992px) and (min-height: 760px) {
  .tr-estudo-card {
    max-width: 820px;
    min-height: min(56vh, 540px);
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 30px 32px;
  }
  .tr-estudo-pergunta { font-size: 1.5rem; }
  .tr-estudo-resposta { font-size: 1.75rem; }
}


/* ===================== metronomo (v0.5.0) ===================== */
/* ============================================================
   Traste — /metronomo (raia A, v0.5.0)
   Volume alto, subdivisão, sugestão de BPM, plano (degraus/rampa) e
   temporizador simples. Usa só os tokens tr-* já definidos em custom.css
   (--brand, --ok, --warn, --danger, --surface, --border, --muted...) —
   nenhum valor novo de cor é introduzido aqui, só composição.
   ============================================================ */

/* ---------- volume ---------- */
.tr-met-volume-wrap { max-width: 100%; }
.tr-met-volume-linha {
  display: flex;
  align-items: center;
  gap: 10px;
}
.tr-met-volume-linha .form-range { flex: 1 1 auto; min-width: 0; }
.tr-met-volume-valor {
  flex: 0 0 auto;
  min-width: 3.4em;
  text-align: right;
  font-weight: 700;
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
}
.tr-met-aviso-volume {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 8px 0 0;
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  background: var(--warn-tint);
  color: var(--warn);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1.4;
}
[data-theme="dark"] .tr-met-aviso-volume { color: #fcd34d; }

/* ---------- sugestão de BPM ---------- */
.tr-met-sugestao-wrap { max-width: 100%; }
.tr-met-sugestao-linha {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.tr-met-sugestao-linha select { flex: 1 1 160px; min-width: 0; }
.tr-met-sugestao-linha button { flex: 0 0 auto; }

/* ---------- plano: degraus ---------- */
.tr-met-degraus-lista {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.tr-met-degrau-linha {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.tr-met-degrau-linha input[type="number"] {
  width: 5.5rem;
  min-width: 4.5rem;
  flex: 0 1 auto;
}
.tr-met-degrau-acoes {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-left: auto;
}
.tr-met-degrau-acoes .tr-icon-btn { width: 30px; height: 30px; font-size: 0.9375rem; }
.tr-met-degrau-acoes .tr-icon-btn:disabled { opacity: 0.35; cursor: not-allowed; }

/* ---------- progresso do plano / fim de sessão ---------- */
.tr-met-etapa {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-2);
}
.tr-met-fim {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  background: var(--ok-tint);
  color: var(--ok);
  font-weight: 700;
  font-size: var(--fs-sm);
}

/* ---------- temporizador simples ---------- */
.tr-met-timer-linha {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.tr-met-timer-restante {
  font-size: 1.25rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--brand-strong);
  min-width: 3.4em;
}

/* ---------- responsivo: nada estoura em 375px, botões continuam clicáveis ---------- */
@media (max-width: 480px) {
  .tr-met-controles #met-compasso,
  .tr-met-controles #met-subdivisao {
    max-width: none !important;
    flex: 1 1 130px;
  }
  .tr-met-degrau-linha { justify-content: space-between; }
  .tr-met-degrau-acoes { margin-left: 0; }
}

/* ---------- alvo (aumentar fonte a 200%): nada em px fixo acima, tudo em rem/em
   herdado dos tokens tr-*; garante quebra de texto nos rótulos de progresso ---------- */
.tr-met-etapa, .tr-met-sugestao-linha, #met-sugestao-info {
  overflow-wrap: anywhere;
}


/* ===================== braco (v0.5.0) ===================== */
/* ============================================================
   Raia B — card tipo braco_branco (braço em branco).
   CSS isolado desta raia (não mexe em custom.css — o cérebro
   decide depois onde integrar). Reusa os tokens já definidos em
   custom.css (--brand, --ok, --danger, --surface*, --border*,
   --muted, --faint) — claro/escuro cobertos por eles, não repito
   nada aqui.
   Componente: grade HTML de <button> (não SVG) — dá teclado de
   graça (Tab + Enter/Espaço nativos), sem overlay de coordenadas.
   ============================================================ */

.tr-bb-wrap {
  overflow-x: auto;
}

.tr-bb-grade {
  display: grid;
  /* 1ª coluna = nome da corda; o resto são as casas */
  grid-template-columns: 22px repeat(var(--tr-bb-cols, 4), minmax(46px, 1fr));
  /* FB-0044/45 ("a mizona está no lugar errado"): as 6 linhas das cordas são
     IGUAIS e a corda mora no CENTRO da sua linha (ver `.tr-bb-cel::before`
     abaixo). Antes as cordas 1–5 eram o topo da linha e a 6ª era a base de uma
     linha encolhida: o passo entre a A e a E saía o dobro dos outros e o
     rótulo "E" ficava 26px acima do traço que ele nomeia. Com a corda no meio,
     o passo é a própria altura da linha (40px) e sobra meia linha de tábua de
     cada lado — a madeira que todo braço tem além da 1ª e da 6ª corda.
     40px também mantém o "sem espaço grande atrás" do FB-0024: da mizona à
     régua de números são 20px (a régua do gate aceita até 28). */
  grid-template-rows: repeat(6, 40px) 20px;
  min-width: max-content;
  padding: 10px 6px 4px;
}

/* Tábua do braço (FB-0024) — fundo atrás das 6 linhas de corda, da 1ª à 6ª
   (linhas 1–6 da grade); a linha 7 (números/marcações) fica de fora, colada
   embaixo. Mistura discreta de âmbar com a superfície do tema — clareia ou
   escurece sozinha com `--surface-2`/`--brand`, sem cor nova fixa. */
.tr-bb-tabua {
  background: color-mix(in srgb, var(--surface-2) 88%, var(--brand) 10%);
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  pointer-events: none;
}

/* Bolinhas de posição DENTRO da tábua (3, 5, 7, 9 · par na 12 e 24) — centro
   vertical do span (linhas 1–6) cai exatamente entre a 3ª e a 4ª corda, o
   centro do braço de verdade. Modificador `.par` (não `.duplo`): a régua de
   auditoria da raia 3 conta qualquer className que contenha "duplo" pra achar
   os marcadores da linha 7 (`.tr-bb-inlay.duplo`) — usar a mesma palavra aqui
   dobrava a conta (10→4 no `test_a_grade_cega_desenha_MARCADOR_de_posicao`). */
.tr-bb-tabua-marca {
  position: relative;
  pointer-events: none;
}
.tr-bb-tabua-marca::before {
  content: '';
  position: absolute; left: 50%; top: 50%;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--muted); opacity: 0.55;
  transform: translate(-50%, -50%);
}
.tr-bb-tabua-marca.par::before { transform: translate(-50%, calc(-50% - 12px)); }
.tr-bb-tabua-marca.par::after {
  content: '';
  position: absolute; left: 50%; top: 50%;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--muted); opacity: 0.55;
  transform: translate(-50%, calc(-50% + 12px));
}

/* Nome da corda (E A D G B e) — sem ele o braço vazio não tem âncora.
   Sem `transform`: a corda agora é o CENTRO da linha, e o rótulo (que ocupa a
   linha inteira, centrado) já cai exatamente nessa altura. O deslocamento de
   -50% existia porque a corda era o TOPO da célula — e era ele que punha o
   "E" fora do lugar, já que a 6ª corda não seguia essa regra (FB-0044/45). */
.tr-bb-corda-rotulo {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.6875rem;
  font-weight: 700;
  color: var(--faint);
}

/* Pestana (FB-0046): "a casa Zero deve estar atrás dessa linha mais forte".
   A borda grossa é o começo da 1ª CASA; a casa 0 (corda solta) fica ATRÁS
   dela, fora da tábua, como no braço de verdade — e como o SVG (`trBraco`)
   sempre desenhou (`xDaCasa(0) = margem - 16`). Antes a linha grossa era a
   borda ESQUERDA da própria casa 0, que então ocupava o lugar da 1ª casa. */
.tr-bb-grade.tem-pestana .tr-bb-cel[data-casa="1"] { border-left: 4px solid var(--text); }
/* A casa 0 não tem traste à esquerda: ali acaba o braço, não começa uma casa. */
.tr-bb-grade.tem-pestana .tr-bb-cel[data-casa="0"] { border-left: 0; }

/* ...e ela é mais ESTREITA que uma casa (é uma corda solta, não um espaço de
   dedo). O piso é o diâmetro da bolinha, pra a nota da corda solta caber
   inteira atrás da pestana sem montar em cima dela. A contagem de colunas vem
   separada do `--tr-bb-cols` porque `repeat()` não aceita conta: o
   `bbMontarGrade` publica `--tr-bb-cols-casas` (as casas SEM a 0). */
.tr-bb-grade.tem-pestana {
  grid-template-columns:
    22px minmax(26px, 0.62fr) repeat(var(--tr-bb-cols-casas, 4), minmax(46px, 1fr));
}
/* Braço INTEIRO (0–24): a única regra de colunas do `completo` — ele nunca
   aparece sem `tem-pestana` (a janela cheia começa na casa 0). O piso de 26px
   é o diâmetro da bolinha, e o `min-width: max-content` da grade faz o
   `.tr-bb-wrap` ROLAR no celular em vez de espremer as casas. */
.tr-bb-grade.tem-pestana.completo {
  grid-template-columns:
    22px minmax(26px, 0.62fr) repeat(var(--tr-bb-cols-casas, 24), minmax(26px, 1fr));
}

.tr-bb-cel {
  position: relative;
  appearance: none;
  border: 0;
  background: transparent;
  padding: 0;
  margin: 0;
  cursor: pointer;
  /* Traste (fret) como filete: mais contraste que o cinza genérico de antes
     (FB-0024 pediu "um pouquinho mais estilizado"), ainda dentro do token de
     tema — não é cor nova, só a variante mais forte que já existia.
     Só o filete VERTICAL: o `border-top` que existia aqui desenhava uma linha
     horizontal no topo de cada célula. Com a corda no topo as duas coincidiam;
     com a corda no CENTRO (FB-0044/45) sobrariam 6 linhas falsas entre as
     cordas — um braço não tem trastes deitados. */
  border-left: 1px solid var(--border-strong);
}
.tr-bb-cel:disabled { cursor: default; }

/* corda: linha no MEIO da célula — mais grossa nas graves (5ª/6ª).
   FB-0044/45: o meio (e não o topo) é o que faz as 6 cordas ficarem
   equidistantes, cada uma na altura do seu rótulo, sem a exceção da 6ª que
   punha "a mizona no lugar errado". */
.tr-bb-cel::before {
  content: '';
  position: absolute; left: 0; right: 0; top: 50%; height: 2px;
  transform: translateY(-50%);
  background: var(--faint); opacity: 0.55; pointer-events: none;
}
.tr-bb-cel[data-corda="6"]::before,
.tr-bb-cel[data-corda="5"]::before { height: 3px; }

.tr-bb-cel::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;                   /* a corda passa no MEIO da célula: a bolinha senta nela */
  width: 26px;
  height: 26px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  transition: background-color .1s ease;
}

/* Marcadores de posição do braço (3, 5, 7, 9 · duplo no 12 e 24): as bolinhas
   de verdade agora são o `.tr-bb-tabua-marca` (dentro da tábua, abaixo) — o
   `box-shadow` que morava aqui era um risco quase invisível (spread negativo
   sobre uma barra de largura total, não um ponto), achado ao comparar com a
   captura do gate. As classes `tr-bb-marcada`/`-dupla` continuam nas células
   (o jogo e os testes as leem), só o desenho antigo saiu. */
.tr-bb-cel:not(:disabled):hover::after { background: var(--surface-3); }
.tr-bb-cel:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: -2px;
  z-index: 2;
}

/* marca neutra do usuário (ainda não conferida / editor) */
.tr-bb-cel.tr-bb-pick::after { background: var(--muted); opacity: 0.6; }

/* resultado do "Conferir" — cor NUNCA é a única pista: acerto tem ✓,
   erro tem ✕ + anel duplo, faltou é contorno tracejado (sem preenchimento) */
.tr-bb-cel.tr-bb-acerto::after { background: var(--ok); opacity: 1; }
.tr-bb-cel.tr-bb-erro::after {
  background: var(--danger);
  opacity: 1;
  box-shadow: 0 0 0 2px var(--danger) inset;
}
.tr-bb-cel.tr-bb-faltou::after {
  background: transparent;
  border: 2px dashed var(--danger);
}

/* revelação do verso — bolinha rotulada, tônica em destaque */
.tr-bb-cel.tr-bb-bola::after { background: var(--brand); opacity: 0.95; }
.tr-bb-cel.tr-bb-bola.tonica::after { background: #dc2626; }

/* O rótulo (nota/intervalo, ✓/✕) mora DENTRO da bolinha — que fica em cima da
   corda, não no centro da célula. Centralizar na célula deixava texto branco
   sobre fundo branco: sumia sem ninguém notar. */
.tr-bb-glifo {
  position: absolute;
  left: 50%; top: 50%;
  width: 26px; height: 26px;
  transform: translate(-50%, -50%);
  display: flex; align-items: center; justify-content: center;
  font-size: 0.6875rem; font-weight: 800; color: #fff;
  pointer-events: none; z-index: 1;
}

.tr-bb-numcasa {
  display: flex; align-items: center; justify-content: center;
  font-size: 0.6875rem; color: var(--faint);
}

.tr-bb-placar { font-weight: 700; }

@media (max-width: 420px) {
  /* Mesmas 6 linhas iguais do desktop (FB-0044/45), só mais baixas: 34px ainda
     passa do piso de toque de 26px e mantém a altura total que a grade já
     tinha no celular. */
  .tr-bb-grade { grid-template-rows: repeat(6, 34px) 18px; }
  .tr-bb-cel::after { width: 22px; height: 22px; }
  .tr-bb-glifo { width: 22px; height: 22px; font-size: 0.625rem; }
}


/* ===================== tags (v0.5.0) ===================== */
/* ============================================================
   Editor de chips de tag (peça + baralho) — v0.5.0
   Reusa os tokens do design system (custom.css) e as classes
   .tr-tag-chip / .tr-tag-dot já existentes; só o que é NOVO do
   editor (caixa, input livre, botão remover, dropdown de
   sugestões) mora aqui. Sem bloco dark separado: as variáveis
   --surface/--text/--border-strong etc. já trocam sozinhas.
   ============================================================ */

.tr-chips-tags { margin-bottom: 1rem; max-width: 100%; }

/* Caixa que parece um .form-control, mas guarda chips + input livre */
.tr-chips-box {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  width: 100%;
  min-height: 2.5rem;
  padding: 6px 8px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: text;
}
.tr-chips-tags.tr-chips-cheio .tr-chips-box { border-color: var(--border-strong); }
.tr-chips-box:focus-within {
  border-color: var(--brand);
  box-shadow: 0 0 0 0.2rem var(--brand-tint);
}

/* Chip editável: estende .tr-tag-chip (mesma pílula neutra + bolinha da
   tag de leitura) só acrescentando o "x" de remover. */
.tr-chip-editavel {
  margin: 0;
  cursor: default;
  max-width: 100%;
}
.tr-chip-tag-texto { overflow-wrap: anywhere; }
.tr-chip-remover {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.1rem;
  height: 1.1rem;
  margin: 0 -2px 0 2px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--faint);
  font-size: 1rem;
  line-height: 1;
  flex: none;
}
.tr-chip-remover:hover { background: var(--danger-tint); color: var(--danger); }
.tr-chip-remover:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 1px;
}

/* Input livre — some dentro da caixa, sem borda própria */
.tr-chips-input {
  flex: 1 1 8ch;
  min-width: 8ch;
  max-width: 100%;
  border: none;
  outline: none;
  background: transparent;
  color: var(--text);
  font-size: var(--fs-body);
  font-family: var(--font);
  padding: 2px 4px;
}
.tr-chips-input::placeholder { color: var(--faint); }
.tr-chips-input:disabled { cursor: not-allowed; }

/* Dropdown de sugestões — ancorado na caixa (posicionada acima) */
.tr-chips-sugestoes {
  position: absolute;
  z-index: 20;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  margin: 0;
  padding: 4px;
  list-style: none;
  max-height: 12rem;
  overflow-y: auto;
  overflow-x: hidden;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  box-shadow: var(--shadow-pop);
}
/* Dropdown virado pra CIMA: usado quando abaixo do campo só há o rodapé do
   modal ("Cancelar"/"Criar"). Ver `posicionarSugestoes` em static/js/tags.js —
   quem decide é a medida, não o CSS; aqui só mora o resultado. */
.tr-chips-sugestoes.acima { top: auto; bottom: calc(100% + 4px); }
.tr-chips-sugestao {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  color: var(--text-2);
  overflow-wrap: anywhere;
}
.tr-chips-sugestao.active,
.tr-chips-sugestao:hover { background: var(--brand-tint); color: var(--brand-strong); }

/* Chips de FILTRO por tag (topo da lista de baralhos — mesmo padrão das
   peças) usam .tr-chip/.tr-chip-tag já existentes; só o alvo clicável some
   quando não há tags do usuário ainda (estado tratado no template). */
.tr-filtro-tags-baralho { margin-bottom: 0.75rem; }

@media (max-width: 420px) {
  .tr-chips-box { min-height: 2.75rem; }
  .tr-chips-sugestoes { max-height: 9rem; }
}


/* ===================== treino (v0.5.0) ===================== */
/* ============================================================
   Sessão de treino + plano (raia D, v0.5.0)
   Integrado no custom.css pelo cérebro da rodada.
   ============================================================ */
.tr-sessao-relogio {
  font-size: 1.5rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  color: var(--brand-strong);
}

.tr-sessao-bpm { display: flex; align-items: center; gap: 10px; }
.tr-sessao-bpm .btn { min-width: 44px; font-size: 1.25rem; line-height: 1; padding: 6px 12px; }
/* FB-0013: virou campo EDITÁVEL — um BPM só, digitável, pros dois (metrônomo e
   tablatura). Continua sendo o número grande da tela. */
.tr-sessao-bpm-num {
  width: 5rem;
  padding: 2px 6px;
  font-size: 1.75rem;
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.2;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.tr-sessao-volume { width: 160px; max-width: 45vw; }
.tr-volume-alto { color: var(--danger); font-weight: 700; }

.tr-sessao-etapa {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}

/* Linha de degrau do plano (BPM × compassos) */
.tr-degrau-linha {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.tr-degrau-linha .form-control { width: 92px; }

@media (max-width: 560px) {
  .tr-sessao-bpm-num { font-size: 1.5rem; width: 4.25rem; }
  .tr-sessao-volume { width: 120px; }
}


/* ============================================================
   Layout consolidado (v0.5.1)

   O app cresceu por partes e cada pedaço virou um card de largura
   total — a tela ficou uma PILHA de caixas iguais, todas com o mesmo
   peso e muito ar. Estas classes existem pra juntar: uma coisa
   principal por tela, o resto agrupado ao lado (ou em abas), e fatos
   curtos numa faixa em vez de um card cada.
   ============================================================ */

/* ---------- grade: conteúdo principal + coluna de apoio ---------- */
.tr-grid-app {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(300px, 1fr);
  gap: var(--gap);
  align-items: start;
}
.tr-grid-app > * { min-width: 0; }
@media (max-width: 980px) {
  .tr-grid-app { grid-template-columns: 1fr; }
}

/* Coluna que gruda ao rolar (o apoio acompanha o conteúdo longo) */
@media (min-width: 981px) {
  .tr-coluna-fixa { position: sticky; top: 76px; }
}

/* ---------- faixa de fatos curtos (substitui cards de 1 linha) ---------- */
.tr-faixa {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 24px;
  padding: 12px 18px;
  margin-bottom: var(--gap);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
}
.tr-faixa-item {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.tr-faixa-rotulo {
  font-size: var(--fs-micro);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  white-space: nowrap;
}
.tr-faixa-valor {
  font-size: 0.9375rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.tr-faixa-espaco { flex: 1 1 auto; }
.tr-faixa .tr-meta-barra { margin-right: 0; }

/* ---------- painel com abas (junta blocos que competem) ---------- */
.tr-abas {
  display: flex;
  gap: 2px;
  border-bottom: 1px solid var(--border);
  margin: -4px -4px 14px;
  overflow-x: auto;
  scrollbar-width: none;
}
.tr-abas::-webkit-scrollbar { display: none; }
.tr-aba {
  appearance: none;
  border: 0;
  background: transparent;
  padding: 9px 14px;
  font-family: inherit;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--muted);
  border-bottom: 2px solid transparent;
  cursor: pointer;
  white-space: nowrap;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}
.tr-aba:hover { color: var(--text); background: var(--surface-2); }
.tr-aba[aria-selected="true"] {
  color: var(--brand-strong);
  border-bottom-color: var(--brand);
}
.tr-aba:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.tr-aba-painel[hidden] { display: none; }

/* ---------- densidade ---------- */
.tr-card-compacto { padding: 14px 16px; }
.tr-card-compacto .tr-card-head { margin-bottom: 10px; }
.tr-empty-compacto { padding: 22px 16px; gap: 8px; }

/* Cabeçalho de página com ação principal + menu (em vez de 3 botões iguais) */
.tr-page-acoes { display: flex; align-items: center; gap: 8px; }
.tr-menu-btn { padding: 8px 10px; line-height: 1; }


/* ---------- metrônomo consolidado (v0.5.1) ---------- */
/* Os ajustes (compasso · clique · volume) numa linha só, embaixo do mostrador —
   antes eram três blocos empilhados que empurravam o botão Iniciar pra fora da
   primeira tela. */
.tr-met-card { padding: 22px 20px; gap: 12px; }
.tr-met-ajustes {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  flex-wrap: wrap;
  width: 100%;
  padding-top: 4px;
  border-top: 1px solid var(--border);
  margin-top: 4px;
}
.tr-met-ajuste {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.tr-met-ajuste-larga { flex: 1 1 190px; }
.tr-met-ajuste .form-range { width: 100%; }
.tr-met-ajuste .tr-faixa-rotulo { display: flex; align-items: center; gap: 6px; }
.tr-met-ajuste .tr-met-volume-valor { min-width: 0; color: var(--text); }
.tr-met-card .tr-met-aviso-volume { align-self: flex-start; margin: 0; }
.tr-met-card .tr-met-etapa,
.tr-met-card #met-fim-sessao { width: 100%; }
.tr-met-sugestao-wrap {
  border-top: 1px solid var(--border);
  margin-top: 14px;
  padding-top: 12px;
}
@media (max-width: 480px) {
  .tr-met-ajustes { gap: 10px; }
  .tr-met-ajuste { flex: 1 1 130px; }
}


/* ---------- fim da caixa-dentro-de-caixa (v0.5.1) ----------
   `.tr-stat` e `.tr-habit-row` nasceram como blocos soltos, com fundo, borda e
   sombra próprios. Quando alguém os pôs DENTRO de um `.tr-card` (dashboard,
   progresso, fila de estudo), virou moldura dupla: dois retângulos brancos, um
   colado no outro. Dentro de um card, eles perdem a casca e ficam só conteúdo. */
.tr-card > .tr-stat,
.tr-card .tr-stat {
  background: transparent;
  border: 0;
  box-shadow: none;
  padding: 2px 0;
}
.tr-card .tr-habit-row {
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}
.tr-card .tr-habit-row:last-child { border-bottom: 0; padding-bottom: 0; }
.tr-card .tr-habit-row:first-of-type { padding-top: 0; }
.tr-card .tr-habit-row:hover { background: var(--surface-2); border-color: var(--border); }

/* O card de número fica com a mesma altura dos irmãos, e o rótulo não empurra
   o número pra cima quando quebra em duas linhas. */
.tr-card .tr-stat { justify-content: flex-start; min-height: 62px; }
.tr-stat-label { text-wrap: balance; }

/* Colunas param na altura do próprio conteúdo (sem esticar o card curto até
   a altura do mais alto, que deixava um vazio enorme embaixo). */
.tr-grid-topo { align-items: start; }

/* FB-0013: o cartão .tr-sessao (painel separado, que aparecia e sumia) virou o
   bloco único .tr-comando — o "gruda abaixo da barra" mudou de casa junto. */

/* Duas colunas que terminam juntas: o mostrador do metrônomo é curto e o painel
   de apoio é alto — esticado e com o conteúdo centrado, some o degrau feio no
   fim da coluna esquerda. */
.tr-grid-app-igual { align-items: stretch; }
.tr-grid-app-igual > .tr-met-card { justify-content: center; }


/* === v0.6.0 braco-caged === */
/* Marcação da TÔNICA no braço em branco (jogo) e o box CAGED que a usa.
   Reusa as bolinhas .tr-bb-cel já existentes — aqui só entram os anéis que
   distinguem "esta casa é a tônica" de "esta casa é nota". Cor nunca é a
   única pista: quem carrega o significado é o glifo R dentro da bolinha. */

/* palpite ainda não conferido, marcado como tônica: mesma bolinha neutra,
   com anel pra destacar do palpite comum */
.tr-bb-cel.tr-bb-pick-tonica::after {
  background: var(--muted);
  opacity: 0.85;
  box-shadow: 0 0 0 2px var(--brand);
}

/* depois do Conferir — o fundo verde/vermelho vem das classes de acerto/erro */
.tr-bb-cel.tr-bb-tonica-ok::after { box-shadow: 0 0 0 2px var(--brand); }
.tr-bb-cel.tr-bb-tonica-erro::after {
  box-shadow: 0 0 0 2px var(--danger);
}
/* "R✕" (tônica no lugar errado) tem 2 caracteres — aperta a letra pra caber
   dentro da bolinha de 26px sem estourar (e de 22px no celular). */
.tr-bb-cel.tr-bb-tonica-erro .tr-bb-glifo {
  font-size: 0.625rem;
  letter-spacing: -0.06em;
}
.tr-bb-cel.tr-bb-tonica-faltou::after {
  box-shadow: 0 0 0 2px var(--warn);
}

/* tônica que passou batido: a bolinha "faltou" é vazada, então o R precisa de
   cor própria — texto branco em fundo transparente sumia. */
.tr-bb-cel.tr-bb-faltou .tr-bb-glifo { color: var(--danger); }

/* ---- tinta do rótulo DENTRO da bolinha (gate CHEIO v0.15.0) -------------
   O desenho do braço se apoia numa frase escrita duas vezes neste arquivo:
   "cor NUNCA é a única pista — quem carrega o significado é o GLIFO dentro da
   bolinha". Se o glifo não se lê, a frase é falsa.

   O glifo era branco fixo e mora em cima do PREENCHIMENTO da bolinha, não do
   fundo da página. Medido no gate: 8 dos 13 estados abaixo de 4,5:1 no tema
   claro e 10 no escuro — o pior, `tr-bb-acerto` no escuro, com 2,0:1.

   Nenhum preenchimento muda: os tons vêm do design (`fretz-ponte.css`) e não
   se reinterpretam. O que muda é a LETRA — e quem manda é o próprio design:
   "texto sobre âmbar é GRAFITE" (`--brand-fg`, do `--bs-btn-color` do
   handoff). `--ok` e `--danger` nascem no design como cor de TEXTO de badge
   (médios no claro, CLAROS no escuro), então a tinta troca junto com eles.
   `tr-bb-faltou` fica de fora: a bolinha dele é vazada (regra acima). */
.tr-bb-cel.tr-bb-pick .tr-bb-glifo,
.tr-bb-cel.tr-bb-acerto .tr-bb-glifo,
.tr-bb-cel.tr-bb-bola .tr-bb-glifo { color: var(--brand-fg, #1B1C23); }

/* preenchimentos ESCUROS nos dois temas (o vermelho forte da tônica) ou só no
   claro (o `--danger` médio): aí o branco é que passa — e é o que já estava
   lá. Branco puro, não o osso `#F8F7F3`: em cima do `#dc2626` da tônica o
   osso dá 4,3:1 e o branco 4,6:1, e o piso é 4,5. */
.tr-bb-cel.tr-bb-pick.tr-bb-pick-tonica .tr-bb-glifo,
.tr-bb-cel.tr-bb-bola.tonica .tr-bb-glifo,
.tr-bb-cel.tr-bb-erro .tr-bb-glifo { color: #fff; }

/* no escuro o `--danger` e o `--muted` do design são CLAROS — a tinta inverte */
[data-theme="dark"] .tr-bb-cel.tr-bb-pick.tr-bb-pick-tonica .tr-bb-glifo,
[data-theme="dark"] .tr-bb-cel.tr-bb-erro .tr-bb-glifo {
  color: var(--brand-fg, #1B1C23);
}

.tr-bb-dica {
  margin: 6px 0 0;
  font-size: 0.8125rem;
  color: var(--muted);
}

/* === v0.6.0 curva-dominio: altura própria ===
   O card da curva é de largura total. Sem altura própria, o Chart.js herda a
   razão do canvas e renderiza 726px — o dobro dos gráficos vizinhos (372px),
   uma tela inteira só pra ele. */
.tr-grafico-largo { height: 320px; }
@media (max-width: 575.98px) { .tr-grafico-largo { height: 240px; } }

/* ── Acessibilidade: fonte ampliada (WCAG 1.4.4) ─────────────────────────────
   Medido pela matriz de usabilidade a 200% de fonte em 375/414px: os controles
   abaixo não cabiam lado a lado e vazavam a viewport (scroll lateral de 55px na
   conta, 19px nos baralhos). As regras só agem quando o conteúdo NÃO cabe — no
   tamanho de fonte padrão o layout é idêntico ao do design. */
.tr-tema-grupo { flex-wrap: wrap; }
/* Só `flex`, sem mexer em `border-radius`: arredondar os cantos internos deixaria
   o grupo mais bonito ao quebrar, mas MUDA o desenho recebido no tamanho normal —
   medido em 0,072% dos pixels da tela. Quando o grupo quebra (fonte a 200%), os
   cantos do meio ficam retos; é estética de caso extremo, não defeito, e vale
   menos que a fidelidade ao design. */
.tr-tema-grupo > .btn { flex: 1 1 auto; }

/* ── Acessibilidade: área de toque dos links de título e de ação ─────────────
   WCAG 2.5.8 (AA) pede alvo de 24x24 CSS px. Medido pela matriz em 375px: os
   títulos-link de card (`Escalas no braço`, `Lick pentatônico em Am`) e os links
   de ação do cabeçalho (`todos os baralhos`, `gerenciar baralhos`) tinham 18–23px
   de altura — a altura da própria linha. A exceção "inline" da norma cobre link
   DENTRO de uma frase; título de card não é frase, então o alvo cresce de fato.
   3px em cima e embaixo cruzam o piso sem mexer no tamanho da letra nem no
   espaçamento entre cards (a caixa do link já tinha folga na linha). */
.tr-card-title a,
.tr-habit-name a,
a.tr-faint { padding-block: 3px; }

/* Mesma correção nas telas de entrada (login/cadastro/recuperar), que têm layout
   próprio (base_auth.html) e não passam pelas classes acima: o wordmark do topo
   (44x18) e os links do rodapé do cartão eram alvos abaixo de 24px. */
.tr-auth-brand,
.tr-auth-links a { padding-block: 3px; }

/* A caixa "Manter conectado" do login tinha 15x15 — o tamanho padrão do Bootstrap,
   abaixo do piso de 24px da WCAG 2.5.8. Aqui o alvo cresce de fato: aumentar o
   rótulo ao lado não resolveria, porque a norma mede o alvo, e num celular é a
   caixa que o dedo persegue. Só nas telas de entrada, onde ela existe. */
.tr-auth-card .form-check-input { width: 24px; height: 24px; margin-top: 0; }
.tr-auth-card .form-check { display: flex; align-items: center; gap: 8px; }
.tr-auth-card .form-check-label { margin: 0; }

/* ============================================================
   Metrônomo embutido no dashboard (chamado FB-0003, 2026-08-25)
   O card da tela cheia (.tr-met-card) é uma COLUNA centrada e alta; aqui a
   mesma peça vira uma FAIXA horizontal que quebra em duas linhas no celular.
   ============================================================ */
.tr-met-mini-linha {
  display: flex; align-items: center; gap: 20px; flex-wrap: wrap;
  justify-content: center;
}
.tr-met-mini-pulso { display: flex; align-items: center; gap: 12px; }
/* pulso menor que o da tela cheia (84px) — aqui ele divide a linha com os
   controles, e o tamanho cheio empurraria o play pra outra linha no notebook */
.tr-met-mini .tr-met-pulso { width: 52px; height: 52px; border-width: 2px; }
.tr-met-mini .tr-met-bpm { font-size: 1.5rem; }
.tr-met-mini .tr-met-controles { flex: 1 1 320px; justify-content: flex-end; }
.tr-met-mini-dica { margin: 10px 0 0; text-align: center; }
@media (max-width: 575.98px) {
  .tr-met-mini .tr-met-controles { justify-content: center; }
  .tr-met-mini-linha { gap: 12px; }
}

/* ============================================================
   Braço rotulado — paleta de nota/grau (chamado FB-0002, 2026-08-25)
   O card não cobra só ONDE fica a casa: cobra QUAL nota/grau ela é. O aluno
   escolhe o rótulo na paleta e carimba nas casas.
   ============================================================ */
.tr-bb-paleta {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin: 0 0 10px;
}
.tr-bb-chip {
  appearance: none;
  min-width: 44px;              /* alvo de toque: piso do gate de usabilidade */
  min-height: 44px;
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text);
  font-weight: 700;
  font-size: 0.875rem;
  cursor: pointer;
}
.tr-bb-chip:hover:not(:disabled) { border-color: var(--brand); }
/* Selecionado: cor NÃO é a única pista — o anel grosso e o negrito também
   mudam, e o `aria-checked` carrega o estado pra quem usa leitor de tela. */
.tr-bb-chip.ativo {
  background: #b45309; border-color: #b45309; color: #fff;
  box-shadow: 0 0 0 2px var(--brand);
}
.tr-bb-chip:disabled { opacity: 0.55; cursor: default; }

/* Resultado do rótulo. O fundo verde vem do .tr-bb-acerto (a POSIÇÃO estava
   certa); o que estes anéis dizem é sobre o RÓTULO — e o glifo dentro da
   bolinha é sempre o rótulo CERTO, então a correção se lê sem cor. */
.tr-bb-cel.tr-bb-rotulo-erro::after { box-shadow: 0 0 0 2px var(--danger); }
.tr-bb-cel.tr-bb-rotulo-faltou::after { box-shadow: 0 0 0 2px var(--warn); }
/* Rótulo de 2 caracteres (b3, b7, F#) não cabe no corpo da bolinha de 26px */
.tr-bb-cel .tr-bb-glifo { letter-spacing: -0.02em; }

/* Marcador de posição da grade CEGA (chamado FB-0002): sem número de casa, o
   pontinho é a ÚNICA referência de onde o shape cai — então ele é desenhado
   como elemento próprio, na linha onde o número ficava. A regra de `box-shadow`
   no corpo da grade (`.tr-bb-marcada`, acima) não serve aqui: o spread negativo
   apaga o ponto, e o braço cego saía como uma grade lisa, sem referência
   nenhuma (medido na captura do gate, 2026-08-25). */
.tr-bb-inlay {
  display: flex;
  align-items: center;
  justify-content: center;
}
.tr-bb-inlay::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--muted);
}
/* casa 12 e 24: dois pontos, como no braço de verdade */
.tr-bb-inlay.duplo::before {
  box-shadow: 9px 0 0 0 var(--muted);
  transform: translateX(-4.5px);
}

/* Coluna do dashboard que empilha dois cards (peças recentes + metrônomo).
   O `.tr-grid-2` põe UM filho por coluna; sem este contêiner, o metrônomo viraria
   uma 3ª coluna no desktop e apertaria as outras duas. */
.tr-col-pilha {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}
/* Empilhado numa coluna estreita, o metrônomo compacto perde a linha única:
   os controles vão pra baixo do pulso em vez de disputar a largura. */
.tr-col-pilha .tr-met-mini .tr-met-controles { flex: 1 1 260px; justify-content: center; }

/* O botão flutuante de feedback (`.cfb-fab`, canto inferior direito, fixo) ROUBA
   o clique das casas do braço que passam por baixo dele — medido em 375px: 2
   casas por vez, nos baralhos com paleta (a paleta empurra a grade uns 44px e
   joga a fileira de baixo bem na faixa do botão).

   A lib já resolve o caso dela — `body { padding-bottom }` faz o ÚLTIMO controle
   da página terminar acima do botão. Mas isso não cobre uma grade alta e
   interativa no MEIO da página: rolando a página, sempre há alguma casa embaixo
   dele.

   Aqui a grade interativa para antes da COLUNA do botão em tela estreita. Como o
   contêiner rola na horizontal, o conteúdo é clipado por ele: nenhuma casa chega
   a existir naquela faixa, em nenhuma posição de rolagem. Custa ~1,5 casa de
   largura visível no celular; em troca, nenhum clique morto. */
/* (remendo do botão flutuante de feedback removido: o widget não tem mais botão flutuante — FEEDBACK_SEM_BOTAO) */

/* raia D — FB-0012 gerador
   Tela do gerador de tablatura com IA: duas colunas (pedido | prévia) que viram
   uma só no celular, estado do pedido com cor semântica e o campo de alphaTex em
   fonte monoespaçada (é código, não prosa). Cores saem das variáveis do tema —
   nada cravado, pra o modo escuro acompanhar. */
.tr-gerador { grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); align-items: start; }
@media (max-width: 991.98px) { .tr-gerador { grid-template-columns: 1fr; } }

.tr-gerador-sub { font-size: var(--fs-h3, 1rem); font-weight: 700; color: var(--text); margin: 0 0 4px; }

.tr-gerador-status { min-height: 1.25rem; font-size: .9375rem; color: var(--muted); }
.tr-gerador-status.ok { color: var(--ok); }
.tr-gerador-status.aviso { color: var(--warn); }
.tr-gerador-status.erro { color: var(--danger); }

.tr-gerador-tex { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .8125rem; line-height: 1.5; white-space: pre; overflow-x: auto; }

.tr-gerador-exemplo { display: inline-block; margin: 0 4px 6px 0; text-align: left; max-width: 100%; white-space: normal; }
.tr-gerador-exemplo:disabled { opacity: .55; cursor: not-allowed; }

/* Spinner do botão "Gerando…": o botão fica travado e precisa DIZER que está
   trabalhando — sem isso o usuário clica de novo e paga duas chamadas. */
.tr-gerador-spin { display: inline-block; width: .85em; height: .85em; margin-right: .35em; vertical-align: -.1em; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: tr-gerador-girar .7s linear infinite; }
@keyframes tr-gerador-girar { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .tr-gerador-spin { animation-duration: 2s; } }

/* raia D — FB-0012 gerador: o erro do parser aparece TAMBÉM na coluna da prévia
   (é onde o olho está quando a tablatura não desenha). Fundo tinto pra separar
   do resto do card, texto em --danger (contraste do tema). */
.tr-gerador-erro { margin: 0 0 12px; padding: 10px 12px; border-radius: 10px; background: var(--danger-tint); color: var(--danger); font-size: .9375rem; }

/* raia D — FB-0012 gerador: NOME DE VARIÁVEL DE AMBIENTE VOLTA À CAIXA REAL.
   A marca do fretz põe `text-transform: lowercase` em todo `<code>`
   (fretz.css: "UI em caixa baixa") — decisão de design que vale pro resto da
   interface. Só que `ANTHROPIC_API_KEY` é o NOME de uma variável de ambiente, e
   nome de variável é case-sensitive: em minúsculas, a única instrução da tela
   "não configurado" manda o dono escrever `anthropic_api_key` no .env, que o
   `os.environ.get("ANTHROPIC_API_KEY")` nunca acha — a tela ensina o caminho
   errado e o gerador continua morto. Escopo mínimo: só o card do aviso, só o
   `<code>`; o resto da UI em caixa baixa fica como o design pediu. */
[data-testid="gerador-nao-configurado"] code { text-transform: none; }

/* raia D — FB-0012 gerador: OS AVISOS PRECISAM SER LEGÍVEIS (WCAG 1.4.3 AA).
   A linha de status e a caixa de erro são o único canal de resposta desta tela
   ("escrevendo…", "prévia pronta", "linha 4: …"). No tema CLARO, sobre o creme
   do card, os tokens da marca ficavam abaixo do piso de 4,5:1 para texto
   normal: verde #47A06A → 3,01:1, âmbar #d97706 → 2,97:1 e, dentro da caixa
   tinta, vermelho #C4442A → 3,88:1 (o fundo translúcido clareia o que está
   atrás e come contraste — por isso a cor da caixa é OUTRA, não a mesma do
   status).
   As substitutas mantêm MATIZ E SATURAÇÃO do token, só escurecem a
   luminosidade até passar (4,64 · 4,69 · 4,65) — o mínimo para obedecer a
   norma sem reinterpretar a paleta. O tema ESCURO já passava em todos, e por
   isso volta a usar os tokens. Medido pela régua com alpha composto
   (gate/reguas.py::CONTRASTE) e travado por
   tests/e2e/test_gerador_e2e.py::test_status_e_erro_do_gerador_passam_no_contraste_aa. */
.tr-gerador-status.ok { color: #377d53; }
.tr-gerador-status.aviso { color: #a75c05; }
.tr-gerador-erro { color: #af3d26; }
[data-theme="dark"] .tr-gerador-status.ok { color: var(--ok); }
[data-theme="dark"] .tr-gerador-status.aviso { color: var(--warn); }
[data-theme="dark"] .tr-gerador-erro { color: var(--danger); }

/* raia C — FB-0023 widget de feedback: A TECLA DE ATALHO PRECISA SER LEGÍVEL.
   Achado do gate CHEIO v0.15.0, medido pela régua de contraste com alpha
   composto (gate/reguas.py::CONTRASTE): o "Cole (Ctrl+V)" da área de print do
   `#cfbModal` saía com razão **1,00:1** nos DOIS temas — texto invisível,
   duas caixinhas vazias na tela.
   Causa: o Bootstrap desenha `kbd` INVERTIDO (fundo = --bs-body-color, texto =
   --bs-body-bg) e o `fretz.css` reescreve só a COR de todo `kbd` para
   `--bs-tertiary-color` — que é o próprio body-color com 45% de alpha. Texto e
   fundo viram a mesma tinta. A lib `concilio-feedback` não pinta `kbd` nenhum
   (só `font: inherit`), então quem apaga a tecla é a folha do app.
   Escopo mínimo — só dentro da janela do widget, só `kbd`: devolve a cor que o
   Bootstrap já pretendia, e o resto da UI em `--bs-tertiary-color` fica como o
   design pediu. Travado por
   tests/e2e/test_feedback_rascunho_e2e.py::test_a_tecla_do_atalho_e_legivel. */
#cfbModal kbd { color: var(--bs-body-bg); }
