/* ══════════════════════════════════════════════════════════════════════════
   IMP SHELL — Impressive shared responsive foundation
   Consumers: /projects, /projects/jobs, /invoicecc, /dtf, future tools.

   RULE (approved by Lucas, 2026-09-07):
     The container grows, the content does not.
     Extra width becomes new columns — never a wider input.

   Tiers:  mobile <640 · tablet 640-1023 · laptop 1024-1439 · desktop >=1440
   Load this BEFORE a page's own <style> so pages can still override.
   ══════════════════════════════════════════════════════════════════════════ */

@import url('/static/imp-foundation.css?v=2026-10-20b');   /* bump when that file changes */
/* The analytics language (KPI tiles, chart cards, legends, tips, breakdown
   bars) lives in its own layer — IMP-008, 21/09/2026. Drawn by imp-chart.js. */
@import url('/static/imp-analytics.css?v=2026-10-21b');   /* bump when that file changes */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  /* ── brand: the identity tokens from imp-foundation.css (I-008, 19/09/2026 —
     Lucas: "todas as páginas… inclusive do project… as cores da marca, com
     degradê da marca"). These names stay for the rules below. ── */
  --pink:    var(--imp-pink);
  --purple:  var(--imp-violet);
  --grad:    var(--imp-grad);
  --bg:      var(--imp-bg);
  --card:    var(--imp-surface);
  --surface: var(--imp-surface);
  --card2:   var(--imp-surface-2);
  --border:  var(--imp-line);
  --border2: var(--imp-line-2);
  --text:    var(--imp-text);
  --muted:   rgba(246,244,250,0.5);
  --subtle:  rgba(246,244,250,0.24);

  /* ── value semantics (already the site's language: see #pw-msg in projects) ── */
  --pos: var(--imp-live);
  --neg: #ff6b9d;
  /* O vermelho do ERRO (12/10/2026). --neg e um rosa — ao lado do rosa da marca
     (NOVO, candidata) um erro rosa nao se distingue. Erro precisa de uma cor so
     dele, e de uma palavra junto (a cor nunca fala sozinha). */
  --err: #f87171;
  --err-soft: #ff8aa5;     /* texto de erro de formulario (Expenses, Inventory) */
  /* Cores que as telas digitavam soltas (Diego, 17/10/2026): o lilas dos links
     e numeros de destaque, o ambar de "esta acabando / confira", o azul de
     "estimado". Um lugar so, para a proxima tela nao inventar a sua. */
  --lilac: #f0abfc;
  --warn: #fbbf24;
  --warn-soft: rgba(251,191,36,.42);
  --info: #93c5fd;
  /* Caixa de marcar, botao de radio, controle deslizante: a cor da marca em vez
     do azul do sistema, em todas as ferramentas de uma vez. */
  accent-color: var(--imp-pink);

  /* ── geometry: the identity's formats (I-010, 19/09/2026) ── */
  --radius:     var(--imp-r);
  --radius-sm:  var(--imp-r-input);
  --imp-gutter: 1rem;
  --imp-max:    680px;   /* default = focused */
  --imp-hdr-max: 100%;   /* the capsule header follows .imp-wide's tiers */

  /* Canonical UI typography — one family for the whole site now (the system font first —
     SF Pro on Apple — then Geist, loaded by imp-foundation.css; Lucas, 19/09: "pode carregar a fonte também").
     The logo wordmark is vector artwork and is unaffected. */
  --font-ui: var(--imp-font);

  /* content widths that NEVER grow */
  --w-field: 420px;
  --w-text:  68ch;
  --w-num:   160px;

  /* data-viz series (--chart-1/2/3, --grid) are the analytics layer's now:
     static/imp-analytics.css. */
}
@media (min-width: 1024px) { :root { --imp-hdr-max: 1200px; } }
@media (min-width: 1440px) { :root { --imp-hdr-max: 1440px; } }

/* ══ Container system ══════════════════════════════════════════════════════
   .imp-container            → focused (forms, reading)
   .imp-container.imp-wide   → productive (dashboards, tables, grids)      */

.imp-container {
  width: 100%;
  max-width: var(--imp-max);
  margin-inline: auto;
  padding-inline: var(--imp-gutter);
}
.imp-wide { --imp-max: 100%; }

@media (min-width: 640px)  { :root { --imp-gutter: 1.25rem; } }
@media (min-width: 1024px) { :root { --imp-gutter: 1.5rem; }  .imp-wide { --imp-max: 1200px; } }
@media (min-width: 1440px) { :root { --imp-gutter: 2rem; }    .imp-wide { --imp-max: 1440px; } }

/* Split: 2 columns on laptop+, stacked below. Extra width = new column. */
.imp-split { display: grid; gap: 1rem; grid-template-columns: 1fr; }
@media (min-width: 1024px) {
  .imp-split { gap: 1.25rem; grid-template-columns: 1fr 1fr; }
  .imp-split.imp-split-60 { grid-template-columns: 1.4fr 1fr; }
}

