/* ============================================================
   NORDEN — SLATE
   ============================================================
   A ground-up stylesheet, not an overlay. Nothing here reads a value
   from style.css and nothing here depends on it loading. Shipped as the
   default in index.html on 2026-09-11 — style.css is kept on disk as a
   manual fallback only (see the "visual clássico" toggle in
   Administração, and setSkin('classic') in 01-core.js), never loaded
   alongside this one.

   What's authored fresh: every color, shadow, radius, surface treatment
   and typeface decision. Flat panels, hard 2px corners, Saira Condensed
   carrying titles instead of Barlow.

   The original version of this comment said "no blur/glow anywhere".
   That stopped being true with the texture pass (SLATE-BUILD.md): glass
   and accent bleed are now deliberate, and scoped. The rule that
   replaced it is narrower and still holds — blur and glow only ever
   appear on something that FLOATS (overlay, popover, drawer, drag
   ghost) or on something LIVE (recording, speaking, unsaved). A panel
   sitting still is flat, always. Every effect value lives as a token in
   the block below with a light/dark pair; no component writes an effect
   rgba() literal of its own.

   What's carried forward as an engineering fact, not a design choice:
   layout math that's entangled with JS (the 820px mobile breakpoint —
   hardcoded in 02-state.js/06-tasks.js, not just here — the drawer's
   transform distance, z-index stacking order, gesture transition
   timing). Rewriting a working swipe-to-open drawer "from scratch"
   wouldn't make it look more like Slate, it would just risk breaking a
   gesture that already works. Those values are reproduced exactly;
   everything about how they LOOK is not.
   ============================================================ */

*{box-sizing:border-box;}
html{background:var(--bg);}
body{
  margin:0;padding:0;color:var(--text);font-family:var(--sans);
  -webkit-font-smoothing:antialiased;background:var(--bg);min-height:100vh;
}
a{color:var(--accent);text-decoration:none;}
a:hover{text-decoration:underline;}
img,svg{max-width:100%;}
/* Baseline so a bare <button> never shows native OS chrome — .btn etc.
   below set their own background/border via a class, which always wins
   over this regardless of source order, so this only affects a button
   that truly has no other class (icon-only ones like the mobile header's
   bell/hamburger). Without it those render as a light OS-default pill. */
button{font-family:var(--sans);cursor:pointer;background:none;border:none;color:inherit;appearance:none;-webkit-appearance:none;padding:0;}
/* 23 — detalhes de um pixel. A parte da interface que o navegador pinta
   sozinho (seleção azul, cursor branco, barra cinza) é justamente a que
   aparece o dia inteiro, em toda tela, em todo texto que alguém copia
   pra mandar pro cliente. Aqui ela passa a ser do tema. */
::selection{background:var(--selection-bg);color:var(--selection-ink);}
input,textarea,[contenteditable]{caret-color:var(--caret);}
::-webkit-scrollbar{width:6px;height:6px;}
::-webkit-scrollbar-thumb{background:var(--scroll-thumb);border-radius:var(--radius-sm);}
::-webkit-scrollbar-thumb:hover{background:var(--accent);}
::-webkit-scrollbar-track{background:transparent;}
/* Firefox: scrollbar-color é herdado, então declarar no html basta. */
html{scrollbar-color:var(--scroll-thumb) transparent;scrollbar-width:thin;}
:focus-visible{outline:2px solid var(--accent);outline-offset:1px;}
h1,h2,h3,h4,h5,h6{margin:0;font-family:var(--display);font-weight:700;}

/* ============================================================
   TOKENS
   ============================================================ */
:root{
  /* -- palette: warm paper/ink, not cool near-black. Same accent red as
     the brand always used — the neutral is what's being redesigned,
     not the identity color. -- */
  --bg:#0C0C0B; --panel:#131312; --panel2:#191918; --panel3:#232321;
  --panel-rgb:19,19,18; --panel2-rgb:25,25,24;
  --border:#3A3A36; --border-soft:#262623;
  --text:#F2EFE7; --text-dim:#A6A29A; --text-faint:#7C7871;
  --accent:#EC2027; --accent-dim:#B81920; --accent-rgb:236,32,39;

  --good:#6FCF97; --good-bg:#1C2A20; --good-rgb:111,207,151;
  --warn:#F2A93B; --warn-bg:#2E2515; --warn-rgb:242,169,59;
  --danger:#EB6B5E; --danger-bg:#2E1C18; --danger-rgb:235,107,94;
  --info:#5AA9E6; --info-bg:#16232E; --info-rgb:90,169,230;
  --violet:#A48CE0; --violet-rgb:164,140,224; --violet-bg:#221D2E;
  --shadow-rgb:0,0,0;

  /* -- geometry: one radius, everywhere. A single value reads as a
     system; the several-nearby-values a "modern SaaS" default carries
     reads as an accident. -- */
  --radius:2px; --radius-sm:1px; --radius-lg:2px; --radius-pill:2px;

  /* -- type: Saira Condensed carries titles/labels/nav — the one
     typographic move that does the most identity work, on purpose,
     everywhere a title/label/badge/button appears. Noto Sans stays for
     anything the USER wrote (task text, email body, comments) — caps
     only where the system is talking, never where a person is. -- */
  --sans:'Noto Sans',system-ui,-apple-system,sans-serif;
  --display:'Saira Condensed','Arial Narrow',sans-serif;
  --mono:'JetBrains Mono',ui-monospace,Consolas,monospace;

  /* Control heights. Anything that can sit on the same line as anything
     else uses --ctl-h, so a button beside an input lines up instead of
     floating 4px short. Three sizes total, no ad-hoc numbers: the
     scattered 24/26/32/36/auto mix is what read as amateurish. */
  --ctl-h:34px; --ctl-h-sm:28px; --ctl-h-xs:22px;

  --fs-9:9px; --fs-10:10px; --fs-11:11px; --fs-12:12px; --fs-14:14px;
  --fs-15:15px; --fs-16:16px; --fs-18:18px; --fs-20:20px; --fs-24:24px; --fs-28:28px;

  /* -- spacing/z-index: mechanical rhythm and stacking order, not a
     look — kept numerically identical to what the rest of the app's
     layout math (mobile drawer, popover positions) already assumes. -- */
  --space-2:2px; --space-4:4px; --space-6:6px; --space-8:8px; --space-10:10px;
  --space-12:12px; --space-14:14px; --space-16:16px; --space-18:18px; --space-20:20px;
  --space-24:24px; --space-28:28px; --space-32:32px; --space-40:40px;
  --space-60:60px; --space-80:80px;

  /* -- rhythm scale: four steps, each with one job, so grouping reads at
     a glance instead of everything sitting at one middling gap. Distinct
     from --space-N above (that's mechanical layout math JS depends on);
     these are a design decision, applied where structure needs it. -- */
  --sp-1:6px;  /* label → its control */
  --sp-2:12px; /* field → field */
  --sp-3:20px; /* block → block */
  --sp-4:32px; /* section → section */

  /* -- motion: two timing profiles cover everything (§4). "peso" for
     modal/toast/menu/controls; "deslize" for the tab underline and the
     sidebar's active-item sweep. Hold-to-delete is the one deliberate
     exception (1400ms linear, hardcoded at its own call site — it
     represents real elapsed hold time, so it can't ride either profile). -- */
  --mo-peso-in:320ms;  --mo-peso-out:220ms;
  --mo-peso-ez:cubic-bezier(.16,.84,.24,1);
  --mo-peso-travel:12px; --mo-peso-scale:.985;

  --mo-desl-in:240ms;  --mo-desl-out:170ms;
  --mo-desl-ez:cubic-bezier(.2,.8,.2,1);
  --mo-desl-travel:6px;

  --z-dropdown:20; --z-mobile-header:40; --z-mobile-edge-swipe:39;
  --z-mobile-nav-backdrop:45; --z-mobile-drawer:50; --z-popover:60;
  --z-floating-widget:80; --z-modal-backdrop:100; --z-priority-banner:150;
  --z-above-modal:200; --z-status-indicator:210; --z-drag:300;
  --z-toast:400; --z-update-banner:500; --z-grain:9998; --z-splash:9999;

  --input-color-scheme:dark;

  /* ============================================================
     EFEITOS — tokens da passada de textura (SLATE-BUILD.md, fase 0).
     Geometria e tempo moram aqui em cima e valem pros dois temas; cor
     e alfa são redefinidos no bloco do tema claro. Um efeito que não
     tiver par claro aqui vira dívida de tema claro na hora que a fase
     1 ou 2 desenhar com ele, então todo valor entra aos pares.
     ============================================================ */

  /* grão de emulsão (01·B) — véu fixo em body::before, por cima de tudo.
     A demo aprovada roda .6 de opacidade e vinheta .66 num cartão de uns
     220px. Espalhado numa viewport inteira aquilo vira névoa, então o que
     está aqui é a mesma emulsão em escala de tela. São só estes dois
     números: subir pro nível exato da demo é editar esta linha. */
  --grain-opacity:.015; --grain-tile:128px; --grain-drift:3.4s;

  /* luz de borda, bisel (02·B) — fio claro no topo, sombra na base, anel
     escuro em volta. --bevel é a composição pronta: quem precisa somar
     outra sombra (.card-selected) escreve a sua e depois var(--bevel),
     em vez de reescrever os três valores e sair do padrão sem querer. */
  --edge-light:rgba(255,255,255,.10); --edge-shade:rgba(0,0,0,.60);
  --edge-ring:rgba(0,0,0,.34);
  --edge-wash:linear-gradient(180deg,rgba(255,255,255,.045),rgba(0,0,0,.06));
  --bevel:inset 0 1px 0 var(--edge-light),inset 0 -1px 0 var(--edge-shade),0 0 0 1px var(--edge-ring);

  /* hachura de ardósia (09) — fundo de vazio e de thumb sem imagem */
  --hatch-ink:rgba(255,255,255,.024); --hatch-angle:135deg;
  --hatch-band:6px; --hatch-period:13px;
  --hatch:repeating-linear-gradient(var(--hatch-angle),var(--hatch-ink) 0 var(--hatch-band),transparent var(--hatch-band) var(--hatch-period));
  --hatch-inner:inset 0 0 44px -14px rgba(var(--shadow-rgb),.95);

  /* marcas de corte (05·B) — quatro cantos no hover/seleção do cartão */
  --crop-ink:var(--accent); --crop-len:10px; --crop-w:1.5px; --crop-inset:3px;

  /* régua de leitura (35) — a linha sob o cursor puxa o olho pra direita
     e some em 62%, em vez de acender o retângulo inteiro */
  --rule-edge:inset 2px 0 0 var(--accent);
  --rule-wash:linear-gradient(90deg,rgba(var(--accent-rgb),.11),transparent 62%);

  /* detalhes de um pixel (23) — seleção, cursor e barra de rolagem */
  --selection-bg:var(--accent); --selection-ink:#FFFFFF;
  --caret:var(--accent); --scroll-thumb:var(--accent-dim);

  /* peso em 4 camadas (04·A). Não é uma sombra borrada: é anel duro de
     1px, lábio de 2px e duas quedas longas. Isso lê como peso; um halo
     desfocado lê como PowerPoint. Raio continua zero.
     1 repouso · 2 popover/toast · 3 modal · 4 arrasto (14).
     A geometria vale pros dois temas; só o alfa muda, e a cor sai de
     --shadow-rgb, que no claro é marrom e não preto. */
  --shadow-ring:.60; --shadow-lip:.50; --shadow-fall1:.85; --shadow-fall2:.90;
  --shadow-1:0 0 0 1px rgba(var(--shadow-rgb),var(--shadow-ring)),0 2px 0 rgba(var(--shadow-rgb),var(--shadow-lip));
  --shadow-2:var(--shadow-1),0 10px 24px -14px rgba(var(--shadow-rgb),var(--shadow-fall1));
  --shadow-3:var(--shadow-1),0 22px 46px -14px rgba(var(--shadow-rgb),var(--shadow-fall1)),0 44px 90px -40px rgba(var(--shadow-rgb),var(--shadow-fall2));
  --shadow-4:0 0 0 1px var(--border),0 20px 34px -14px rgba(var(--shadow-rgb),var(--shadow-fall2));

  /* vidro 6px (03·B) — só em coisa que flutua (overlay, popover, drawer),
     nunca num painel parado. --panel-rgb já muda sozinho por tema. */
  --glass-blur:6px; --glass-alpha:.92;
  --glass-bg:rgba(var(--panel-rgb),var(--glass-alpha));
  /* o escurecedor atrás de modal e drawer: menos preto que antes, porque
     agora o desfoque também separa o fundo do primeiro plano */
  --scrim-bg:rgba(8,8,7,.68); --scrim-blur:4px;

  /* brilho e sangria (06·A) — a única fonte de glow do tema, só em
     estado vivo (gravando, falando, item ativo da sidebar) */
  --glow-a:.42; --glow-a-soft:.18;
  --glow-accent:0 0 12px rgba(var(--accent-rgb),var(--glow-a));
  --glow-accent-soft:0 0 20px rgba(var(--accent-rgb),var(--glow-a-soft));

  /* varredura que preenche (07·B) — anda em background-size, então não
     briga com o .hold-fill do .btn-icon, que anda em width */
  --sweep-ink:rgba(255,255,255,.10); --sweep-dur:620ms;

  /* cronômetro do toast (15) — TEM que casar com o setTimeout(dismiss)
     de toast() em 02-state.js. Mudou aqui, muda lá. */
  --toast-dur:5000ms;

  /* marca d'agua do vazio (11) */
  --watermark-a:.05;
}
:root[data-theme="light"]{
  /* "cal" (44·A) — papel caiado, não branco de escritório. O neutro é
     quente, mesma família do escuro virada do avesso: por isso o texto
     é #171511 e não preto, e a sombra é marrom e não azul. Os tons de
     estado mantêm a cor de frente que já passava no contraste; só o
     fundo deles foi puxado pro papel, senão hortelã e azul-bebê ficam
     boiando por cima do creme. */
  --bg:#E7E2D4; --panel:#F6F2E6; --panel2:#EFE9DA; --panel3:#E1DAC7;
  --panel-rgb:246,242,230; --panel2-rgb:239,233,218;
  --border:#BCB4A0; --border-soft:#D5CDB9;
  --text:#171511; --text-dim:#4A463C; --text-faint:#6E6A5E;
  --accent:#C22A24; --accent-dim:#9C1F1A; --accent-rgb:194,42,36;
  --good:#2F7A46; --good-bg:#DCEBDB; --good-rgb:47,122,70;
  --warn:#966319; --warn-bg:#F4E7CB; --warn-rgb:150,99,25;
  --danger:#BB3A2C; --danger-bg:#F4DED7; --danger-rgb:187,58,44;
  --info:#2265A3; --info-bg:#DBE6EE; --info-rgb:34,101,163;
  --violet:#6E58B0; --violet-rgb:110,88,176; --violet-bg:#E3DEEE;
  --shadow-rgb:58,50,34;

  /* -- efeitos: mesma geometria do escuro, cor e alfa refeitos pro papel.
     No claro a luz de borda é branco quase opaco (e não um branco de 6%
     que some), a hachura e a régua viram tinta marrom em vez de tinta
     clara, e o peso das sombras cai pela metade — papel não projeta a
     mesma sombra que ardósia. -- */
  --grain-opacity:.015;
  --edge-light:rgba(255,255,255,.90); --edge-shade:rgba(58,50,34,.22);
  --edge-ring:rgba(58,50,34,.13);
  --edge-wash:linear-gradient(180deg,rgba(255,255,255,.55),rgba(58,50,34,.035));
  --hatch-ink:rgba(58,50,34,.055);
  --hatch-inner:inset 0 0 44px -16px rgba(var(--shadow-rgb),.38);
  --shadow-ring:.14; --shadow-lip:.10; --shadow-fall1:.22; --shadow-fall2:.26;
  --glass-alpha:.94;
  --glow-a:.26; --glow-a-soft:.12;
  --sweep-ink:rgba(255,255,255,.55);
  --scrim-bg:rgba(62,54,38,.42);
  --watermark-a:.07;

  --input-color-scheme:light;
}

/* ============================================================
   UTILITIES — pure spacing/text plumbing, not a design decision.
   Carried at the same numeric values as the app's spacing scale above
   since hundreds of render() calls already lay out around them.
   ============================================================ */
.row{display:flex;gap:var(--space-10);flex-wrap:wrap;align-items:center;}
.row-nowrap{flex-wrap:nowrap;}
.row-between{justify-content:space-between;}
.row-end{justify-content:flex-end;}
.row-center{justify-content:center;}
.align-start{align-items:flex-start;}
.spacer{flex:1;}
.flex-1{flex:1;}
.flex-shrink-0{flex-shrink:0;}
.self-end{align-self:flex-end;}
.relative{position:relative;}
.hidden{display:none !important;}
.pre-wrap{white-space:pre-wrap;}
.truncate{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.gap-6{gap:var(--space-6);} .gap-8{gap:var(--space-8);} .gap-12{gap:var(--space-12);}
.gap-16{gap:var(--space-16);} .gap-18{gap:var(--space-18);} .gap-20{gap:var(--space-20);}
.mr-8{margin-right:var(--space-8) !important;}
.text-right{text-align:right !important;}
.text-base{color:var(--text) !important;} .text-dim{color:var(--text-dim) !important;}
.text-faint{color:var(--text-faint) !important;} .text-danger{color:var(--danger) !important;}
.text-good{color:var(--good) !important;} .text-warn{color:var(--warn) !important;}
.text-accent{color:var(--accent) !important;}
.fs-12-5{font-size:var(--fs-12) !important;}
.line-through{text-decoration:line-through;}
.min-w-0{min-width:0;}
.w-100{width:100%;} .w-70{width:70px;}
.max-w-220{max-width:220px;} .max-w-240{max-width:240px;} .max-w-560{max-width:560px;}
.col-100{width:100px;} .col-120{width:120px;} .col-160{width:160px;}
.cursor-pointer{cursor:pointer;}
.nowrap{white-space:nowrap;}
.m0{margin:0 !important;}
.mt-0{margin-top:0 !important;} .mt-2{margin-top:var(--space-2) !important;}
.mt-4{margin-top:var(--space-4) !important;} .mt-6{margin-top:var(--space-6) !important;}
.mt-8{margin-top:var(--space-8) !important;} .mt-10{margin-top:var(--space-10) !important;}
.mt-12{margin-top:var(--space-12) !important;} .mt-14{margin-top:var(--space-14) !important;}
.mt-16{margin-top:var(--space-16) !important;} .mt-20{margin-top:var(--space-20) !important;}
.mt-24{margin-top:var(--space-24) !important;} .mt-26{margin-top:var(--space-28) !important;}
.mb-0{margin-bottom:0 !important;} .mb-2{margin-bottom:var(--space-2) !important;}
.mb-3{margin-bottom:var(--space-4) !important;} .mb-4{margin-bottom:var(--space-4) !important;}
.mb-6{margin-bottom:var(--space-6) !important;} .mb-8{margin-bottom:var(--space-8) !important;}
.mb-10{margin-bottom:var(--space-10) !important;} .mb-12{margin-bottom:var(--space-12) !important;}
.mb-14{margin-bottom:var(--space-14) !important;} .mb-16{margin-bottom:var(--space-16) !important;}
.mb-18{margin-bottom:var(--space-18) !important;} .mb-20{margin-bottom:var(--space-20) !important;}
.mb-26{margin-bottom:var(--space-28) !important;}
.ml-auto{margin-left:auto !important;}
.py-16{padding-top:var(--space-16) !important;padding-bottom:var(--space-16) !important;}
.px-16{padding-left:var(--space-16) !important;padding-right:var(--space-16) !important;}
.fw-500{font-weight:500;} .fw-600{font-weight:600;} .fw-700{font-weight:700;}
.fs-9{font-size:var(--fs-9) !important;} .fs-10{font-size:var(--fs-10) !important;}
.fs-11{font-size:var(--fs-11) !important;} .fs-12{font-size:var(--fs-12) !important;}
.fs-14{font-size:var(--fs-14) !important;} .fs-18{font-size:var(--fs-18) !important;}
.link-accent{color:var(--accent);font-size:var(--fs-11);cursor:pointer;}
.section-summary{cursor:pointer;font-family:var(--display);text-transform:uppercase;letter-spacing:.8px;font-size:var(--fs-12);color:var(--text-dim);margin-bottom:var(--space-10);}
.section-title{font-family:var(--display);font-weight:700;font-size:var(--fs-14);text-transform:uppercase;letter-spacing:1.1px;color:var(--text-dim);margin:var(--sp-4) 0 var(--space-12);}
.hint{font-size:var(--fs-11);color:var(--text-faint);margin-top:var(--space-4);}
label{font-family:var(--display);font-size:var(--fs-10);text-transform:uppercase;letter-spacing:.9px;color:var(--text-faint);font-weight:700;display:block;margin:var(--space-2) 0 var(--space-6);}

/* ============================================================
   APP SHELL
   ============================================================ */
.app{display:flex;align-items:stretch;min-height:100vh;}
.app-watermark{position:fixed;inset:0;z-index:0;overflow:hidden;pointer-events:none;}
.app-watermark svg,.app-watermark img{position:absolute;right:-7vw;bottom:-9vh;width:min(38vw,460px);height:auto;opacity:.04;transform:rotate(6deg);}
.main{flex:1;min-width:0;position:relative;z-index:1;}
.main-inner{max-width:1180px;margin:0 auto;padding:var(--space-28) var(--space-28) var(--space-80);}
.main-inner-wide{max-width:none;}

.sidebar{
  width:236px;flex-shrink:0;background:var(--panel);border-right:1px solid var(--border-soft);
  display:flex;flex-direction:column;padding:var(--space-20) var(--space-14);
  position:sticky;top:0;height:100vh;z-index:2;
}
.sidebar-brand{display:flex;align-items:center;justify-content:space-between;padding:var(--space-4) var(--space-4) var(--space-24);}
.sidebar-logo{height:30px;width:auto;flex-shrink:0;}
.sidebar-logo svg{height:100%;width:auto;display:block;}
/* Scrolling lives here, not on .sidebar itself — overflow-y:auto on .sidebar
   (the alert panel's own ancestor, via .sidebar-brand) clips ANY child that
   visually extends past its box no matter the z-index, which is exactly
   what was cutting the alert popover off. min-height:0 is required for a
   flex:1 child to actually shrink and scroll instead of stretching .sidebar
   past 100vh. */
.sidebar-nav{display:flex;flex-direction:column;gap:var(--space-4);flex:1;min-height:0;overflow-y:auto;position:relative;}
.sidebar-group{display:flex;flex-direction:column;}
.sidebar-divider{height:1px;background:var(--border-soft);margin:var(--space-14) var(--space-4);flex-shrink:0;}
.sidebar-footer{margin-top:auto;padding-top:var(--space-16);border-top:1px solid var(--border-soft);display:flex;flex-direction:column;gap:var(--space-12);flex-shrink:0;}
/* 31 — salvando / salvo. É o texto mais lido do app e estava com cara de
   nota de rodapé. Caixa-alta, mono, um quadrado âmbar enquanto escreve e
   verde quando termina, mais a hora de verdade. Confiança se constrói num
   widget que ninguém olha de propósito. */
.savebadge{font-size:var(--fs-10);color:var(--text-faint);font-family:var(--mono);display:flex;align-items:center;gap:var(--space-6);text-transform:uppercase;letter-spacing:.4px;}
.savebadge .sq{width:7px;height:7px;flex-shrink:0;display:block;background:var(--good);}
.savebadge .sq.warn{background:var(--warn);animation:blinkSq 1s steps(2) infinite;}
.savebadge .sq.bad{background:var(--danger);}
.savebadge .hora{color:var(--text-dim);}
@keyframes blinkSq{50%{opacity:.25;}}

.sidenav-item{
  position:relative;display:flex;align-items:center;gap:var(--space-10);
  background:none;border:none;color:var(--text-dim);padding:var(--space-8) var(--space-10);
  border-radius:var(--radius);font-size:var(--fs-12);font-weight:500;
  text-align:left;text-decoration:none;width:100%;white-space:nowrap;
  transition:background .12s ease,color .12s ease;
  overflow:hidden;
}
.sidenav-item:not(.active):hover{background:var(--panel2);color:var(--text);}
/* Item ativo, deslize profile: Varredura. The item's own background lives
   on .fillw instead of the item itself, so switching to it can sweep in
   (scaleX 0→1, hard edge, no wave) rather than just appearing — a plain
   CSS transition can't do this because the sidebar only rebuilds (and
   .active only lands) when the tab actually changes, so this has to
   replay as a keyframe animation on mount, same reasoning as the tab
   underline's FLIP above. Every other direct child gets stacked above it. */
.sidenav-item .fillw{position:absolute;inset:0;background:var(--panel3);transform:scaleX(0);transform-origin:left;z-index:0;}
.sidenav-item.active .fillw{animation:sidenavSweep var(--mo-desl-in) var(--mo-desl-ez) forwards;}
.sidenav-item>:not(.fillw){position:relative;z-index:1;}
@keyframes sidenavSweep{to{transform:scaleX(1);}}
/* Option B from the kit review: solid fill one step up + a hard bar
   flush against the sidebar's own true edge (left:-14px = the sidebar's
   horizontal padding, so the bar lands exactly at the browser-rendered
   edge, not floating inset inside the item). Text stays --text, not
   accent — only the icon and the bar carry the color, which is why it
   reads as "selected" rather than "this row is red". The bar grows
   0→4px alongside the sweep above instead of appearing at full width. */
.sidenav-item.active{color:var(--text);font-weight:700;}
/* 06·A — sangria. A barra de acento já existia; agora ela vaza pra
   superfície: lavada horizontal que some em 78% mais uma queda interna
   vermelha. Um elemento aceso na tela inteira, então continua sendo
   sinal e não decoração.
   ATENÇÃO: sidenavBarGrow anima box-shadow com forwards, ou seja o
   estado final é o do keyframe. Os DOIS insets têm que estar no keyframe
   também, senão a queda interna some assim que a animação termina. */
.sidenav-item.active:not(.sidenav-subitem){
  box-shadow:inset 0 0 0 var(--accent),inset 0 0 26px -10px rgba(var(--accent-rgb),var(--glow-a));
  animation:sidenavBarGrow var(--mo-desl-in) var(--mo-desl-ez) forwards;
  margin-left:-14px;padding-left:calc(var(--space-10) + 14px);
  width:calc(100% + 14px);
}
.sidenav-item.active:not(.sidenav-subitem) .fillw{
  background:linear-gradient(90deg,rgba(var(--accent-rgb),.16),transparent 78%),var(--panel3);
}
@keyframes sidenavBarGrow{to{box-shadow:inset 4px 0 0 var(--accent),inset 0 0 26px -10px rgba(var(--accent-rgb),var(--glow-a));}}
.sidenav-item.active .nav-icon{color:var(--accent);}
.sidenav-item.voz-live{color:var(--accent);}
.sidenav-label{overflow:hidden;text-overflow:ellipsis;}
/* Plain right-aligned count, not a .tag/.badge pill — matches the artifact's
   sidebar exactly (its .cnt is bare mono text, no border/dot/background).
   Accent instead of the artifact's --faint since this one flags unseen
   items needing a look, not a static total. */
.sidenav-count{margin-left:auto;font-family:var(--mono);font-size:var(--fs-10);color:var(--accent);flex-shrink:0;padding-left:var(--space-6);}
.sidenav-chevron{margin-left:auto;color:var(--text-faint);font-size:var(--fs-16);line-height:1;transition:transform .15s ease;flex-shrink:0;}
.sidenav-chevron.open{transform:rotate(90deg);}
.sidenav-subnav{display:flex;flex-direction:column;gap:var(--space-4);margin:var(--space-4) 0 var(--space-6) var(--space-28);padding-left:var(--space-12);border-left:1px solid var(--border-soft);}
/* animateSubnav() (02-state.js) drives this container's height as a raw px
   value mid-animation, always shorter than its natural content height until
   the very last frame. Flex items default to flex-shrink:1, so without this
   the buttons themselves compressed to fit the shrinking box — squashing
   their padding and reading as "items too close together" — then jumped
   back to full size the instant the animation finished and height snapped
   to auto. Pinning children to their natural size means the animating
   height just reveals/clips them via the container's overflow:hidden
   instead, so spacing looks right throughout. */
.sidenav-subnav>*{flex-shrink:0;}

.nav-icon{display:inline-flex;width:18px;height:18px;flex-shrink:0;}
.nav-icon-sm{width:18px;height:18px;} .nav-icon-xs{width:14px;height:14px;}
.nav-icon-wrap{position:relative;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;}
.nav-icon svg{width:100%;height:100%;display:block;}
.nav-icon svg path:not([style*="fill:none" i]),.nav-icon svg g:not([style*="fill:none" i]){fill:currentColor;}
.nav-icon svg [style*="fill:none" i]{stroke:currentColor;}

.mobile-header{display:none;}
.mobile-nav-backdrop{display:none;}
.mobile-edge-swipe-zone{display:none;}

/* Mobile: sidebar becomes an off-canvas drawer; header collapses to a
   floating circle past a scroll threshold. Positions/transforms/timing
   preserved as-is — this is gesture code (see sidebarEdgePointerDown in
   02-state.js), not a look. */
@media(max-width:820px){
  .app{flex-direction:column;min-height:0;padding-top:var(--space-60);}
  .mobile-header{
    display:flex;align-items:center;gap:var(--space-12);
    position:fixed;top:0;left:0;right:0;z-index:var(--z-mobile-header);
    background:var(--panel);border-bottom:1px solid var(--border-soft);
    padding:var(--space-14) var(--space-16);
    transition:top .25s ease,left .25s ease,right .25s ease,width .25s ease,height .25s ease,
               padding .25s ease,border-radius .25s ease,border-color .25s ease;
  }
  .mobile-header.scrolled{
    top:14px;left:14px;right:auto;width:48px;height:48px;padding:0;
    border-radius:50%;border:1px solid var(--border);justify-content:center;
  }
  .mobile-header-logo{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);height:20px;width:auto;max-width:140px;overflow:hidden;transition:opacity .15s ease,max-width .2s ease;background:none;border:none;padding:0;cursor:pointer;}
  .mobile-header-logo svg{height:100%;width:auto;display:block;}
  .mobile-header.scrolled .mobile-header-logo{opacity:0;max-width:0;pointer-events:none;}
  .mobile-header-alert-wrap{position:relative;flex-shrink:0;margin-left:auto;}
  .mobile-header-alert-btn{display:flex;justify-content:center;align-items:center;width:32px;height:32px;background:none;border:none;padding:0;flex-shrink:0;color:var(--text);cursor:pointer;position:relative;}
  .mobile-header-alert-btn .nav-icon{width:20px;height:20px;}
  .mobile-header-alert-panel{position:absolute;top:100%;right:0;left:auto;}
  .mobile-header.scrolled .mobile-header-alert-wrap{display:none;}
  .mobile-hamburger{display:flex;justify-content:center;align-items:center;width:32px;height:32px;background:none;border:none;padding:0;flex-shrink:0;color:var(--text);font-size:var(--fs-24);line-height:1;}
  .mobile-hamburger svg{display:block;}

  .sidebar{
    position:fixed;top:0;left:0;bottom:0;width:280px;max-width:82vw;height:100vh;
    flex-direction:column;align-items:stretch;
    padding:var(--space-24) var(--space-18);
    transform:translateX(-100%);transition:transform .25s ease;
    z-index:var(--z-mobile-drawer);border-right:1px solid var(--border-soft);
    touch-action:pan-y;
  }
  .sidebar.mobile-open{transform:translateX(0);}
  .sidebar-brand{padding:var(--space-4) var(--space-6) var(--space-28);flex-shrink:0;}
  /* The mobile header has its own bell (.mobile-header-alert-wrap) — this
     one lives inside the off-canvas drawer, which sits translated fully
     off-screen while closed. Both share the same sidebarAlertPanelOpen
     state and open together, so with the drawer closed its popover (now
     anchored left, growing rightward — see .sidebar-alert-wrap
     .sidebar-alert-panel) landed just wide enough to peek back onto the
     visible screen, overlapping the mobile header's own panel. Hiding this
     copy at the same breakpoint the drawer becomes off-canvas removes the
     duplicate control entirely instead of chasing its position. */
  .sidebar-alert-wrap{display:none;}
  .sidebar-footer{border-left:none;padding-left:0;}
  .sidenav-item{padding:var(--space-8) var(--space-12);font-size:var(--fs-12);}

  .mobile-nav-backdrop{
    display:block;position:fixed;inset:0;background:rgba(0,0,0,0);z-index:var(--z-mobile-nav-backdrop);
    opacity:0;pointer-events:none;transition:opacity .25s ease,background-color .25s ease;
  }
  .mobile-nav-backdrop.open{background:var(--scrim-bg);backdrop-filter:blur(var(--scrim-blur));-webkit-backdrop-filter:blur(var(--scrim-blur));opacity:1;pointer-events:auto;}
  .mobile-edge-swipe-zone{
    display:block;position:fixed;top:0;left:0;bottom:0;width:24px;
    z-index:var(--z-mobile-edge-swipe);touch-action:pan-y;
  }
  .main-inner{padding:var(--space-16);}
}

