feat: redesign the Kanban and keep test wording out of production
All checks were successful
Build and deploy / Validate source (push) Successful in 11s
Build and deploy / Integration suite on a real stack (push) Successful in 3m3s
Build and deploy / Secret scan and release gate (push) Successful in 7s
Build and deploy / Publish images (push) Successful in 1m51s

Kanban: tabs for production, quote review and payments/integrations; compact
cards with products, metres, print-file status, delivery and time in stage;
an order panel with stage progress, one main action, a correction reason in
place, items with a preview drawn from the approved layout, final-file
approval and the history as a timeline. Quote review gets a list and a pane;
payment issues resolve in place; integrations show their real state, Tiny's
connection with a read-only "Testar conexão", and a readable send log. The
previous Kanban is kept in git tag ui-v1 and is no longer served.

Production wording: the customer portal no longer says it is a local test
environment outside the local stack; the checkout no longer tells customers
to use the Kanban or shows internal stage codes; sign-in, session, quota and
print-file messages are Portuguese and never say "local". A simulated freight
price is refused outside the local stack until a real freight provider
exists, so production only offers pickup.

The browser suite drives the new tabs and panel and still checks the whole
upload, quote, payment and production journey. Full CI sequence passes locally.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Cauê Faleiros
2026-09-24 15:28:04 -03:00
parent 641dc6053b
commit 99a558ddd9
22 changed files with 861 additions and 297 deletions

182
web/kanban.css Normal file
View File