/* Auto grid — cards reflow by available width, never by hardcoded count */
.imp-autogrid { display: grid; gap: 1rem; grid-template-columns: 1fr; }
@media (min-width: 560px)  { .imp-autogrid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .imp-autogrid { gap: 1.25rem; grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1440px) { .imp-autogrid { grid-template-columns: repeat(4, 1fr); } }

/* ══ Base ═════════════════════════════════════════════════════════════════ */

/* Reserve the scrollbar's width whether or not it is showing. Without this,
   anything that changes page height — expanding a job, loading a list — makes
   the scrollbar appear, narrows the viewport, and shifts every centred element
   sideways. Mobile overlay scrollbars are unaffected. */
html {
  scrollbar-gutter: stable;
  overflow-y: scroll;          /* fallback where scrollbar-gutter is unsupported */
}
@supports (scrollbar-gutter: stable) {
  html { overflow-y: auto; }
}

body {
  font-family: var(--font-ui);
  background: var(--bg);
  color: var(--text);
  line-height: 1.35;
  min-height: 100dvh;
  -webkit-font-smoothing: antialiased;
}

/* Form controls do not inherit type from their parent — without this a button
   or input on any page falls back to the UA default and escapes the system.
   Family only: size and weight stay with the component. */
button, input, select, textarea { font-family: inherit; }

/* ══ App header — the identity's capsule (I-010, 19/09/2026) ══════════════
   The same floating glass pill the public site wears (imp-brand.css .nav),
   drawn here for the tools: sticky, inset to the container's edges, the
   wordmark at the left, the page's name in the brand gradient at the centre.
   Base = /projects variant. --inset = pages whose body carries side padding
   (invoice, dtf) and that show a back link on the left.                    */

.app-header {
  position: sticky; top: var(--imp-nav-top); z-index: 50;
  display: flex; align-items: center;
  width: min(100% - 2 * var(--imp-gutter), var(--imp-hdr-max) - 2 * var(--imp-gutter));
  margin: var(--imp-nav-top) auto 0;
  padding: 0 1rem;
  height: var(--imp-nav-bar);
  border-radius: var(--imp-r-pill);
  background: var(--imp-glass);
  border: 1px solid var(--imp-line-2);
  box-shadow: 0 14px 40px -22px rgba(0,0,0,.9), inset 0 1px 0 rgba(255,255,255,.10);
  backdrop-filter: blur(var(--imp-glass-blur)) saturate(160%);
  -webkit-backdrop-filter: blur(var(--imp-glass-blur)) saturate(160%);
}
/* ══ UM ARRANJO SO PARA A CAPSULA (Lucas, 06/10/2026) ══════════════════════
   "quero que a logo fique no mesmo lugar em todas as paginas ... Crie um
   padrao ... eu gosto de escolher um caminho e seguir nele."

   O arranjo e: MARCA a esquerda · TITULO ao centro · PROJECTS a direita.
   A marca e a constante da identidade — ela nunca troca de lado, nem na tela
   do hub (/projects), que foi a que ele aprovou. O link de voltar foi para a
   direita porque so um dos dois pode ocupar a ponta esquerda, e entre uma
   NAVEGACAO e a MARCA, quem fica fixa e a marca.

   Havia quatro arranjos em onze telas: marca a esquerda sem voltar; voltar a
   esquerda com marca a direita; voltar e marca grudados a esquerda (estas
   nunca tiveram `justify-content`); e o Studio, com marca e menu numa caixa.
   As onze foram acertadas nesta mesma entrega.

   A ordem e imposta AQUI por `order`, nao pela ordem das tags: e a garantia
   de que a proxima tela nova nao reinventa o arranjo. E a largura deixou de
   ser `100%`: a capsula vive fora do `.imp-container`, entao `100%` era a
   tela inteira e ela encostava nas duas bordas do iPhone enquanto os paineis
   abaixo respeitavam a goteira (Lucas: "ela nao tem margem, esta tocando no
   final da tela"). Agora usa a mesma conta do container. */
.app-header { justify-content: space-between; }

.app-brand      { order: 0; display: flex; align-items: center; flex: 0 0 auto; }

/* A marca sozinha nunca fica encostada num canto com o resto vazio
   (Lucas, 06/10/2026: "nao tem nenhum titulo na pagina, entao esta vazio ...
   seria bom a logo ficar no meio. Caso nao, a logo permanece no superior
   esquerdo").

   Duas situacoes em que a capsula fica com UM item so:
   · uma tela sem titulo — hoje nao existe, e o check_capsula.py recusa uma;
   · abaixo de 360px, onde o titulo se esconde e uma tela sem link de voltar
     (o proprio /projects) sobra so com a marca.
   Nos dois casos ela vai para o centro. */
.app-header:not(:has(.app-header-title)) { justify-content: center; }
@media (max-width: 359px) {
  .app-header:not(:has(.app-back)) { justify-content: center; }
}
.app-header-title { order: 1; }
.app-back       { order: 2; margin-left: auto; }
.app-header-right { order: 3; display: flex; align-items: center; gap: .5rem; }

/* O galho a direita: texto primeiro, seta depois, porque ela aponta para onde
   o toque leva. Nas telas em que ele estava a esquerda a seta apontava para
   tras — manter o desenho antigo do lado novo seria mentir sobre o destino. */
.app-back svg { flex: 0 0 auto; }
/* The real brand artwork (website/logo.svg — the icon plus the drawn wordmark
   and "Creative Center", 1978×751). IMP-009, 22/09: it was 24px and read as a
   smudge; the capsule is 56px tall, so 36px is the largest height that keeps
   its breathing room. Never retyped in a font, never squashed: width auto. */
.app-logo { height: 32px; width: auto; display: block; }
@media (max-width: 639px) {
  .app-logo { height: 26px; }
}

.app-header-title {
  position: absolute; left: 50%; transform: translateX(-50%);
  font-family: var(--font-ui);
  font-size: .9rem; font-weight: 600; letter-spacing: -.01em;
  background: var(--grad);
  -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
  white-space: nowrap; pointer-events: none;
}
/* The page's name is centred on the bar; with a 36px logo on the left it can
   no longer run under it, so it hides where the two would meet. */
@media (max-width: 639px) { .app-header { padding: 0 .85rem; } .app-header-title { font-size: .82rem; } }
/* O titulo so desaparece nos telefones realmente estreitos. Era 420px, de
   quando a capsula tinha tres coisas de cada lado; agora ela tem duas (marca e
   Projects) e sobram ~150px no meio de uma tela de 390. Medido antes de mudar:
   o titulo nao encosta em nenhum dos dois ate 360px. */
@media (max-width: 359px) { .app-header-title { display: none; } }
.app-back {
  display: flex; align-items: center; gap: .35rem;
  font-size: .72rem; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--muted);
  text-decoration: none; transition: color .15s; white-space: nowrap;
}@media (hover: hover) and (pointer: fine) { .app-back:hover { color: var(--text); } }

/* ══ Page title ═══════════════════════════════════════════════════════════ */

.imp-page-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  padding: 1.75rem 0 1.25rem;
}
.imp-page-head h1 {
  font-family: var(--font-ui);
  font-size: 1.9rem; font-weight: 600; letter-spacing: -.035em; line-height: 1.1;
  background: var(--grad);
  -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
}
.imp-page-head .sub {
  font-size: .72rem; color: var(--muted); font-weight: 400;
  letter-spacing: .05em; text-transform: uppercase; margin-top: .3rem;
}
@media (min-width: 1024px) { .imp-page-head h1 { font-size: 2.2rem; } }
@media (min-width: 1440px) { .imp-page-head { padding: 2.25rem 0 1.5rem; } .imp-page-head h1 { font-size: 2.5rem; } }

/* The line under a page's title, with a switch (EN | PT) at its right: the text takes the room it has
   and the switch keeps its own size (lifted from the Key Changer, 08/11/2026; psd_png.html still has its
   own `.pp-head` copy until its pinned bytes are moved on purpose). */
.imp-head-row { display: flex; align-items: center; justify-content: space-between; gap: .75rem 1rem; margin: 1.5rem 0 1rem; }
.imp-head-row-text { flex: 1 1 16rem; min-width: 0; }
.imp-head-row-text p { color: var(--muted); font-size: .86rem; max-width: 60ch; line-height: 1.5; margin: 0; }
.imp-head-row > .imp-seg { flex: none; }

/* ══ Surfaces ═════════════════════════════════════════════════════════════ */

.imp-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem;
}
.imp-block-title {
  font-size: .68rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted);
  margin-bottom: .9rem;
}

/* ══ Controls ═════════════════════════════════════════════════════════════ */

/* Buttons are pills, like everywhere on the site: the primary in the brand's
   gradient, the ghost as an outline that warms to pink. */
.imp-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  padding: .62rem 1.15rem; border: 1px solid transparent; border-radius: var(--imp-r-pill);
  background: var(--grad); color: #fff;
  font-family: var(--font-ui);
  font-size: .78rem; font-weight: 600; letter-spacing: 0; text-transform: none;
  box-shadow: 0 10px 30px -12px rgba(255,16,144,.55), inset 0 1px 0 rgba(255,255,255,.2);
  cursor: pointer; text-decoration: none; white-space: nowrap;
  transition: filter .2s, transform .12s, border-color .2s, background-color .2s;
}@media (hover: hover) and (pointer: fine) { .imp-btn:hover { filter: brightness(1.08); } }
.imp-btn:active { transform: scale(.98); }
.imp-btn-ghost {
  background: rgba(255,255,255,.05); border-color: var(--border2); color: var(--text); box-shadow: none;
}@media (hover: hover) and (pointer: fine) { .imp-btn-ghost:hover { background: rgba(255,255,255,.09); border-color: rgba(255,45,120,.45); filter: none; } }
.imp-btn-danger { background: rgba(255,107,157,.12); border-color: rgba(255,107,157,.3); color: var(--neg); box-shadow: none; }
/* Disabled = a flat, muted pill on every page (Diego, 22/10/2026): no gradient,
   no glow, no press. A link styled as a button says it with aria-disabled. */