/* ============================================================
   BUTTONS — flat, bordered, Saira caps. No gradient, no glow.
   ============================================================ */
.btn{
  display:inline-flex;align-items:center;gap:var(--space-6);height:var(--ctl-h);
  padding:0 var(--space-14);border-radius:var(--radius);
  background:var(--panel2);color:var(--text);
  font-family:var(--display);font-weight:700;text-transform:uppercase;letter-spacing:.7px;
  font-size:var(--fs-11);cursor:pointer;white-space:nowrap;
  transition:background .12s ease,border-color .12s ease,transform 80ms ease;
  box-shadow:var(--bevel);
  /* 07·B varredura: a camada de cima cresce 0%→100% em background-size,
     e por isso não encosta no .hold-fill do .btn-icon, que anda em width.
     A segunda camada é o bisel do 02·B, parada em 100%. */
  background-image:linear-gradient(90deg,var(--panel3),var(--panel3)),var(--edge-wash);
  background-size:0% 100%,100% 100%;
  background-repeat:no-repeat,repeat;
  transition:background-size var(--mo-desl-in) var(--mo-desl-ez),border-color .12s ease,transform 80ms ease;
}
.btn:hover{border-color:var(--text-faint);background-size:100% 100%,100% 100%;}
/* Physical feedback, not a transition profile — stays outside peso/deslize
   on purpose (§4 of the motion spec). */
.btn:active{transform:translateY(1px);}
.btn:disabled{opacity:.5;cursor:default;pointer-events:none;}
.btn-accent{background:var(--accent);border-color:var(--accent);color:#fff;box-shadow:var(--bevel),var(--glow-accent-soft);}
/* o .btn-accent zera background-image no shorthand acima, então a
   varredura do 07·B precisa ser redeclarada aqui na cor dele */
.btn-accent{background-image:linear-gradient(90deg,var(--accent-dim),var(--accent-dim));background-size:0% 100%;background-repeat:no-repeat;}
.btn-accent:hover{background-color:var(--accent);border-color:var(--accent-dim);background-size:100% 100%;}
.btn-sm{height:var(--ctl-h-sm);padding:0 var(--space-10);font-size:var(--fs-10);}
.btn-xs{height:var(--ctl-h-xs);padding:0 var(--space-8);font-size:var(--fs-9);}
.btn-icon{width:var(--ctl-h);height:var(--ctl-h);padding:0;justify-content:center;position:relative;overflow:hidden;}
.btn-sm.btn-icon,.btn-icon.btn-sm{width:var(--ctl-h-sm);height:var(--ctl-h-sm);}
.drive-file-actions .btn-icon{width:var(--ctl-h-sm);height:var(--ctl-h-sm);}
.dpp-node-row .btn-icon{width:var(--ctl-h-sm);height:var(--ctl-h-sm);flex-shrink:0;}
.btn-danger{color:var(--danger);border-color:var(--border);}
.btn-danger:hover{border-color:var(--danger);}
/* Icon-only delete trigger — full accent fill + white icon at rest, not
   just a tinted icon on a neutral button, so it reads as the one truly
   destructive control in a row of otherwise-neutral icon buttons. */
.btn-icon.btn-danger{background:var(--accent);border-color:var(--accent);color:#fff;}
.btn-icon.btn-danger:hover{background:var(--accent-dim);border-color:var(--accent-dim);}
/* Hold-to-delete's own fill on the small trigger button — a secondary echo
   of the big centered overlay's progress, in case a glance stays on the
   button itself. .nav-icon needs its own stacking context here since the
   fill span is appended to the DOM (and therefore painted) after it. */
.btn-icon .nav-icon{position:relative;z-index:1;}
.btn-icon .hold-fill{position:absolute;left:0;right:0;bottom:0;height:0%;background:var(--danger);z-index:0;pointer-events:none;}
.btn-icon.holding{border-color:var(--danger);}

/* ============================================================
   FORM CONTROLS
   ============================================================ */
input[type=text],input[type=number],input[type=date],input[type=time],
input[type=url],input[type=email],input[type=password],select,textarea{
  background:var(--panel2);border:1px solid var(--border);color:var(--text);
  padding:var(--space-10) var(--space-12);border-radius:var(--radius);
  font-family:var(--sans);font-size:var(--fs-12);width:100%;height:var(--ctl-h);
  transition:border-color .12s ease;
  color-scheme:var(--input-color-scheme);
}
input,select,textarea{font-family:var(--sans);}
textarea{height:auto;resize:vertical;}
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--accent-dim);box-shadow:0 0 0 3px rgba(var(--accent-rgb),.16);}
input:disabled,select:disabled,textarea:disabled{opacity:.5;cursor:default;}
input[type=color]{width:44px;height:var(--ctl-h);padding:2px;border-radius:var(--radius);}
input[type=color]::-webkit-color-swatch-wrapper{padding:0;}
input[type=color]::-webkit-color-swatch{border:none;border-radius:1px;}
input[type="checkbox"]{
  appearance:none;width:34px;height:19px;border-radius:var(--radius-pill);
  background:var(--panel3);border:1px solid var(--border);position:relative;
  cursor:pointer;flex-shrink:0;transition:background var(--mo-peso-in) var(--mo-peso-ez),border-color var(--mo-peso-in) var(--mo-peso-ez);
}
/* Controles/peso: a native :checked flip is a direct attribute change, not
   a JS remove-class/reflow/add-class replay, so a transition (unlike the
   sidebar's Varredura or the tab underline) plays reliably every time —
   keyframes are reserved below for the cases that actually need a replay. */
input[type="checkbox"]::before{
  content:'';position:absolute;top:1px;left:1px;width:15px;height:15px;
  border-radius:1px;background:var(--text-faint);transition:left var(--mo-peso-in) var(--mo-peso-ez),background var(--mo-peso-in) var(--mo-peso-ez);
}
input[type="checkbox"]:checked{background:rgba(var(--accent-rgb),.14);border-color:var(--accent);}
input[type="checkbox"]:checked::before{left:16px;background:var(--accent);}
input[type="checkbox"]:focus-visible{box-shadow:0 0 0 3px rgba(var(--accent-rgb),.25);}
input[type="checkbox"]:disabled{opacity:.5;cursor:default;pointer-events:none;}
.checkbox-row{display:flex;align-items:center;gap:var(--space-8);cursor:pointer;}
.checkbox-row label{margin:0;text-transform:none;letter-spacing:0;font-family:var(--sans);font-size:var(--fs-12);color:var(--text);font-weight:400;}

.filters{display:flex;align-items:center;gap:var(--space-8);flex-wrap:wrap;margin-bottom:var(--space-28);padding-bottom:var(--space-20);border-bottom:1px solid var(--border-soft);}
.filters select,.filters input{width:auto;min-width:130px;}
/* A filter bar is a row of inputs; anything dropped into it matches their
   height, including buttons that carry .btn-sm for use elsewhere. */
.filters .btn{height:var(--ctl-h);}
.sort-dir-btn{width:var(--ctl-h);flex-shrink:0;padding:0;font-size:var(--fs-12);line-height:1;margin:0;justify-content:center;}
.sort-dir-btn .nav-icon{width:14px;height:14px;}
.field{margin-bottom:var(--space-12);}
.card-body>.field:last-child{margin-bottom:0;}
.field-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-12);}
@media(max-width:560px){.field-grid{grid-template-columns:1fr;}}
.field-grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:var(--space-12);}
@media(max-width:680px){.field-grid-3{grid-template-columns:1fr;}}
/* Modal fields: label always above the control. The old rule picked
   label-left vs label-above by counting a field's DOM children, so hidden
   inputs and empty hint divs flipped the layout field by field. Label-left
   is now an explicit opt-in (.field-inline) for short label+control pairs. */
.modal .field{display:block;margin-bottom:0;padding:var(--space-6) 0;}
.modal .field>label:not(.checkbox-row){display:block;margin:var(--space-6) 0 var(--sp-1) var(--space-2);color:var(--text-faint);}
.modal .field>label.checkbox-row{display:flex;margin:var(--space-4) 0;}
.modal .field.field-inline{display:grid;grid-template-columns:104px minmax(0,1fr);align-items:center;gap:var(--space-14);}
.modal .field.field-inline>label{margin:0;}
.modal .field-grid>.field.field-inline,.modal .field-grid-3>.field.field-inline{grid-template-columns:78px minmax(0,1fr);}
.thumb-upload{display:flex;gap:var(--space-10);align-items:flex-start;margin-bottom:var(--space-12);}

/* ============================================================
   CARDS
   ============================================================ */
.card,.stat-card,.person-card{
  background:var(--panel);border:1px solid var(--border-soft);border-radius:var(--radius-lg);
  transition:border-color .15s ease,background .15s ease;
  /* 02·B bisel: luz em cima, sombra embaixo, anel em volta. Chapado
     continua chapado — isto não é sombra projetada, nada levanta do
     plano; é só a placa passando a ter espessura. */
  box-shadow:var(--bevel);
  background-image:var(--edge-wash);
}
.card,.person-card{overflow:hidden;}
.card{position:relative;}
.card-body{padding:var(--space-14) var(--space-14) var(--space-16);}
.card-thumb{width:100%;height:130px;background:var(--panel2);display:flex;align-items:center;justify-content:center;overflow:hidden;position:relative;}
.card-thumb:not(:has(img)){background-image:var(--hatch);box-shadow:var(--hatch-inner);}
.card-tag{font-family:var(--mono);font-size:var(--fs-10);color:var(--text-faint);letter-spacing:.5px;}
.card-name{font-weight:600;font-size:var(--fs-14);margin:var(--space-4) 0 var(--space-14);line-height:1.25;}
.card-meta{font-size:var(--fs-11);color:var(--text-dim);line-height:1.7;}
.card-actions{display:flex;gap:var(--space-6);margin-top:var(--space-16);padding-top:var(--space-12);border-top:1px solid var(--border-soft);}
.card.selectable,.person-card.selectable{cursor:pointer;}
.card.selectable:hover,.stat-card.selectable:hover,.person-card.selectable:hover{border-color:var(--text-faint);background:var(--panel2);}
.card-selected{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent),var(--bevel);}
/* 05·B — marcas de corte, quatro cantos. Marca de registro completa, e o
   código do job vira acento junto. Só em cartão clicável ou selecionado:
   num cartão de tarefa isso brigaria com a faixa de status, a escada de
   prioridade e a barra de tags que aquele cartão já carrega. */
.card.selectable::before,.card-selected::before{
  content:'';position:absolute;inset:var(--crop-inset);z-index:2;pointer-events:none;
  opacity:0;transition:opacity .16s ease;
  background:
    linear-gradient(var(--crop-ink),var(--crop-ink)) 0 0/var(--crop-len) var(--crop-w) no-repeat,
    linear-gradient(var(--crop-ink),var(--crop-ink)) 0 0/var(--crop-w) var(--crop-len) no-repeat,
    linear-gradient(var(--crop-ink),var(--crop-ink)) 100% 0/var(--crop-len) var(--crop-w) no-repeat,
    linear-gradient(var(--crop-ink),var(--crop-ink)) 100% 0/var(--crop-w) var(--crop-len) no-repeat,
    linear-gradient(var(--crop-ink),var(--crop-ink)) 0 100%/var(--crop-len) var(--crop-w) no-repeat,
    linear-gradient(var(--crop-ink),var(--crop-ink)) 0 100%/var(--crop-w) var(--crop-len) no-repeat,
    linear-gradient(var(--crop-ink),var(--crop-ink)) 100% 100%/var(--crop-len) var(--crop-w) no-repeat,
    linear-gradient(var(--crop-ink),var(--crop-ink)) 100% 100%/var(--crop-w) var(--crop-len) no-repeat;
}
.card.selectable:hover::before,.card-selected::before{opacity:1;}
.card.selectable:hover .card-tag,.card-selected .card-tag{color:var(--accent);}
.stat-card{padding:var(--space-16);}
.stat-card .num{font-family:var(--display);font-weight:800;font-size:var(--fs-28);color:var(--accent);text-shadow:0 0 18px rgba(var(--accent-rgb),var(--glow-a-soft));}
.stat-card .lbl{font-size:var(--fs-11);color:var(--text-faint);text-transform:uppercase;letter-spacing:.7px;margin-top:var(--space-2);}

/* ============================================================
   BADGES / TAGS / CHIPS — one CSS-variable-driven color system:
   modifiers set --tag-accent, the base rule reads it.
   ============================================================ */
.badge,.tag{
  display:inline-flex;align-items:center;gap:var(--space-6);font-weight:700;
  border-radius:var(--radius);background:var(--tag-bg);border:1px solid var(--border-soft);
  color:var(--tag-ink);--tag-accent:var(--text-faint);
  --tag-bg:var(--panel2);--tag-ink:var(--text-dim);
}
.tag{font-size:var(--fs-11);padding:var(--space-4) var(--space-10);}
.tag svg{width:12px;height:12px;flex-shrink:0;display:block;color:var(--tag-accent);}
.tag:not(:has(svg))::before{content:'';width:6px;height:6px;border-radius:50%;background:var(--tag-accent);flex-shrink:0;}
.badge{font-size:var(--fs-10);padding:var(--space-4) var(--space-10) var(--space-4) var(--space-8);text-transform:uppercase;letter-spacing:.5px;}
.badge::before{content:'';width:6px;height:6px;border-radius:50%;background:var(--tag-accent);flex-shrink:0;}
.badge.plain::before{display:none;}
/* 13 — estado vira forma. Os tokens --*-bg existem nos dois temas desde
   sempre e quase não eram usados: aqui cada modificador passa a pintar a
   superfície e o texto, não só a bolinha. O resto da ideia (faixa no topo
   da coluna, tarja de prioridade no cartão) o kanban já tinha. */
.tag-good,.badge.available{--tag-accent:var(--good);--tag-bg:var(--good-bg);--tag-ink:var(--good);border-color:rgba(var(--good-rgb),.45);}
.tag-bad,.badge.atrasado{--tag-accent:var(--danger);--tag-bg:var(--danger-bg);--tag-ink:var(--danger);border-color:rgba(var(--danger-rgb),.45);}
.tag-warn,.badge.maintenance{--tag-accent:var(--warn);--tag-bg:var(--warn-bg);--tag-ink:var(--warn);border-color:rgba(var(--warn-rgb),.45);}
.tag-info{--tag-accent:var(--info);--tag-bg:var(--info-bg);--tag-ink:var(--info);border-color:rgba(var(--info-rgb),.45);}
.tag-violet{--tag-accent:var(--violet);--tag-bg:var(--violet-bg);--tag-ink:var(--violet);border-color:rgba(var(--violet-rgb),.45);}
.tag-gray{--tag-accent:var(--text-faint);}
.tag-accent{--tag-accent:var(--accent);--tag-bg:rgba(var(--accent-rgb),.12);--tag-ink:var(--accent);border-color:rgba(var(--accent-rgb),.45);}
.person-chip{display:inline-flex;align-items:center;gap:var(--space-6);background:var(--panel2);border:1px solid var(--border);border-radius:var(--radius);padding:var(--space-6) var(--space-10);font-size:var(--fs-12);}
.mail-attachment-chip{display:inline-flex;align-items:center;gap:var(--space-6);background:var(--panel2);border:1px solid var(--border);border-radius:var(--radius);padding:var(--space-4) var(--space-6) var(--space-4) var(--space-12);font-size:var(--fs-12);}
.mail-attachment-chip button{background:none;border:none;color:var(--text-faint);cursor:pointer;font-size:var(--fs-15);line-height:1;padding:var(--space-2) var(--space-4);}
.mail-attachment-chip button:hover{color:var(--danger);}
.mail-attachment-chip[href]{color:var(--text);text-decoration:none;}
.mail-attachment-chip[href]:hover{border-color:var(--accent);color:var(--accent);}
.chip-remove-btn{background:none;border:none;color:var(--text-faint);cursor:pointer;font-size:var(--fs-12);}

/* ============================================================
   12 — CABEÇALHO QUE CONDENSA
   ============================================================
   Até aqui o app não tinha cabeçalho de página nenhum: o shell era só
   .main-inner e cada aba começava direto no próprio conteúdo, com a
   sidebar sendo a única pista de onde você está. Isto é a chrome que o
   app de desktop não tinha.

   O 47 (título como cartela, 58px) foi descartado, então o título aqui é
   o discreto que a própria ideia 12 descreve: 20px no topo, 14px depois
   de rolar, padding pela metade, e a sombra só aparece quando você já
   saiu do topo — antes disso não tem nada pra separar.

   No celular ele NÃO gruda nem condensa. O .mobile-header logo acima já
   faz exatamente esse truque (vira um círculo flutuante ao rolar), e dois
   elementos de chrome encolhendo em cima do outro seria a mesma piada
   contada duas vezes. Lá ele só rola embora junto com o conteúdo.
   ============================================================ */
.page-head{
  position:sticky;top:0;z-index:var(--z-dropdown);
  background:var(--bg);
  padding:var(--space-20) 0 var(--space-14);
  margin-bottom:var(--space-4);
  transition:padding var(--mo-desl-in) var(--mo-desl-ez),box-shadow var(--mo-desl-in) var(--mo-desl-ez);
}
.page-head h1{
  font-family:var(--display);font-weight:700;font-size:var(--fs-20);
  text-transform:uppercase;letter-spacing:1.2px;color:var(--text);
  line-height:1.1;
  transition:font-size var(--mo-desl-in) var(--mo-desl-ez);
}
.page-head:empty,.page-head:has(h1:empty){display:none;}
.page-head.small{
  padding:var(--space-8) 0;
  box-shadow:0 12px 22px -20px rgba(var(--shadow-rgb),.95);
}
.page-head.small h1{font-size:var(--fs-14);}
@media(max-width:820px){
  .page-head{position:static;padding:var(--space-14) 0 var(--space-10);}
  .page-head.small{padding:var(--space-14) 0 var(--space-10);box-shadow:none;}
  .page-head.small h1{font-size:var(--fs-20);}
}

/* ============================================================
   18 — VOZ DE MÁQUINA
   ============================================================
   Saira fala pelo sistema e Noto pelas pessoas; essa regra já estava
   tomada. Faltava a terceira voz, que nunca teve regra nenhuma: o que
   foi gerado por máquina. Código de job, hora, tamanho de arquivo,
   contagem — tudo JetBrains Mono, tabular, uma largura só. A lista
   deixa de ser prosa e vira manifesto.

   Duas listas separadas de propósito. A primeira troca a família; a
   segunda só alinha os dígitos, porque número grande de painel é
   tipografia de display, não saída de máquina — vira mono e perde o
   peso que faz ele ser o primeiro elemento que se lê na tela.
   ============================================================ */
.card-tag,.task-card-plate .cd,.sidebar-alert-item-time,.savebadge,.machine{
  font-family:var(--mono);font-variant-numeric:tabular-nums;letter-spacing:-.2px;
}
.stat-card .num,.dash-row-value,.changelog-vnum,.sidenav-count{
  font-variant-numeric:tabular-nums;
}

/* ============================================================
   TABLES
   ============================================================ */
table.plain{width:100%;border-collapse:collapse;}
table.plain th{text-align:left;font-family:var(--display);font-weight:700;font-size:var(--fs-10);text-transform:uppercase;letter-spacing:1.1px;color:var(--text-faint);padding:var(--space-8) var(--space-10);border-bottom:1px solid var(--border);}
table.plain td{padding:var(--space-10);border-bottom:1px solid var(--border-soft);font-size:var(--fs-12);}
table.plain tr:last-child td{border-bottom:none;}
.table-fixed{table-layout:fixed;}
@media(max-width:820px){
  table.plain.responsive-stack thead{display:none;}
  table.plain.responsive-stack,table.plain.responsive-stack tbody,table.plain.responsive-stack tr,table.plain.responsive-stack td{display:block;width:100%;}
  table.plain.responsive-stack tr{border-bottom:1px solid var(--border);padding:var(--space-10) 0;}
  table.plain.responsive-stack tr:last-child{border-bottom:none;}
  table.plain.responsive-stack td{border-bottom:none;padding:var(--space-6) 0;text-align:left !important;}
  table.plain.responsive-stack td::before{content:attr(data-label);display:block;font-size:var(--fs-10);text-transform:uppercase;letter-spacing:.5px;color:var(--text-faint);margin-bottom:var(--space-2);}
}

/* ============================================================
   MODALS / TOASTS / DROPDOWNS — solid, no blur, no cast shadow.
   Border does the separation.
   ============================================================ */
/* 03·B — vidro, e só onde a coisa flutua. O desfoque é caro, então ele
   só aparece em camada transitória (scrim, popover, drawer) e nunca num
   painel parado. Como o fundo agora borra, o preto do scrim pode cair. */
.overlay{position:fixed;inset:0;background:var(--scrim-bg);backdrop-filter:blur(var(--scrim-blur));-webkit-backdrop-filter:blur(var(--scrim-blur));display:flex;align-items:center;justify-content:center;z-index:var(--z-modal-backdrop);padding:var(--space-16);animation:overlayIn var(--mo-peso-in) var(--mo-peso-ez);}
.overlay.closing{animation:overlayOut var(--mo-peso-out) ease forwards;}
.overlay.closing .modal{animation:modalOut var(--mo-peso-out) cubic-bezier(.4,0,1,1) forwards;}
@keyframes overlayIn{from{opacity:0;}to{opacity:1;}}
@keyframes overlayOut{to{opacity:0;}}
@keyframes modalIn{from{opacity:0;transform:translateY(var(--mo-peso-travel)) scale(var(--mo-peso-scale));}to{opacity:1;transform:translateY(0) scale(1);}}
@keyframes modalOut{to{opacity:0;transform:translateY(var(--mo-peso-travel)) scale(var(--mo-peso-scale));}}
.modal{background:var(--panel);border:1px solid var(--border);border-radius:var(--radius-lg);max-width:520px;width:100%;max-height:88vh;overflow-y:auto;padding:0 var(--space-24) var(--space-14);animation:modalIn var(--mo-peso-in) var(--mo-peso-ez);box-shadow:var(--shadow-3);}
/* Bleeds to the modal's own edges (negative margin cancels .modal's
   horizontal padding) and lays out as a real header row — the close
   button is a child of this h2 in the markup, so without display:flex
   it renders inline right after the title text. */
/* "Placa": no filled band — the title itself is the header, set large in
   Saira over a hairline. Bleeds to the modal's edges (negative margin
   cancels .modal's padding); the close button is a child of this h2 in
   the markup, so this must stay display:flex or it renders inline after
   the title text. An optional mono eyebrow can be supplied by the markup
   as a real element (.modal-eyebrow) inside .modal-h2-title, wrapped
   with the title text so the two form one flex child — that's what lets
   align-items:center below center the × against the whole two-line
   block instead of just the title's own line. */
.modal h2{
  font-family:var(--display);font-weight:800;font-size:var(--fs-24);
  text-transform:uppercase;letter-spacing:.4px;line-height:1.05;color:var(--text);
  display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--space-12);
  margin:0 calc(-1 * var(--space-24)) var(--space-18);
  padding:var(--space-20) var(--space-24) var(--space-14);
  position:sticky;top:0;z-index:2;
  background:var(--panel);border-bottom:1px solid var(--border);
}
.modal-h2-title{display:block;}
.modal-eyebrow{
  display:block;font-family:var(--mono);font-size:var(--fs-9);letter-spacing:1.8px;
  text-transform:uppercase;color:var(--accent);font-weight:400;margin-bottom:var(--sp-1);
}
/* A status-badges row (.hdmeta in the design artifact) belongs inside the
   header, not as a separate block floating below it — flex-basis:100% on
   .modal h2 (already flex-wrap) drops it to its own line under the
   title+close pairing without needing to restructure either of those. */