@@ -0,0 +1,182 @@
/* Kanban DTF. The previous look is kept in git tag ui-v1. */
:root{
--bg:#0F1113;--bar:#13161A;--col:#13161A;--card:#1A1D21;--card2:#23282D;--panel:#15181B;
--line:#262A2F;--line2:#2A2F35;--line3:#3A4047;
--tx:#ECE9E4;--tx2:#D5D2CC;--muted:#A3A9B0;--faint:#8B929A;
--accent:#FF8B2B;--accent-tx:#FFB575;--ok:#6FD19C;--warn:#F2B33D;--bad:#F4968B;--bad-line:#5A3530;
--rec:#2BB6D9;--tra:#E0508F;--fil:#E9C23A;--imp:#D9D6D0;--cor:#F06A5B;--fin:#3FB97A;
--mono:Manrope,system-ui,sans-serif;
}
*{box-sizing:border-box}
html,body{margin:0;background:var(--bg);color:var(--tx)}
body{font:14px/1.45 Manrope,system-ui,sans-serif;font-variant-numeric:tabular-nums}
button,input,textarea{font:inherit;color:inherit}
button{cursor:pointer}
button:disabled{opacity:.5;cursor:default}
a{color:var(--accent-tx)}
[hidden]{display:none!important}
.mono{font-family:var(--mono)}
.muted{color:var(--muted)}
.faint{color:var(--faint)}
.btn{height:36px;padding:0 12px;border-radius:8px;border:1px solid var(--line2);background:var(--card2);color:var(--tx);font-size:13px;font-weight:600;white-space:nowrap}
.btn:hover{border-color:var(--line3)}
.btn.ghost{background:transparent;color:var(--muted)}
.btn.primary{height:44px;border:0;background:var(--accent);color:#0F1113;font-weight:800;font-size:14px;padding:0 18px}
.btn.primary:hover{filter:brightness(1.08)}
.btn.danger{height:44px;background:transparent;border-color:var(--bad-line);color:var(--bad);font-weight:700;font-size:14px}
.btn.warn{border:0;background:var(--warn);color:#0F1113;font-weight:800}
.chip{height:34px;padding:0 12px;border-radius:8px;border:1px solid var(--line2);background:transparent;color:var(--muted);font-size:13px;font-weight:600}
.chip[aria-pressed=true]{border-color:var(--accent);background:rgba(255,139,43,.12);color:var(--accent-tx)}
.badge{font-size:12px;font-weight:700;border-radius:999px;padding:1px 8px;background:var(--accent);color:#0F1113}
.badge.warn{background:var(--warn);color:#0F1113}
.badge:empty{display:none}
.eyebrow{font-size:12px;color:var(--faint);font-weight:700;text-transform:uppercase;letter-spacing:.06em;margin:0 0 8px}
input[type=text],input[type=email],input[type=password],input[type=number],input:not([type]),textarea{height:40px;padding:0 12px;border-radius:8px;border:1px solid var(--line3);background:var(--bg);color:var(--tx)}
textarea{height:auto;padding:10px 12px;min-height:72px;width:100%;resize:vertical}
input[type=checkbox]{width:18px;height:18px;accent-color:var(--accent)}
input[type=file]{font-size:13px;color:var(--muted);max-width:100%}
.check{display:flex;align-items:center;gap:10px;font-size:13px;color:var(--tx2)}
.ok{color:var(--ok)}.warn{color:var(--warn)}.bad{color:var(--bad)}
/* Sign-in */
.login{max-width:380px;margin:12vh auto 0;padding:32px;border:1px solid var(--line2);border-radius:14px;background:var(--panel);display:flex;flex-direction:column;gap:14px}
.login label{display:flex;flex-direction:column;gap:6px;font-size:13px;font-weight:600;color:var(--muted)}
.login .hint{font-size:12px;color:var(--faint);margin:0}
/* Top bar */
.top{height:64px;padding:0 24px;display:flex;align-items:center;gap:22px;border-bottom:1px solid var(--line);background:var(--bar);position:sticky;top:0;z-index:5}
.brand{display:flex;align-items:center;gap:10px;font-weight:800;font-size:16px;letter-spacing:-.01em;white-space:nowrap}
.brand i{width:28px;height:28px;border-radius:7px;background:var(--accent);color:#0F1113;font-style:normal;font-weight:800;font-size:15px;display:flex;align-items:center;justify-content:center}
.tabs{display:flex;gap:4px;align-self:stretch}
.tabs button{display:flex;align-items:center;gap:8px;padding:0 14px;border:0;border-bottom:2px solid transparent;background:none;color:var(--muted);font-weight:600;font-size:14px}
.tabs button[aria-selected=true]{color:var(--tx);font-weight:700;border-bottom-color:var(--accent)}
.tabs .count{font-family:var(--mono);font-size:12px;color:var(--muted)}
.search{display:flex;align-items:center;gap:8px;width:300px;height:38px;padding:0 12px;border:1px solid var(--line2);border-radius:9px;background:var(--card);color:var(--faint);margin-left:auto}
.search input{flex:1;min-width:0;border:0;background:transparent;height:auto;padding:0;outline:none}
.tinydot{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--muted);white-space:nowrap}
.tinydot::before{content:"";width:8px;height:8px;border-radius:999px;background:var(--dot,#5B6168)}
.tinydot:empty{display:none}
.who{font-size:13px;color:var(--muted);white-space:nowrap;max-width:220px;overflow:hidden;text-overflow:ellipsis}
#status{margin:0;padding:8px 24px 0;min-height:28px;font-size:13px;color:var(--muted)}
#status.error,#login-status.error{color:var(--bad)}
/* Board */
main{padding:0 24px 24px}
.bar{display:flex;align-items:center;gap:16px;flex-wrap:wrap;padding:8px 0 12px}
.bar h1,.split h1,.page h1{margin:0;font-size:22px;font-weight:800;letter-spacing:-.02em}
.chips{display:flex;gap:8px;flex-wrap:wrap}
.bar .chips{margin-left:auto}
.kan{display:grid;grid-template-columns:repeat(6,minmax(220px,1fr));gap:12px;overflow-x:auto;padding-bottom:8px;align-items:start}
.col{display:flex;flex-direction:column;gap:10px;background:var(--col);border:1px solid #22262B;border-radius:12px;padding:12px;min-height:320px}
.col.target{border-color:var(--accent)}
.col-head{display:flex;flex-direction:column;gap:6px;padding:2px 2px 8px;border-bottom:1px solid #22262B}
.col-head div{display:flex;align-items:center;gap:8px}
.col-head h2{margin:0;font-size:14px;font-weight:700}
.col-head .swatch{width:10px;height:10px;border-radius:3px;background:var(--c)}
.col-head .n{margin-left:auto;font-family:var(--mono);font-size:12px;color:var(--muted)}
.col-head small{font-size:12px;color:var(--faint)}
.col .empty{font-size:12px;color:var(--faint);padding:8px 2px}
.card{text-align:left;display:flex;flex-direction:column;gap:8px;padding:12px;border-radius:10px;border:1px solid var(--line2);background:var(--card);width:100%}
.card:hover,.card.open{border-color:var(--line3);background:#1E2226}
.card .row{display:flex;align-items:baseline;gap:8px;width:100%}
.card .num{font-size:14px;font-weight:800}
.card .age{margin-left:auto;font-size:12px;color:var(--faint)}
.card .cust{font-size:13px;font-weight:600;color:var(--tx);width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tags{display:flex;flex-wrap:wrap;gap:6px}
.tag{font-size:12px;padding:3px 8px;border-radius:6px;background:var(--card2);color:var(--tx2)}
.card .foot{display:flex;align-items:center;gap:6px;font-size:12px}
.card .foot .where{margin-left:auto;color:var(--muted)}
.late{font-size:12px;color:#F06A5B;font-weight:600}
/* Order panel */
.drawer{position:fixed;inset:0;z-index:10;display:flex;justify-content:flex-end}
.scrim{position:absolute;inset:0;background:rgba(8,9,11,.6)}
.panel{position:relative;width:min(600px,100vw);height:100%;background:var(--panel);border-left:1px solid var(--line2);display:flex;flex-direction:column}
.panel-head{padding:20px 24px;border-bottom:1px solid var(--line);display:flex;flex-direction:column;gap:14px}
.panel-head .row{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.panel-head .num{font-size:22px;font-weight:800}
.stage{font-size:12px;font-weight:700;padding:4px 10px;border-radius:999px;background:color-mix(in srgb,var(--c) 18%,transparent);color:var(--c)}
.close{margin-left:auto;width:40px;height:40px;border-radius:8px;border:1px solid var(--line2);background:transparent;color:var(--muted);display:flex;align-items:center;justify-content:center}
.steps{margin:0;padding:0;list-style:none;display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:6px}
.steps li{display:flex;flex-direction:column;gap:6px;font-size:11px;color:var(--faint)}
.steps li::before{content:"";height:4px;border-radius:4px;background:var(--line2)}
.steps li.done{color:var(--muted)}.steps li.done::before{background:var(--c)}
.steps li.now{color:var(--tx);font-weight:700}.steps li.now::before{background:var(--c)}
.moves{display:flex;gap:10px;flex-wrap:wrap}
.moves .primary{flex:1}
.reason{display:flex;flex-direction:column;gap:8px}
.panel-body{flex:1;overflow:auto;padding:20px 24px 32px;display:flex;flex-direction:column;gap:24px}
.facts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}
.facts b{display:block;font-size:14px}
.facts span{font-size:13px;color:var(--muted);overflow-wrap:anywhere}
.item{display:flex;gap:14px;padding:14px;border:1px solid var(--line2);border-radius:12px;background:var(--card)}
.item.attention{border-color:#4A3A1E;background:#1C1A15}
.item .preview{width:96px;flex-shrink:0;border-radius:8px;background:var(--card2);display:flex;align-items:flex-start;justify-content:center;padding:6px}
.item .preview svg{width:100%;height:auto;display:block}
.item .body{flex:1;min-width:0;display:flex;flex-direction:column;gap:8px}
.item .title{display:flex;align-items:baseline;gap:8px}
.item .title b{font-size:14px}
.item .title .mono{margin-left:auto;font-size:13px}
.item .line{font-size:12px;color:var(--muted)}
.item .file{display:flex;align-items:center;gap:8px;font-size:13px}
.buttons{display:flex;gap:8px;flex-wrap:wrap}
.finals{display:flex;flex-direction:column;gap:12px}
.finals .rev{font-size:13px;display:flex;flex-direction:column;gap:4px;padding:10px 12px;border:1px solid var(--line2);border-radius:10px}
.finals form{display:flex;flex-direction:column;gap:12px;padding:14px;border:1px solid var(--line2);border-radius:12px}
.finals .slot{display:flex;flex-direction:column;gap:6px;font-size:13px;font-weight:600}
.timeline{margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:10px}
.timeline li{display:flex;gap:12px;font-size:13px}
.timeline li::before{content:"";width:8px;height:8px;margin-top:6px;border-radius:999px;background:var(--c,var(--muted));flex-shrink:0}
.timeline small{display:block;color:var(--faint);font-size:12px}
/* Quotes */
.split{display:flex;gap:0;border:1px solid var(--line);border-radius:12px;overflow:hidden;min-height:calc(100vh - 140px)}
.split .list{width:460px;flex-shrink:0;border-right:1px solid var(--line);padding:16px;display:flex;flex-direction:column;gap:12px;background:#111316}
.qitem{text-align:left;display:flex;justify-content:space-between;gap:12px;padding:14px;border-radius:10px;border:1px solid var(--line2);background:var(--card);width:100%}
.qitem[aria-current=true]{border-color:var(--accent);background:#1F1A15}
.qitem b{display:block;font-size:14px;overflow-wrap:anywhere}
.qitem span{font-size:12px;color:var(--muted)}
.qitem .right{text-align:right;flex-shrink:0}
.qitem .flag{display:block;color:var(--warn);font-weight:600;margin-top:4px}
.pane{flex:1;min-width:0;display:flex;flex-direction:column}
.pane .head{padding:18px 24px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.pane .head b{font-size:18px;overflow-wrap:anywhere}
.pane .content{flex:1;padding:20px 24px;display:flex;flex-direction:column;gap:16px}
.pane .fields{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}
.pane .fields label{display:flex;flex-direction:column;gap:6px;font-size:12px;font-weight:600;color:var(--muted)}
.pane .fields input[readonly]{color:var(--faint);background:var(--panel);border-color:var(--line2)}
.pane .foot{padding:16px 24px;border-top:1px solid var(--line);background:var(--bar);display:flex;align-items:center;gap:16px;flex-wrap:wrap}
.pane .foot .total{margin-left:auto;font-family:var(--mono);color:var(--muted)}
.pane .foot .total b{color:var(--tx)}
.pane .note{padding:24px;color:var(--muted)}
/* Payments and integrations */
.page{display:flex;flex-direction:column;gap:22px;padding-top:8px}
.page h2{margin:0 0 10px;font-size:15px;font-weight:800}
.issue{display:flex;align-items:center;gap:16px;flex-wrap:wrap;padding:16px 18px;border-radius:12px;border:1px solid #4A3A1E;background:#1C1A15;margin-bottom:8px}
.issue .text{flex:1;min-width:260px;display:flex;flex-direction:column;gap:4px}
.issue .text b{font-size:14px}
.issue .text span{font-size:13px;color:var(--muted);overflow-wrap:anywhere}
.issue form{display:flex;gap:8px;align-items:center}
.issue input{width:320px}
.grid4{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px}
.integration{display:flex;flex-direction:column;gap:10px;padding:16px;border-radius:12px;border:1px solid var(--line2);background:var(--card)}
.integration .head{display:flex;align-items:center;gap:8px}
.integration .head b{font-size:15px}
.integration .head .dot{width:9px;height:9px;border-radius:999px;background:var(--dot,#5B6168)}
.integration .head em{margin-left:auto;font-style:normal;font-size:12px;font-weight:700;color:var(--dotx,var(--muted))}
.integration p{margin:0;font-size:13px;color:var(--muted)}
.integration .buttons{margin-top:auto}
table.log{width:100%;border-collapse:collapse;font-size:13px}
table.log th{text-align:left;color:var(--faint);font-weight:600;padding:8px 12px;border-bottom:1px solid var(--line)}
table.log td{padding:10px 12px;border-bottom:1px solid #1E2226;vertical-align:top}
.good{color:var(--ok);font-weight:600}.retry{color:var(--warn);font-weight:600}
@media (max-width:900px){
.top{flex-wrap:wrap;height:auto;padding:10px 16px;gap:10px}
.search{order:5;width:100%;margin-left:0}
main{padding:0 16px 16px}
.split{flex-direction:column}
.split .list{width:auto;border-right:0;border-bottom:1px solid var(--line)}
.facts,.pane .fields{grid-template-columns:1fr}
}