.imp-btn:disabled, .imp-btn[aria-disabled="true"] { background: rgba(255,255,255,.05); border-color: var(--border);
  color: var(--muted); box-shadow: none; filter: none; transform: none; cursor: not-allowed; }
.imp-btn[aria-disabled="true"] { pointer-events: none; }
/* A money amount or a duration never breaks in the middle ("Reserve $70.03");
   produced by impNoWrapMoney() in imp-foundation.js. */
.imp-nw { white-space: nowrap; }

.imp-field { display: flex; flex-direction: column; gap: .4rem; min-width: 0; }
.imp-field label {
  font-size: .68rem; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--muted);
}
.imp-input, .imp-select, .imp-textarea {
  width: 100%;
  max-width: var(--w-field);          /* the field never stretches with the page */
  padding: .7rem .9rem;
  border: 1px solid var(--border2);
  border-radius: var(--radius-sm);
  background: rgba(0,0,0,.32);
  color: var(--text);
  font-family: var(--font-ui); font-size: .85rem;
  outline: none; transition: border-color .15s, box-shadow .15s;
}
.imp-input:focus, .imp-select:focus, .imp-textarea:focus {
  border-color: rgba(255,45,120,.65); box-shadow: 0 0 0 4px rgba(255,45,120,.13);
}
.imp-input[type="number"] { max-width: var(--w-num); }
.imp-input::placeholder { color: var(--subtle); }
.imp-textarea { max-width: 100%; resize: vertical; min-height: 76px; }
/* O select e `appearance: none` (para o campo ter o desenho do shell), e sem seta
   ele parecia um campo de texto: ninguem sabia que abria uma lista (12/10/2026,
   achado na revisao do /projects/trends). A seta mora AQUI, no motor, e vale para
   todos os consumidores. O respiro da direita e `!important` de proposito — e uma
   GARANTIA (o texto nunca corre por baixo da seta): varias telas escrevem
   `padding: a b` de atalho, e um atalho de pagina apagaria o respiro. A cor da
   seta e a do texto secundario, em SVG embutido (nenhum arquivo a mais).
   Quem pinta o fundo do select usa `background-color`, nunca `background:` de
   atalho — o atalho apaga a seta. */
.imp-select {
  appearance: none; -webkit-appearance: none; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%23f6f4fa' stroke-opacity='.62' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1.5l5 5 5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .85rem center;
  background-size: .75rem auto;
  padding-right: 2.2rem !important;
  text-overflow: ellipsis;
}
.imp-select:disabled { cursor: not-allowed; opacity: .55; }
/* a disabled field reads as disabled too (22/10, the Investor's forex settings without an
   OANDA token): same dim as the select */
.imp-input:disabled { cursor: not-allowed; opacity: .55; }
.imp-select option { background: var(--card2); color: var(--text); }
/* A checkbox and its words as ONE target: the box is the system's, in the brand accent (accent-color above);
   44 px tall on a finger (IMP-011, the label dialog). psd_png.html types the same anatomy as .gs-check and keeps
   it until the gang-sheet editor leaves that page (F1): then it reads this one. */
.imp-check { display: flex; align-items: center; gap: .6rem; font-size: .84rem; line-height: 1.4; cursor: pointer; }
.imp-check input { width: 18px; height: 18px; flex: none; margin: 0; }
@media (any-pointer: coarse) { .imp-check { min-height: 44px; } }

/* ══ Value semantics ══════════════════════════════════════════════════════ */

.imp-pos { color: var(--pos); }
.imp-neg { color: var(--neg); }
.imp-muted { color: var(--muted); }
.imp-num { font-variant-numeric: tabular-nums; }