.modal-h2-badges{flex-basis:100%;display:flex;gap:var(--sp-1);flex-wrap:wrap;margin-top:var(--sp-1);}
.modal-close{background:none;border:none;color:var(--text-faint);cursor:pointer;font-size:var(--fs-24);line-height:1;padding:0 var(--space-4);position:relative;flex-shrink:0;}
.modal-close:hover{color:var(--text);}
/* Invisible larger hit target around the small × glyph. */
.modal-close::after{content:"";position:absolute;width:200%;height:175%;top:-36%;left:-50%;}
/* Outside a modal this is a real grouped well; inside one it flattens to
   a ruled section, since the modal already provides the container. */
.modal-group{background:var(--panel2);border:1px solid var(--border-soft);border-radius:var(--radius);padding:var(--space-12) var(--space-12) var(--space-8);margin-bottom:var(--sp-3);}
.modal .modal-group{background:none;border:none;border-radius:0;border-top:1px solid var(--border-soft);padding:var(--sp-3) 0 0;margin:var(--sp-3) 0 var(--space-4);}
/* Footer band (.mk-foot in the design artifact) — every modal's action row
   uses it: bleeds to the modal's edges same as the header, pinned to the
   bottom while the body scrolls. Sticky lands on .modal's padding-box
   edge, so a modal ending in a footer drops its own bottom padding and
   the footer sits flush (no negative bottom margin). */
.modal:has(>.modal-footer:last-child){padding-bottom:0;}
.modal-footer{
  display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-2);
  margin:var(--space-14) calc(-1 * var(--space-24)) 0;
  padding:var(--space-16) var(--space-24);
  border-top:1px solid var(--border);background:var(--panel2);
  position:sticky;bottom:0;z-index:2;
}
/* Footer actions are always full size, even if markup carries a small
   size class. */
.modal-footer .btn-sm{height:var(--ctl-h);padding:0 var(--space-14);font-size:var(--fs-11);}
.modal-footer .btn-icon.btn-sm,.modal-footer .btn-icon-sm{width:var(--ctl-h);height:var(--ctl-h);padding:0;}
/* Heading for a ruled .modal-group section, so a section name never has to
   pose as a label-only .field. */
.modal-section-title{font-family:var(--display);font-weight:700;font-size:var(--fs-12);text-transform:uppercase;letter-spacing:1px;color:var(--text-dim);margin:0 0 var(--space-2);}

/* ---------- Pagamento modal ---------- */
.pg-share-row{display:flex;gap:var(--space-8);}
.pg-share-row select{flex:1;min-width:0;}
.pg-share-row .btn{height:var(--ctl-h);white-space:nowrap;flex-shrink:0;}
@media(max-width:560px){.pg-share-row{flex-wrap:wrap;}.pg-share-row .btn{width:100%;justify-content:center;}}
.pg-valor-head{display:flex;align-items:center;justify-content:space-between;gap:var(--space-12);padding:var(--space-10) var(--space-12);background:var(--panel2);border:1px solid var(--border-soft);border-radius:var(--radius);}
.pg-valor-head:not(.hidden)+input{margin-top:var(--space-8);}
.pg-valor-head .checkbox-row{margin:0;flex-shrink:0;}
.pg-valor-amount{font-size:20px;font-weight:700;line-height:1.2;font-variant-numeric:tabular-nums;}
.pg-valor-orig{font-size:11px;color:var(--text-faint);margin-top:var(--space-2);}
.pg-doc .btn{height:var(--ctl-h);}
.pg-doc #pg-doc-preview{height:var(--ctl-h);min-width:0;}
.pg-doc #pg-doc-link{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.pg-split td{padding:var(--space-8) var(--space-10);vertical-align:middle;}
.pg-split td:nth-child(2){font-family:var(--mono);font-size:11px;color:var(--text-faint);}
.pg-split td:last-child{font-weight:600;font-variant-numeric:tabular-nums;}
.pg-split tr.nor td{background:rgba(var(--accent-rgb),.05);}
.pg-split tr.nor td:first-child{box-shadow:inset 3px 0 0 var(--accent);}
.pg-split tfoot td{border-top:1px solid var(--border);border-bottom:none;}
.pg-split tfoot td:first-child{font-family:var(--display);font-weight:700;font-size:var(--fs-10);text-transform:uppercase;letter-spacing:1px;color:var(--text-faint);}
/* Phone: the table sheds its tag and % column to fit, and Salvar takes its
   own row so pago status + delete share the second one instead of the
   trash icon wrapping alone. */
@media(max-width:560px){
  .pg-split .divisao-kind,.pg-split th:nth-child(2),.pg-split td:nth-child(2){display:none;}
  .modal-pagamento #save-pagamento{flex-basis:100%;justify-content:center;}
}

.toast{
  position:relative;overflow:hidden;box-shadow:var(--shadow-2);
  pointer-events:auto;display:flex;align-items:flex-start;gap:var(--space-8);
  background:var(--panel2);border:1px solid var(--border);border-left:3px solid var(--danger);
  border-radius:var(--radius);padding:var(--space-12) var(--space-10) var(--space-12) var(--space-14);
  z-index:var(--z-toast);
  animation:toastIn var(--mo-peso-in) var(--mo-peso-ez);
}
.toast.closing{animation:toastOut var(--mo-peso-out) ease forwards;}
@keyframes toastIn{from{opacity:0;transform:translateX(24px);}to{opacity:1;transform:translateX(0);}}
@keyframes toastOut{to{opacity:0;transform:translateX(24px);}}
/* 15 — cronômetro. A barra escoa pelo tempo exato que o toast vai ficar
   na tela, então some a dúvida de "dá tempo de ler?" e o auto-dismiss
   deixa de parecer que a app mudou de ideia sozinha.
   --toast-dur TEM que casar com o setTimeout(dismiss) de toast() em
   02-state.js. Mudou lá, muda aqui. */
.toast::after{
  content:'';position:absolute;left:0;bottom:0;height:2px;width:100%;
  background:var(--accent);transform-origin:left;
  animation:drain var(--toast-dur) linear forwards;
}
.toast.closing::after{animation-play-state:paused;}
@keyframes drain{from{transform:scaleX(1);}to{transform:scaleX(0);}}

.sidebar-alert-panel,.drive-action-menu,.quick-actions-menu,.address-results,.selection-bar,.task-tag-popover{
  background:var(--glass-bg);border:1px solid var(--border);border-radius:var(--radius);
  backdrop-filter:blur(var(--glass-blur));-webkit-backdrop-filter:blur(var(--glass-blur));
  box-shadow:var(--shadow-2);
}
.address-results.open{display:block;}
.address-result-item{padding:var(--space-8) var(--space-12);font-size:var(--fs-12);color:var(--text-dim);cursor:pointer;border-bottom:1px solid var(--border-soft);}
.address-result-item:last-child{border-bottom:none;}
/* Menu/dropdown, peso profile: grows from the corner nearest its toggle
   button — transform-origin flips per anchor side so it never looks like
   it's growing away from what opened it. */
.sidebar-alert-panel{position:absolute;top:100%;right:0;margin-top:var(--space-6);min-width:262px;max-width:310px;max-height:min(70vh,480px);overflow-y:auto;z-index:var(--z-popover);opacity:0;display:none;transform-origin:top right;transform:translateY(var(--mo-peso-travel)) scale(var(--mo-peso-scale));transition:opacity var(--mo-peso-in) var(--mo-peso-ez),transform var(--mo-peso-in) var(--mo-peso-ez);}
.sidebar-alert-panel.open{opacity:1;display:block;transform:translateY(0) scale(1);}
.drive-action-menu{position:absolute;z-index:var(--z-popover);padding:var(--space-4);display:flex;flex-direction:column;min-width:200px;transform-origin:top left;animation:menuIn var(--mo-peso-in) var(--mo-peso-ez);}
.quick-actions-menu{position:absolute;top:100%;left:0;margin-top:var(--space-6);padding:var(--space-4);flex-direction:column;min-width:230px;z-index:var(--z-popover);opacity:0;display:none;transform-origin:top left;transform:translateY(var(--mo-peso-travel)) scale(var(--mo-peso-scale));transition:opacity var(--mo-peso-in) var(--mo-peso-ez),transform var(--mo-peso-in) var(--mo-peso-ez);}
.quick-actions-menu.open{opacity:1;display:flex;transform:translateY(0) scale(1);}
.address-results{position:absolute;top:100%;left:0;right:0;z-index:var(--z-dropdown);margin-top:var(--space-4);max-height:220px;overflow-y:auto;display:none;}
.selection-bar{position:fixed;right:20px;bottom:20px;z-index:var(--z-popover);padding:var(--space-10) var(--space-14);max-width:calc(100vw - 40px);}
.selection-bar-enter{transform-origin:bottom right;animation:menuIn var(--mo-peso-in) var(--mo-peso-ez);}
.task-tag-popover{position:fixed;z-index:var(--z-above-modal);width:300px;max-width:calc(100vw - 24px);padding:var(--space-14);transform-origin:top left;animation:menuIn var(--mo-peso-in) var(--mo-peso-ez);}
@keyframes menuIn{from{opacity:0;transform:translateY(var(--mo-peso-travel)) scale(var(--mo-peso-scale));}to{opacity:1;transform:translateY(0) scale(1);}}
#upload-bar{
  position:fixed;left:50%;bottom:20px;transform:translate(-50%,12px);z-index:var(--z-status-indicator);
  display:flex;align-items:center;gap:var(--space-10);background:var(--panel2);border:1px solid var(--border);
  border-radius:var(--radius);padding:var(--space-10) var(--space-16) var(--space-10) var(--space-12);
  opacity:0;pointer-events:none;transition:opacity .2s ease,transform .2s ease;
}
#upload-bar.show{opacity:1;transform:translate(-50%,0);pointer-events:auto;}

/* ============================================================
   AVATARS / EMPTY STATES / SKELETONS
   ============================================================ */
/* 19·C — retrato. Todo avatar era o mesmo círculo vermelho, então três
   pessoas em fila liam como uma forma repetida. Agora: quadrado no mesmo
   canto de 2px do resto, o preenchimento vai pro escuro e quem carrega a
   cor é a LETRA mais o fio embaixo. A cor vem de --hue, que cada chamada
   define com userColorForName() — nunca mais background inline, senão o
   inline ganha da regra e o retrato volta a ser bolinha colorida.
   Presença virou quadradinho de canto em vez de elemento separado. */
.avatar{
  width:20px;height:20px;border-radius:0;position:relative;overflow:hidden;
  background:var(--panel3);color:var(--hue,var(--accent));
  border-bottom:2px solid var(--hue,var(--accent));
  font-weight:700;font-size:var(--fs-10);font-family:var(--display);
  display:flex;align-items:center;justify-content:center;
}
.avatar img{width:100%;height:100%;object-fit:cover;display:block;}
.avatar .pr{position:absolute;right:0;bottom:0;width:6px;height:6px;background:var(--good);}
.avatar.off .pr{background:var(--text-faint);}
.dot{width:6px;height:6px;border-radius:50%;background:var(--good);}

/* ============================================================
   AUDIT FIXES — found by diffing every class actually used across all
   21 public/js/*.js files against every selector this stylesheet
   defines (comm -23 on two sorted lists), rather than waiting to
   discover each one from a screen that happens to render it. .filters
   itself (flagged directly) turned out to be one of many — the sidebar
   alert panel's contents, toasts' own inner markup, the task detail
   modal, and the Projetos list card were all missing entirely despite
   being used on nearly every screen. Foundational/shared ones live
   here; screen-specific ones are folded into their own step below.
   ============================================================ */
.btn-good{color:var(--good);}
.btn-good:hover{background:var(--good-bg);border-color:var(--good);color:var(--good);}
.btn-icon-sm{width:var(--ctl-h-sm);height:var(--ctl-h-sm);}
.modal-lg{max-width:720px;}
.modal-sm{max-width:400px;}
.modal-sm .field.field-inline{grid-template-columns:132px minmax(0,1fr);}
.modal-sm .field-grid>.field.field-inline,.modal-sm .field-grid-3>.field.field-inline{grid-template-columns:78px minmax(0,1fr);}
.divider-top{border-top:1px solid var(--border-soft);padding-top:var(--space-10);}
.divider-bottom{border-bottom:1px solid var(--border-soft);padding-bottom:var(--space-10);}
.hint-empty{padding:var(--space-8) var(--space-2);}
.ph-error{font-size:var(--fs-9);padding:var(--space-4);text-align:center;line-height:1.3;}
.radio-inline{display:flex;align-items:center;gap:var(--space-6);text-transform:none;font-size:var(--fs-12);color:var(--text);font-weight:400;margin-bottom:0;cursor:pointer;}
.radio-inline input{width:auto;}
.quick-actions-dropdown{position:relative;display:inline-block;}
.quickadd-icon-wrap{position:relative;display:inline-flex;}
.quickadd-badge{position:absolute;right:-5px;bottom:-5px;width:15px;height:15px;border-radius:50%;background:var(--bg);color:var(--accent);display:flex;align-items:center;justify-content:center;}
.quickadd-badge .nav-icon{width:13px;height:13px;}
.ptr-spinner{width:22px;height:22px;border-radius:50%;border:2.5px solid var(--border-soft);border-top-color:var(--accent);}
.svc-icon{display:inline-flex;width:15px;height:15px;flex-shrink:0;}
.svc-icon svg{width:100%;height:100%;display:block;}
.settings-help-text{font-size:var(--fs-12);color:var(--text-dim);line-height:1.6;}
.settings-fine-print{font-size:var(--fs-11);color:var(--text-faint);line-height:1.5;}
.person-links{display:flex;gap:var(--space-6);flex-wrap:wrap;margin-top:var(--space-12);}
.person-links a{text-decoration:none;}
.date-input-wrap{position:relative;display:flex;gap:var(--space-6);align-items:center;}
.date-input-wrap input[type=text]{flex:1;min-width:0;}
.date-input-native{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;opacity:0;pointer-events:none;}
.date-input-pick-btn{flex:none;}
.event-card .card-body{padding:var(--space-12);}
.event-card-grid{display:flex;flex-direction:column;gap:var(--space-10);margin-bottom:var(--space-28);}

/* Multi-select on a card's thumbnail corner — used on Inventário's grid,
   not the row-style .select-toggle Drive/Mail use (see Step 3). */
.select-check{position:absolute;top:8px;left:8px;z-index:2;width:22px;height:22px;border-radius:50%;background:var(--accent);color:#fff;font-size:var(--fs-12);font-weight:700;display:flex;align-items:center;justify-content:center;}

/* Inventory item's maintenance/borrowed stamp — flat instead of the
   soft-rotated badge-with-shadow it isn't (it never had a shadow; this
   is a one-word note, not a call-out). */
.stamp{position:absolute;top:8px;right:-6px;font-family:var(--display);font-size:var(--fs-10);font-weight:700;letter-spacing:1px;text-transform:uppercase;padding:var(--space-4) var(--space-10);transform:rotate(6deg);border:1.5px solid;}
.stamp.maintenance{color:var(--warn);border-color:var(--warn);background:var(--panel2);}
.stamp.borrowed{color:var(--accent);border-color:var(--accent);background:var(--panel2);}
.card-thumb:has(.stamp) img{filter:grayscale(100%) blur(2px) opacity(50%);}

/* Sidebar alert panel's contents — the panel shell itself was already
   covered (Step 1), its rows were not. */
.sidebar-alert-empty{padding:var(--space-16) var(--space-12);text-align:center;color:var(--text-faint);font-size:var(--fs-12);}
.sidebar-alert-item{display:flex;gap:var(--space-10);padding:var(--space-10) var(--space-12);border-left:3px solid transparent;cursor:pointer;}
.sidebar-alert-item:hover{background:var(--panel3);}
.sidebar-alert-item.unseen{background:rgba(var(--accent-rgb),.06);}
.sidebar-alert-item+.sidebar-alert-item{border-top:1px solid var(--border-soft);}
.sidebar-alert-icon{width:26px;height:26px;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
.sidebar-alert-icon .nav-icon{width:13px;height:13px;}
.sidebar-alert-body{flex:1;min-width:0;}
.sidebar-alert-item-text{font-size:var(--fs-12);color:var(--text);line-height:1.4;overflow:auto;}
.sidebar-alert-meta{display:flex;align-items:center;gap:var(--space-8);margin-top:var(--space-2);}
.sidebar-alert-item-time{font-size:var(--fs-11);color:var(--text-faint);}
.sidebar-alert-go{font-size:var(--fs-11);font-weight:700;color:var(--accent);opacity:0;}
.sidebar-alert-item:hover .sidebar-alert-go{opacity:1;}
.sidebar-alert-tier-good{border-left-color:var(--good);}
.sidebar-alert-tier-info{border-left-color:var(--info);}
.sidebar-alert-tier-warn{border-left-color:var(--warn);}
.sidebar-alert-tier-danger{border-left-color:var(--danger);}
.sidebar-alert-tier-violet{border-left-color:var(--violet);}
.sidebar-alert-icon.sidebar-alert-tier-good{background:var(--good-bg);color:var(--good);}
.sidebar-alert-icon.sidebar-alert-tier-info{background:var(--info-bg);color:var(--info);}
.sidebar-alert-icon.sidebar-alert-tier-warn{background:var(--warn-bg);color:var(--warn);}
.sidebar-alert-icon.sidebar-alert-tier-danger{background:var(--danger-bg);color:var(--danger);}
.sidebar-alert-icon.sidebar-alert-tier-violet{background:var(--violet-bg);color:var(--violet);}

/* Toast's own inner markup — the toast shell was covered (Step 1). */
.toast-stack{position:fixed;top:18px;right:18px;z-index:var(--z-toast);display:flex;flex-direction:column;gap:var(--space-8);max-width:min(360px,calc(100vw - 36px));pointer-events:none;}
.toast-msg{flex:1;font-size:var(--fs-12);line-height:1.5;color:var(--text);}
.toast-close{background:none;border:none;color:var(--text-faint);font-size:var(--fs-16);line-height:1;padding:var(--space-2) var(--space-4);flex-shrink:0;}
.toast-close:hover{color:var(--text);}
.sidebar-alert-wrap{position:relative;flex-shrink:0;}
.sidebar-alert-btn{position:relative;display:flex;align-items:center;justify-content:center;width:38px;height:38px;flex-shrink:0;border:1px solid var(--border-soft);background:var(--panel2);color:var(--text-dim);cursor:pointer;}
.sidebar-alert-btn:hover{background:var(--panel3);color:var(--text);border-color:var(--text-faint);}
.sidebar-alert-btn .nav-icon{width:20px;height:20px;}
.sidebar-alert-dot{position:absolute;top:-3px;right:-3px;width:10px;height:10px;border-radius:50%;background:var(--danger);border:2px solid var(--bg);}
/* Unlike the mobile header's bell (top-right of the screen, panel correctly
   hangs left off it), the sidebar's bell sits at the top-LEFT of the whole
   layout — anchoring this panel to its right edge like the base rule does
   made it grow leftward off the edge of the viewport entirely. Anchor left
   and grow right into the sidebar/main-content area instead, where there's
   actually room. */
.sidebar-alert-wrap .sidebar-alert-panel{left:-14px;right:auto;transform-origin:top left;}
.theme-toggle-icon{width:17px;height:17px;flex-shrink:0;}
.mail-attachment-chips{display:flex;flex-wrap:wrap;gap:var(--space-6);margin-top:var(--space-8);}
.portfolio-thumb-candidates{margin-top:var(--space-4);}
.trim-overlay{position:fixed;inset:0;z-index:var(--z-priority-banner);background:rgba(0,0,0,.8);display:flex;align-items:center;justify-content:center;padding:var(--space-16);animation:overlayIn var(--mo-peso-in) var(--mo-peso-ez);}
.trim-overlay.closing{animation:overlayOut var(--mo-peso-out) ease forwards;}
.trim-overlay.closing .modal{animation:modalOut var(--mo-peso-out) cubic-bezier(.4,0,1,1) forwards;}
.upload-bar-spinner{width:16px;height:16px;border-radius:50%;flex-shrink:0;border:2px solid var(--border-soft);border-top-color:var(--accent);animation:ptrSpin .7s linear infinite;}
.upload-bar-text{font-size:var(--fs-12);font-weight:500;color:var(--text);white-space:nowrap;}

/* Hold-to-delete gesture (mobile long-press) — kept the liquid-fill wave
   (a real progress indicator), dropped the blurred aura around the
   circle (pure decoration, and "no blur anywhere" applies to glow same
   as it did to cards/sidebar). */
/* Matches "Movimento" §07 Segurar para excluir, Option A exactly: flat
   96px plate, brand --accent (not --danger) for border/fill, smooth solid
   fill with no tick/stripe texture — the artifact's own note calls that
   out explicitly ("as listras saíram", the stripes came out) as a
   deliberate revision of the earlier 3-ajustes-do-slate.html "Cortina"
   draft this used to follow instead. The round liquid-wave version was
   the only organic shape in a system of live corners; .hold-delete-circle
   keeps its name (the JS drives it) despite the shape.
   pointer-events stays none even while .open — this overlay is decoration
   only, nothing inside it is clickable, and it sits fixed/full-screen
   directly over the real trigger button. Letting it capture clicks meant
   the mouseup that's supposed to cancel the hold on release landed on the
   overlay (now the topmost element at that point) instead of the button,
   so releasing early did nothing and the hold just ran to completion
   regardless — the exact "click twice, no time to cancel" bug reported. */
.hold-delete-overlay{
  position:fixed;inset:0;z-index:var(--z-above-modal);
  background:rgba(0,0,0,.7);
  display:flex;align-items:center;justify-content:center;
  opacity:0;pointer-events:none;
}
.hold-delete-overlay.open{opacity:1;}
.hold-delete-wrap{position:relative;width:96px;height:96px;}
.hold-delete-glow{display:none;}
.hold-delete-circle{
  position:relative;z-index:1;width:96px;height:96px;border-radius:var(--radius);
  background:var(--panel2);border:2px solid var(--accent);
  display:flex;align-items:center;justify-content:center;overflow:hidden;
}
.hold-delete-circle .hold-fill-big{position:absolute;left:0;right:0;bottom:0;height:0%;background:var(--accent);z-index:0;}
.hold-delete-circle .hold-fill-big::before{display:none;}
.hold-delete-circle .hold-delete-icon{position:relative;z-index:3;color:var(--text);}
.hold-delete-circle .hold-delete-icon .nav-icon{width:40px;height:40px;}
/* 09 — hachura de ardósia. O app fica mais nu justamente onde não tem
   dado. A borda deixa de ser tracejada: a hachura faz o trabalho que o
   tracejado fazia, e o retângulo morto vira pedra cortada. */
.empty{position:relative;overflow:hidden;border:1px solid var(--border);border-radius:var(--radius);padding:var(--space-32) var(--space-24);text-align:left;color:var(--text-faint);font-size:var(--fs-12);animation:emptyIn .3s ease both;}
/* 11 — vazio com marca. Decisão do Kervin (2026-09-16): a marca SUBSTITUI a
   hachura do 09 aqui dentro; a hachura continua só na capa sem imagem.
   Um tratamento por superfície. A marca vai por mask e não por <img>: o
   arquivo é branco, e no tema claro um branco a 5% sobre papel some. Com
   mask a cor sai de --text e funciona nos dois temas. */
.empty::after{
  content:'';position:absolute;right:-14px;bottom:-26px;width:180px;height:180px;
  background:var(--text);pointer-events:none;
  -webkit-mask:url('/logo/NORDEN-FILMES--LOGO--WHITE.svg') no-repeat center/contain;
  mask:url('/logo/NORDEN-FILMES--LOGO--WHITE.svg') no-repeat center/contain;
  opacity:var(--watermark-a);transform:rotate(-6deg);
}
.empty>*{position:relative;z-index:1;}
@keyframes emptyIn{from{opacity:0;transform:translateY(4px);}to{opacity:1;transform:translateY(0);}}

/* 20 — entrada em cascata. O JS (itemCard em 08-inventario.js) sempre
   aplicou .card-enter e um animation-delay por cartão, mas a regra só
   existia no style.css clássico: no Slate a cascata estava morta desde o
   dia do lançamento. backwards é obrigatório, senão o cartão aparece
   inteiro e some antes de começar a subir. */
.card-enter{animation:cardEnter .42s var(--mo-peso-ez) backwards;}
@keyframes cardEnter{from{opacity:0;transform:translateY(10px);}}
#content.no-entrance-anim .empty,#content.no-entrance-anim .card-enter{animation:none;}
.empty b{color:var(--text-dim);display:block;font-family:var(--display);font-weight:700;font-size:var(--fs-15);text-transform:uppercase;letter-spacing:.7px;margin-bottom:var(--space-4);}
.skeleton{background:linear-gradient(90deg,var(--panel2) 25%,var(--panel3) 37%,var(--panel2) 63%);background-size:400% 100%;animation:skeletonShimmer 1.4s ease infinite;border-radius:var(--radius);}
.skeleton-line{height:12px;}
.skeleton-thumb{width:100%;height:130px;border-radius:0;}
@keyframes skeletonShimmer{0%{background-position:100% 0;}100%{background-position:0 0;}}
@media(prefers-reduced-motion:reduce){.skeleton{animation:none;}}

/* ============================================================
   STEP 2 — PAINEL (dashboard rows), AGENDA, TAREFAS (kanban)
   ============================================================ */

/* ---------- Painel: stat grid + the compact row-list widgets
   ("Próximos compromissos", "A receber", "Tarefas que precisam de
   atenção") — .dash-row sits inside a plain .card, already styled. ---------- */
.stat-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:var(--space-12);margin-bottom:var(--space-28);}
.stat-grid-2col{grid-template-columns:1fr 1fr;}
.dash-rows{display:flex;flex-direction:column;}
.dash-row{display:flex;align-items:center;gap:var(--space-10);padding:var(--space-10) var(--space-14);border-bottom:1px solid var(--border-soft);cursor:pointer;transition:background .12s ease,box-shadow .12s ease;}
.dash-row-value,.dash-row-sub{transition:color .12s ease;}
.dash-row:last-child{border-bottom:none;}
/* 35 — régua de leitura. Trocar o fundo inteiro não diz pra onde olhar;
   o fio de acento à esquerda e o esmaecer em 62% puxam o olho no sentido
   da leitura, e o número daquela linha sai do apagado. */
.dash-row:hover{background:var(--rule-wash);box-shadow:var(--rule-edge);}
.dash-row:hover .dash-row-value,.dash-row:hover .dash-row-sub{color:var(--text);}
.dash-row-main{flex:1;min-width:0;}
.dash-row-title{font-size:var(--fs-12);font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.dash-row-sub{font-size:var(--fs-11);color:var(--text-faint);margin-top:var(--space-2);}
.dash-row-value{font-family:var(--display);font-weight:700;font-size:var(--fs-16);flex-shrink:0;white-space:nowrap;}
.dash-row-prio{width:6px;height:6px;border-radius:50%;flex-shrink:0;}
.dash-task-board{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:var(--space-16);}
.dash-task-board .task-card{margin-bottom:0;min-width:0;}
.event-date-badge{background:var(--panel2);border:1px solid var(--border-soft);border-radius:var(--radius-sm);padding:var(--space-6) var(--space-4);text-align:center;min-width:50px;flex-shrink:0;}
.event-date-month{font-family:var(--display);font-weight:700;font-size:var(--fs-10);letter-spacing:1px;color:var(--accent);text-transform:uppercase;}
.event-date-day{font-family:var(--display);font-weight:700;font-size:var(--fs-18);color:var(--text);line-height:1.15;}
.event-date-badge-personal .event-date-month{color:var(--warn);}
.event-date-badge-pagamento .event-date-month{color:var(--text-faint);}
.event-date-badge-pagamento.overdue{border-color:var(--danger);}
.event-date-badge-pagamento.overdue .event-date-month,
.event-date-badge-pagamento.overdue .event-date-day{color:var(--danger);}

/* ---------- Agenda ----------
   Note found while building this: the real Lista/Mês/Ano control in
   11-agenda.js renders `.tab-strip`/`.tab-strip-btn`, and `.proj-grid`/
   `.proj-col` for its layout — neither has a matching rule in style.css
   today (confirmed via git diff: 11-agenda.js's tab-strip markup is
   itself uncommitted, ahead of style.css). Not a Slate regression, a
   pre-existing gap in the current live app too — styled fresh here. */
/* Ruled tabs: the rule does the separating, not a box inside a box.
   flex:1 lets the rule run the full width of the row it sits in, so the
   tabs read as a section header rather than a floating control. */
.tab-strip{display:flex;flex:1;gap:0;align-items:flex-end;background:none;border:none;
  border-bottom:1px solid var(--border);border-radius:0;padding:0;position:relative;}
/* Filete da aba, deslize profile: captureTabStripBar()/playTabStripBarSlide()
   in 02-state.js FLIP a temporary bar between the old and new active tab's
   positions (a click here calls render(), which replaces the whole strip,
   so there's no persisting element left for a CSS transition to animate) —
   the resting ::after bar above is hidden for that moment so the two are
   never visible at once. */
.tab-strip.sliding .tab-strip-btn.on::after{opacity:0;}
.tab-strip-slidebar{position:absolute;left:0;bottom:-1px;height:2px;background:var(--accent);pointer-events:none;}
.tab-strip-btn{
  height:38px;padding:0 var(--space-18);position:relative;
  background:none;border:none;border-radius:0;cursor:pointer;
  font-family:var(--display);font-weight:700;font-size:var(--fs-14);
  text-transform:uppercase;letter-spacing:1.2px;color:var(--text-faint);
}
.tab-strip-btn:first-child{padding-left:0;}
.tab-strip-btn:hover{color:var(--text-dim);}
.tab-strip-btn.on{color:var(--text);background:none;}
.tab-strip-btn.on::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;background:var(--accent);}
.tab-strip-btn:first-child.on::after{left:0;}
.proj-grid{display:grid;grid-template-columns:1.4fr 1fr;gap:var(--space-18);align-items:start;}
@media(max-width:820px){.proj-grid{grid-template-columns:1fr;}}
.proj-col{display:flex;flex-direction:column;gap:var(--space-14);min-width:0;}

.agenda-toolbar{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-12);flex-wrap:wrap;gap:var(--space-10);}
.agenda-toolbar-title{font-family:var(--display);font-weight:700;font-size:var(--fs-18);text-transform:uppercase;letter-spacing:.6px;}
.agenda-legend{display:flex;gap:var(--space-16);margin-bottom:var(--space-14);flex-wrap:wrap;}
.agenda-legend-item{display:flex;align-items:center;gap:var(--space-6);font-size:var(--fs-11);color:var(--text-dim);}
.agenda-legend-dot{width:8px;height:8px;flex-shrink:0;display:inline-block;}
.agenda-legend-dot-upcoming{background:var(--accent);}
.agenda-legend-dot-past{background:var(--text-dim);}
.agenda-legend-dot-personal{background:var(--warn);}
.agenda-legend-list{display:flex;flex-direction:column;gap:var(--space-6);}
.agenda-legend-row{display:flex;align-items:center;gap:var(--space-8);font-size:var(--fs-11);color:var(--text-dim);}
.agenda-legend-row b{width:8px;height:8px;display:block;flex-shrink:0;}