.imp-pill {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .22rem .6rem; border-radius: 999px;
  font-size: .64rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  border: 1px solid var(--border2); background: rgba(255,255,255,.04); color: var(--muted);
  white-space: nowrap;
}
.imp-pill[data-status="Quoted"],      .imp-pill[data-status="to_ship"]   { color:var(--imp-pink-soft); border-color:rgba(255,45,120,.35); background:rgba(255,45,120,.1); }
.imp-pill[data-status="In Production"],.imp-pill[data-status="produced"] { color:#fbbf24; border-color:rgba(251,191,36,.3);  background:rgba(251,191,36,.09); }
.imp-pill[data-status="Delivered"],   .imp-pill[data-status="shipped"]   { color:#60a5fa; border-color:rgba(96,165,250,.3);  background:rgba(96,165,250,.09); }
.imp-pill[data-status="Closed"],      .imp-pill[data-status="active"]    { color:var(--pos); border-color:rgba(74,222,128,.28); background:rgba(74,222,128,.08); }
/* NFC keychains (IMP-011): the six statuses ride the groups above. Created and Archived are the neutral
   pill on purpose (nothing to do yet / nothing to do any more); the word travels with the colour. */

/* Trend Studio (12/10/2026) — SO o ESTADO (pauta, referência, pedido) é pílula.
   A "situação" que o motor dá (candidata, evergreen, validar…) é outro
   vocabulário e vira etiqueta NEUTRA (.tr-chip na página): duas famílias de
   palavras na mesma paleta de quatro cores se confundiam (VALIDAR e APROVADO
   ambos âmbar, CANDIDATA e NOVO ambos rosa). Sem regra = neutro (descartado,
   cancelado). O erro tem cor própria e mais peso — nunca parecido com o rosa
   da marca — e a pílula carrega a palavra: a cor nunca fala sozinha. */
.imp-pill[data-status="novo"]        { color:var(--imp-pink-soft); border-color:rgba(255,45,120,.35); background:rgba(255,45,120,.1); }
.imp-pill[data-status="aprovado"],   .imp-pill[data-status="construindo"],
.imp-pill[data-status="processando"],.imp-pill[data-status="leased"]      { color:#fbbf24; border-color:rgba(251,191,36,.3); background:rgba(251,191,36,.09); }
.imp-pill[data-status="na_fila"],    .imp-pill[data-status="queued"]      { color:#60a5fa; border-color:rgba(96,165,250,.3); background:rgba(96,165,250,.09); }
.imp-pill[data-status="pronto"],     .imp-pill[data-status="pronta"],
.imp-pill[data-status="done"]        { color:var(--pos); border-color:rgba(74,222,128,.28); background:rgba(74,222,128,.08); }
.imp-pill[data-status="erro"],       .imp-pill[data-status="failed"]      { color:#fff1f1; border-color:rgba(248,113,113,.7); background:rgba(248,113,113,.26); }

/* ══ KPI tiles / KPI strip / chart cards → static/imp-analytics.css ═══════ */

/* ══ Table → cards on mobile ══════════════════════════════════════════════ */

.imp-table-wrap { width: 100%; overflow-x: auto; }
.imp-table { width: 100%; border-collapse: collapse; font-size: .82rem; }
.imp-table th {
  text-align: left; padding: .7rem .8rem;
  font-size: .62rem; font-weight: 700; letter-spacing: .055em;
  text-transform: uppercase; color: var(--muted);
  border-bottom: 1px solid var(--border2); white-space: nowrap;
}
.imp-table th.num, .imp-table td.num { text-align: right; font-variant-numeric: tabular-nums; }
.imp-table td { padding: .8rem; border-bottom: 1px solid var(--border); vertical-align: middle; }
.imp-table tbody tr { cursor: pointer; transition: background .15s; }@media (hover: hover) and (pointer: fine) { .imp-table tbody tr:hover { background: rgba(255,255,255,.028); } }
.imp-table tbody tr:last-child td { border-bottom: none; }

@media (max-width: 767px) {
  .imp-table, .imp-table tbody, .imp-table tr, .imp-table td { display: block; width: 100%; }
  .imp-table thead { display: none; }
  .imp-table tr {
    background: var(--card); border: 1px solid var(--border);
    border-radius: 14px; padding: .9rem 1rem; margin-bottom: .7rem;
  }
  .imp-table td {
    display: flex; align-items: center; justify-content: space-between; gap: 1rem;
    padding: .3rem 0; border-bottom: none; text-align: right;
  }
  .imp-table td::before {
    content: attr(data-label);
    font-size: .62rem; font-weight: 700; letter-spacing: .05em;
    text-transform: uppercase; color: var(--muted); text-align: left;
  }
  /* mobile card priority: these lead, the rest is secondary */
  .imp-table td.lead { justify-content: flex-start; padding-bottom: .55rem; }
  .imp-table td.lead::before { display: none; }
  .imp-table td.hide-sm { display: none; }
}

/* ══ Dialog — fits the viewport, no trapped inner scroll ══════════════════ */

.imp-overlay {
  position: fixed; inset: 0; z-index: 100;
  display: none; align-items: center; justify-content: center;
  padding: 1rem;
  background: rgba(4,2,8,.72);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  overflow-y: auto;                      /* the page scrolls, not a box inside it */
}
.imp-overlay.open { display: flex; }
.imp-dialog {
  width: 100%; max-width: 560px; margin: auto;
  background: var(--card2);
  border: 1px solid var(--border2);
  border-radius: var(--imp-r-lg);
  padding: 1.5rem;
}
.imp-dialog.wide { max-width: 780px; }
.imp-dialog-title {
  font-family: var(--font-ui); font-size: 1.2rem; font-weight: 600;
  letter-spacing: -.03em; margin-bottom: 1.1rem;
}
.imp-dialog-actions {
  display: flex; gap: .6rem; justify-content: flex-end;
  margin-top: 1.4rem; flex-wrap: wrap;
}
@media (min-width: 1024px) { .imp-dialog { padding: 1.85rem; } }
/* The buttons pinned to the bottom of a long dialog, in view even with the
   iPhone keyboard open (Diego, 18/10 — was .iv-stick in the Inventory; the
   Investor's Settings uses it since 21/10). The bar is the dialog's LAST
   child; it bleeds to the dialog's edges, so the margins undo its padding. */
.imp-dialog-stick { position: sticky; bottom: -1.5rem; margin: 1.2rem -1.5rem -1.5rem;
  padding: .9rem 1.5rem; background: var(--card2); border-top: 1px solid var(--border);
  border-radius: 0 0 var(--imp-r-lg) var(--imp-r-lg); }
@media (min-width: 1024px) { .imp-dialog-stick { bottom: -1.85rem; margin: 1.2rem -1.85rem -1.85rem;
  padding: .9rem 1.85rem; } }

/* ══ Section head — title + actions on one line ═══════════════════════════ */

.imp-section-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  margin: 1.75rem 0 .75rem;
}
/* The reference's kicker: small, tracked, in the brand's pink. */
.imp-section-head h2 {
  font-family: var(--font-ui);
  font-size: var(--imp-kicker); font-weight: 500;
  letter-spacing: .24em; text-transform: uppercase;
  color: var(--imp-pink);
}
.imp-section-actions { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }

/* ══ Disclosure panel — summary always visible, body expands ══════════════ */

.imp-panel {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  margin-bottom: .45rem;
  overflow: hidden;
  transition: border-color .15s;
}@media (hover: hover) and (pointer: fine) { .imp-panel:hover { border-color: var(--border2); } }
.imp-panel.open { border-color: rgba(255,45,120,.3); background: var(--card2); }

.imp-panel-summary {
  display: grid; align-items: center; gap: .75rem;
  padding: .6rem .8rem;
  cursor: pointer; user-select: none;
  transition: background .12s;
}@media (hover: hover) and (pointer: fine) { .imp-panel-summary:hover { background: rgba(255,255,255,.022); } }
.imp-panel-summary:active { background: rgba(255,255,255,.04); }

.imp-caret {
  width: 16px; height: 16px; flex-shrink: 0;
  color: var(--subtle);
  transition: transform .2s cubic-bezier(.2,.8,.2,1), color .15s;
}
.imp-panel.open .imp-caret { transform: rotate(90deg); color: var(--pink); }

.imp-panel-body {
  padding: 0 .8rem .85rem;
  border-top: 1px solid var(--border);
  margin-top: -1px;
}

/* ══ Launcher — the tools, as a grid of equal tiles ═══════════════════════
   Redone 25/09/2026 (Lucas: "esse tools ficou horrível, os botões"). What was
   wrong: seven pills on one row with the eighth ("Settings") alone below, each
   one wearing its own glass (eight blurs for buttons) and a bright outline.
   Now: a tile is a solid surface with a hairline — glass is for the layer that
   floats, not for buttons in the content — an icon in a round badge on top and
   the name below, so a long name ("DTF Calculator") never fights the icon for
   width. The grid is 2 across on a phone and 4 across from 900px, so eight
   tools are 4 + 4 and never 7 + 1. A ninth tool would make 4 + 4 + 1: change
   the column rule when the count changes, not the tiles.                     */
.imp-launcher {
  display: grid; gap: .6rem;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
/* 3 colunas no desktop. A ultima linha nunca fica com buraco nem com uma
   ferramenta sozinha (a reclamacao de 25/09): a ultima ferramenta estica sobre
   o que sobrou da linha, para QUALQUER contagem. Em 12/10/2026 o Remote Control
   saiu e ficaram ONZE: no telefone 5 linhas de 2 + Settings na largura toda; no
   desktop 3+3+3 + (1 + Settings ocupando 2). Mudar a contagem nao exige mexer aqui. */
@media (min-width: 900px) { .imp-launcher { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.imp-launcher > .imp-launch:last-child:nth-child(odd) { grid-column: 1 / -1; }
@media (min-width: 900px) {
  .imp-launcher > .imp-launch:last-child:nth-child(odd) { grid-column: auto; }
  .imp-launcher > .imp-launch:last-child:nth-child(3n+2) { grid-column: span 2; }
  .imp-launcher > .imp-launch:last-child:nth-child(3n+1) { grid-column: 1 / -1; }
}

.imp-launch {
  display: flex; flex-direction: column; align-items: flex-start; justify-content: space-between; gap: .8rem;
  min-height: 92px; min-width: 0; width: 100%;
  padding: .9rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 20px;
  color: var(--text); text-decoration: none; text-align: left;
  font: inherit; cursor: pointer;
  transition: border-color .2s var(--imp-ease), background-color .2s var(--imp-ease), transform .12s var(--imp-ease);
}
@media (hover: hover) and (pointer: fine) { .imp-launch:hover {
  border-color: rgba(255,45,120,.45);
  background: var(--card2);
} }
.imp-launch:active { transform: scale(.98); }
.imp-launch-icon {
  width: 34px; height: 34px; border-radius: 50%; flex-shrink: 0;
  background: rgba(255,45,120,.10);
  border: 1px solid rgba(255,45,120,.22);
  display: flex; align-items: center; justify-content: center;
  transition: background-color .2s var(--imp-ease);
}
@media (hover: hover) and (pointer: fine) { .imp-launch:hover .imp-launch-icon { background: rgba(255,45,120,.18); } }
.imp-launch-icon svg { width: 16px; height: 16px; }
.imp-launch-name {
  max-width: 100%;
  font-size: .88rem; font-weight: 600; letter-spacing: -.01em; line-height: 1.2;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ══════════════════════════════════════════════════════════════════════════
   WORKSPACE ENGINE — one skeleton, two configurations (InvoiceCC / DTF)

   COMMAND STRIP  → the few controls that define the document + the CTA
   WORKSPACE      → document pane  +  history pane, side by side on desktop

   Below 1024px the two panes stack and the tool falls back to its tabs; above
   it, tabs are irrelevant because both panes are on screen at once.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Command strip — thin by construction, never a second card ── */
.imp-cmd {
  display: flex; align-items: flex-end; gap: .6rem; flex-wrap: wrap;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: .6rem .7rem;
  margin-bottom: .7rem;
}
.imp-cmd-field { display: flex; flex-direction: column; gap: .25rem; min-width: 0; flex: 1 1 190px; }
.imp-cmd-field > label {
  font-size: .56rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--muted); white-space: nowrap;
}
.imp-cmd-field input, .imp-cmd-field select {
  width: 100%; max-width: var(--w-field);
  padding: .45rem .6rem;
  border: 1px solid var(--border2); border-radius: 8px;
  background: rgba(0,0,0,.32); color: var(--text);
  font-size: .82rem; outline: none; transition: border-color .15s;
}
.imp-cmd-field input:focus, .imp-cmd-field select:focus { border-color: var(--pink); }
.imp-cmd-field.narrow { flex: 0 1 132px; }
.imp-cmd-field.narrow input { max-width: var(--w-num); }
.imp-cmd-cta { flex: 0 0 auto; margin-left: auto; }
/* What saving will do to the document's job — its own line at the foot of the
   strip (order), so the fields above stay on one baseline. Shown only when there
   is something to say; a move or an unlink is tinted, because it changes a
   second job's money. Consumer: static/imp-doc-job.js. */
.imp-cmd-note { order: 99; flex: 1 1 100%; font-size: .72rem; line-height: 1.4; color: var(--muted); }
.imp-cmd-note.aviso { color: #fcd34d; }

@media (min-width: 1024px) {
  .imp-cmd { position: sticky; top: calc(var(--imp-nav-top) + var(--imp-nav-bar) + 8px); z-index: 40;
    background: rgba(8,11,24,.92);
    backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); }
}
/* ── A faixa no telefone (06/10/2026) ──────────────────────────────────────
   Lucas abriu /dtf no iPhone e o campo de data estava POR CIMA do "$ per
   foot", com os dois rotulos em alturas diferentes.

   Causa: `.narrow` prende o campo em `flex: 0 1 132px` e o input de data do
   WebKit tem largura intrinseca propria — ele nao cabe em 132px menos 28 de
   padding, e transborda por cima do vizinho. O `align-items: flex-end` da
   faixa fazia o resto: campos de alturas diferentes alinhados pela base
   deixam os rotulos desencontrados.

   A correcao nao e espremer melhor, e RECOMPOR: no telefone a faixa vira uma
   coluna so e cada campo ocupa a largura inteira. Vale para as duas
   ferramentas que usam a faixa (DTF e InvoiceCC) — e o motor, nao a pagina. */
@media (max-width: 639px) {
  .imp-cmd { align-items: stretch; gap: .8rem; padding: .8rem; }
  .imp-cmd-field, .imp-cmd-field.narrow { flex: 1 1 100%; }
  .imp-cmd-field input, .imp-cmd-field select,
  .imp-cmd-field.narrow input { max-width: none; }
  .imp-cmd-field > label { font-size: .62rem; }
  .imp-cmd-cta { margin-left: 0; flex: 1 1 100%; }
}

/* ── Two-pane workspace ── */
.imp-ws { display: grid; gap: .7rem; grid-template-columns: 1fr; align-items: start; }
@media (min-width: 1024px) { .imp-ws { gap: .85rem; grid-template-columns: 42fr 58fr; } }

.imp-pane {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: .85rem .9rem 1rem;
  min-width: 0;
}
@media (min-width: 1440px) { .imp-pane { padding: 1rem 1.1rem 1.15rem; } }

.imp-pane-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: .6rem; margin-bottom: .7rem;
}
.imp-pane-title {
  font-size: .6rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--muted);
}

/* Above 1024px both panes are visible, so the tabs stop mattering. */
@media (min-width: 1024px) {
  .imp-ws .panel { display: block !important; }
  .imp-ws-tabs { display: none !important; }
}

/* ── Compact upload tiles — an optional field must not own the page ── */
.imp-tiles { display: grid; gap: .4rem; grid-template-columns: repeat(2, 1fr); }
@media (min-width: 560px) { .imp-tiles { grid-template-columns: repeat(4, 1fr); } }

.imp-tile {
  position: relative; height: 84px;
  border: 1px dashed var(--border2); border-radius: 9px;
  background: rgba(255,255,255,.02);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .1rem; cursor: pointer; overflow: hidden;
  transition: border-color .15s, background .15s;
}@media (hover: hover) and (pointer: fine) { .imp-tile:hover { border-color: rgba(192,9,193,.45); background: rgba(192,9,193,.05); } }
.imp-tile .t-plus { font-size: 1rem; color: var(--subtle); line-height: 1; }
.imp-tile .t-label { font-size: .56rem; color: var(--muted); letter-spacing: .04em; }
.imp-tile img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: none;
}
.imp-tile.filled img { display: block; }
.imp-tile.filled .t-plus, .imp-tile.filled .t-label { display: none; }
.imp-tile .t-remove {
  position: absolute; top: 3px; right: 3px; z-index: 2; display: none;
  width: 18px; height: 18px; border-radius: 50%;
  border: none; background: rgba(0,0,0,.68); color: #fff;
  font-size: .62rem; line-height: 1; cursor: pointer;
}
.imp-tile.filled .t-remove { display: block; }
@media (min-width: 1440px) { .imp-tile { height: 96px; } }

/* ── Dense history rows — scan many records, not scroll through cards ── */
.imp-hist { display: flex; flex-direction: column; gap: 2px; }
.imp-hist-row {
  display: grid; align-items: center; gap: .5rem;
  padding: .42rem .5rem; border-radius: 8px;
  border: 1px solid transparent;
  transition: background .12s, border-color .12s;
}@media (hover: hover) and (pointer: fine) { .imp-hist-row:hover { background: rgba(255,255,255,.03); border-color: var(--border); } }
.imp-hist-head {
  font-size: .55rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--subtle);
  padding: 0 .5rem .3rem; border-bottom: 1px solid var(--border); margin-bottom: .25rem;
}
.imp-hist-row .h-num { font-size: .72rem; font-weight: 700; color: var(--imp-pink-soft);
  font-variant-numeric: tabular-nums; white-space: nowrap; }
.imp-hist-row .h-main { font-size: .78rem; font-weight: 600; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.imp-hist-row .h-sub { font-size: .64rem; color: var(--muted); white-space: nowrap; }
.imp-hist-row .h-amt { font-size: .78rem; font-weight: 700; text-align: right;
  font-variant-numeric: tabular-nums; white-space: nowrap; }
.imp-hist-actions { display: flex; gap: .18rem; justify-content: flex-end; }
.imp-hist-actions button, .imp-hist-actions a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; padding: 0;
  border: 1px solid var(--border); border-radius: 6px;
  background: rgba(255,255,255,.03); color: var(--muted);
  cursor: pointer; text-decoration: none; transition: color .15s, border-color .15s;
}@media (hover: hover) and (pointer: fine) { .imp-hist-actions button:hover, .imp-hist-actions a:hover {
  color: var(--text); border-color: var(--border2);
} }@media (hover: hover) and (pointer: fine) { .imp-hist-actions .danger:hover { color: var(--neg); border-color: rgba(255,107,157,.4); } }

/* ── Compact stat tiles for a tool header ── */
.imp-toolstats { display: grid; gap: .4rem; grid-template-columns: repeat(3, 1fr); margin-bottom: .6rem; }
.imp-toolstats.two { grid-template-columns: repeat(2, 1fr); }
.imp-toolstat {
  background: rgba(255,255,255,.025); border: 1px solid var(--border);
  border-radius: 9px; padding: .4rem .55rem; min-width: 0;
}
.imp-toolstat .s-label {
  font-size: .52rem; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted); margin-bottom: .1rem;
}
.imp-toolstat .s-value {
  font-size: .95rem; font-weight: 800; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* ══ Footer ═══════════════════════════════════════════════════════════════ */

.imp-footer {
  text-align: center; padding: 2rem 1rem;
  font-size: .65rem; letter-spacing: .12em; text-transform: uppercase;
  color: rgba(255,255,255,.15); font-weight: 500;
}

/* ══════════════════════════════════════════════════════════════════════════
   GLASS — elevated, interactive surfaces only
   ══════════════════════════════════════════════════════════════════════════
   Base stays solid, content stays readable, and only the layer you can touch
   is made of glass. Making every card transparent is how a dashboard stops
   being legible. One set of tokens so two components can never end up with
   two slightly different pieces of glass.                                    */

/* The `--imp-glass-*` tokens moved to imp-foundation.css (25/09/2026): the
   public capsule and drawer are glass too and do not load this file. */

.imp-glass {
  position: relative;
  background: var(--imp-glass-bg);
  border: 1px solid var(--imp-glass-border);
  border-radius: var(--imp-glass-radius);
  box-shadow: var(--imp-glass-shadow);
  backdrop-filter: blur(var(--imp-glass-blur)) saturate(160%);
  -webkit-backdrop-filter: blur(var(--imp-glass-blur)) saturate(160%);
}
/* The bright hairline along the top is what reads as "a real pane of glass"
   rather than "a box with some opacity". */
.imp-glass::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  padding-top: 1px; pointer-events: none;
  background: linear-gradient(var(--imp-glass-highlight), transparent 42%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
}
.imp-glass-accent { border-color: var(--imp-glass-accent);
  box-shadow: var(--imp-glass-shadow), var(--imp-glass-glow); }

/* Blur is the whole effect — without it, transparency alone is just muddy
   text. Browsers that cannot do it get an opaque surface instead. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .imp-glass { background: #15151f; }
  /* the sticky capsule too (Diego 22/10): without blur, the page scrolled under
     "Investor · LIVE" showed through sharp */
  .app-header, .imp-cmd { background: var(--imp-glass-solid); }
}
@media (prefers-reduced-transparency: reduce) {
  .imp-glass { background: #15151f; backdrop-filter: none; -webkit-backdrop-filter: none; }
  /* The capsule header, the command bar and dialogs are glass too (25/09/2026):
     opaque when the person asked the system for less transparency. */
  .app-header, .imp-cmd { background: var(--imp-glass-solid); backdrop-filter: none; -webkit-backdrop-filter: none; }
  .imp-overlay { backdrop-filter: none; -webkit-backdrop-filter: none; }
}
@media (prefers-contrast: more) {
  .app-header, .imp-cmd, .imp-glass { background: #000; border-color: currentColor; backdrop-filter: none; -webkit-backdrop-filter: none; }
}

/* ── Aurora ───────────────────────────────────────────────────────────────
   Depth behind the page, not decoration on top of it. Two fixed radial
   gradients — no blur region, no canvas, nothing per-frame. Opt in per page
   with class="imp-aurora" on <body>.                                        */
.imp-aurora::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(60rem 40rem at 18% -10%, rgba(255,16,144,.11), transparent 62%),
    radial-gradient(52rem 38rem at 88% 8%,  rgba(139,47,201,.12), transparent 60%),
    radial-gradient(46rem 30rem at 50% 108%, rgba(255,179,221,.05), transparent 64%);
}
@media (prefers-contrast: more) {
  .imp-aurora::before { display: none; }
}


/* ── Quadro arrumável (impBoard, 17/10/2026) ─────────────────────────────
   As janelas que o Lucas arruma (static/imp-board.js). Uma coluna no
   telefone; duas no computador, e "Wide" ocupa a linha inteira. Editando,
   cada janela vira um móvel com moldura tracejada rosa: o conteúdo não
   responde (não se segue um link sem querer), só as ferramentas dela.     */
.imp-board { display: grid; gap: 1rem; grid-template-columns: minmax(0, 1fr); align-items: start; }
@media (min-width: 1024px) {
  /* Pares esticam (stretch): janela ao lado de uma mais alta nao deixa buraco.
     A que ficaria sem par (antes de uma Wide, ou a ultima) ganha .is-fill do
     motor e ocupa a linha — calculado no JS, porque :nth-child contaria as
     escondidas (Diego, 17/10/2026). */
  .imp-board { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.1rem; align-items: stretch; }
  .imp-bcard.is-wide, .imp-bcard.is-fill { grid-column: 1 / -1; }
}
/* Wide/Half so existe onde ha duas colunas. */
@media (max-width: 1023px) { .imp-board-size { display: none !important; } }
.imp-bcard {
  min-width: 0; background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 1rem 1.1rem 1.1rem;
}
.imp-bcard-head { display: flex; align-items: center; justify-content: space-between;
  gap: .75rem; margin-bottom: .8rem; min-height: 1.6rem; }
.imp-bcard-title { font-size: .68rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--muted); margin: 0; }
.imp-bcard-act { display: flex; gap: .4rem; flex-wrap: wrap; justify-content: flex-end; }
.imp-bcard-tools { display: none; }
.imp-board.is-editing .imp-bcard {
  border: 1px dashed rgba(255,45,120,.5); background: rgba(255,45,120,.035);
}
.imp-board.is-editing .imp-bcard > :not(.imp-bcard-tools) { pointer-events: none; user-select: none; opacity: .72; }
/* Editando, o nome já está na barra de ferramentas da janela: o título some. */
.imp-board.is-editing .imp-bcard-head { display: none; }
.imp-board.is-editing .imp-bcard-tools {
  display: flex; align-items: center; gap: .35rem; flex-wrap: wrap; margin-bottom: .7rem;
}
.imp-bcard.is-dragging { border-style: solid; border-color: var(--pink);
  box-shadow: 0 18px 40px -12px rgba(255,16,144,.45); }
.imp-board-grip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 32px; padding: 0; border-radius: var(--radius-sm);
  border: 1px solid var(--border2); background: rgba(255,255,255,.05);
  color: var(--text); font-size: 1rem; cursor: grab; touch-action: none;
}
.imp-board-grip:active { cursor: grabbing; }
.imp-board-name { font-size: .66rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text); flex: 1 1 0; min-width: 0;
  white-space: normal; line-height: 1.2; overflow-wrap: anywhere; }
.imp-board.is-editing .imp-bcard-tools { flex-wrap: nowrap; }
.imp-board-mini {
  display: inline-flex; align-items: center; min-height: 32px; padding: .2rem .65rem;
  border-radius: 999px; border: 1px solid var(--border2); background: rgba(255,255,255,.05);
  color: var(--text); font-family: var(--font-ui); font-size: .72rem; font-weight: 600; cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .imp-board-mini:hover { border-color: rgba(255,45,120,.45); background: rgba(255,255,255,.09); }
}
@media (any-pointer: coarse) {
  .imp-board-grip { width: 44px; height: 44px; }
  .imp-board-mini { min-height: 44px; padding: .3rem .85rem; }
}
.imp-board-bar { display: flex; justify-content: flex-end; align-items: center; margin-bottom: 1rem; }
.imp-board-hint { margin: 0; font-size: .78rem; color: var(--muted); line-height: 1.45; min-width: 0; }
.imp-board-hint:empty { display: none; }
/* Editando, o que a pagina marcou como "fixo" gruda sob a capsula: Cancel e
   Save layout a um toque em qualquer altura de uma pagina de 4000px. */
.imp-board-sticky { position: sticky; z-index: 30;
  top: calc(var(--imp-nav-top) + var(--imp-nav-bar) + .4rem);
  background: var(--bg); padding-block: .55rem; margin-inline: -.25rem; padding-inline: .25rem;
  border-radius: var(--radius-sm); box-shadow: 0 12px 24px -16px rgba(0,0,0,.9); }