/* Month grid: gutter is the border. Cells carry no border of their own —
   the 2px gap showing the page's own --border-soft through is the
   separation, same trick as the sidebar's active bar reusing structure
   instead of adding decoration. */
.agenda-grid{
  --agenda-cell-pad-top:6px; --agenda-daynum-h:20px; --agenda-bar-h:20px;
  display:flex;flex-direction:column;gap:1px;background:var(--border-soft);
  border:1px solid var(--border-soft);border-radius:var(--radius);overflow:hidden;
}
.agenda-grid-headrow,.agenda-week{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:1px;background:var(--border-soft);}
.agenda-week{position:relative;}
.agenda-grid-headcell{background:var(--panel2);color:var(--text-faint);font-family:var(--display);font-weight:700;font-size:var(--fs-10);text-transform:uppercase;letter-spacing:1.1px;padding:var(--space-8) var(--space-10);text-align:center;}
/* 39 — calor do mês. position:relative é seguro: as barras de vários dias
   (.agenda-bar, absolutas) moram em .agenda-week-bars, irmão das células,
   não dentro delas. --load vem de agendaDayCell() em 11-agenda.js. */
.agenda-day-cell::after{content:'';position:absolute;left:3px;right:3px;bottom:3px;height:3px;background:var(--accent);opacity:var(--load,0);pointer-events:none;}
.agenda-day-cell{position:relative;background:var(--panel);min-height:104px;padding:var(--agenda-cell-pad-top) var(--space-6) var(--space-8);cursor:pointer;transition:background .12s ease;display:flex;flex-direction:column;min-width:0;}
.agenda-day-cell:hover{background:var(--panel2);}
.agenda-day-cell-outside{background:var(--bg);}
.agenda-day-cell-outside .agenda-day-num{color:var(--text-faint);}
.agenda-day-num{height:16px;line-height:16px;margin-bottom:var(--space-4);font-family:var(--display);font-size:var(--fs-12);font-weight:700;color:var(--text-dim);}
.agenda-day-num-today{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;background:var(--accent);color:#fff;}
.agenda-day-events{display:flex;flex-direction:column;gap:var(--space-4);min-width:0;}
.agenda-day-more{font-size:var(--fs-10);color:var(--text-faint);padding:var(--space-2) var(--space-6);}
.agenda-week-lanes-1 .agenda-day-events{margin-top:var(--agenda-bar-h);}
.agenda-week-lanes-2 .agenda-day-events{margin-top:calc(var(--agenda-bar-h)*2);}
.agenda-week-bars{position:absolute;inset:0;pointer-events:none;}
.agenda-bar{position:absolute;left:calc(var(--col) / 7 * 100% + 2px);width:calc(var(--span) / 7 * 100% - 4px);top:calc(var(--agenda-cell-pad-top) + var(--agenda-daynum-h) + var(--lane) * var(--agenda-bar-h));white-space:nowrap;overflow:hidden;}
.agenda-bar-cont-start{border-top-left-radius:0;border-bottom-left-radius:0;}
.agenda-bar-cont-end{border-top-right-radius:0;border-bottom-right-radius:0;}

/* Chips: border + tint from the accent-rgb triplet, one rule for both
   themes — the old dark-only hardcoded hex pair (#FFE5E6/#323232) needed
   a separate light-mode override; a token-driven tint doesn't. */
.agenda-chip{display:flex;align-items:center;gap:var(--space-6);padding:var(--space-4) var(--space-10);border-radius:var(--radius-sm);font-size:var(--fs-10);font-weight:600;line-height:1.2;min-width:0;border:1px solid transparent;}
.agenda-chip-title{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.agenda-chip-time{flex-shrink:0;opacity:.85;font-family:var(--mono);font-size:var(--fs-9);}
.agenda-chip-upcoming{background:rgba(var(--accent-rgb),.14);color:var(--text);border-color:rgba(var(--accent-rgb),.4);}
.agenda-chip-past{background:var(--panel2);color:var(--text-faint);border-color:var(--border-soft);}
.agenda-chip-personal{background:rgba(var(--warn-rgb),.14);color:var(--warn);border-color:rgba(var(--warn-rgb),.4);}
.agenda-chip-personal-past{filter:saturate(.15);opacity:.65;}

.agenda-year-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--space-12);}
.agenda-year-cell{background:var(--panel);border:1px solid var(--border-soft);border-radius:var(--radius);padding:var(--space-14) var(--space-14) var(--space-12);cursor:pointer;transition:background .12s ease,border-color .12s ease;}
.agenda-year-cell:hover{background:var(--panel2);}
.agenda-year-cell-current{border-color:var(--accent);}
.agenda-year-cell-name{font-family:var(--display);font-weight:700;font-size:var(--fs-14);margin-bottom:var(--space-10);text-transform:uppercase;letter-spacing:.6px;}
.agenda-year-cell-dots{display:flex;gap:var(--space-12);flex-wrap:wrap;}
.agenda-year-dot{display:flex;align-items:center;gap:var(--space-6);font-size:var(--fs-12);font-family:var(--mono);color:var(--text-dim);}

.agenda-list-month-label{display:flex;align-items:center;gap:var(--space-10);font-family:var(--display);font-weight:700;font-size:var(--fs-12);text-transform:uppercase;letter-spacing:1.1px;color:var(--text-faint);margin:var(--sp-4) 0 var(--space-10);}
.agenda-list-month-label:first-child{margin-top:0;}
.agenda-list-event{display:flex;gap:var(--space-12);padding:var(--space-10) var(--space-12);margin-bottom:var(--space-8);align-items:flex-start;border-bottom:1px solid var(--border-soft);}
.agenda-list-event.past{opacity:.5;}
.agenda-list-when{width:52px;flex-shrink:0;text-align:center;}
.agenda-list-weekday{font-family:var(--display);font-weight:700;font-size:var(--fs-10);letter-spacing:1.2px;color:var(--text-faint);text-transform:uppercase;margin-bottom:var(--space-2);}
.agenda-list-daynum{font-family:var(--display);font-weight:700;font-size:var(--fs-20);line-height:1.05;}
.agenda-list-time{font-size:var(--fs-10);color:var(--text-faint);margin-top:var(--space-4);line-height:1.3;}
.agenda-list-body{flex:1;min-width:0;}
.agenda-list-top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--space-10);}
.agenda-list-where{font-size:var(--fs-11);color:var(--text-faint);margin-top:var(--space-6);line-height:1.35;display:flex;align-items:center;gap:var(--space-4);}
.agenda-list-where svg{width:11px;height:11px;flex-shrink:0;}
.agenda-list-span{margin-top:var(--space-8);display:flex;align-items:center;gap:var(--space-8);}
.agenda-list-spanbar{flex:1;height:4px;background:var(--panel3);overflow:hidden;position:relative;}
.agenda-list-spanbar i{position:absolute;top:0;bottom:0;left:0;width:100%;display:block;}
.agenda-list-spantxt{font-size:var(--fs-10);color:var(--text-faint);flex-shrink:0;}

.agenda-todayline{display:flex;align-items:center;gap:var(--space-10);margin:var(--space-14) 0 var(--space-12);}
.agenda-todayline b{font-family:var(--display);font-weight:700;font-size:var(--fs-11);color:var(--accent);letter-spacing:1px;text-transform:uppercase;}
.agenda-todayline::after{content:'';flex:1;height:1px;background:var(--accent);opacity:.4;}
.agenda-todaydot{width:6px;height:6px;background:var(--accent);flex-shrink:0;}

.agenda-mini-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-10);}
.agenda-mini-title{font-family:var(--display);font-weight:700;font-size:var(--fs-14);letter-spacing:1px;text-transform:uppercase;color:var(--text-dim);}
.agenda-mini-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:5px;}
.agenda-mini-wdh{font-size:var(--fs-9);color:var(--text-faint);text-align:center;padding-bottom:var(--space-4);text-transform:uppercase;letter-spacing:.5px;}
.agenda-mini-day{position:relative;aspect-ratio:1;display:flex;align-items:center;justify-content:center;border-radius:var(--radius-sm);font-size:var(--fs-11);color:var(--text-dim);cursor:pointer;border:1px solid var(--border-soft);}
.agenda-mini-day.out{color:var(--border);}
.agenda-mini-day.today{background:var(--accent);color:#fff;font-weight:700;border-color:var(--accent);}
.agenda-mini-dot{position:absolute;bottom:7px;right:7px;width:4px;height:4px;border-radius:50%;}

.agenda-rail-label{font-family:var(--display);font-weight:700;font-size:var(--fs-12);text-transform:uppercase;letter-spacing:1.1px;color:var(--text-dim);margin:0 0 var(--space-10);}
.agenda-rail-row{display:flex;align-items:center;gap:var(--space-8);padding:var(--space-8) 0;border-bottom:1px solid var(--border-soft);}
.agenda-rail-row:last-child{border-bottom:none;}
.agenda-rail-row-t{flex:1;min-width:0;font-size:var(--fs-11);color:var(--text-dim);}
.agenda-rail-row-n{font-family:var(--display);font-size:var(--fs-15);font-weight:700;}

/* ---------- Tarefas (kanban) ---------- */
.task-board{display:flex;gap:var(--space-16);align-items:start;overflow-x:auto;padding-bottom:var(--space-6);cursor:grab;}
.task-board.task-board-dragging{cursor:grabbing;user-select:none;-webkit-user-select:none;}
.task-board.task-board-dragging .task-card{pointer-events:none;}
.task-column{flex:0 0 268px;width:268px;border-radius:var(--radius);}
.task-column-title{font-family:var(--display);font-weight:700;font-size:var(--fs-12);text-transform:uppercase;letter-spacing:1px;color:var(--text-dim);margin-bottom:var(--space-2);min-height:34px;}
.task-column-count{font-family:var(--display);font-size:var(--fs-14);font-weight:700;color:var(--text-faint);}
.task-column-line{height:3px;margin-bottom:var(--space-10);}
.task-column-actions{gap:var(--space-2);}
.task-column-move{background:none;border:none;color:var(--text-faint);opacity:.5;width:var(--ctl-h-xs);height:var(--ctl-h-xs);}
.task-column-move .nav-icon{width:14px;height:14px;}
.task-column-move:hover{opacity:1;color:var(--text);background:none;}
.task-column-move:disabled{opacity:.18;pointer-events:none;}
.task-column.drag-over::after{position:absolute;display:block;content:"";top:-8px;left:-10px;width:100%;height:100%;background:rgba(var(--accent-rgb),.06);border:1px dashed rgba(var(--accent-rgb),.4);padding:var(--space-6) var(--space-10);}

/* ---------- Task card ("Placa Dupla + Escada") ----------
   Seven stacked slices, always all rendered (even empty/dimmed) so every
   card keeps the same silhouette regardless of how much data it carries —
   see SLATE-CARTAO-E-ORCAMENTO.md §1.2/1.4 and taskCard() (06-tasks.js) for
   the full anatomy. .task-card also carries .card (Step 1's flat recipe);
   these are the additive properties on top of it, not a second surface. */
.task-card{
  margin-bottom:var(--space-18);cursor:pointer;touch-action:none;
  user-select:none;-webkit-user-select:none;overflow:hidden;
}
/* .card-body's own padding (line ~1378, shared with .drive-file-card) is
   replaced here — the card's body is now slices 4-6 (.task-card-body,
   its own padding) plus slice 7 (.task-card-foot, its own padding+band),
   not one padded box. */
.task-card .card-body{padding:0;}

/* 1 · tag bar */
.task-card-tagbar{display:flex;gap:1px;height:4px;background:var(--border-soft);}
.task-card-tagbar i{flex:1;display:block;}

/* 2 · origin plate */
.task-card-plate{
  background:var(--panel3);padding:var(--space-6) var(--space-10);
  display:flex;align-items:center;gap:var(--space-6);
  border-bottom:1px solid var(--border);min-height:26px;
}
.task-card-plate .nm{
  font-family:var(--display);font-weight:700;text-transform:uppercase;
  letter-spacing:1.1px;font-size:var(--fs-12);color:var(--text);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.task-card-plate .cd{
  font-family:var(--mono);font-size:var(--fs-9);color:var(--text-faint);
  letter-spacing:.8px;flex-shrink:0;margin-left:auto;
}
.task-card-plate.solo{background:transparent;border-bottom-color:var(--border-soft);}
.task-card-plate.solo .nm{color:var(--text-faint);font-weight:600;}
.task-card-plate.rev{
  background:rgba(var(--violet-rgb),.16);
  border-bottom-color:rgba(var(--violet-rgb),.4);
}
.task-card-plate.rev .nm{color:var(--violet);}
.task-card-plate.rev .nav-icon{width:10px;height:10px;color:var(--violet);flex-shrink:0;}

/* 3 · status band */
.task-card-band{
  display:flex;align-items:center;gap:var(--space-6);
  padding:var(--space-4) var(--space-10);
  border-bottom:1px solid var(--border-soft);border-left:3px solid transparent;
  font-family:var(--mono);font-size:9.5px;letter-spacing:.9px;
  text-transform:uppercase;color:var(--text-dim);min-height:24px;
}
.task-card-band .sp{margin-left:auto;}
.task-card-band .nav-icon{width:10px;height:10px;flex-shrink:0;}
.task-card-band.st-over{border-left-color:var(--danger);color:var(--danger);}
.task-card-band.st-soon{border-left-color:var(--warn);color:var(--warn);}
.task-card-band.st-ready,
.task-card-band.st-done{border-left-color:var(--good);color:var(--good);}
.task-card-band.st-none{color:var(--text-faint);}

/* 3b · priority ladder — block count reads before color: one lit = baixa,
   two = média, three = alta. */
.task-card-prio{display:flex;gap:2px;flex-shrink:0;align-items:center;}
.task-card-prio i{
  width:7px;height:11px;display:block;
  background:var(--panel3);border:1px solid var(--border);
}
.task-card-prio.hi i.on{background:var(--danger);border-color:var(--danger);}
.task-card-prio.md i.on{background:var(--warn);border-color:var(--warn);}
.task-card-prio.lo i.on{background:var(--text-faint);border-color:var(--text-faint);}

/* 4-6 · body */
.task-card-body{
  padding:var(--space-10) var(--space-12) 11px;
  display:flex;flex-direction:column;gap:var(--space-8);
}
.task-card-title{
  font-size:13px;font-weight:600;line-height:1.34;color:var(--text);
  overflow-wrap:anywhere;
}
.task-card.completed .task-card-title{
  text-decoration:line-through;color:var(--text-faint);font-weight:400;
}
.task-card-tagnames{
  font-family:var(--mono);font-size:var(--fs-9);letter-spacing:.6px;
  color:var(--text-faint);text-transform:uppercase;line-height:1.55;
  overflow-wrap:anywhere;
}

/* 6 · checklist as step blocks. A finished step is NEUTRAL; only at 100%
   does it turn green — amber stays reserved for urgency/média priority. */
.task-card-steps{display:flex;align-items:center;gap:7px;}
.task-card-steps .t{flex:1;display:flex;gap:1px;height:5px;min-width:0;}
.task-card-steps .t i{flex:1;display:block;background:var(--panel3);}
.task-card-steps .t i.on{background:var(--text-dim);}
.task-card-steps.full .t i.on{background:var(--good);}
.task-card-steps .x{
  font-family:var(--mono);font-size:9.5px;color:var(--text-faint);
  flex-shrink:0;font-variant-numeric:tabular-nums;
}
.task-card-steps.full .x{color:var(--good);}
/* > 20 items: one continuous bar instead of one block per step */
.task-card-steps.cont .t{display:block;background:var(--panel3);position:relative;}
.task-card-steps.cont .t i{position:absolute;inset:0 auto 0 0;background:var(--text-dim);}

/* 7 · footer */
.task-card-foot{
  display:flex;align-items:center;gap:var(--space-8);
  padding:var(--space-6) var(--space-10);min-height:30px;
  background:var(--panel2);border-top:1px solid var(--border-soft);
}
.task-card-foot .sp{margin-left:auto;}
.task-card-foot .glyphs{display:flex;gap:7px;color:var(--text-faint);}
.task-card-foot .glyphs .nav-icon{width:12px;height:12px;}
.task-card-foot .edited{
  font-family:var(--mono);font-size:8.5px;color:var(--text-faint);
  font-style:normal;letter-spacing:.4px;
}
.task-card-av{display:flex;}
.task-card-av span{
  width:19px;height:19px;display:grid;place-items:center;
  font-family:var(--display);font-weight:700;font-size:var(--fs-9);
  color:var(--text);background:var(--panel3);border:1px solid var(--border);
  margin-left:-5px;border-radius:var(--radius);letter-spacing:.3px;
}
.task-card-av span:first-child{margin-left:0;}
.task-card-av span.more{color:var(--text-faint);}

/* completed — the whole card recedes */
.task-card.completed{background:var(--panel2);border-color:var(--border-soft);}
.task-card.completed .task-card-tagbar i{opacity:.3;}
.task-card.completed .task-card-plate{background:transparent;border-bottom-color:var(--border-soft);}
.task-card.completed .task-card-plate .nm{color:var(--text-faint);font-weight:600;}
.task-card.completed .task-card-prio i.on{background:var(--text-faint);border-color:var(--border);}
.task-card.completed .task-card-steps .t i.on{background:rgba(var(--good-rgb),.45);}
.task-card.completed .task-card-foot{background:transparent;}
.task-card.completed .task-card-av span{opacity:.6;}

.task-card.drag-source{opacity:.35;}
.task-drag-ghost{position:fixed !important;z-index:var(--z-drag);pointer-events:none;margin:0;user-select:none;}
/* 14 — arrasto com peso. Só a sombra entra aqui: a inclinação e a escala
   que a ideia pedia já existem, e melhores, em 06-tasks.js — são molas
   com rotação proporcional à velocidade, escritas direto no style.transform
   do fantasma. Mexer em transform daqui só brigaria com elas. */
.task-drag-ghost.lifted{box-shadow:var(--shadow-4);}
.task-drag-ghost.dropping{opacity:0;transition:opacity .15s ease .08s;}

/* Complex-modal main+rail split — two-column, collapsing to one column on
   mobile. Originally built for the task detail modal (found missing
   entirely in the audit; opens on every single task card click) and
   reused as-is for the item modal (§3 of the redesign) rather than
   forking a near-identical second set of rules. */
.task-modal-body,.item-modal-body{display:grid;grid-template-columns:minmax(0,1fr) 220px;}
.task-modal-main,.item-modal-main{min-width:0;padding-right:var(--space-16);}
.task-modal-rail,.item-modal-rail{min-width:0;padding-left:var(--space-16);border-left:1px solid var(--border-soft);background:var(--bg);margin-right:calc(-1 * var(--space-24));padding-right:var(--space-24);margin-top:-18px;margin-bottom:-12px;padding-top:8px;}
.task-modal-rail .field,.item-modal-rail .field{display:block;padding:var(--sp-2) 0;}
.task-modal-rail .field>label,.item-modal-rail .field>label{display:block;margin:0 0 var(--sp-1);}
/* Item modal's main column, vertical too (label above input) — matching
   the rail instead of the horizontal 104px-label grid used elsewhere in
   the app, so the two columns of one modal read as the same system. */
.item-modal-main .field{display:block;margin-bottom:var(--sp-2);}
.item-modal-main .field:last-child{margin-bottom:0;}
.item-modal-main .field>label{display:block;margin:0 0 var(--sp-1);}
@media(max-width:680px){
  .task-modal-body,.item-modal-body{display:block;}
  .task-modal-rail,.item-modal-rail{border-left:none;margin-top:var(--space-14);border-top:1px solid var(--border-soft);padding-top:var(--space-14);margin-right:calc(-1 * var(--space-24));padding-right:var(--space-24);margin-left:calc(-1 * var(--space-24));padding-left:var(--space-24);}
}
/* Read-only label/value row — the Depreciação section's computed Idade/
   Valor hoje, or anywhere else a "here's a fact, not a field" line is
   needed. .v is mono so numbers line up; color it inline (e.g. --accent
   for an amount worth calling out) when a row needs to stand out. */
.disc{display:flex;justify-content:space-between;align-items:baseline;padding:var(--space-10) 0;border-bottom:1px solid var(--border-soft);font-size:var(--fs-12);}
.disc:last-child{border-bottom:none;}
.disc .v{font-family:var(--mono);color:var(--text);}
/* Vertical flex stack at the field-to-field spacing step — pairs with a
   fixed-width sidekick (a photo, an icon) in a nowrap row. */
.stack{display:flex;flex-direction:column;gap:var(--sp-2);min-width:0;}
.task-title-field{font-size:var(--fs-15);font-weight:600;line-height:1.35;color:var(--text);background:none;border:none;height:auto;padding:0 0 var(--space-12);border-bottom:1px solid var(--border-soft);}
.task-title-field:focus{box-shadow:none;border-color:var(--accent-dim);}
/* Numbered section label ("01 Identificação") — generic and reusable on
   purpose (per the design artifact's own .sect), not a task- or item-
   specific class: it's just a field and a label. Mono number in --accent,
   name in full --text (not dimmed) — a numbered heading, not a hint. */
.sect{display:flex;align-items:baseline;gap:9px;margin:var(--sp-4) 0 var(--sp-3);}
.sect:first-child{margin-top:6px;}
.sect .n{font-family:var(--mono);font-size:var(--fs-9);color:var(--accent);letter-spacing:1.4px;flex-shrink:0;}
.sect b{font-family:var(--display);font-weight:700;font-size:13px;text-transform:uppercase;letter-spacing:1.3px;color:var(--text);white-space:nowrap;}
.sect .aside{margin-left:auto;font-family:var(--mono);font-size:9.5px;color:var(--text-faint);}
.seg{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1px;background:var(--border-soft);border:1px solid var(--border-soft);}
.seg.seg-2{grid-template-columns:repeat(2,minmax(0,1fr));}
.seg>div{background:var(--panel2);font-size:var(--fs-11);height:34px;color:var(--text-faint);display:flex;align-items:center;justify-content:center;cursor:pointer;font-weight:500;}
/* Neutral "on" look — a fallback for any segmented control that isn't a
   traffic-light scale (priority below overrides with lo/md/hi coloring). */
.seg>div.on{font-weight:700;background:var(--panel3);color:var(--text);}
.seg>div.on[data-value="Alta"]{background:var(--danger-bg);color:var(--danger);}
.seg>div.on[data-value="Média"]{background:var(--warn-bg);color:var(--warn);}
.seg>div.on[data-value="Baixa"]{background:var(--good-bg);color:var(--good);}
.task-history-entry{padding:var(--space-6) 0;border-bottom:1px solid var(--border-soft);}
.task-history-entry:last-child{border-bottom:none;padding-bottom:0;}
.task-history-entry:first-child{padding-top:0;}
.task-history-meta{font-size:var(--fs-10);color:var(--text-faint);margin-bottom:var(--space-2);}
.task-history-meta-note{font-size:var(--fs-11);color:var(--text-faint);line-height:1.5;margin-top:var(--space-14);}
.task-history-changes{margin:0;padding-left:var(--space-16);font-size:var(--fs-12);color:var(--text-dim);}
.task-history-changes li{margin:var(--space-2) 0;}

.task-load-band{display:flex;align-items:stretch;gap:1px;background:var(--border-soft);border:1px solid var(--border-soft);border-radius:var(--radius);overflow:hidden;margin-bottom:var(--space-14);flex-wrap:wrap;}
.task-load-tile{background:var(--panel);padding:var(--space-10) var(--space-14);display:flex;align-items:center;gap:var(--space-10);flex:1;min-width:150px;}
.task-load-who{font-size:var(--fs-11);color:var(--text-dim);line-height:1.3;}
.task-load-sub{font-size:var(--fs-10);color:var(--text-faint);margin-top:var(--space-2);line-height:1.3;}
.task-load-num{font-family:var(--display);font-size:var(--fs-20);font-weight:800;line-height:1;margin-left:auto;flex-shrink:0;}
.task-fchip{display:inline-flex;align-items:center;gap:var(--space-6);height:27px;padding:0 var(--space-10);border-radius:var(--radius);font-size:var(--fs-11);font-weight:500;background:var(--panel2);border:1px solid var(--border);color:var(--text-dim);cursor:pointer;}
.task-fchip.on{background:rgba(var(--accent-rgb),.12);border-color:var(--accent);color:var(--text);}

.task-complete-check{display:inline-flex;width:22px;height:22px;color:var(--good);}
.task-complete-check svg{width:100%;height:100%;display:block;}

.task-checklist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--space-6);}
.task-checklist li{display:flex;align-items:center;gap:var(--space-8);background:var(--panel2);border:1px solid var(--border-soft);border-radius:var(--radius);padding:var(--space-6) var(--space-8);}
.task-checklist li.dragging{opacity:.4;}
.task-checklist li.drag-over{border-color:var(--accent);}
.task-checklist .drag-handle{cursor:grab;color:var(--text-faint);flex-shrink:0;user-select:none;font-size:var(--fs-14);line-height:1;}
.task-checklist .check-text{flex:1;font-size:var(--fs-12);word-break:break-word;cursor:text;}
.task-checklist .check-text.done{color:var(--text-faint);text-decoration:line-through;}
.task-checklist .check-text-input{flex:1;font-size:var(--fs-12);font-family:inherit;background:var(--panel);border:1px solid var(--border-soft);border-radius:var(--radius-sm);padding:var(--space-2) var(--space-6);color:var(--text);}

.task-audio-list{display:flex;flex-direction:column;gap:var(--space-10);}
.task-audio-row{background:var(--panel);border:1px solid var(--border-soft);border-radius:var(--radius);padding:var(--space-8) var(--space-10);}
.task-audio-row-top{display:flex;align-items:center;gap:var(--space-8);margin-bottom:var(--space-6);flex-wrap:wrap;}
.task-audio-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--fs-12);color:var(--text-dim);}
.task-audio-speed{display:flex;gap:var(--space-2);flex-shrink:0;background:var(--panel2);border-radius:var(--radius-sm);padding:var(--space-2);}
.task-audio-speed-btn{border:none;background:transparent;color:var(--text-faint);font-size:var(--fs-10);font-family:var(--mono);padding:var(--space-4) var(--space-8);border-radius:var(--radius-sm);cursor:pointer;}
.task-audio-speed-btn:hover{color:var(--text-dim);}
.task-audio-speed-btn.active{background:var(--accent);color:#fff;}
.task-audio-row audio{width:100%;height:32px;display:block;}

.task-attach-list{display:flex;flex-direction:column;gap:var(--space-6);}
.task-attach-row{display:flex;align-items:center;justify-content:space-between;gap:var(--space-10);background:var(--panel);border:1px solid var(--border-soft);border-radius:var(--radius);padding:var(--space-8) var(--space-10);}
.task-attach-info{display:flex;align-items:baseline;gap:var(--space-8);min-width:0;flex:1;}
.task-attach-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--fs-12);color:var(--text-dim);}
.task-attach-size{flex-shrink:0;font-size:var(--fs-10);font-family:var(--mono);color:var(--text-faint);}

/* Foldrows (Checklist/Anexos/Áudios/Histórico) stack directly against each
   other sharing hairlines — same as .foldrow in the design artifact —
   instead of each one being its own .modal-group box with 20px of padding
   and margin around it. Four of those stacked was most of what made
   Editar Tarefa feel bulky next to the artifact's compact list. */
.task-section{border-bottom:1px solid var(--border-soft);}
.task-section:last-of-type{border-bottom:none;}
.task-section > summary{
  list-style:none;cursor:pointer;display:flex;align-items:center;
  gap:var(--space-12);height:48px;
  font-family:var(--display);font-weight:700;font-size:12.5px;
  text-transform:uppercase;letter-spacing:1.1px;color:var(--text-dim);
}
.task-section > summary:hover{color:var(--text);}
.task-section > summary::-webkit-details-marker{display:none;}
.task-sub-ico{width:26px;height:26px;background:var(--panel2);border:1px solid var(--border-soft);display:flex;align-items:center;justify-content:center;color:var(--text-faint);flex-shrink:0;}
.task-sub-ico .nav-icon{width:14px;height:14px;}
.task-sub-name{font-family:var(--display);font-weight:700;font-size:12.5px;text-transform:uppercase;letter-spacing:1.1px;color:inherit;flex:1;min-width:0;}
.task-section-count{font-size:var(--fs-11);color:var(--text-faint);flex-shrink:0;display:flex;align-items:center;gap:var(--space-8);}
.task-sub-bar{width:52px;height:4px;background:var(--panel2);overflow:hidden;flex-shrink:0;}
.task-sub-bar i{display:block;height:100%;}
.task-section-chevron{display:inline-flex;align-items:center;justify-content:center;width:12px;height:12px;flex-shrink:0;color:var(--text-faint);}
.task-section-chevron .nav-icon{width:12px;height:12px;}
.task-section-chevron.chevron-open{display:none;}
.task-section[open] .task-section-chevron.chevron-open{display:inline-flex;}
.task-section[open] .task-section-chevron.chevron-closed{display:none;}
.task-section-body{margin-top:var(--space-10);}
.task-section-body:last-of-type{margin-bottom:var(--sp-2);}

.task-tag-pills{display:flex;flex-wrap:wrap;gap:var(--space-6);align-items:center;}
.task-tag-pill{display:inline-flex;align-items:center;font-size:var(--fs-11);font-weight:700;color:#fff;padding:var(--space-4) var(--space-10);border-radius:var(--radius-sm);line-height:1.2;}
.task-tag-pill-btn{background:none;border:none;padding:0;cursor:pointer;}
.task-tag-pill-btn:hover .task-tag-pill{filter:brightness(1.15);}
.task-assignee-pill{background:var(--panel3);color:var(--text);}
.task-tag-pill-btn:hover .task-assignee-pill{background:var(--border-soft);}
.task-tag-popover-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-10);font-family:var(--display);font-size:var(--fs-12);font-weight:700;text-transform:uppercase;letter-spacing:1px;color:var(--text-dim);}
.task-tag-popover .field{margin-bottom:var(--space-10);}
.task-tag-search{margin-bottom:var(--space-8);}
.task-tag-list{max-height:260px;overflow-y:auto;display:flex;flex-direction:column;gap:var(--space-4);}
.task-tag-row{display:flex;align-items:center;justify-content:space-between;gap:var(--space-8);}
.task-tag-row-label{display:flex;align-items:center;gap:var(--space-8);flex:1;min-width:0;cursor:pointer;margin:0;}
.task-tag-row-label input[type=checkbox]{flex-shrink:0;}
.task-tag-row-label .task-tag-pill{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:var(--space-10);}
.task-tag-color-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:var(--space-8);}
.task-tag-color-swatch{width:100%;aspect-ratio:1;border-radius:var(--radius-sm);border:2px solid transparent;cursor:pointer;color:#fff;font-weight:700;display:flex;align-items:center;justify-content:center;}
.task-tag-color-swatch.selected{border-color:#fff;box-shadow:0 0 0 2px var(--panel);}
.task-tag-color-swatch.selected::after{content:"✓";}

.task-desc-field{margin:var(--space-24) 0 var(--space-28);}
.task-desc-actions{margin-top:var(--space-8);justify-content:flex-end;}
.task-desc-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-2);margin-bottom:var(--space-8);padding:var(--space-4);background:var(--panel2);border:1px solid var(--border-soft);border-radius:var(--radius);}
.task-desc-tb-btn{width:28px;height:28px;flex-shrink:0;border:none;background:transparent;color:var(--text-dim);border-radius:var(--radius-sm);font-size:var(--fs-12);cursor:pointer;}
.task-desc-tb-btn:hover{background:var(--panel);color:var(--text);}
.task-desc-tb-bold{font-weight:700;}
.task-desc-tb-italic{font-style:italic;}
.task-desc-tb-strike{text-decoration:line-through;}
.task-desc-tb-sep{width:1px;height:18px;background:var(--border-soft);margin:0 var(--space-4);flex-shrink:0;}

/* Small markdown renderer's output — shared by task descriptions and
   05-recorrentes.js's own renderer, hence the generic name rather than
   a task- prefix. */
.md-content,.task-desc-view{font-size:var(--fs-12);line-height:1.6;color:var(--text-dim);}
.md-content h1,.md-content h2{color:var(--text);font-family:var(--display);font-weight:700;margin:var(--space-14) 0 var(--space-6);}
.md-content h1:first-child,.md-content h2:first-child{margin-top:0;}
.md-content h1{font-size:var(--fs-18);}
.md-content h2{font-size:var(--fs-15);}
.md-content p{margin:0 0 var(--space-8);}
.md-content p:last-child{margin-bottom:0;}
.md-content ul,.md-content ol{margin:0 0 var(--space-8);padding-left:var(--space-24);}
.md-content li{margin-bottom:var(--space-2);}
.md-content blockquote{margin:0 0 var(--space-8);padding:var(--space-4) var(--space-12);border-left:3px solid var(--accent);color:var(--text-faint);}
.md-content a{color:var(--accent);text-decoration:underline;}
.md-content .md-img{max-width:100%;display:block;margin:var(--space-6) 0;}
.md-content .md-empty{color:var(--text-faint);font-style:italic;}

/* Checklists de Trabalho — live per-job checklist (14-modals.js), a table
   rather than the .task-checklist list used for kanban subtasks; distinct
   feature, not a duplicate. Battery-charge icon states drop the original's
   drop-shadow bloom (decorative glow, not a live-state signal like the
   pipeline ripple or a speaking ring) — color alone already carries it. */
.jc-table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;}
.jc-table{margin-bottom:var(--space-18);table-layout:fixed;width:100%;min-width:480px;}
.jc-table th:nth-child(1),.jc-table td:nth-child(1){width:36px;}
.jc-table th:nth-child(2),.jc-table td:nth-child(2){width:50%;}
.jc-table th:nth-child(3),.jc-table td:nth-child(3){width:20%;}
.jc-table th:nth-child(4),.jc-table td:nth-child(4){width:70px;}
.jc-table td{overflow:hidden;text-overflow:ellipsis;}
.jc-table .jc-check{cursor:pointer;}
.jc-row[data-missing="1"]{background:var(--danger-bg);}
.jc-row[data-missing="1"] td{color:var(--danger);}
.jc-row[data-missing="1"] td.text-dim{color:var(--danger);opacity:.8;}
.jc-charge-row{display:flex;gap:var(--space-8);flex-wrap:wrap;}
.jc-charge-btn{width:var(--ctl-h-sm);height:var(--ctl-h-sm);padding:0;cursor:pointer;flex-shrink:0;border:none;background:none;display:flex;align-items:center;justify-content:center;}
.jc-charge-btn:hover{transform:scale(1.15);}
.jc-charge-btn .nav-icon{width:100%;height:100%;}
.jc-charge-btn .nav-icon svg{width:100%;height:100%;display:block;}
.jc-charge-btn[data-state="empty"]{color:var(--danger);}
.jc-charge-btn[data-state="empty"] .batt-bar{opacity:0;}
.jc-charge-btn[data-state="low"]{color:var(--warn);}
.jc-charge-btn[data-state="low"] .batt-bar-2,.jc-charge-btn[data-state="low"] .batt-bar-3{opacity:0;}
.jc-charge-btn[data-state="half"]{color:var(--warn);}
.jc-charge-btn[data-state="half"] .batt-bar-3{opacity:0;}
.jc-charge-btn[data-state="full"]{color:var(--good);}

.proj-inline-tasks{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:var(--space-12);}

/* ============================================================
   STEP 3 — PROJETOS, ORÇAMENTO, DRIVE, CONTATO
   ============================================================ */

/* ---------- Projeto (single-project workspace) ---------- */
.proj-back{display:inline-flex;align-items:center;gap:var(--space-6);color:var(--text-faint);font-size:var(--fs-12);font-weight:600;margin-bottom:var(--space-14);}
.proj-back:hover{color:var(--text);}
.proj-back svg{width:14px;height:14px;}
.proj-head{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-14);flex-wrap:wrap;margin-bottom:var(--space-18);}
.proj-title-row{display:flex;align-items:center;gap:var(--space-12);flex-wrap:wrap;}
.proj-title{font-family:var(--display);font-weight:800;font-size:var(--fs-20);text-transform:uppercase;letter-spacing:.5px;}
.proj-headtags{display:flex;gap:var(--space-6);flex-shrink:0;}
.proj-cancel-link{display:inline-flex;align-items:center;font-size:var(--fs-11);color:var(--text-faint);padding:0 var(--space-4);}
.proj-cancel-link:hover{color:var(--danger);}
.proj-pipe-card{margin-bottom:var(--space-14);}
.proj-pipe-card .card-body{padding:var(--space-6) var(--space-10);}

.proj-link-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:var(--space-10);margin-bottom:var(--space-24);}
.proj-link-card{background:var(--panel2);border:1px solid var(--border-soft);border-radius:var(--radius);padding:var(--space-12);display:flex;flex-direction:column;gap:var(--space-8);min-width:0;}
.proj-link-card.linked{border-color:rgba(var(--good-rgb),.4);}
.proj-link-card.suggest{border-color:rgba(var(--warn-rgb),.5);}
.proj-link-card-head{display:flex;align-items:center;gap:var(--space-8);font-family:var(--display);font-size:var(--fs-10);font-weight:700;text-transform:uppercase;letter-spacing:.8px;color:var(--text-faint);}
.proj-link-card.linked .proj-link-card-head{color:var(--good);}
.proj-link-card-head svg{width:13px;height:13px;flex-shrink:0;}
.proj-link-card-value{font-size:var(--fs-12);font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.proj-link-card-suggest{font-size:var(--fs-11);color:var(--text-dim);line-height:1.4;}
.proj-link-card-suggest b{color:var(--text);}
.proj-link-card select{width:100%;font-size:var(--fs-11);height:var(--ctl-h-sm);padding:var(--space-2) var(--space-6);}
.proj-link-card .btn{align-self:flex-start;}

/* Tab rail + content, side by side — no matching rule existed in
   style.css for this wrapper (11-agenda.js-style gap: the markup is
   ahead of the stylesheet), so this layout is designed fresh rather
   than ported. */
.proj-body-rail{display:flex;gap:var(--space-20);align-items:flex-start;}
@media(max-width:820px){.proj-body-rail{flex-direction:column;}}
.proj-tab-rail{display:flex;flex-direction:column;gap:2px;flex:0 0 176px;position:sticky;top:var(--space-20);}
@media(max-width:820px){.proj-tab-rail{position:static;flex-direction:row;flex-wrap:wrap;width:100%;}}
.proj-tab-rail-btn{display:flex;align-items:center;gap:var(--space-10);justify-content:flex-start;text-align:left;padding:var(--space-8) var(--space-10);border-radius:var(--radius);font-size:var(--fs-12);font-weight:500;color:var(--text-dim);background:none;border:none;cursor:pointer;}
.proj-tab-rail-btn:hover{background:var(--panel2);color:var(--text);}
.proj-tab-rail-btn .nav-icon{width:16px;height:16px;flex:none;}
.proj-tab-rail-btn.on{background:var(--panel3);color:var(--text);font-weight:700;box-shadow:inset 3px 0 0 var(--accent);}
.proj-rail-content{flex:1;min-width:0;}

.proj-section-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-10);}
.proj-section-head .section-title{margin:0;}
.proj-agenda-list{display:flex;flex-direction:column;gap:var(--space-6);}
.proj-agenda-row{display:flex;align-items:center;gap:var(--space-10);background:var(--panel);border:1px solid var(--border-soft);border-radius:var(--radius);padding:var(--space-8) var(--space-10);font-size:var(--fs-12);cursor:pointer;}
.proj-agenda-row:hover{border-color:var(--text-faint);}
.proj-agenda-row .d{font-family:var(--mono);font-size:var(--fs-10);color:var(--text-faint);flex-shrink:0;white-space:nowrap;}

.proj-feed{display:flex;flex-direction:column;}
.proj-feed-item{display:flex;gap:var(--space-12);padding:0 0 var(--space-16);position:relative;}
.proj-feed-item:last-child{padding-bottom:0;}
.proj-feed-rail{position:relative;width:24px;flex-shrink:0;display:flex;justify-content:center;}
.proj-feed-rail::before{content:'';position:absolute;top:24px;bottom:-16px;width:1px;background:var(--border-soft);}
.proj-feed-item:last-child .proj-feed-rail::before{display:none;}
.proj-feed-dot{width:24px;height:24px;background:var(--panel2);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;flex-shrink:0;z-index:1;color:var(--text-dim);}
.proj-feed-dot.auto{border-color:var(--violet);color:var(--violet);}
.proj-feed-dot.good{border-color:var(--good);color:var(--good);}
.proj-feed-dot.info{border-color:var(--info);color:var(--info);}
.proj-feed-dot svg{width:12px;height:12px;}
.proj-feed-body{flex:1;min-width:0;padding-top:var(--space-2);}
.proj-feed-txt{font-size:var(--fs-12);line-height:1.5;color:var(--text);}
.proj-feed-txt b{font-weight:600;}
.proj-feed-meta{display:flex;align-items:center;gap:var(--space-8);margin-top:var(--space-4);}
.proj-feed-time{font-family:var(--mono);font-size:var(--fs-10);color:var(--text-faint);}
.proj-feed-auto-tag{font-size:var(--fs-9);font-weight:700;letter-spacing:.6px;text-transform:uppercase;color:var(--violet);background:var(--violet-bg);padding:var(--space-2) var(--space-6);}

/* Projetos LIST view's own card top — .project-card itself rides on
   .card, only its content rows needed styling. */
.project-eyebrow{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-8);}
.project-client{font-family:var(--mono);font-size:var(--fs-10);color:var(--text-faint);text-transform:uppercase;letter-spacing:.6px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;}
.project-cash{display:flex;align-items:baseline;gap:var(--space-8);flex-wrap:wrap;}
.project-cash-value{font-family:var(--display);font-size:var(--fs-16);font-weight:700;color:var(--text);}
.project-cash-paid{font-size:var(--fs-11);color:var(--good);}
.project-cash-pending{font-size:var(--fs-11);color:var(--text-faint);}
.proj-avatar-stack{display:flex;align-items:center;}
.proj-avatar{width:22px;height:22px;font-size:var(--fs-10);border:1.5px solid var(--panel);margin-left:-6px;}
.proj-avatar:first-child{margin-left:0;}
.proj-coverage-note{display:flex;align-items:flex-start;gap:var(--space-8);padding:var(--space-8) var(--space-10);background:var(--warn-bg);border:1px solid rgba(var(--warn-rgb),.35);color:var(--text-dim);font-size:var(--fs-11);line-height:1.45;}

/* Confirmed real and distinct from .pipe-* below, not a duplicate: this is
   the Projetos LIST view's aggregate distribution bar ("12 em orçamento,
   5 aprovados…" across every project), .pipe-* is one project's own
   pipeline on its detail page. Different data, different job. */
.proj-stage-bar{display:flex;height:8px;overflow:hidden;gap:2px;margin-bottom:var(--space-10);}
.proj-stage-bar span{display:block;}
.proj-stage-key{display:flex;flex-wrap:wrap;gap:var(--space-14);}
.proj-stage-key span{display:flex;align-items:center;gap:var(--space-6);font-size:var(--fs-11);color:var(--text-dim);}
.proj-stage-key b{width:7px;height:7px;display:block;}
.proj-stage-key em{font-style:normal;color:var(--text-faint);}

/* Pipeline stage tracker — the real one (proj-head uses this). Ripple
   is a genuine "this is the live/current stage" signal, not ambient
   glow, so it's a deliberate exception to "no motion for decoration". */
.pipe-row{display:flex;align-items:flex-start;overflow-x:auto;padding:var(--space-4) 0;}
.pipe-node{display:flex;flex-direction:column;align-items:center;gap:var(--space-8);flex:0 0 auto;padding:var(--space-8);border-radius:var(--radius);cursor:pointer;}
.pipe-node:hover{background:var(--panel2);}
.pipe-mark{width:24px;height:24px;border-radius:50%;border:2px solid var(--border);background:var(--panel);display:flex;align-items:center;justify-content:center;font-size:var(--fs-12);font-weight:700;color:var(--text-faint);flex-shrink:0;position:relative;}
.pipe-node-label{font-size:var(--fs-11);color:var(--text-faint);white-space:nowrap;text-align:center;}
.pipe-node.done .pipe-mark{background:var(--good);border-color:var(--good);color:#08130c;}
.pipe-node.done .pipe-node-label{color:var(--text-dim);}
.pipe-node.current .pipe-mark{border-color:var(--accent);color:var(--accent);}
.pipe-node.current .pipe-node-label{color:var(--text);font-weight:700;}
.pipe-ripple{position:absolute;inset:0;border-radius:50%;border:2px solid var(--accent);opacity:0;pointer-events:none;}
.pipe-node.current .pipe-ripple{animation:pipeRipple 1.5s ease-out infinite;}
.pipe-node.current .pipe-ripple:nth-child(2){animation-delay:.01s;}
@media(prefers-reduced-motion:reduce){.pipe-node.current .pipe-ripple{animation:none;}}
@keyframes pipeRipple{0%{transform:scale(1);opacity:.75;}50%{opacity:.01;}100%{transform:scale(5);opacity:0;}}
.pipe-line{flex:1 1 28px;min-width:16px;height:2px;background:var(--border-soft);margin:var(--space-20) var(--space-8) 0;}
.pipe-line.done{background:var(--good);}
.pipe-line.current{background:var(--accent);}
.pipe-nav-row{display:flex;align-items:center;gap:var(--space-8);margin-top:var(--space-10);margin-bottom:var(--space-24);}
.pipe-nav-btn svg{width:15px;height:15px;}
.pipe-nav-done{margin-left:auto;}
.pipe-compact{display:flex;align-items:center;margin-top:var(--space-8);}
.pipe-compact-dot{width:8px;height:8px;border-radius:50%;background:var(--panel);border:2px solid var(--border);flex-shrink:0;}
.pipe-compact-dot.done{background:var(--good);border-color:var(--good);}
.pipe-compact-dot.current{border-color:var(--accent);background:var(--panel);box-shadow:0 0 0 3px rgba(var(--accent-rgb),.2);}
.pipe-compact-line{flex:1 1 auto;height:2px;background:var(--border-soft);}
.pipe-compact-line.done{background:var(--good);}
.pipe-compact-label{font-size:var(--fs-11);font-weight:600;color:var(--text);}

/* ---------- Orçamento (budget calculator) ----------
   See SLATE-CARTAO-E-ORCAMENTO.md Parte 2 for the full brief. Restyling more
   than new structure — renderBudget() already had collapsible sections,
   checkbox-based equipment selection, category grouping, a global rental-
   days field and the sticky summary rail; the six changes here are cards
   → rows, "Dono" breathing room, a sticky category separator, accent
   section numbering, and dropping the per-line price + "Em" (home base). */
.budget-equip-list{max-height:460px;overflow-y:auto;position:relative;border:1px solid var(--border-soft);background:var(--panel2);}

.budget-equip-row{
  display:flex;align-items:center;gap:11px;
  padding:var(--space-8) var(--space-14) var(--space-8) 11px;
  border-bottom:1px solid var(--border-soft);
  border-left:3px solid transparent;cursor:pointer;position:relative;
  /* The row is a <label> (wraps the checkbox) — the generic label{} rule
     further up sets uppercase/mono-ish inherited text properties meant
     for actual form field labels, which would otherwise leak onto every
     bit of plain text inside this row (item name, tag, owner). Reset
     here so each child sets its own typography instead of inheriting it. */
  text-transform:none;font-family:var(--sans);color:var(--text);font-weight:400;
}
.budget-equip-row:hover{background:var(--panel3);}
.budget-equip-row.selected{border-left-color:var(--accent);background:rgba(var(--accent-rgb),.06);}
.budget-equip-row input[type=checkbox]{position:absolute;opacity:0;width:1px;height:1px;pointer-events:none;}
.budget-equip-check-badge{
  width:18px;height:18px;flex-shrink:0;border:1px solid var(--border);
  background:var(--panel2);display:grid;place-items:center;
  color:transparent;font-size:11px;line-height:1;border-radius:var(--radius);
}
.budget-equip-row.selected .budget-equip-check-badge{
  background:var(--accent);border-color:var(--accent);color:#fff;
}
.budget-equip-thumb{
  width:46px;height:46px;flex-shrink:0;background:var(--panel3);
  border:1px solid var(--border-soft);position:relative;overflow:hidden;
  display:grid;place-items:center;
}
.budget-equip-thumb img{width:100%;height:100%;object-fit:cover;display:block;}
.budget-equip-thumb .ph{
  font-family:var(--mono);font-size:7.5px;color:var(--text-faint);
  text-align:center;letter-spacing:.4px;line-height:1.3;padding:2px;
}
/* Same "unavailable" concept as the inventory card's own .stamp+dimmed-
   thumb (style-slate.css, Inventário section), scaled down for a 46px
   square instead of the card's ~130px one — the full rotated corner
   banner doesn't fit here, so this is a thin bottom band instead. */
.budget-equip-thumb:has(.stamp) img{filter:grayscale(100%) blur(1px) opacity(50%);}
.budget-equip-thumb .stamp{
  position:absolute;inset:auto 0 0 0;top:auto;right:auto;transform:none;
  font-size:6px;line-height:1.3;padding:1px 2px;text-align:center;
  letter-spacing:.2px;border-width:1px 0 0;white-space:nowrap;overflow:hidden;
}
.budget-equip-card-body{flex:1 1 auto;min-width:0;}
.budget-equip-name{
  font-size:13px;font-weight:600;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.budget-equip-tag{
  font-family:var(--mono);font-size:var(--fs-9);letter-spacing:.8px;
  color:var(--text-faint);text-transform:uppercase;margin-top:3px;
}
/* "Dono" — label→value gets --sp-1 (the scale's own label-to-control
   step) instead of the ~1px the two used to sit at, where they read as
   one run-on word. Fixed width so names line up down the whole list. */
.budget-equip-owner{flex-shrink:0;width:86px;text-align:right;}
.budget-equip-owner .lb{
  display:block;font-family:var(--display);font-weight:700;
  text-transform:uppercase;letter-spacing:1.3px;font-size:8.5px;
  color:var(--text-faint);margin-bottom:var(--sp-1);line-height:1;
}
.budget-equip-owner .nm{
  display:block;font-size:var(--fs-12);color:var(--text-dim);
  white-space:nowrap;line-height:1;overflow:hidden;text-overflow:ellipsis;
}
.budget-equip-row.selected .budget-equip-owner .nm{color:var(--text);}

/* Category separator sticks to the top of the scrolling list, and says
   how many of the category's items are already in the budget, not just
   how many exist. Scoped here (not on the bare .checklist-group-title,
   shared with Checklists de Trabalho) on purpose. */
.budget-equip-list .checklist-group-title{
  position:sticky;top:0;z-index:2;margin:0;
  display:flex;align-items:center;gap:var(--space-8);
  padding:5px var(--space-14);background:var(--panel3);
  border-top:1px solid var(--border);border-bottom:1px solid var(--border);
  font-family:var(--display);font-weight:700;text-transform:uppercase;
  letter-spacing:1.6px;font-size:var(--fs-10);color:var(--text-dim);
}
.budget-equip-list .checklist-group-title:first-child{border-top:none;}
.budget-equip-list .checklist-group-title .n{
  margin-left:auto;font-family:var(--mono);font-size:var(--fs-9);
  letter-spacing:.8px;color:var(--text-faint);font-weight:400;
  text-transform:none;
}
.budget-equip-list .checklist-group-title .n b{color:var(--accent);font-weight:500;}

.budget-table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;}
.budget-row-grid{display:flex;flex-direction:column;}
.budget-row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-10);padding:var(--space-10) 0;border-bottom:1px solid var(--border-soft);}
.budget-row:first-child{padding-top:0;}
.budget-row:last-child{border-bottom:none;}
.budget-row-name{display:flex;flex-direction:column;align-items:start;gap:var(--space-2);flex:0 0 auto;font-size:var(--fs-12);text-align:left;min-width:90px;}
.budget-row > .row{flex-shrink:0;max-width:100%;}
.budget-row input[type="number"], .budget-row input[type="text"]{width:100%;}
.budget-row-field{text-align:center;flex:0 0 82px;}
.budget-row-field input{text-align:center;padding-left:var(--space-6);padding-right:var(--space-6);}
.budget-row-field input::placeholder{font-size:var(--fs-10);}
.budget-row-cost{text-align:right;font-weight:600;white-space:nowrap;margin-left:auto;flex:0 0 auto;}

.section-summary-row{display:flex;align-items:center;gap:var(--space-10);}
.section-summary-row > *:last-child{margin-left:auto;}
.budget-section{margin-bottom:var(--space-16);}
.proj-col .budget-section:last-child{margin-bottom:0;}
.budget-section > summary{padding:var(--space-10) var(--space-14);margin-bottom:0;list-style:none;cursor:pointer;}
.budget-section > summary::-webkit-details-marker{display:none;}
.budget-section > summary::before{content:"›";display:inline-block;flex-shrink:0;font-size:var(--fs-18);color:var(--text-faint);transition:transform .15s ease;margin-right:var(--space-4);}
.budget-section[open] > summary::before{transform:rotate(90deg);}
.budget-section-body{padding:0 var(--space-14) var(--space-12);border-top:1px solid var(--border-soft);}
.budget-section-title{font-family:var(--display);font-weight:700;text-transform:uppercase;letter-spacing:1px;font-size:var(--fs-12);color:var(--text-dim);}
.budget-section-sum{font-family:var(--display);font-size:var(--fs-16);font-weight:700;color:var(--text);}
/* Real sequence numbering (the order a budget actually gets built in),
   not decoration — if the sections ever get reordered, this follows. */