.imp-board-btns { display: flex; gap: .45rem; justify-content: flex-end; flex-wrap: wrap; }
.imp-board-tray { grid-column: 1 / -1; display: grid; gap: .55rem;
  padding: .75rem .85rem; border-radius: var(--radius-sm);
  border: 1px solid rgba(255,45,120,.3); background: rgba(255,45,120,.06); }
.imp-board-off { display: flex; align-items: center; flex-wrap: wrap; gap: .45rem; }
.imp-board-tray[hidden] { display: none; }
.imp-board-tray-label { font-size: .62rem; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted); margin-right: .2rem; }
.imp-board-tray-none { font-size: .78rem; color: var(--muted); }
@media (max-width: 560px) { .imp-board-bar { justify-content: flex-start; } }
/* Janela leve (21/10/2026, o quadro do /projects). O conteudo ja traz o
   proprio cabecalho (.imp-section-head) e as proprias superficies, entao o
   motor nao desenha titulo, fundo nem moldura: fora da edicao a pagina parece
   a mesma de antes. Editando, a moldura tracejada volta, com respiro. */
.imp-bcard--light { background: none; border: 0; border-radius: var(--radius); padding: 0; }
.imp-board.is-editing .imp-bcard--light { padding: .75rem .85rem .85rem; }
/* Lado a lado, a janela mais baixa estica ate a altura da vizinha: o corpo
   cresce, e a pagina estica a propria superficie dentro dele. :not([hidden]),
   porque um display aqui venceria o [hidden] de uma janela fora do quadro. */