.section-summary-row .budget-section-n{
  font-family:var(--mono);font-size:var(--fs-10);color:var(--accent);
  letter-spacing:1.4px;flex-shrink:0;font-weight:500;
}

/* ---------- 04 Porte e desconto ---------- */
.budget-section-state{font-family:var(--mono);font-size:var(--fs-11);color:var(--text-dim);letter-spacing:.6px;white-space:nowrap;}
.budget-porte-fields{display:flex;gap:var(--sp-2);flex-wrap:wrap;align-items:flex-start;padding-top:var(--space-14);}
.budget-porte-fields > .field{flex:1 1 220px;min-width:0;}
.budget-porte-fields > .budget-desconto-field{flex:0 1 220px;}
.budget-pct-input{display:flex;}
.budget-pct-input .num-stepper{flex:1 1 auto;border-right:none;}
.budget-pct-input .num-stepper input{text-align:right;}
.budget-pct-suffix{
  height:var(--ctl-h);display:grid;place-items:center;padding:0 var(--space-10);
  border:1px solid var(--border);background:var(--panel3);flex-shrink:0;
  font-family:var(--mono);font-size:var(--fs-11);color:var(--text-faint);
}

/* Compact −/+ stepper for plain numeric fields (Serviços, Despesas, dias de
   aluguel, desconto) — same press-and-hold repeat as .divisao-stepper
   (bindStepperButtons handles both), just narrower to fit the tight columns
   these fields already live in. Replaces the browser's own spinner arrows,
   which are inconsistent across browsers/OSes and mostly absent on mobile. */
.num-stepper{display:inline-flex;width:100%;border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;height:var(--ctl-h);touch-action:manipulation;}
.num-stepper button{width:20px;flex:0 0 20px;border:none;background:var(--panel2);color:var(--text-dim);font-size:var(--fs-14);line-height:1;user-select:none;}
.num-stepper button:hover{background:var(--panel3);color:var(--text);}
.num-stepper button:active{background:var(--panel3);}
.num-stepper input[type=number]{
  flex:1 1 auto;min-width:0;height:100%;padding:0;text-align:center;border:none;border-radius:0;
  border-left:1px solid var(--border);border-right:1px solid var(--border);
  background:var(--panel);font-family:var(--mono);font-size:var(--fs-12);-moz-appearance:textfield;
}
.num-stepper input::-webkit-inner-spin-button,
.num-stepper input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0;}
.num-stepper input[type=number]:focus{box-shadow:none;background:var(--panel2);}
.budget-row-field:has(.num-stepper){flex-basis:104px;}
.budget-calc-line{font-family:var(--mono);font-size:var(--fs-10);color:var(--text-faint);letter-spacing:.3px;margin-top:var(--sp-1);line-height:1.6;}
.budget-calc-line b{color:var(--text);font-weight:500;}
.budget-calc-line .down{color:var(--danger);}

/* ---------- 05 Divisão da equipe + Divisão manual ---------- */
.divisao{
  --divisao-labor:var(--text-dim); --divisao-aluguel:var(--info);
  --divisao-lucro:var(--good);     --divisao-nor:var(--accent);
  --divisao-indicacao:var(--violet);
  padding-top:var(--space-14);
}
.divisao-head{display:flex;justify-content:space-between;align-items:center;gap:var(--space-12);flex-wrap:wrap;margin-bottom:var(--space-10);}
.divisao-head-lbl{font-family:var(--display);font-weight:700;text-transform:uppercase;letter-spacing:1.1px;font-size:var(--fs-10);color:var(--text-faint);}
.divisao-legend{display:flex;gap:var(--space-16);flex-wrap:wrap;font-family:var(--mono);font-size:9.5px;color:var(--text-faint);letter-spacing:.4px;text-transform:uppercase;}
.divisao-legend span{display:flex;align-items:center;gap:var(--space-6);}
.divisao-legend i{width:9px;height:9px;display:block;}

/* Régua. NADA de padding ou border nas células: com flex-basis:0, eles
   criam um piso de tamanho diferente em cada linha e as bordas deixam de
   alinhar com a barra. Tique via box-shadow inset e recuo via text-indent
   não ocupam espaço. */
.divisao-ruler{display:flex;flex-direction:column;gap:5px;margin:var(--space-4) 0 var(--space-12);}
.divisao-ruler-row{display:flex;gap:2px;}
.divisao-ruler-row > span{min-width:0;flex-basis:0;overflow:hidden;white-space:nowrap;}
.divisao-ruler-row.names > span{font-family:var(--display);font-weight:700;text-transform:uppercase;letter-spacing:1px;font-size:10.5px;color:var(--text-dim);box-shadow:inset 1px 0 0 var(--border);text-indent:6px;}
.divisao-ruler-row.names > span.nor{color:var(--accent);box-shadow:inset 1px 0 0 var(--accent);}
.divisao-ruler-row.names > span.ind{color:var(--divisao-indicacao);box-shadow:inset 1px 0 0 var(--divisao-indicacao);}
.divisao-ruler-row.bar{height:16px;}
.divisao-ruler-row.bar > span{display:flex;height:100%;}
.divisao-ruler-row.bar i{display:block;height:100%;flex-basis:0;}
.divisao-ruler-row.vals > span{font-family:var(--mono);font-size:10.5px;color:var(--text);text-indent:6px;font-variant-numeric:tabular-nums;}
.divisao-ruler-row.vals > span.nor{color:var(--accent);}
.divisao-ruler-row.vals > span.ind{color:var(--divisao-indicacao);}
.divisao-ruler-row.pct > span{font-family:var(--mono);font-size:var(--fs-9);color:var(--text-faint);text-indent:6px;}

.divisao-recon{display:flex;align-items:center;gap:var(--space-10);flex-wrap:wrap;padding:var(--space-10) var(--space-12);background:var(--panel2);border:1px solid var(--border-soft);font-family:var(--mono);font-size:10.5px;color:var(--text-dim);letter-spacing:.3px;}
.divisao-recon .ok{color:var(--good);font-weight:500;}
.divisao-recon .warn{color:var(--warn);font-weight:500;}
.divisao-recon.off{border-color:rgba(var(--warn-rgb),.4);}
.divisao-recon b{color:var(--text);font-weight:500;}
.divisao-recon b.neg{color:var(--danger);}
.divisao-recon .sp{margin-left:auto;}

.divisao-base{display:flex;align-items:flex-end;gap:var(--sp-2);flex-wrap:wrap;margin:var(--sp-3) 0;}
.divisao-base .field{width:210px;}
.divisao-base-state{height:var(--ctl-h);display:flex;align-items:center;gap:var(--space-8);}
.divisao-badge{font-family:var(--mono);font-size:var(--fs-9);letter-spacing:1px;text-transform:uppercase;color:var(--good);border:1px solid rgba(var(--good-rgb),.35);padding:2px 6px;}
.divisao-badge.editado{color:var(--warn);border-color:rgba(var(--warn-rgb),.35);}
.divisao-base-why{flex:1 1 280px;font-family:var(--mono);font-size:var(--fs-10);color:var(--text-faint);line-height:1.6;letter-spacing:.2px;padding-bottom:2px;}

.divisao-plist{border:1px solid var(--border-soft);}
.divisao-grp{display:flex;align-items:center;gap:var(--space-8);padding:var(--space-6) var(--space-10);background:var(--panel3);border-top:1px solid var(--border);border-bottom:1px solid var(--border);font-family:var(--display);font-weight:700;text-transform:uppercase;letter-spacing:1.5px;font-size:var(--fs-10);color:var(--text-dim);}
.divisao-grp .n{margin-left:auto;font-family:var(--mono);font-size:var(--fs-9);letter-spacing:.6px;color:var(--text-faint);font-weight:400;text-transform:none;}

.divisao-prow{
  display:grid;grid-template-columns:minmax(150px,1fr) auto minmax(0,1.9fr) 124px;
  grid-template-areas:"who step compo val";
  gap:var(--space-14);align-items:center;
  padding:var(--space-10) var(--space-12);border-bottom:1px solid var(--border-soft);
}
.divisao-prow > .divisao-who{grid-area:who;}
.divisao-prow > .divisao-step{grid-area:step;}
.divisao-prow > .divisao-compo{grid-area:compo;min-width:0;}
.divisao-prow > .divisao-val{grid-area:val;}
.divisao-prow.nor{background:rgba(var(--accent-rgb),.05);border-left:3px solid var(--accent);padding-left:9px;}
.divisao-prow.ind{background:rgba(var(--violet-rgb),.06);border-left:3px solid var(--divisao-indicacao);padding-left:9px;}
.divisao-prow.ind .divisao-val{color:var(--divisao-indicacao);}

.divisao-who{display:flex;align-items:center;gap:var(--space-8);min-width:0;}
.divisao-av{width:24px;height:24px;display:grid;place-items:center;flex-shrink:0;font-family:var(--display);font-weight:700;font-size:var(--fs-10);background:var(--panel3);border:1px solid var(--border);border-radius:var(--radius);letter-spacing:.3px;}
.divisao-av.nor{background:var(--accent);border-color:var(--accent);color:#fff;font-size:var(--fs-9);}
.divisao-av.ind{background:var(--divisao-indicacao);border-color:var(--divisao-indicacao);color:#fff;font-size:8px;}
.divisao-nm{font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.divisao-kind{font-family:var(--mono);font-size:8.5px;letter-spacing:1px;text-transform:uppercase;color:var(--text-faint);border:1px solid var(--border-soft);padding:1px 5px;flex-shrink:0;}
.divisao-kind.freela{color:var(--warn);border-color:rgba(var(--warn-rgb),.35);}
.divisao-fixed{font-family:var(--mono);font-size:var(--fs-10);color:var(--text-faint);display:block;max-width:140px;}

.divisao-stepper{display:inline-flex;border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;height:var(--ctl-h);touch-action:manipulation;}
.divisao-stepper button{width:30px;border:none;background:var(--panel2);color:var(--text-dim);font-size:var(--fs-15);line-height:1;user-select:none;}
.divisao-stepper button:hover{background:var(--panel3);color:var(--text);}
.divisao-stepper button:active{background:var(--panel3);}
.divisao-stepper input[type=number]{
  width:44px;height:100%;padding:0;text-align:center;border:none;border-radius:0;
  border-left:1px solid var(--border);border-right:1px solid var(--border);
  background:var(--panel);font-family:var(--mono);font-size:var(--fs-12);-moz-appearance:textfield;
}
.divisao-stepper input::-webkit-inner-spin-button,
.divisao-stepper input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0;}
.divisao-stepper input[type=number]:focus{box-shadow:none;background:var(--panel2);}

.divisao-compobar{display:flex;height:6px;gap:1px;background:var(--panel3);}
.divisao-compobar i{display:block;height:100%;flex-basis:0;}
.divisao-labels{display:flex;gap:var(--space-12);flex-wrap:wrap;margin-top:5px;font-family:var(--mono);font-size:9.5px;color:var(--text-faint);letter-spacing:.3px;}
.divisao-labels span{display:flex;align-items:center;gap:5px;white-space:nowrap;}
.divisao-labels i{width:6px;height:6px;display:block;flex-shrink:0;}
.divisao-labels b{color:var(--text);font-weight:500;}
.divisao-labels b.neg{color:var(--danger);}
.divisao-val{text-align:right;font-family:var(--display);font-weight:700;font-size:17px;font-variant-numeric:tabular-nums;white-space:nowrap;}
.divisao-prow.nor .divisao-val{color:var(--accent);}
.divisao-pct{font-size:var(--fs-11);color:var(--text-faint);}

details.divisao-fora{border-top:1px solid var(--border-soft);}
details.divisao-fora > summary{list-style:none;padding:9px var(--space-10);cursor:pointer;font-family:var(--mono);font-size:var(--fs-10);color:var(--text-faint);letter-spacing:.3px;display:flex;gap:var(--space-8);align-items:center;}
details.divisao-fora > summary::-webkit-details-marker{display:none;}
details.divisao-fora > summary::before{content:"+";font-size:var(--fs-12);width:10px;}
details.divisao-fora[open] > summary::before{content:"−";}
details.divisao-fora > summary:hover{color:var(--text-dim);}

.divisao-actions{display:flex;justify-content:flex-start;margin-top:var(--space-12);}

.budget-tool-eyebrow{font-family:var(--mono);font-size:var(--fs-9);letter-spacing:1.8px;text-transform:uppercase;color:var(--text-faint);border:1px solid var(--border);padding:2px 6px;flex-shrink:0;}
.budget-attach{
  display:flex;align-items:flex-end;gap:var(--sp-2);flex-wrap:wrap;
  padding:var(--space-14);margin:var(--space-14) calc(-1 * var(--space-14)) calc(-1 * var(--space-12));
  background:var(--panel2);border-top:1px solid var(--border);
}
.budget-attach .field{flex:1 1 280px;min-width:0;}
.budget-attach-status{flex:1 1 100%;font-family:var(--mono);font-size:var(--fs-10);color:var(--text-faint);letter-spacing:.2px;}
.budget-attach-status b{color:var(--warn);font-weight:500;}

@media(max-width:820px){
  .divisao-prow{grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"who val" "step step" "compo compo";gap:var(--space-8) var(--space-12);}
  .divisao-ruler-row.pct{display:none;}
  .divisao-base .field{width:100%;}
}

/* Hero total — was a gradient-tinted glass card; flat tint instead. */
/* Never actually stuck to anything — this class had no rule at all, only
   .proj-col's plain flex-column layout. .proj-grid already sets
   align-items:start (required for sticky to work inside a grid track at
   all), so this only needed the position+offset itself. */
.budget-sticky-col{position:sticky;top:var(--space-20);align-self:start;}
.budget-hero{background:var(--panel2);border-color:var(--accent);margin-bottom:var(--space-14);}
.budget-hero-lbl{font-family:var(--mono);font-size:var(--fs-9);text-transform:uppercase;letter-spacing:1.8px;color:var(--text-faint);font-weight:400;}
.budget-hero-val{font-family:var(--display);font-size:44px;font-weight:800;line-height:1;margin:var(--space-6) 0 var(--space-2);color:var(--accent);}
.budget-hero-alt{display:flex;gap:var(--space-20);margin-top:var(--space-14);padding-top:var(--space-12);border-top:1px solid var(--border-soft);}
.budget-hero-alt .l{font-size:var(--fs-10);color:var(--text-faint);text-transform:uppercase;letter-spacing:.7px;line-height:1.3;}
.budget-hero-alt .v{font-family:var(--display);font-size:var(--fs-18);font-weight:700;margin-top:var(--space-6);}
.budget-total-row .lbl{font-weight:600;}
.budget-total-row .val{font-weight:700;}
.budget-total-row.featured .lbl{font-family:var(--display);text-transform:uppercase;letter-spacing:1px;color:var(--accent);font-size:var(--fs-14);}
.budget-total-row.featured .val{font-family:var(--display);font-size:var(--fs-24);font-weight:800;color:var(--accent);}

/* One-shot flash after "Abrir" loads a saved orçamento back into the
   Calculadora (see budgetLoadedFlashPending in 09-orcamento.js) — a glow
   pulse on the hero card plus a scale pop on every number in it, so it
   reads as "this just loaded" instead of looking like nothing happened. */
.budget-summary-flash .budget-hero{animation:budgetHeroGlow .9s ease-out;}
.budget-summary-flash .budget-hero-val,
.budget-summary-flash .budget-hero-alt .v,
.budget-summary-flash .budget-total-row .val{animation:budgetValPop .5s ease-out;}
@keyframes budgetHeroGlow{
  0%{box-shadow:0 0 0 0 rgba(var(--accent-rgb),.5);}
  100%{box-shadow:0 0 0 18px rgba(var(--accent-rgb),0);}
}
@keyframes budgetValPop{
  0%{transform:scale(1.18);color:var(--accent);}
  100%{transform:scale(1);}
}
@media(prefers-reduced-motion:reduce){
  .budget-summary-flash .budget-hero,
  .budget-summary-flash .budget-hero-val,
  .budget-summary-flash .budget-hero-alt .v,
  .budget-summary-flash .budget-total-row .val{animation:none;}
}
.budget-relatorio-textarea{font-family:var(--mono);font-size:var(--fs-12);width:100%;resize:vertical;}

/* Revenue-split visualization — same "labeled segmented bar" language as
   .recorrente-share above and .fluxo-bars on Painel (flat fill, no
   radius), kept visually consistent on purpose even though it's a
   separate selector family already in the app. */
.wf-bar{display:flex;height:9px;overflow:hidden;gap:1px;margin-bottom:var(--space-12);background:var(--border-soft);}
.wf-row{display:flex;align-items:center;gap:var(--space-8);padding:var(--space-6) 0;}
.wf-dot{width:8px;height:8px;flex-shrink:0;}
.wf-name{flex:1;min-width:0;font-size:var(--fs-11);color:var(--text-dim);}
.wf-pct{font-size:var(--fs-11);color:var(--text-faint);width:34px;text-align:right;flex-shrink:0;}
.wf-val{font-size:var(--fs-12);font-weight:600;width:92px;text-align:right;flex-shrink:0;}
.wf-note{margin-top:var(--space-10);padding-top:var(--space-10);border-top:1px solid var(--border-soft);font-size:var(--fs-11);color:var(--text-faint);line-height:1.5;}

/* ---------- Drive ---------- */
.drive-breadcrumbs{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-4);margin-bottom:var(--space-14);font-size:var(--fs-12);}
.drive-crumb{background:none;border:none;color:var(--text-dim);padding:var(--space-2) var(--space-4);cursor:pointer;border-radius:var(--radius-sm);}
.drive-crumb:hover{color:var(--text);background:var(--panel2);}
.drive-crumb:last-child{color:var(--text);font-weight:600;}
.drive-crumb-sep{color:var(--text-faint);}
.drive-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:var(--space-10);}
.drive-file-card{cursor:pointer;}
.drive-file-card .card-body{padding:var(--space-12) var(--space-14);}
.drive-file-icon{flex-shrink:0;width:32px;height:32px;display:flex;align-items:center;justify-content:center;color:var(--text-faint);}
.drive-file-thumb-wrap{width:100%;aspect-ratio:16/9;background:var(--panel2);overflow:hidden;}
.drive-file-thumb{width:100%;height:100%;object-fit:cover;display:block;}
.drive-move-list{display:flex;flex-direction:column;gap:var(--space-2);max-height:280px;overflow-y:auto;margin-bottom:var(--space-4);}
.drive-move-folder-row{display:flex;align-items:center;gap:var(--space-8);text-align:left;background:none;border:none;color:var(--text);padding:var(--space-8) var(--space-10);border-radius:var(--radius-sm);cursor:pointer;font-size:var(--fs-14);}
.drive-move-folder-row:hover{background:var(--panel2);}
.drive-move-folder-row .nav-icon{width:18px;height:18px;color:var(--text-faint);flex-shrink:0;}
.drive-action-menu-item{display:flex;align-items:center;gap:var(--space-10);background:none;border:none;color:var(--text);padding:var(--space-8) var(--space-10);border-radius:var(--radius-sm);cursor:pointer;font-size:var(--fs-12);text-align:left;width:100%;}
.drive-action-menu-item:hover{background:var(--panel);}
.drive-action-menu-item svg{flex-shrink:0;}
.drive-action-menu-danger{color:var(--danger);}
.drive-action-menu-danger:hover{background:var(--danger-bg);}
/* 45 — mesa de corte. Com uma imagem ou vídeo aberto, tudo que não é a
   imagem cai pra 20% e dessatura. A classe é recalculada em todo render()
   a partir de modal.type, então fechar por qualquer caminho já devolve o
   app ao normal, sem listener de fechamento pra esquecer. */
.sidebar,.page-head,.mobile-header{transition:opacity .3s ease,filter .3s ease;}
body.modo-mesa .sidebar,body.modo-mesa .page-head,body.modo-mesa .mobile-header{opacity:.2;filter:saturate(.3);}
.drive-preview-modal{max-width:min(900px,92vw);}
.drive-preview-media{max-width:100%;max-height:70vh;display:block;margin:0 auto;}
.drive-preview-frame{width:100%;height:70vh;border:none;}

/* ---------- Contato (mail) ---------- */
.select-toggle{position:relative;flex-shrink:0;width:18px;height:18px;border:1.5px solid var(--border);background:var(--panel2);color:transparent;font-size:var(--fs-11);font-weight:700;display:flex;align-items:center;justify-content:center;cursor:pointer;padding:0;margin-right:var(--space-10);}
.select-toggle:hover{border-color:var(--text-faint);}
.select-toggle.checked{border-color:var(--accent);background:var(--accent);color:#fff;}
@media(max-width:820px){.select-toggle::before{content:'';position:absolute;top:50%;left:50%;width:40px;height:40px;transform:translate(-50%,-50%);}}
/* Toolbar: ruled folder tabs on the left, filter/refresh on the right,
   sharing one rule (same idea as .mail-tabs-row in the message modal). */
.mail-toolbar{display:flex;align-items:flex-end;gap:var(--space-12);border-bottom:1px solid var(--border);margin-bottom:var(--space-12);}
.mail-toolbar .tab-strip{border-bottom:none;min-width:0;overflow-x:auto;scrollbar-width:none;}
.mail-toolbar .tab-strip::-webkit-scrollbar{display:none;}
.mail-toolbar-side{display:flex;align-items:center;gap:var(--space-8);padding-bottom:var(--space-6);flex-shrink:0;}
.mail-toolbar-side .hint{margin:0;white-space:nowrap;}
.mail-toolbar-side .btn-sm .nav-icon{width:14px;height:14px;}
.mail-filter-chip{display:inline-flex;align-items:center;gap:var(--space-6);height:var(--ctl-h-sm);padding:0 var(--space-6) 0 var(--space-10);border:1px solid var(--border);border-radius:var(--radius);background:var(--panel2);font-family:var(--display);font-weight:700;font-size:var(--fs-10);letter-spacing:.7px;text-transform:uppercase;color:var(--text-dim);transition:border-color .12s ease,color .12s ease,background .12s ease;}
.mail-filter-chip:hover{border-color:var(--text-faint);color:var(--text);}
.mail-filter-chip.on{border-color:var(--accent);color:var(--text);background:rgba(var(--accent-rgb),.1);}
.mail-filter-count{font-family:var(--mono);font-weight:500;font-size:var(--fs-10);letter-spacing:0;min-width:18px;padding:var(--space-2) var(--space-4);text-align:center;background:var(--panel3);color:var(--text);}
.mail-filter-chip.on .mail-filter-count{background:var(--accent);color:#fff;}

/* Mailbox list: one panel, hairlines between rows. Unread and selected
   rows carry an accent edge instead of a dot/boxed card. */
.mail-list{border:1px solid var(--border-soft);background:var(--panel);}
.mail-item{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:var(--space-12);padding:var(--space-10) var(--space-14);border-top:1px solid var(--border-soft);position:relative;}
.mail-item:first-child{border-top:none;}
.mail-row{grid-template-columns:auto auto minmax(0,1fr) auto;cursor:pointer;overflow:hidden;max-height:120px;transition:background .12s ease,opacity 240ms ease,transform 240ms ease,max-height 240ms ease,padding 240ms ease;}
.mail-row:hover{background:var(--panel2);}
.mail-row.is-selected{background:rgba(var(--accent-rgb),.07);}
.mail-row.unread::before,.mail-row.is-selected::before{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;background:var(--accent);}
.mail-row .select-toggle{margin-right:0;}
.mail-row.mail-row-removing{opacity:0;transform:translateX(12px);max-height:0;padding-top:0;padding-bottom:0;pointer-events:none;}
.mail-row-avatar{width:32px;height:32px;font-size:var(--fs-12);}
.mail-row-ico{width:32px;height:32px;display:grid;place-items:center;background:rgba(var(--info-rgb),.12);color:var(--info);}
.mail-row-ico .nav-icon{width:16px;height:16px;}
.mail-row-main{min-width:0;}
.mail-row-top{display:flex;align-items:baseline;gap:var(--space-8);min-width:0;}
.mail-row-top .tag{flex-shrink:0;align-self:center;}
.mail-row-from{font-size:var(--fs-14);font-weight:500;color:var(--text-dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;}
.mail-row-when{margin-left:auto;padding-left:var(--space-8);flex-shrink:0;font-family:var(--mono);font-size:var(--fs-10);color:var(--text-faint);white-space:nowrap;}
.mail-row-subject{font-size:var(--fs-12);color:var(--text-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:var(--space-2);}
.mail-row.unread .mail-row-from{font-weight:700;color:var(--text);}
.mail-row.unread .mail-row-subject{color:var(--text-dim);}
.mail-row.unread .mail-row-when{color:var(--accent);}
.mail-row-error{font-size:var(--fs-11);color:var(--danger);margin-top:var(--space-4);}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;}
.mail-row-act{display:flex;gap:var(--space-4);}
@media(hover:hover){
  .mail-row .mail-row-act{opacity:0;transition:opacity .12s ease;}
  .mail-row:hover .mail-row-act,.mail-row:focus-within .mail-row-act{opacity:1;}
}
@media(max-width:820px){
  .mail-toolbar{flex-wrap:wrap;border-bottom:none;gap:var(--space-8);}
  .mail-toolbar .tab-strip{flex:1 1 100%;border-bottom:1px solid var(--border);}
  .mail-toolbar-side{width:100%;padding-bottom:0;}
  .mail-toolbar-side .mail-updated{order:-1;margin-right:auto;}
  .mail-btn-label{display:none;}
}
@media(max-width:560px){
  .mail-row{grid-template-columns:auto minmax(0,1fr) auto;}
  /* Doubled class: .mail-avatar (display:grid) is defined further down. */
  .mail-row .mail-row-avatar{display:none;}
  .mail-item{padding:var(--space-10) var(--space-12);gap:var(--space-10);}
}
.mail-html-frame{width:100%;border:1px solid var(--border-soft);min-height:220px;background:#fff;}

/* ---------- mail view: ficha, tabs, folha, attachments (Slate redesign) ---------- */
/* Email longo: title/footer pinned, body scrolls between them. The sticky
   pieces land on the border of .modal's own padding-box, not its edge — see
   SLATE-EMAIL-VIEWER.md's "Pegadinha" — so this modal zeroes both the
   bottom padding .modal normally carries and .modal-footer's usual negative
   bottom margin, scoped here so itemModal/taskModal don't change. */
.modal-email{padding-bottom:0;}
.modal-email .modal-footer{position:sticky;bottom:0;z-index:2;margin-bottom:0;}

.mail-ficha{display:grid;grid-template-columns:auto minmax(0,1fr);gap:var(--space-16);align-items:start;margin-bottom:var(--sp-3);}
.mail-avatar{width:40px;height:40px;border-radius:50%;flex-shrink:0;display:grid;place-items:center;font-family:var(--display);font-weight:800;font-size:var(--fs-16);letter-spacing:.6px;}
.mail-tone-violet{background:rgba(var(--violet-rgb),.16);color:var(--violet);}
.mail-tone-info{background:rgba(var(--info-rgb),.16);color:var(--info);}
.mail-tone-good{background:rgba(var(--good-rgb),.16);color:var(--good);}
.mail-ficha dl{display:grid;grid-template-columns:52px minmax(0,1fr);gap:var(--space-6) var(--space-12);margin:0;align-items:baseline;}
.mail-ficha dt{font-family:var(--display);font-weight:700;font-size:var(--fs-10);text-transform:uppercase;letter-spacing:1.1px;color:var(--text-faint);}
.mail-ficha dd{margin:0;font-size:var(--fs-12);min-width:0;}
.mail-ficha dd b{font-weight:600;margin-right:var(--space-6);}
.mail-ficha dt.mail-ficha-att-dt{align-self:center;}
.mail-ficha dd.mail-ficha-att-dd{padding-top:var(--space-4);}
.mail-addr{font-family:var(--mono);font-size:var(--fs-11);color:var(--text-dim);overflow-wrap:anywhere;}
.mail-ficha time[title]{text-decoration:underline dotted var(--text-faint);text-underline-offset:3px;cursor:help;}

.mail-chips{display:flex;flex-wrap:wrap;gap:var(--space-6);}
.mail-chip{display:inline-flex;align-items:center;gap:var(--space-6);max-width:100%;min-width:0;height:30px;padding:0 var(--space-10) 0 var(--space-4);background:var(--panel2);border:1px solid var(--border);border-radius:var(--radius);color:var(--text);text-decoration:none;font-size:var(--fs-12);cursor:pointer;}
.mail-chip:hover{border-color:var(--accent);}
.mail-chip-ico{width:22px;height:22px;flex-shrink:0;display:grid;place-items:center;background:rgba(var(--mail-fam-rgb,120,116,108),.14);color:var(--mail-fam,var(--text-dim));}
.mail-chip-ico svg{width:14px;height:14px;}
.mail-chip-nm{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:210px;}
.mail-chip-sz{font-family:var(--mono);font-size:var(--fs-9);color:var(--text-faint);white-space:nowrap;}
.mail-chip-more{font-family:var(--mono);font-size:var(--fs-11);color:var(--text-dim);padding:0 var(--space-10);}
.mail-fam-pdf{--mail-fam:var(--danger);--mail-fam-rgb:var(--danger-rgb);}
.mail-fam-sheet{--mail-fam:var(--good);--mail-fam-rgb:var(--good-rgb);}
.mail-fam-img{--mail-fam:var(--info);--mail-fam-rgb:var(--info-rgb);}
.mail-fam-video{--mail-fam:var(--violet);--mail-fam-rgb:var(--violet-rgb);}

.mail-tabs-row{display:flex;align-items:flex-end;gap:var(--space-8);border-bottom:1px solid var(--border);margin-bottom:var(--space-16);}
.mail-tabs-row .tab-strip{border-bottom:none;}

.mail-sheet{border:1px solid var(--border);background:var(--panel2);margin-bottom:var(--space-16);}
.mail-sheet-in{padding:var(--space-20) var(--space-24);}
.mail-shadow-host{display:block;overflow-x:auto;}
.mail-plain{white-space:pre-wrap;font-size:var(--fs-12);line-height:1.65;color:var(--text);overflow-wrap:anywhere;margin:0;font-family:var(--sans);}
.mail-plain .mail-quote{color:var(--text-faint);}
.mail-plain .mail-sig{color:var(--text-dim);}

/* Footer "Anexos N" recall — only meaningful once the ficha's own
   attachments row has scrolled out of view (see mailBindAttRowObserver,
   12-contato.js), so it starts hidden rather than conditionally rendered:
   the IntersectionObserver needs the row in the DOM regardless. */
.mail-att-footer-wrap{position:relative;opacity:0;visibility:hidden;pointer-events:none;transition:opacity 180ms ease,visibility 180ms;}
.modal-email.mail-att-row-hidden .mail-att-footer-wrap{opacity:1;visibility:visible;pointer-events:auto;}
.mail-att-btn[aria-expanded="true"]{border-color:var(--accent);}
.mail-att-count{font-family:var(--mono);font-weight:500;font-size:var(--fs-11);letter-spacing:0;color:var(--text-dim);}
.mail-att-popover{position:absolute;right:0;bottom:calc(100% + var(--space-8));width:min(380px,calc(100vw - 72px));max-height:300px;overflow-y:auto;background:var(--panel);border:1px solid var(--border);box-shadow:0 14px 40px rgba(var(--shadow-rgb),.3);padding:var(--space-6);z-index:var(--z-popover);}
.mail-att-pop-row{display:grid;grid-template-columns:26px minmax(0,1fr) auto;align-items:center;gap:var(--space-10);padding:var(--space-6) var(--space-8);color:var(--text);text-decoration:none;font-size:var(--fs-12);}
.mail-att-pop-row:hover,.mail-att-pop-row:focus-visible{background:var(--panel2);}
.mail-att-pop-nm{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.mail-att-pop-sz{font-family:var(--mono);font-size:var(--fs-9);color:var(--text-faint);}

@media(max-width:520px){
  .mail-ficha{grid-template-columns:minmax(0,1fr);}
  .mail-ficha .mail-avatar{display:none;}
  .mail-chip-nm{max-width:150px;}
  .mail-sheet-in{padding:var(--space-16);}
  /* .modal h2 is sized for short titles (project names, task titles) — a
     real email subject is free text and often runs long, which pushed the
     sticky header to 4-5 lines tall on a phone, eating most of the screen
     before any actual message content showed. Clamped to 2 lines with an
     ellipsis and a smaller size, just for this modal. */
  .modal-email h2{
    font-size:var(--fs-16);padding-top:var(--space-14);padding-bottom:var(--space-10);
  }
  .modal-email .modal-h2-title{
    display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;
    /* Without this, a flex child sizes to its content's unwrapped intrinsic
       width instead of the space .modal h2 (display:flex) actually gives
       it — the line-clamp then clips vertically as intended but the title
       still pushes the header past the modal's own width. */
    min-width:0;
  }
}

/* ============================================================
   STEP 4 — FINANCEIRO (Pagamentos, Gastos Recorrentes, Fluxo de
   Caixa, Histórico Financeiro) + Relatório
   ============================================================ */

/* ---------- Pagamentos ---------- */
.pagamento-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(360px,100%),1fr));gap:var(--space-14);}
.pagamento-card .card-actions{cursor:default;}

/* ---------- Gastos Recorrentes ---------- */
/* Was a gradient-tinted glass card (see .budget-hero, same recipe) — flat
   tint instead, same as everywhere else this pattern showed up. */
.recorrente-renew{background:var(--warn-bg);border-color:var(--warn);}
.recorrente-renew-icon{width:15px;height:15px;color:var(--warn);flex-shrink:0;display:flex;}
.recorrente-renew-icon svg{width:100%;height:100%;}
.recorrente-renew-title{font-family:var(--display);font-weight:700;font-size:var(--fs-14);text-transform:uppercase;letter-spacing:.8px;color:var(--text);}
/* 37 — fita de renovação. Doze células, uma por mês, no lugar da régua de
   dias que já teve rótulo sobreposto (commit 91e800b). Doze células em grid
   não têm como colidir. A lista de "vence logo" embaixo continua: ela é o
   alerta, a fita é o ritmo do ano. */
.renov-fita{display:grid;grid-template-columns:repeat(12,1fr);gap:2px;margin:0 0 var(--space-14);}
.renov-mes{display:flex;flex-direction:column;gap:var(--space-4);min-width:0;}
.renov-cel{height:22px;background:var(--panel2);border:1px solid var(--border-soft);position:relative;}
.renov-cel i{position:absolute;inset:0;background:var(--warn);opacity:var(--peso,0);}
.renov-mes.atual .renov-cel{border-color:var(--accent);}
.renov-mes.atual .renov-cel i{background:var(--accent);}
.renov-lbl{font-family:var(--mono);font-size:var(--fs-9);color:var(--text-faint);text-align:center;text-transform:uppercase;}
.renov-mes.atual .renov-lbl{color:var(--accent);}
.recorrente-renewrows{display:flex;gap:var(--space-10);flex-wrap:wrap;}
.recorrente-rr{flex:1 1 180px;display:flex;align-items:center;gap:var(--space-10);padding:var(--space-10) var(--space-12);background:var(--panel2);border:1px solid var(--border-soft);cursor:pointer;}
.recorrente-rr:hover{border-color:var(--text-faint);}
.recorrente-rr-d{font-family:var(--display);font-size:var(--fs-16);font-weight:700;color:var(--warn);flex-shrink:0;}
.recorrente-rr-t{flex:1;min-width:0;font-size:var(--fs-12);line-height:1.3;}
.recorrente-rr-t small{display:block;color:var(--text-faint);font-size:var(--fs-10);margin-top:var(--space-4);line-height:1.3;}
.recorrente-share{display:flex;align-items:center;gap:var(--space-8);min-width:120px;}
.recorrente-sharebar{flex:1;height:5px;background:var(--panel3);overflow:hidden;}
.recorrente-sharebar i{display:block;height:100%;background:var(--accent);}
.recorrente-sharepct{font-size:var(--fs-10);color:var(--text-faint);width:28px;text-align:right;flex-shrink:0;}

/* ---------- Fluxo de Caixa (embedded widget on Painel) ---------- */
.fluxo-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:var(--space-14);margin-bottom:var(--space-14);}
.fluxo-card .card-body{display:flex;flex-direction:column;gap:var(--space-2);}
.fluxo-card-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-10);min-height:24px;}
.fluxo-card-month{font-family:var(--display);font-weight:700;font-size:var(--fs-12);text-transform:uppercase;letter-spacing:1px;color:var(--text-dim);}
.fluxo-current{border-color:var(--accent);}
.fluxo-net{font-family:var(--display);font-size:var(--fs-24);font-weight:800;line-height:1.15;margin-top:var(--space-2);}
.fluxo-bars{display:flex;flex-direction:column;gap:var(--space-8);margin:var(--space-14) 0 var(--space-12);}
.fluxo-bar-row{display:flex;align-items:center;gap:var(--space-10);}
.fluxo-bar-label{font-size:var(--fs-11);color:var(--text-faint);width:34px;flex:0 0 auto;}
.fluxo-bar{position:relative;flex:1;height:6px;background:var(--panel3);overflow:hidden;min-width:32px;}
.fluxo-bar-fill{position:absolute;left:0;top:0;bottom:0;transition:width .3s ease;}
.fluxo-in{background:var(--good);z-index:2;}
.fluxo-in-forecast{background:var(--text-faint);z-index:1;}
.fluxo-out{background:var(--danger);}
.fluxo-bar-value{font-size:var(--fs-12);font-variant-numeric:tabular-nums;white-space:nowrap;flex:0 0 auto;min-width:80px;text-align:right;color:var(--text-dim);}
.fluxo-forecast-value{color:var(--text-faint);font-size:var(--fs-20);}
.fluxo-running{padding-top:var(--space-10);border-top:1px solid var(--border-soft);}
.fluxo-running b{font-variant-numeric:tabular-nums;}
.fluxo-detail{margin-top:var(--space-10);padding-top:var(--space-10);border-top:1px solid var(--border-soft);font-size:var(--fs-11);line-height:1.6;color:var(--text-dim);}
.fluxo-detail .hint{display:inline;margin-right:var(--space-4);}
.fluxo-expense-totals{display:flex;flex-direction:column;gap:var(--space-6);margin-top:var(--space-8);}
.fluxo-expense-row{display:flex;align-items:flex-start;gap:var(--space-6);font-size:var(--fs-11);}
.fluxo-expense-row b{margin-left:auto;font-variant-numeric:tabular-nums;}
.fluxo-chip-icon{display:inline-flex;flex:0 0 auto;color:var(--text-faint);}
.fluxo-chip-icon .nav-icon svg{display:block;}
.fluxo-team-bars{margin:0;}
.fluxo-team-label{width:70px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}

/* ---------- Histórico Financeiro ---------- */
.historico-table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;}

/* ============================================================
   STEP 5 — PORTFÓLIO/checklists/Membros, Contas, Revisão de Vídeo,
   Chat de voz, Prospecção core
   ============================================================
   Revisão de Vídeo's admin-side project tab (projectVideoReviewSectionHtml
   in 20c-video-review.js) turned out to carry zero unique classes — it's
   entirely .card/.hint/.task-checklist, already covered. Nothing to add.
   Clientes/Configurações turned out to be a much bigger surface than
   "Clientes" implied — the changelog editor, import-diff viewer,
   category/pipeline-stage editors, DPP tree, pagination and filters live
   there too, none with matching CSS yet. Deferred to Step 6 rather than
   guessing at components I haven't seen rendered once; covering the core
   Prospecção card here since that's the actual "Clientes" concept. */

.item-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:var(--space-14);}
.card-reorder{display:flex;gap:var(--space-2);margin-right:auto;}
.card-reorder .btn-icon{width:var(--ctl-h-sm);height:var(--ctl-h-sm);}
.card-reorder .btn-icon:disabled{opacity:.3;cursor:default;}
.thumb-preview{width:88px;height:88px;background:var(--panel2);border:1px solid var(--border);overflow:hidden;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
.thumb-preview img{width:100%;height:100%;object-fit:cover;}
.thumb-preview.ratio-1-1{width:96px;height:96px;}
.thumb-preview.thumb-preview-round{width:64px;height:64px;border-radius:50%;}
.thumb-preview.ratio-receipt{width:110px;height:150px;}
.thumb-preview.ratio-4-3{width:168px;height:126px;flex:0 0 168px;}
.thumb-preview .mono{font-size:var(--fs-10);color:var(--text-faint);}
.thumb-preview.ratio-receipt img{object-fit:contain;}
.upload-progress{height:5px;background:var(--panel2);overflow:hidden;margin-top:var(--space-8);}
.upload-progress-fill{height:100%;width:0%;background:var(--accent);transition:width .2s ease;}

.portfolio-dropzone.drag-over{background:var(--panel2);box-shadow:inset 0 0 0 2px var(--accent);}
.portfolio-dropzone-video{border:1px dashed var(--border);padding:var(--space-12);}
.portfolio-dropzone-video.drag-over{border-color:var(--accent);border-style:solid;}
.portfolio-dropzone-multi{border:1px dashed transparent;padding:var(--space-4);margin:-4px;}
.portfolio-dropzone-multi.drag-over{border-color:var(--accent);background:var(--panel2);}
.portfolio-thumb-candidate-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:var(--space-8);}
@media(max-width:480px){.portfolio-thumb-candidate-grid{grid-template-columns:repeat(3,1fr);}}
.portfolio-thumb-candidate{padding:0;border:2px solid transparent;overflow:hidden;cursor:pointer;background:var(--panel2);aspect-ratio:16/9;}
.portfolio-thumb-candidate img{width:100%;height:100%;object-fit:cover;display:block;}
.portfolio-thumb-candidate:hover{border-color:var(--text-faint);}
.portfolio-thumb-candidate.selected{border-color:var(--accent);}
.thumb-search-results{display:flex;flex-wrap:wrap;gap:var(--space-6);margin-top:var(--space-8);}
.thumb-search-results .thumb-search-thumb{width:52px;height:52px;object-fit:cover;border:1px solid var(--border);cursor:pointer;}
.thumb-search-results .thumb-search-thumb:hover{border-color:var(--accent);}

.person-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:var(--space-14);margin-bottom:var(--space-8);}
.person-link-icon{display:inline-flex;width:16px;height:16px;flex-shrink:0;}
.person-link-icon svg{width:100%;height:100%;display:block;}
.person-photo{width:100%;aspect-ratio:1/1;background:var(--panel2);overflow:hidden;}
.person-photo img{width:100%;height:100%;object-fit:cover;display:block;}
.person-photo .avatar{width:100%;height:100%;border-radius:0;font-size:var(--fs-24);}
.person-body{padding:var(--space-14);}
.role-chips{display:flex;flex-wrap:wrap;gap:var(--space-6);margin:var(--space-10) 0 var(--space-4);}
.role-chip{font-family:var(--mono);font-size:var(--fs-10);letter-spacing:.6px;text-transform:uppercase;color:var(--text-dim);background:var(--panel2);border:1px solid var(--border);padding:var(--space-4) var(--space-8);}

/* Video-trim tool (upload flow) — one deliberate exception again: the
   buffering spinner is a real loading signal, kept spinning. */
.trim-video-wrap{position:relative;}
.trim-preview-video{width:100%;max-height:340px;background:#000;display:block;object-fit:contain;}
.trim-loading{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-10);background:rgba(0,0,0,.6);color:#fff;font-size:var(--fs-12);transition:opacity .2s ease;pointer-events:none;}
.trim-loading.hidden{opacity:0;}
.trim-spinner{width:26px;height:26px;border-radius:50%;border:2.5px solid rgba(255,255,255,.25);border-top-color:var(--accent);animation:ptrSpin .7s linear infinite;}
.trim-buffering{position:absolute;top:10px;right:10px;display:flex;align-items:center;gap:var(--space-6);background:rgba(0,0,0,.7);padding:var(--space-6) var(--space-10) var(--space-6) var(--space-8);font-size:var(--fs-11);color:#fff;transition:opacity .15s ease;}
.trim-buffering.hidden{opacity:0;pointer-events:none;}
.trim-buffering .trim-spinner{width:13px;height:13px;border-width:2px;}
.trim-play-btn{background:var(--panel2);border:1px solid var(--border-soft);border-radius:50%;width:34px;height:34px;flex:0 0 34px;display:flex;align-items:center;justify-content:center;color:var(--text);cursor:pointer;font-size:var(--fs-12);}
.trim-play-btn:hover{border-color:var(--accent);color:var(--accent);}
.trim-time{font-variant-numeric:tabular-nums;font-size:var(--fs-12);color:var(--text-dim);min-width:38px;}
.trim-timeline{position:relative;height:34px;margin:var(--space-6) var(--space-2) var(--space-4);touch-action:none;user-select:none;}
.trim-track{position:absolute;left:7px;right:7px;top:50%;transform:translateY(-50%);height:5px;background:var(--panel2);border:1px solid var(--border-soft);cursor:pointer;}
.trim-range{position:absolute;top:50%;transform:translateY(-50%);height:5px;background:var(--accent);pointer-events:none;}
.trim-playhead{position:absolute;top:2px;bottom:2px;width:2px;background:#fff;pointer-events:none;}
.trim-handle{position:absolute;top:50%;width:14px;height:26px;transform:translate(-50%,-50%);background:var(--accent);cursor:ew-resize;touch-action:none;}
.trim-handle::before{content:"";position:absolute;left:50%;top:50%;width:2px;height:12px;background:rgba(255,255,255,.75);transform:translate(-50%,-50%);}
.trim-labels{display:flex;justify-content:space-between;font-size:var(--fs-12);color:var(--text-dim);margin:var(--space-2) var(--space-2) var(--space-14);}
.trim-labels b{color:var(--text);font-weight:600;}

/* ---------- Contas (credentials vault) ---------- */
.cred-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(360px,100%),1fr));gap:var(--space-14);}
.cred-row{display:flex;align-items:center;gap:var(--space-8);font-size:var(--fs-12);margin-top:var(--space-4);}
.cred-field-icon{color:var(--text-faint);flex-shrink:0;}
.cred-value{font-family:var(--mono);color:var(--text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.cred-favicon{width:24px;height:24px;border-radius:50%;flex-shrink:0;display:block;object-fit:cover;}

/* ---------- Configurações: collapsible settings groups (shared by
   several screens, not just Chat de voz — found here first) ---------- */
.settings-group{border:1px solid var(--border-soft);background:var(--panel2);margin:var(--sp-4) 0;overflow:hidden;}
.settings-group-summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:var(--space-10);padding:var(--space-16) var(--space-18);font-family:var(--display);font-weight:700;font-size:var(--fs-14);text-transform:uppercase;letter-spacing:1px;color:var(--text);user-select:none;}
.settings-group-summary::-webkit-details-marker{display:none;}
.settings-group-summary::before{content:"›";display:inline-block;flex-shrink:0;font-size:var(--fs-18);line-height:1;color:var(--text-faint);transition:transform .18s ease;}
.settings-group[open] .settings-group-summary::before{transform:rotate(90deg);}
.settings-group-summary .settings-group-hint{margin-left:auto;text-transform:none;letter-spacing:normal;font-family:var(--sans);font-size:var(--fs-11);font-weight:400;color:var(--text-faint);}
.settings-group-body{padding:var(--space-2) var(--space-18) var(--space-24);}
.settings-group-body .section-title{font-size:var(--fs-12);margin:var(--sp-4) 0 var(--space-10);}
.settings-group-body .section-title.mt-0,.settings-group-body .section-title:first-child{margin-top:0;}

/* CSS-only accordion body — the smooth open/close .settings-group itself
   doesn't have: that one is JS-animated (animateDetailsToggle in
   02-state.js, wired in 15-actions.js), since the app already has a JS
   layer to hook into. A standalone page (briefing.html, and anything
   after it that needs a "click to expand" section) doesn't load that
   bundle, so this is the equivalent done in pure CSS instead — a grid-row
   transition needs exactly one child to size, hence the required -inner
   wrapper (don't put content straight in .accordion-body, it won't clip
   correctly with more than one child). Reuses .settings-group/-summary/
   -hint for the outer chrome so both mechanisms look identical; only the
   body differs. */
.accordion-body{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--mo-peso-in) var(--mo-peso-ez);}
.settings-group[open] .accordion-body{grid-template-rows:1fr;}
.accordion-body-inner{overflow:hidden;min-height:0;padding:var(--space-2) var(--space-18) var(--space-24);opacity:0;transition:opacity .3s ease;}
.settings-group[open] .accordion-body-inner{opacity:1;transition-delay:.1s;}

/* ---------- Public form components — built for briefing.html but kept
   generic/unprefixed for the same reason as .timeline (§5): any other
   public-facing form (this app is meant to be resold, per
   SLATE-IMPLEMENTATION.md's framing) should reuse these instead of
   growing its own copies. ---------- */
.required-mark{color:var(--danger);font-weight:700;}

/* A form label sized for the QUESTION above a group of pills/checkboxes/a
   textarea — bigger and sentence-case, unlike the default <label>'s
   all-caps micro-caption which reads fine next to a single input but
   flattens a real question into noise. */
.field-question{font-family:var(--sans);font-size:var(--fs-14);text-transform:none;letter-spacing:normal;color:var(--text);font-weight:600;margin:0 0 var(--sp-1);}

/* Square chip with a real radio dot — the deliberate alternative to a
   plain capsule pill, picked for the left-accent-stripe treatment it
   allows on the checked state. */
.pill-group{display:flex;flex-wrap:wrap;gap:0 var(--space-8);}
.pill{position:relative;display:inline-flex;align-items:center;gap:var(--space-8);padding:var(--space-8) var(--space-14) var(--space-8) var(--space-12);border:1px solid var(--border);border-radius:var(--radius);font-size:var(--fs-12);color:var(--text-dim);cursor:pointer;transition:border-color .15s ease,color .15s ease,background .15s ease,border-left-width .15s ease;background:var(--bg);}
.pill input{position:absolute;opacity:0;width:1px;height:1px;pointer-events:none;}
.pill-dot{width:16px;height:16px;border-radius:50%;flex-shrink:0;position:relative;border:1.5px solid var(--border);background:var(--panel2);transition:border-color .15s ease;}
.pill:has(input:checked){border-color:var(--accent);border-left-width:3px;color:var(--text);background:rgba(var(--accent-rgb),.06);}
.pill:has(input:checked) .pill-dot{border-color:var(--accent);}
.pill:has(input:checked) .pill-dot::after{content:'';position:absolute;inset:3px;border-radius:50%;background:var(--accent);}
.pill:has(input:focus-visible){outline:2px solid var(--accent-dim);outline-offset:2px;}
.pill:hover{border-color:var(--text-faint);}

.checkbox-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-8) var(--space-16);}
@media(max-width:560px){.checkbox-grid{grid-template-columns:1fr;}}

/* Static (click-to-browse, not drag-and-drop — that's .portfolio-dropzone-*
   elsewhere, a different interaction) file-upload wrapper. */
.upload-dropzone{border:1px dashed var(--border);background:var(--panel2);padding:var(--space-14) var(--space-16);border-radius:var(--radius);}
.upload-dropzone input[type=file]{border:0;padding:0;background:transparent;height:auto;color:var(--text-dim);font-size:var(--fs-12);width:auto;}
.upload-dropzone-hint{color:var(--text-faint);font-size:var(--fs-11);margin-top:var(--space-6);}

/* Post-submit confirmation screen. */
.success-panel{text-align:center;padding:var(--space-40) var(--space-28);}
.success-icon{width:52px;height:52px;border-radius:50%;background:rgba(var(--accent-rgb),.12);color:var(--accent);display:flex;align-items:center;justify-content:center;font-size:var(--fs-24);margin:0 auto var(--space-18);}

/* Mono, boxed reference code — a submission protocol number, a short-code,
   anything meant to be read back over the phone/WhatsApp. */
.code-chip{font-family:var(--mono);font-size:var(--fs-12);color:var(--text-faint);background:var(--panel2);border:1px solid var(--border-soft);border-radius:var(--radius);padding:var(--space-10) var(--space-14);display:inline-block;}
.code-chip b{color:var(--text);letter-spacing:1px;}

/* ---------- Reuniões agendadas (meetings) ---------- */
.meeting-list{display:flex;flex-direction:column;gap:var(--space-10);}
.meeting-card{cursor:pointer;}
.meeting-rsvp-row{display:flex;flex-wrap:wrap;gap:var(--space-10);}
.meeting-rsvp-person{display:flex;align-items:center;gap:var(--space-8);background:var(--panel2);border:1px solid var(--border-soft);padding:var(--space-6) var(--space-8);}
.meeting-rsvp-name{font-size:var(--fs-11);color:var(--text-dim);}
.meeting-rsvp-btns{display:flex;gap:var(--space-2);background:var(--panel);padding:var(--space-2);}
.meeting-rsvp-btn{border:none;background:transparent;color:var(--text-faint);font-size:var(--fs-10);font-weight:700;padding:var(--space-4) var(--space-8);cursor:pointer;}
.meeting-rsvp-btn:hover{color:var(--text-dim);}
.meeting-rsvp-btn.yes.active{background:var(--good);color:#fff;}
.meeting-rsvp-btn.no.active{background:var(--danger);color:#fff;}
.meeting-rsvp-status{font-size:var(--fs-10);font-weight:700;padding:var(--space-4) var(--space-8);color:var(--text-faint);}
.meeting-rsvp-status.yes{color:var(--good);}
.meeting-rsvp-status.no{color:var(--danger);}

/* ---------- Chat de voz (/voz WebRTC) ----------
   .voz-person.speaking / .voz-presence-dot.active / .voz-avatar.speaking
   are real live-state signals (someone is talking right now), kept as
   deliberate exceptions to "no glow" — same reasoning as the pipeline
   ripple and the drag ghost's shadow. Everything else is flat. */
.voz-join-card{max-width:320px;}
.voz-join-card .card-body{display:flex;flex-direction:column;}
.voz-presence-indicator{display:flex;align-items:center;gap:var(--space-8);font-size:var(--fs-12);color:var(--text-dim);margin-bottom:var(--space-14);}
.voz-presence-dot{width:8px;height:8px;border-radius:50%;background:var(--text-faint);flex-shrink:0;transition:background .15s ease;}
.voz-presence-dot.active{background:var(--accent);box-shadow:0 0 0 3px rgba(var(--accent-rgb),.2);}
.voz-inroom-pill{display:inline-flex;align-items:center;gap:var(--space-8);padding:var(--space-6) var(--space-12);background:var(--good-bg);border:1px solid rgba(var(--good-rgb),.4);font-size:var(--fs-11);color:var(--good);font-weight:700;flex-shrink:0;}
.voz-inroom-dot{width:6px;height:6px;border-radius:50%;background:var(--good);}
.voz-people-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:var(--space-12);margin-bottom:var(--space-14);}
.voz-person{padding:var(--space-12);display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-10);}
.voz-person.speaking{border-color:var(--good);box-shadow:0 0 0 1px var(--good);}
.voz-person-ring{position:relative;flex-shrink:0;line-height:0;}
.voz-person-ring.speaking::after{content:'';position:absolute;inset:-4px;border-radius:50%;border:2px solid var(--good);}
.voz-person-who{flex:1;min-width:0;display:flex;flex-direction:column;gap:var(--space-4);}
.voz-person-name{font-size:var(--fs-12);font-weight:600;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.voz-person-status{font-size:var(--fs-11);color:var(--text-faint);line-height:1.3;}
.voz-person-status.good{color:var(--good);}
.voz-person-status.danger{color:var(--danger);}
.voz-micbtn{width:28px;height:28px;background:var(--panel2);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;color:var(--text-dim);flex-shrink:0;}
.voz-micbtn .nav-icon{width:14px;height:14px;display:flex;}
.voz-micbtn.off{background:var(--danger-bg);border-color:var(--danger);color:var(--danger);}
.voz-person-volume{display:flex;align-items:center;gap:var(--space-8);width:100%;margin-top:var(--space-2);padding-top:var(--space-10);border-top:1px solid var(--border-soft);}
.voz-volume-slider{flex:1;height:4px;accent-color:var(--accent);}
.voz-volume-val{font-size:var(--fs-10);color:var(--text-faint);font-family:var(--mono);min-width:32px;text-align:right;flex-shrink:0;}
.voz-stage{position:relative;background:#000;border:1px solid var(--border-soft);overflow:hidden;margin-bottom:var(--space-14);}
.voz-stage video{display:block;width:100%;max-height:440px;background:#000;}
.voz-stage-sharer{position:absolute;top:var(--space-10);left:var(--space-10);display:inline-flex;align-items:center;gap:var(--space-8);background:rgba(0,0,0,.75);border:1px solid var(--border);padding:4px 12px 4px 4px;font-size:var(--fs-11);color:var(--text-dim);}
.voz-stage-fullscreen-btn{position:absolute;top:var(--space-10);right:var(--space-10);width:28px;height:28px;background:rgba(0,0,0,.75);border:1px solid var(--border);color:var(--text-dim);display:flex;align-items:center;justify-content:center;}
.voz-stage-fullscreen-btn .nav-icon{width:14px;height:14px;}
.voz-chat-log{display:flex;flex-direction:column;gap:var(--space-12);background:var(--panel);border:1px solid var(--border-soft);padding:var(--space-14);height:360px;overflow-y:auto;}
.voz-chat-msg{line-height:1.5;font-size:var(--fs-12);color:var(--text-dim);}
.voz-chat-msg b{font-size:var(--fs-12);color:var(--text);}
.voz-chat-msg.mine b{color:var(--accent);}
.voz-chat-msg-time{color:var(--text-faint);font-size:var(--fs-11);}
.voz-chat-msg-edited{color:var(--text-faint);font-size:var(--fs-10);}
.voz-chat-msg a{color:var(--accent);word-break:break-all;}
.voz-msg-actions{display:inline-flex;gap:var(--space-4);margin-left:var(--space-6);vertical-align:middle;opacity:.7;}
.voz-msg-actions .btn-icon{width:var(--ctl-h-xs);height:var(--ctl-h-xs);}
.voz-msg-actions:hover{opacity:1;}
.voz-diag-log{display:flex;flex-direction:column;gap:var(--space-2);background:var(--panel);border:1px solid var(--border-soft);padding:var(--space-10) var(--space-12);max-height:280px;overflow-y:auto;font-family:var(--mono);font-size:var(--fs-11);line-height:1.6;}
.voz-log-time{color:var(--text-faint);margin-right:var(--space-8);}
.voz-log-warn{color:var(--warn);}
.voz-log-error{color:var(--danger);}
.voz-avatar-overlay{position:fixed;left:50%;bottom:20px;transform:translateX(-50%);z-index:var(--z-floating-widget);display:flex;pointer-events:none;}
.voz-avatar{width:150px;height:150px;border-radius:50%;object-fit:contain;}
.voz-avatar + .voz-avatar{margin-left:-40px;}
.voz-back-btn{align-self:center;pointer-events:auto;width:44px;height:44px;margin-left:var(--space-16);border-radius:50%;border:none;background:var(--accent);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;}
.voz-back-btn .nav-icon{width:20px;height:20px;}
.voz-ripple{position:fixed;pointer-events:none;}
.voz-ripple span{position:absolute;inset:0;border-radius:50%;border:1px solid var(--accent);opacity:0;animation:pipeRipple 2.4s ease-out infinite;}
.voz-ripple span:nth-child(2){animation-delay:.8s;}
.voz-ripple span:nth-child(3){animation-delay:1.6s;}
@media(prefers-reduced-motion:reduce){.voz-ripple span{animation:none;}}

/* ---------- Prospecção (sales funnel) core card ---------- */
.prospect-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(320px,100%),1fr));gap:var(--space-14);}
.prospect-footer{display:flex;justify-content:space-between;align-items:center;margin-top:var(--space-12);padding-top:var(--space-10);border-top:1px solid var(--border-soft);cursor:default;}