.imp-bcard--light:not([hidden]) { display: flex; flex-direction: column; }
.imp-bcard--light > .imp-bcard-body { flex: 1 1 auto; display: flex; flex-direction: column; min-width: 0; }
/* Editando, o nome ja esta na barra de ferramentas da janela: o cabecalho que
   o conteudo trouxe some, como o .imp-bcard-head some nas janelas comuns. */
.imp-board.is-editing .imp-bcard--light .imp-bcard-body > .imp-section-head:first-child,
.imp-board.is-editing .imp-bcard--light .imp-bcard-body > * > .imp-section-head:first-child { display: none; }

/* A state line and a note line (21/10/2026 on the /projects board, moved here 04/11/2026 so the board
   and /nfc read ONE definition). .pj-state is what a window says instead of its content: Loading…,
   "Nothing counted yet.", and with .is-err "Could not load …" (colour + the words, never colour alone).
   .pj-note is a quiet line inside a window; .warn is amber, and says what is wrong in words. */
.pj-state { font-size: .84rem; color: var(--muted); line-height: 1.5; margin: 0; }
.pj-state.is-err { color: var(--err-soft); }
.pj-note { font-size: .78rem; color: var(--muted); line-height: 1.5; margin: 0; }
.pj-note b { color: var(--text); font-variant-numeric: tabular-nums; }
.pj-note.warn { color: var(--warn); }

/* Onde tocar (21/10/2026): tres batidas de luz no controle para o qual um
   atalho trouxe a pessoa — o botao dos favoritos em Settings, o Take out by
   photo vindo do /projects. Movimento reduzido: a fundacao corta a animacao. */
.imp-cue { animation: imp-cue 900ms ease-in-out 3; }
@keyframes imp-cue { 50% { box-shadow: 0 0 0 6px rgba(255,45,120,.35); transform: scale(1.04); } }

/* ── Etiqueta de estado (17/10/2026) ─────────────────────────────────────
   OUT, LOW, ESTIMATED, a linha do Schedule C... Era .ex-tag no Expenses e
   .iv-tag no Inventory, a .58rem (~9px no iPhone). Uma so, legivel.       */
.imp-tag { display: inline-flex; align-items: center; font-size: .66rem; font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase; padding: .1rem .4rem; border-radius: 4px;
  border: 1px solid var(--border2); color: var(--muted); vertical-align: 1px; line-height: 1.3; }
.imp-tag.out { color: var(--err); border-color: rgba(248,113,113,.45); }
.imp-tag.low { color: var(--warn); border-color: var(--warn-soft); }
.imp-tag.est { color: var(--info); border-color: rgba(147,197,253,.38); }
/* Ligado / funcionando (21/10/2026, a janela do IMP Investor): verde, e a
   palavra junto — a cor nunca fala sozinha. */
.imp-tag.ok { color: var(--pos); border-color: rgba(74,222,128,.4); }
/* Paper ou Live (21/10/2026, IMP Investor): UMA cor por modo, onde quer que
   apareca — a pilula da pagina, a etiqueta da janela no /projects, a marca
   Live do ledger. Vai junto com .imp-pill ou .imp-tag (a forma) e o
   data-mode diz qual: paper = azul de "pretend", live = rosa cheio de
   "dinheiro de verdade". A palavra vai junto: a cor nunca fala sozinha. */