/* ---------- Relatório ----------
   .report-line/.report-person/.report-equip-check/.report-equip-problem/
   .report-service-input are JS query hooks (document.querySelectorAll),
   not visual classes — no rule ever existed for them in style.css and
   none is needed here either: they ride on .field-grid/.row/.checkbox-row/
   input, all already covered above. Confirmed by reading 20-relatorio.js
   rather than assumed, precisely to avoid inventing a redundant sibling
   of a class that already does the job. */

/* ============================================================
   STEP 7 — Configurações admin tooling: changelog editor,
   import-diff viewer, Drive folder-template tree, project
   checklist-step editor, and the remaining small gaps.
   ============================================================
   .situacao-list/.situacao-label-input/.situacao-color-select and
   .cat-chip/.p-role-check/.prospect-card/.budget-equip-row/
   .budget-svc-input/.budget-table/.notification-pref-toggle/
   .col-menu-toggle/.scheduled-row confirmed (same method as Relatório
   above) to carry zero dedicated rule in style.css either — they ride
   entirely on .row/.tag/input/select/.card/table.plain/.checkbox-row,
   all already covered. Not styled separately on purpose. */

.pagination-bar{display:flex;align-items:center;justify-content:center;gap:var(--space-14);margin-top:var(--space-16);}

.changelog-version+.changelog-version{margin-top:var(--space-20);padding-top:var(--space-18);border-top:1px solid var(--border-soft);}
/* 42 — novidades com versão. O changelog já tinha badge tipado e flag de
   admin, e renderizava como lista. A versão vira número grande e o que
   chegou desde a última visita ganha uma régua: o modal passa a reportar
   em vez de listar. O dado já existia — WHATS_NEW_SEEN_KEY guarda a
   última versão vista desde sempre, só nunca tinha sido desenhado. */
.changelog-vnum{font-family:var(--display);font-weight:800;font-size:29px;line-height:1;color:var(--accent);}
.changelog-since{
  display:flex;align-items:center;gap:var(--space-10);
  margin:var(--space-20) 0 var(--space-14);
  font-family:var(--display);font-size:var(--fs-10);font-weight:700;
  text-transform:uppercase;letter-spacing:1px;color:var(--accent);
}
.changelog-since::after{content:'';flex:1;height:1px;background:rgba(var(--accent-rgb),.45);}
.changelog-version-header{display:flex;align-items:baseline;gap:var(--space-10);margin-bottom:var(--space-8);}
.changelog-version-header b{font-family:var(--display);font-weight:700;font-size:var(--fs-12);letter-spacing:.6px;color:var(--text);}
.changelog-list{margin:0;padding-left:var(--space-20);display:flex;flex-direction:column;gap:var(--space-8);}
.changelog-list li{font-size:var(--fs-12);line-height:1.6;color:var(--text-dim);}
.changelog-list li.is-minor{font-size:var(--fs-11);color:var(--text-faint);}
.changelog-tag{margin-right:var(--space-2);vertical-align:1px;}
.changelog-pager{display:flex;align-items:center;justify-content:center;gap:var(--space-10);margin-top:var(--space-18);padding-top:var(--space-16);border-top:1px solid var(--border-soft);flex-wrap:wrap;}
.changelog-pager .btn:disabled{opacity:.4;cursor:default;}
.changelog-edit-btn{margin-left:auto;flex-shrink:0;}
.changelog-edit-textarea{width:100%;font-size:var(--fs-12);line-height:1.5;}

/* Import diff — added/updated/removed rows share one shape, color comes
   from the same accent-rgb/good-rgb/warn-rgb/danger-rgb tint pattern
   used everywhere else (agenda chips, badges), not a new one. */
.import-diff-list{display:flex;flex-direction:column;gap:var(--space-6);max-height:240px;overflow-y:auto;}
.import-diff-row{font-size:var(--fs-12);line-height:1.5;padding:var(--space-8) var(--space-10);background:var(--panel);border:1px solid var(--border-soft);}
.import-diff-tag{display:inline-block;font-size:var(--fs-10);text-transform:uppercase;letter-spacing:.6px;padding:var(--space-2) var(--space-6);margin-right:var(--space-8);font-weight:700;vertical-align:1px;}
.import-diff-added .import-diff-tag{background:var(--good-bg);color:var(--good);}
.import-diff-updated .import-diff-tag{background:var(--warn-bg);color:var(--warn);}
.import-diff-removed .import-diff-tag{background:var(--danger-bg);color:var(--danger);}
.import-diff-changes{margin-top:var(--space-4);color:var(--text-faint);font-size:var(--fs-11);}

/* Drive folder-template tree (project-folder creation defaults). */
.dpp-tree{max-height:340px;overflow-y:auto;margin-bottom:var(--space-4);}
.dpp-node-row{display:flex;align-items:center;gap:var(--space-8);padding:var(--space-6) var(--space-4);}
.dpp-node-icon{flex-shrink:0;width:18px;height:18px;display:flex;align-items:center;justify-content:center;color:var(--text-faint);}
.dpp-node-icon .nav-icon{width:16px;height:16px;}
.dpp-node-name{font-size:var(--fs-14);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.dpp-node-name-input{flex:1;min-width:0;}
.dpp-node-row .btn-icon{width:24px;height:24px;flex-shrink:0;}
.dpp-add-btn{display:inline-flex;align-items:center;gap:var(--space-6);background:none;border:1px dashed var(--border-soft);color:var(--text-dim);padding:var(--space-6) var(--space-12);cursor:pointer;font-size:var(--fs-12);margin:var(--space-2) 0 var(--space-6);}
.dpp-add-btn:hover{color:var(--text);border-color:var(--text-dim);}
.dpp-add-btn .nav-icon{width:14px;height:14px;}
.dpp-add-root-btn{border-style:solid;background:var(--panel2);margin-left:0!important;margin-top:var(--space-4);}

/* Category chips (Listas e categorias) — .cat-chip layers onto
   .person-chip, already covered; only its inner rename-in-place input
   needed a rule. */
.cat-name-input{background:none;border:none;color:var(--text);font:inherit;padding:0 var(--space-2);min-width:16px;}
.cat-name-input:hover{background:var(--panel3);}
.cat-name-input:focus{outline:none;background:var(--panel);box-shadow:0 0 0 2px rgba(var(--accent-rgb),.18);}
.cat-name-autogrow{position:relative;display:inline-block;vertical-align:middle;height:32px;}
.cat-name-autogrow::after{content:attr(data-value) " ";visibility:hidden;white-space:pre;font:inherit;padding:0 var(--space-12);}
.cat-name-autogrow .cat-name-input{position:absolute;inset:0;width:100%;min-width:0;margin-left:-5px;}

.col-menu{min-width:200px;}
.log-row{display:flex;gap:var(--space-10);padding:var(--space-8) 0;border-bottom:1px solid var(--border-soft);font-size:var(--fs-12);}
.log-row .t{color:var(--text-faint);font-family:var(--mono);font-size:var(--fs-11);white-space:nowrap;}
.member-name{color:var(--member-color,inherit);font-weight:600;}

/* Checklist templates (Portfolio module) — distinct feature from both
   .task-checklist (kanban subtasks) and .jc-* (live per-job checklist),
   confirmed by reading 10-portfolio.js. */
.checklist-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:var(--space-14);}
.checklist-item{display:flex;align-items:center;justify-content:space-between;gap:var(--space-10);padding:var(--space-10) var(--space-12);border:1px solid var(--border-soft);margin-bottom:var(--space-6);background:var(--panel);}
.checklist-item .name{font-size:var(--fs-14);}
.checklist-item .qty{font-size:var(--fs-11);color:var(--text-dim);font-family:var(--mono);background:var(--panel2);border:1px solid var(--border);padding:var(--space-2) var(--space-10);flex-shrink:0;}
.checklist-group-title{font-family:var(--display);font-weight:700;font-size:var(--fs-12);text-transform:uppercase;letter-spacing:1px;color:var(--text-faint);margin:var(--space-18) 0 var(--space-8);padding-bottom:var(--space-6);border-bottom:1px solid var(--border-soft);}
.checklist-group-title:first-of-type{margin-top:var(--space-2);}
.c-entry-row{display:flex;gap:var(--space-8);align-items:center;margin-bottom:var(--space-8);}
.c-entry-row .c-entry-label{flex:2;min-width:0;}
.c-entry-row .c-entry-qty{flex:0 0 64px;}
.c-entry-row .c-entry-cat{flex:1.2;min-width:0;}
.checklist-inv-list{max-height:240px;overflow-y:auto;border:1px solid var(--border-soft);padding:var(--space-4) var(--space-10);background:var(--panel2);}
.checklist-inv-row{display:flex;align-items:center;gap:var(--space-10);padding:var(--space-8) var(--space-4);font-size:var(--fs-12);cursor:pointer;}
.checklist-inv-row:hover{background:var(--panel3);}
.checklist-inv-row input[type=checkbox]{flex-shrink:0;}
.checklist-inv-row .c-inv-name{flex:1;}
.checklist-inv-row .c-inv-qty{width:60px;flex-shrink:0;}


/* Projeto's checklist-step editor (Produção/Pós stages) — deliberately
   reuses .checklist-group-title/.task-checklist/.check-text rather than
   a parallel set of rules (see 19-projetos.js's projectStepStageHtml
   comment); only the stage container and delete link are unique. */
.project-link-row{padding:var(--space-8) var(--space-2);border-top:1px solid var(--border-soft);font-size:var(--fs-12);gap:var(--space-10);}
.project-link-row:first-child{border-top:none;}
.project-link-row-pick{display:block;}
.project-link-pick-label{color:var(--text-dim);}
select.project-link-pick{flex:1;min-width:0;font-size:var(--fs-12);padding:var(--space-6) var(--space-28) var(--space-6) var(--space-10);height:auto;}
.project-suggest-group{background:rgba(var(--accent-rgb),.06);border-color:rgba(var(--accent-rgb),.3);}
.project-step-stage+.project-step-stage{margin-top:var(--space-16);padding-top:var(--space-14);border-top:1px solid var(--border-soft);}
.project-step-del{background:none;border:none;padding:0;margin:0;font-family:var(--sans);font-size:var(--fs-11);color:var(--danger);cursor:pointer;}
.project-step-del:hover{text-decoration:underline;}

/* ============================================================
   TIMELINE — vertical stage tracker, §5 of the redesign, tightened to
   match the picked "Linha do tempo" frame in 4-modais-e-avulsas.html
   exactly (.tl/.tli). Built for cliente.html's "Acompanhamento de
   projeto" page but kept generic/unprefixed on purpose so any other
   screen needing the same story-in-order pattern reuses this instead of
   hand-rolling its own. One continuous neutral line for the whole list
   (not a per-item segment that turns green as stages complete — that was
   this component's own embellishment, not part of the picked frame);
   only the dots and the current stage's title carry color. Dot states:
   done (filled --good), current (filled --accent), pending (hollow,
   --border outline). .timeline-substeps(-details) is the optional nested
   checklist for a stage that tracks its own sub-items (e.g.
   Gravação/Edição) — same done/pending logic, one level down.
   ============================================================ */
.timeline{list-style:none;margin:0;padding:0;position:relative;padding-left:26px;}
.timeline::before{content:'';position:absolute;left:5px;top:6px;bottom:6px;width:1px;background:var(--border-soft);}
.timeline-item{position:relative;padding-bottom:var(--sp-3);}
.timeline-item:last-child{padding-bottom:0;}
/* 27 — espinha do projeto. A espinha e os três estados já existiam; o que
   faltava era a forma: um quadrado por etapa, não um círculo — o único
   marcador redondo que sobrava no Slate. Cheio = feito, acento = agora,
   vazado = pela frente. Sem número: as datas já carregam a ordem. */
.timeline-dot{
  position:absolute;left:-26px;top:3px;width:11px;height:11px;border-radius:0;
  box-sizing:border-box;border:2px solid var(--border);background:var(--panel);
}
.timeline-item.done .timeline-dot{background:var(--good);border-color:var(--good);}
/* o trecho de espinha já percorrido fica sólido até a etapa atual */
.timeline-item.done::before{content:'';position:absolute;left:-21px;top:14px;bottom:-3px;width:1px;background:var(--good);}
.timeline-item.current .timeline-dot{background:var(--accent);border-color:var(--accent);}
.timeline-title{font-weight:700;font-size:var(--fs-14);color:var(--text);}
.timeline-item.pending .timeline-title{color:var(--text-faint);}
.timeline-item.current .timeline-title{color:var(--accent);}
.timeline-date{font-size:var(--fs-11);color:var(--text-faint);margin-top:var(--space-2);}

.timeline-substeps-details{margin:var(--sp-2) 0 0 2px;}
.timeline-substeps-details summary{
  list-style:none;cursor:pointer;font-size:var(--fs-12);font-weight:600;color:var(--text-dim);
  background:var(--panel2);border:1px solid var(--border-soft);border-radius:var(--radius);
  padding:var(--space-8) var(--space-10);display:flex;align-items:center;gap:var(--space-8);user-select:none;
  transition:border-color .15s ease;
}
.timeline-substeps-details summary:hover{border-color:var(--text-faint);}
.timeline-substeps-details summary::-webkit-details-marker{display:none;}
.timeline-substeps-details summary::before{
  content:'';width:0;height:0;flex:0 0 auto;color:var(--text-faint);
  border-left:5px solid currentColor;border-top:4px solid transparent;border-bottom:4px solid transparent;
  transition:transform .15s ease;
}
.timeline-substeps-details[open] summary{border-bottom-color:transparent;}
.timeline-substeps-details[open] summary::before{transform:rotate(90deg);}
.timeline-substeps{
  list-style:none;padding:var(--space-2) var(--space-10);margin:0;
  background:var(--panel2);border:1px solid var(--border-soft);border-top:none;
}
.timeline-substeps li{
  display:flex;align-items:center;gap:var(--space-8);padding:var(--space-10) 0;border:none;
  font-size:var(--fs-12);color:var(--text-faint);
}
.timeline-substeps li+li{border-top:1px solid var(--border-soft);}
.timeline-substeps li .mark{
  width:15px;height:15px;border-radius:50%;border:2px solid var(--border);
  flex:0 0 auto;display:flex;align-items:center;justify-content:center;font-size:9px;
  color:var(--good);
}
.timeline-substeps li.done{color:var(--text-dim);}
.timeline-substeps li.done .mark{background:var(--good);border-color:var(--good);color:#fff;font-weight:700;}

/* ============================================================
   PRE-AUTH SHELL — the PWA launch splash, the "update available" banner,
   and the page-leaving fade. Shared by every page that can be someone's
   very first paint (login.html, and index.html once §7's cutover lands),
   which is why this lives here rather than page-scoped: duplicating it
   per file is exactly the "hard to reuse elsewhere" problem §5 already
   ran into with the timeline. Only §6 needs it for now (login.html); the
   index.html/app.js side keeps running on style.css until the cutover.
   ============================================================ */
#pwa-intro{
  position:fixed;inset:0;z-index:var(--z-splash);
  display:flex;align-items:center;justify-content:center;flex-direction:column;
  background:radial-gradient(circle at 50% 46%, #0d0d0f 0%, #050506 55%, #000 100%);
  transition:opacity .5s ease;
}
#pwa-intro.fade-out{opacity:0;pointer-events:none;}
#pwa-intro .vignette{
  position:absolute;inset:0;
  background:radial-gradient(circle at 50% 50%, transparent 40%, rgba(0,0,0,.65) 100%);
  pointer-events:none;
}
#pwa-intro .logo-wrap{width:min(34vw, 168px);opacity:0;transition:opacity 2s linear;}
#pwa-intro .logo-wrap.in{opacity:1;}
#pwa-intro .logotype{width:min(9vw, 46px);margin-top:var(--space-14);opacity:0;transition:opacity 1s linear;}
#pwa-intro .logotype.in{opacity:1;}
#pwa-intro-draw path{fill:none;stroke-width:1.6;vector-effect:non-scaling-stroke;transition:stroke-dashoffset 2s cubic-bezier(0.33, 1, 0.68, 1);}
#pwa-intro .draw-white{stroke:var(--text);}
#pwa-intro .draw-red{stroke:var(--accent);}
#pwa-intro-fillgroup{opacity:0;transition:opacity 2s linear;}
#pwa-intro-draw{transition:opacity 2s linear;}

/* Persistent top bar, not a dismissible toast — should stay until acted
   on. Flat/bordered instead of style.css's drop-shadow version, matching
   "no cast shadow, border does the separation" everywhere else in slate. */
#update-banner{
  position:fixed;top:0;left:0;right:0;z-index:var(--z-update-banner);
  display:flex;align-items:center;justify-content:center;gap:var(--space-14);flex-wrap:wrap;
  padding:var(--space-10) var(--space-16);background:var(--accent);color:#fff;
  font-size:var(--fs-12);font-weight:500;border-bottom:1px solid var(--accent-dim);
  animation:updateBannerIn var(--mo-peso-in) var(--mo-peso-ez);
}
#update-banner.hidden{display:none;}
#update-banner a{color:#fff;text-decoration:underline;text-underline-offset:2px;opacity:.9;flex-shrink:0;}
#update-banner a:hover{opacity:1;}
#update-banner button{background:#fff;color:var(--accent-dim);border:none;border-radius:var(--radius);padding:var(--space-6) var(--space-14);font-size:var(--fs-12);font-weight:700;flex-shrink:0;transition:opacity .15s ease;}
#update-banner button:hover{opacity:.85;}
#update-banner button:disabled{opacity:.6;cursor:default;}
@keyframes updateBannerIn{from{opacity:0;transform:translateY(-100%);}to{opacity:1;transform:translateY(0);}}
body.has-update-banner{padding-top:var(--space-40);}
body.has-update-banner .mobile-header{top:40px;}
body.has-update-banner .mobile-header.scrolled{top:54px;}

body.page-leaving{opacity:0;transition:opacity .18s ease;pointer-events:none;}

/* Generic inline form-error line — under a login/briefing/etc form, not
   boxed, just a centered line that reserves its own height so the form
   doesn't jump when an error appears. */
.form-err{color:var(--danger);font-size:var(--fs-12);text-align:center;margin-bottom:var(--space-10);min-height:16px;}

/* ============================================================
   STEP PROGRESS — a thin segmented bar for any multi-step flow (built for
   briefing.html's paginated form, kept generic since any other wizard-
   shaped screen should reuse it instead of growing its own copy). One <i>
   per step; .done marks everything up to and including the current one.
   ============================================================ */
.step-progress{display:flex;gap:2px;margin:var(--sp-2) 0 var(--sp-3);}
.step-progress i{flex:1;height:3px;background:var(--panel3);display:block;}
.step-progress i.done{background:var(--accent);}

/* ============================================================
   KEY CAPS + SHORTCUT LEGEND — .kbd is one key, drawn like a flat Slate
   key (mono, 2px corner, heavier bottom edge). .shortcuts is a collapsible
   <details> legend listing them (built for the Gerador de PDF editor, kept
   generic so any screen with shortcuts reuses it). Hidden on touch-width
   screens: nobody there has a keyboard to use them with.
   ============================================================ */
.kbd{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:20px;height:20px;padding:0 var(--space-4);
  font-family:var(--mono);font-size:var(--fs-10);font-weight:500;line-height:1;color:var(--text);
  background:var(--panel3);border:1px solid var(--border);border-bottom-width:2px;border-bottom-color:var(--bg);
  border-radius:var(--radius);white-space:nowrap;
}
:root[data-theme="light"] .kbd{border-bottom-color:var(--border);}
.kbd-combo{display:inline-flex;align-items:center;gap:3px;}

.shortcuts{border:1px dashed var(--border);}
.shortcuts summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:var(--space-10);padding:var(--space-10) var(--space-12);user-select:none;}
.shortcuts summary::-webkit-details-marker{display:none;}
.shortcuts summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px;}
.shortcuts-title{font-family:var(--display);font-weight:700;font-size:var(--fs-12);letter-spacing:1px;text-transform:uppercase;color:var(--text-dim);}
.shortcuts summary:hover .shortcuts-title{color:var(--text);}
.shortcuts-peek{display:flex;gap:var(--space-4);margin-left:auto;}
.shortcuts[open] .shortcuts-peek{display:none;}
.shortcuts-chev{width:12px;height:12px;color:var(--text-faint);flex-shrink:0;transition:transform var(--mo-peso-in) var(--mo-peso-ez);}
.shortcuts[open] .shortcuts-chev{transform:rotate(90deg);}
.shortcuts[open] summary{border-bottom:1px dashed var(--border);}
.shortcuts-list{list-style:none;margin:0;padding:var(--space-4) var(--space-12) var(--space-6);}
.shortcuts-list li{display:grid;grid-template-columns:104px 1fr;gap:var(--space-12);align-items:center;padding:var(--space-6) 0;border-bottom:1px solid var(--border-soft);}
.shortcuts-list li:last-child{border-bottom:none;}
.shortcuts-desc{font-size:var(--fs-12);line-height:1.4;color:var(--text-dim);}
@media(max-width:760px),(hover:none) and (pointer:coarse){ .shortcuts{display:none;} }

/* ============================================================
   MOTION — reduced-motion guard, §4 of the redesign. Applies
   unconditionally and last, so it wins over every animation/transition
   declared above regardless of source order. Per-component `animation:none`
   overrides elsewhere (skeleton shimmer, pipe ripple, voz ripple — the
   genuinely-infinite ones, where 1ms still means visibly looping) stay as
   they are; this collapses everything else to effectively instant instead.
   ============================================================ */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:1ms !important;
    animation-iteration-count:1 !important;
    transition-duration:1ms !important;
  }
}

/* ============================================================
   01·B — GRÃO DE EMULSÃO
   ============================================================
   Última camada do app, e de propósito: folhas fixas sobre tudo, sem
   captar clique. É o que amarra a leva inteira — sem ela as superfícies
   da fase 1 são só CSS bem-comportado; com ela viram material.

   POR QUE ESTA VERSÃO É ESTÁTICA E SEM BLEND
   A primeira versão copiava a demo do artifact: mix-blend-mode:overlay
   mais um drift em transform. Bonito e caro, e o caro não era o ruído.

   1. mix-blend-mode obriga o navegador a rasterizar o fundo atrás da
      folha pra poder misturá-lo. Numa folha do tamanho da tela isso
      significa que qualquer coisa que mude embaixo derruba a composição
      em GPU da viewport inteira. Era esse o custo real, não o grão.
   2. O ruído em si nunca foi o problema: vira textura em cache depois do
      primeiro paint. Só a rasterização inicial custava, e trocar o
      filtro SVG por um PNG pronto zera até isso.
   3. Estático, sem blend, a folha é uma textura enviada pra GPU uma vez
      e reaproveitada pra sempre. Rolagem passa a custar zero.

   Sem o blend, um ruído cinza chapado embaçaria os pretos. Por isso o
   ladrilho é um PNG RGBA gerado (scripts/make-grain.py): cada pixel é
   preto OU branco, com alfa proporcional a |gauss|. Escurece e clareia,
   que é o que o overlay fazia, sem precisar misturar com o fundo.

   PNG e não feTurbulence de propósito: o filtro SVG precisa ser
   rasterizado pelo navegador no primeiro paint (e de novo se o DPR ou o
   zoom mudar), enquanto um PNG de 24KB é só decodificar. Como é ruído
   branco puro, sem correlação espacial, ladrilha sem emenda por
   construção: não existe borda pra casar.

   Pra comparar com a versão viva: data-grain="live" no <html> liga o
   drift de volta (custa pouco, steps(5) repinta ~1,5x por segundo, mas
   não é de graça como o estático).

   O bloco global de prefers-reduced-motion no fim do arquivo já mata a
   animação quando ela estiver ligada; o véu em si continua, que é
   textura e não movimento.
   ============================================================ */
body::before{
  content:'';position:fixed;inset:0;z-index:var(--z-grain);pointer-events:none;
  opacity:var(--grain-opacity);
  background-image:url('/img/grain.png');
  background-size:var(--grain-tile) var(--grain-tile);
}
/* opt-in: o grão vivo da demo original, pra comparar lado a lado */
:root[data-grain="live"] body::before{
  inset:-12%;
  animation:grainDrift var(--grain-drift) steps(5) infinite;
}
@keyframes grainDrift{
  0%{transform:translate(0,0);}   20%{transform:translate(-6%,3%);}
  40%{transform:translate(4%,-5%);} 60%{transform:translate(-3%,-3%);}
  80%{transform:translate(5%,4%);} 100%{transform:translate(0,0);}
}