.imp-mode[data-mode="paper"],
.imp-seg > button[data-mode="paper"][aria-pressed="true"] { color: var(--info); border-color: rgba(147,197,253,.38); background: rgba(147,197,253,.08); }
.imp-mode[data-mode="live"],
.imp-seg > button[data-mode="live"][aria-pressed="true"]  { color: #fff1f1; border-color: rgba(255,45,120,.6); background: rgba(255,45,120,.22); }

/* ── Segmented switch (21/10/2026) ─────────────────────────────────────────
   One pill holding two to four choices: tabs (role=tab + aria-selected), a
   setting (aria-pressed: 300 | 600 DPI) and the EN | PT language switch
   (data-lang-switch, run by static/imp-lang.js). Inventory (.iv-tabs) and
   Trends (.tr-tabs) still carry their own copies of this shape; the next change
   to either moves it here. */
.imp-seg { display: inline-flex; gap: .25rem; padding: .25rem; max-width: 100%;
  border: 1px solid var(--border2); border-radius: var(--imp-r-pill); background: rgba(255,255,255,.03); }
.imp-seg > button { min-height: 34px; padding: .3rem 1rem; border: 0; border-radius: var(--imp-r-pill);
  background: none; color: var(--muted); font-family: var(--font-ui); font-size: .78rem; font-weight: 600;
  white-space: nowrap; cursor: pointer; transition: background-color .15s, color .15s; }
.imp-seg > button[aria-selected="true"], .imp-seg > button[aria-pressed="true"] {
  background: rgba(255,45,120,.16); color: var(--text); }
@media (hover: hover) and (pointer: fine) { .imp-seg > button:hover { color: var(--text); } }
@media (any-pointer: coarse) { .imp-seg > button { min-height: 44px; } }
.imp-seg.imp-seg-sm > button { min-height: 28px; padding: .2rem .7rem; font-size: .7rem; letter-spacing: .04em; }
.imp-seg > button:disabled { opacity: .5; cursor: not-allowed; }
@media (any-pointer: coarse) { .imp-seg.imp-seg-sm > button { min-height: 44px; } }

/* The big switch (22/10/2026, IMP Investor: DEMO | LIVE). Lucas asked for a
   bigger, obvious toggle. Same pill, larger: the word carries the state and
   the chosen side wears the mode's colour from the .imp-mode rules above (one
   colour per mode, wherever it appears). Full width on a phone, two equal
   halves; from 640 px it sizes to its words. Each button carries data-mode. */
.imp-seg.imp-seg-lg { display: flex; width: 100%; gap: .3rem; padding: .3rem; }
.imp-seg.imp-seg-lg > button { flex: 1 1 0; display: inline-flex; align-items: center; justify-content: center;
  gap: .5rem; min-height: 48px; padding: .45rem 1.4rem; border: 1px solid transparent;
  font-size: .95rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; }
@media (min-width: 640px) { .imp-seg.imp-seg-lg { display: inline-flex; width: auto; justify-self: start; align-self: start; }
  .imp-seg.imp-seg-lg > button { flex: 0 0 auto; min-width: 9.5rem; } }

/* The live dot (22/10/2026): a page that updates by itself says so. Green while
   the stream is open, amber while it falls back to asking every few seconds,
   grey when the last answer failed; the word beside it says the same (the colour
   never speaks alone). The page adds .is-beat on every message it receives and
   the ring runs once; reduced motion keeps the colour and drops the ring. */
.imp-live-dot { position: relative; display: inline-block; flex-shrink: 0; width: 8px; height: 8px;
  border-radius: 50%; background: var(--subtle); vertical-align: 1px; }
.imp-live-dot[data-state="live"] { background: var(--pos); }
.imp-live-dot[data-state="polling"] { background: var(--warn); }
.imp-live-dot[data-state="off"] { background: var(--err); }
.imp-live-dot.is-beat::after { content: ''; position: absolute; inset: -1px; border-radius: 50%;
  border: 2px solid currentColor; color: inherit; animation: imp-beat 900ms var(--imp-ease) 1; }
.imp-live-dot[data-state="live"].is-beat::after { color: var(--pos); }
.imp-live-dot[data-state="polling"].is-beat::after { color: var(--warn); }
@keyframes imp-beat { from { transform: scale(1); opacity: .9; } to { transform: scale(2.8); opacity: 0; } }

/* Underline tabs (22/10/2026, Diego on the IMP Investor floors): tabs change
   only what you LOOK at; .imp-seg (the pill) is for a choice that changes
   something (DEMO | LIVE, 300 | 600 DPI). The chosen tab is the brighter word
   with a pink rule under it. role=tab + aria-selected. */
.imp-tabs { display: flex; gap: 1.25rem; border-bottom: 1px solid var(--border); }
.imp-tabs > button { position: relative; min-height: 40px; padding: .35rem .1rem; border: 0; background: none;
  color: var(--muted); font-family: var(--font-ui); font-size: .84rem; font-weight: 600; white-space: nowrap;
  cursor: pointer; transition: color .15s; }
.imp-tabs > button[aria-selected="true"] { color: var(--text); }
.imp-tabs > button[aria-selected="true"]::after { content: ''; position: absolute; left: 0; right: 0; bottom: -1px;
  height: 2px; border-radius: 2px; background: var(--imp-pink); }
@media (hover: hover) and (pointer: fine) { .imp-tabs > button:hover { color: var(--text); } }
@media (any-pointer: coarse) { .imp-tabs > button { min-height: 44px; } }

/* A see-through image shown on the checkerboard every editor uses, so empty
   pixels read as empty, not as black. */
.imp-checker { background-color: #2a2d38;
  background-image: conic-gradient(#363a47 25%, transparent 0 50%, #363a47 0 75%, transparent 0);
  background-size: 12px 12px; }

/* The side panel (22/10/2026, the Investor's desk panel): an .imp-overlay whose
   .imp-dialog docks to the right edge, full height, and slides in from it (a light
   backdrop: what opened it stays visible beside it); under
   640 px it is the whole screen (a sheet). Same open class, backdrop click, Esc
   and sticky action bar (.imp-dialog-stick) as every dialog; only the shape
   changes. The overlay still scrolls, never a box inside it. The dialog is a
   column: give the content flex: 1 and the action bar sits at the foot. */
/* The dialog is as tall as its content, never shorter than the screen (min-height below). With `align-items: stretch`
   it was exactly the screen's height, so a panel with more content than fits showed that content scrolling out of the
   panel and over the backdrop, with no background behind it (found in /nfc, 05/11/2026: a keychain's panel). */
.imp-overlay.imp-side { padding: 0; align-items: flex-start; justify-content: flex-end;
  background: rgba(4,2,8,.45); backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px); }
/* while a side panel is open the page does not scroll (impScrollLock in imp-foundation.js):
   no page scrollbar, so the overlay reaches the right edge in Edge too */
html.imp-locked { overflow: hidden; scrollbar-gutter: auto; }   /* the reserved gutter (html above) would stay
   uncovered: a fixed overlay never paints over it */
.imp-overlay.imp-side > .imp-dialog { display: flex; flex-direction: column; margin: 0; max-width: 440px;
  min-height: 100%; min-height: 100dvh;
  border-radius: var(--imp-r-lg) 0 0 var(--imp-r-lg); border-right: 0;
  animation: imp-side-in 280ms var(--imp-ease) both; }
/* the overlay has no padding here, so the bar sticks to the very bottom of the screen
   (a dialog's -1.5rem would leave the button just under the edge) */
.imp-overlay.imp-side .imp-dialog-stick { bottom: 0; border-radius: 0 0 0 var(--imp-r-lg); }
@keyframes imp-side-in { from { transform: translateX(32px); opacity: 0; } }
@media (max-width: 639.98px) {
  .imp-overlay.imp-side > .imp-dialog { max-width: none; border: 0; border-radius: 0;
    padding-top: max(1.25rem, env(safe-area-inset-top)); }
  .imp-overlay.imp-side .imp-dialog-stick { border-radius: 0; padding-bottom: max(.9rem, env(safe-area-inset-bottom)); }
}
@media (prefers-reduced-motion: reduce) { .imp-overlay.imp-side > .imp-dialog { animation: none; } }
