sdlc-hub/web/src/board/board.css

181 lines
17 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 3. Закреплённая шапка: заголовок и действия (PageHeader), панель управления (Panel), предупреждения, легенда */
.sticky{position:sticky;top:env(safe-area-inset-top,0px);z-index:10;background:var(--color-bg-canvas);padding-block:var(--space-4) var(--space-2);margin:0 0 var(--space-2);box-shadow:0 1px 0 var(--color-border-default)}
.sticky .ui-page-header{margin-bottom:var(--space-3);gap:var(--space-2)}
.stats{font-variant-numeric:tabular-nums}
.stats b{color:var(--color-text-primary);font-weight:600}
.board-src{display:flex;align-items:center;flex-wrap:wrap;gap:var(--space-2) var(--space-3);min-height:var(--lh-body)}
.board-src:empty{display:none}
.board-src__label{font-size:var(--fs-caption);line-height:var(--lh-caption);color:var(--color-text-secondary);max-width:420px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.board-event{font-size:var(--fs-body);line-height:var(--lh-body);color:var(--color-text-secondary)}
.board-event--warn{color:var(--color-status-warning)}
.menu__label{display:inline-flex;align-items:center;gap:var(--space-2)}
.confirm{display:flex;flex-direction:column;gap:var(--space-2);padding:var(--space-2) var(--space-3);font-size:var(--fs-body);line-height:var(--lh-body);max-width:280px}
.confirm__row{display:flex;gap:var(--space-2)}
.menu .confirm .ui-btn{width:auto;flex:1 1 0;justify-content:center;border-radius:var(--radius-round);min-height:var(--control-h);padding:0 var(--space-3);font-weight:600}
.menu .confirm .ui-btn--danger{background:var(--color-action-danger);color:var(--color-text-on-primary)}
.menu .confirm .ui-btn--secondary{background:transparent;border:1px solid var(--color-border-strong)}
/* 5. Панель управления: выбор спринтов и исполнителей, группы «Показать» и «Режим» */
.board-controls{display:flex;align-items:center;flex-wrap:wrap;gap:var(--space-2) var(--space-3);padding:var(--space-3) var(--space-4);margin:0 0 var(--space-2)}
.board-controls__group{display:flex;align-items:center;flex-wrap:wrap;gap:var(--space-2)}
.board-controls__label{font-size:var(--fs-caption);line-height:var(--lh-caption);color:var(--color-text-secondary)}
.board-controls__sep{width:1px;align-self:stretch;min-height:var(--control-h);background:var(--color-border-default)}
.board-controls__text{font-size:var(--fs-body);color:var(--color-text-secondary)}
.multi-btn{display:inline-flex;align-items:center;justify-content:space-between;gap:var(--space-2);width:auto;min-width:180px;max-width:360px;text-align:left;cursor:pointer}
.multi-btn .lbl{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.multi-btn[aria-expanded="true"]{border-color:var(--color-action-primary)}
.legend-box{margin:0}
.legend-head{display:flex;align-items:center;gap:var(--space-2)}
.legend{display:flex;flex-wrap:wrap;align-items:center;gap:2px 12px;margin:var(--space-1) 0 0;font-size:var(--fs-caption);line-height:var(--lh-caption);color:var(--color-text-secondary)}
.legend span{display:inline-flex;align-items:center;gap:6px}
.legend .sep{width:1px;height:14px;background:var(--color-border-default)}
.legend .hint{margin-left:auto}
.lg{font:inherit;font-size:var(--fs-caption);line-height:var(--lh-caption);color:var(--color-text-secondary);background:none;border:1px solid transparent;padding:2px 6px;border-radius:var(--radius-xs);cursor:pointer;display:inline-flex;align-items:center;gap:6px}
.lg:hover{background:var(--color-bg-hover);color:var(--color-text-primary)}
.lg:focus-visible{background:var(--color-bg-hover);color:var(--color-text-primary);border-color:var(--color-border-selected);outline:none}
.lg.off{opacity:.45;text-decoration:line-through}
.sw{width:10px;height:10px;border-radius:2px;display:inline-block}
.ln{width:26px;height:0;border-top:2px solid var(--edge-strong);display:inline-block}
.ln.dash{border-top-style:dashed;border-top-color:var(--edge)}
.ln.hand{border-top-color:var(--guide)}
.ln.crit{border-top-width:4px;border-top-color:var(--guide)}
.out-sw{width:16px;height:11px;border:1.5px dashed var(--color-text-secondary);border-radius:3px;display:inline-block}
/* 6. Доска: прокрутка только по горизонтали (вертикальная — у страницы), дорожки по эпикам, карточки абсолютные */
.stage{display:flex;gap:var(--space-3);align-items:stretch}
.wrap{flex:1 1 auto;min-width:0;overflow-x:auto;overflow-y:hidden;border:1px solid var(--color-border-default);border-radius:var(--radius-xl);background:var(--color-bg-surface);user-select:none;-webkit-user-select:none}
.board{position:relative;min-width:100%}
svg.edges,svg.guides{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}
svg.guides{z-index:3}
svg.guides line{stroke:var(--guide);stroke-width:1;stroke-dasharray:4 3}
.empty{padding:40px 16px;color:var(--color-text-secondary);text-align:center}
#hubState{white-space:normal;min-width:0}
.lane{position:absolute;left:0;right:0;border-top:1px solid var(--color-border-default)}
.lane:nth-child(even of .lane){background:var(--lane-alt)}
.lane.folded{background:var(--color-bg-track);border-bottom:1px solid var(--color-border-strong);border-top-color:var(--color-border-strong)}
.lane.target{box-shadow:inset 0 3px 0 var(--color-action-primary)}
.lane.target-after{box-shadow:inset 0 -3px 0 var(--color-action-primary)}
.lane.dragging{opacity:.6}
.lane-head{position:absolute;left:8px;top:8px;display:flex;align-items:center;gap:4px;z-index:1}
.fold{width:20px;height:20px;border:0;background:none;color:var(--color-text-secondary);cursor:pointer;padding:0;border-radius:var(--radius-xs);display:inline-flex;align-items:center;justify-content:center}
.fold svg{transition:transform .15s}
.fold:hover{background:var(--color-bg-hover);color:var(--color-text-primary)}
.fold:focus-visible,.lane-tools button:focus-visible,.card .open-card:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:1px}
.lane.folded .fold svg{transform:rotate(-90deg)}
.lane-name{font-size:var(--fs-caption);line-height:var(--lh-caption);color:var(--color-text-secondary);font-weight:600;cursor:grab;padding:2px 4px;border-radius:var(--radius-xs);user-select:none;touch-action:none}
.lane-name:hover{background:var(--color-bg-hover);color:var(--color-text-primary)}
.lane-count{display:none;font-size:var(--fs-caption);line-height:var(--lh-caption);color:var(--color-text-secondary);margin-left:4px}
.lane.folded .lane-count{display:inline}
.lane-tools{display:none;gap:2px}
.lane:hover .lane-tools{display:inline-flex}
.lane-tools button{display:inline-flex;align-items:center;justify-content:center;color:var(--color-text-secondary);background:var(--color-bg-surface);border:1px solid var(--color-border-strong);border-radius:var(--radius-xs);width:22px;height:22px;cursor:pointer;padding:0}
.lane-tools button:hover{border-color:var(--color-action-primary);color:var(--color-action-primary)}
.lane-tools button:disabled{opacity:.35;cursor:default}
/* режим «по датам»: колонки по плановым датам окончания, шапка колонки над дорожками; карточки двигаются внутри своей колонки */
.dcol{position:absolute;top:0;border-left:1px solid var(--color-border-default);box-sizing:border-box;pointer-events:none}
.dcol:first-of-type{border-left:0}
.dcol.past{background:color-mix(in srgb,var(--p-crit) 5%,transparent)}
.dcol.today{background:color-mix(in srgb,var(--color-action-primary) 7%,transparent)}
/* полоса дат над доской: липнет под шапкой страницы, по горизонтали двигается вместе с доской (transform по scrollLeft) */
.dates-bar{position:sticky;top:calc(var(--head-h,0px) + env(safe-area-inset-top,0px));z-index:9;background:var(--color-bg-canvas)}
.dates-in{overflow:hidden;border:1px solid var(--color-border-default);border-bottom:0;border-radius:var(--radius-xl) var(--radius-xl) 0 0;background:var(--color-bg-surface);height:36px;box-sizing:border-box}
.dates-track{position:relative;height:100%}
.dlabel{position:absolute;top:10px;font-size:var(--fs-caption);line-height:var(--lh-caption);color:var(--color-text-primary);font-weight:600;white-space:nowrap}
.dlabel .n{font-weight:400;color:var(--color-text-secondary);margin-left:6px;font-variant-numeric:tabular-nums}
.dlabel.past{color:var(--p-crit)}
.dlabel.today{color:var(--color-action-primary)}
.dlabel.none{color:var(--color-text-secondary);font-weight:400}
.stage.bydate .wrap{border-top-left-radius:0;border-top-right-radius:0}
.dsplit{position:absolute;top:0;bottom:0;width:11px;margin-left:-5px;cursor:col-resize;z-index:1}
.dsplit::after{content:"";position:absolute;left:5px;top:6px;bottom:6px;width:1px;background:var(--color-border-default)}
.dsplit:hover::after,.dsplit.on::after{background:var(--color-action-primary);width:3px;left:4px;border-radius:2px}
.dates-in.resizing{cursor:col-resize}
/* горизонтальная прокрутка доски, прилипшая к низу окна: полоса всегда видна, скроллбар нарисован явно (на macOS системный прячется) */
.hscroll{position:sticky;bottom:0;z-index:8;overflow-x:scroll;overflow-y:hidden;height:14px;background:var(--color-bg-canvas);padding-top:2px;box-sizing:border-box;scrollbar-width:thin;scrollbar-color:var(--color-border-strong) var(--color-bg-track)}
.hscroll>div{height:1px}
.hscroll::-webkit-scrollbar{height:12px}
.hscroll::-webkit-scrollbar-track{background:var(--color-bg-track);border-radius:6px}
.hscroll::-webkit-scrollbar-thumb{background:var(--color-border-strong);border-radius:6px;border:2px solid var(--color-bg-track)}
.hscroll::-webkit-scrollbar-thumb:hover{background:var(--color-action-primary)}
/* карточка: текст выделяется, тянуть можно только за рамку (появляется при наведении) и за уголок */
.card{position:absolute;width:240px;height:120px;box-sizing:border-box;background:var(--color-bg-surface);border:1px solid var(--color-border-default);border-radius:var(--radius-lg);padding:12px;display:flex;flex-direction:column;gap:4px;overflow:hidden;cursor:default;touch-action:none}
.card:hover{border-color:var(--color-border-strong)}
.card.out{border-style:dashed;opacity:.7}
.card.closed{opacity:.4}
.card.closed:hover,.card.closed:focus-within{opacity:1}
.edges path.closed{opacity:.4}
.card.crit{box-shadow:0 0 0 2px var(--guide)}
.card.focus{box-shadow:0 0 0 2px var(--color-action-primary)}
.card.drag{cursor:grabbing;border-color:var(--color-action-primary);box-shadow:var(--shadow-popover);z-index:2}
.card .title,.card .state,.card .who,.card .meta,.card .key,.card .sprint-tag{user-select:text;-webkit-user-select:text;cursor:text;touch-action:auto}
.card .key{cursor:pointer}
.card .meta{cursor:default}
.card .grip{position:absolute;background:var(--color-action-primary);opacity:0;cursor:grab;z-index:1;transition:opacity .12s}
.card .grip.t{left:0;right:0;top:0;height:8px;border-radius:11px 11px 0 0}
.card .grip.b{left:0;right:14px;bottom:0;height:8px;border-radius:0 0 0 11px}
.card .grip.l{left:0;top:0;bottom:0;width:8px;border-radius:11px 0 0 11px}
.card .grip.r{right:0;top:0;bottom:14px;width:8px;border-radius:0 11px 0 0}
.card:hover .grip,.card.drag .grip{opacity:.6}
.card.drag .grip{cursor:grabbing}
.card .rsz{position:absolute;right:0;bottom:0;width:14px;height:14px;cursor:nwse-resize;background:linear-gradient(135deg,transparent 50%,var(--color-border-strong) 50%);border-bottom-right-radius:11px;z-index:2}
.card:hover .rsz{background:linear-gradient(135deg,transparent 50%,var(--color-action-primary) 50%)}
.head{display:flex;align-items:center;justify-content:space-between;gap:6px;min-width:0}
.card .key{font-family:var(--font-mono);font-size:13px;font-weight:600;color:var(--color-action-primary);text-decoration:none;flex:0 0 auto}
.sprint-tag{font-size:11px;line-height:1;padding:4px 7px;border-radius:var(--radius-round);background:var(--color-bg-track);color:var(--color-text-secondary);max-width:55%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:0 1 auto}
.sprint-tag.sel{background:var(--color-action-primary);color:var(--color-text-on-primary)}
.sprint-tag.none{background:transparent;border:1px dashed var(--color-border-strong)}
.title{font-size:14.5px;line-height:19px;font-weight:600;color:var(--color-text-primary);min-width:0;flex:1 1 auto;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}
.meta{display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--color-text-secondary);white-space:nowrap;flex:0 0 auto}
.kind{display:inline-flex;align-items:center;gap:4px}
.kind i{width:8px;height:8px;border-radius:2px;display:inline-block}
.prio{font-weight:600}
/* состояние задачи (статус, срок, исполнитель) — отдельный блок под чертой, основным цветом: это главное после названия */
.state,.who{font-size:13px;flex:0 0 auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--color-text-primary)}
.state{display:flex;align-items:center;gap:6px;margin-top:4px;padding-top:7px;border-top:1px solid var(--color-border-default)}
/* статус — вид Badge (neutral) */
.status{font-size:var(--fs-caption);line-height:var(--lh-caption);font-weight:600;padding:1px 8px;border:1px solid var(--color-border-default);border-radius:var(--radius-round);background:var(--color-bg-track);color:var(--color-text-secondary);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.due{font-variant-numeric:tabular-nums;font-weight:600;flex:0 0 auto}
.who::before{content:"";display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--color-action-primary);margin-right:5px;vertical-align:1px}
.who.none{color:var(--color-text-secondary);font-style:italic}
.who.none::before{background:transparent;border:1px solid var(--color-text-secondary)}
/* 7. Панель проблем справа от доски, липнет под шапкой; прокручивается содержимое внутри рамки Panel */
.drawer{flex:0 0 340px;max-width:40%;box-sizing:border-box;align-self:flex-start;position:sticky;top:calc(var(--head-h,0px) + 8px);max-height:calc(100vh - var(--head-h,0px) - 24px);display:flex;font-size:var(--fs-body)}
.drawer>.ui-panel{display:flex;flex-direction:column;gap:var(--space-3);min-height:0;min-width:0;flex:1 1 auto;padding:var(--space-4) 0 var(--space-4) var(--space-4)}
.drawer-head{display:flex;justify-content:space-between;align-items:center;gap:var(--space-2);padding-right:var(--space-4)}
.drawer-body{overflow-y:auto;min-height:0;padding-right:var(--space-4)}
.board-h2{margin:0;font-size:var(--fs-lg);line-height:var(--lh-lg);font-weight:700;color:var(--color-text-primary)}
.board-h3{margin:var(--space-3) 0 var(--space-1);font-size:var(--fs-caption);line-height:var(--lh-caption);font-weight:600;color:var(--color-text-secondary)}
.board-h3:first-child{margin-top:0}
.drawer ul{margin:0;padding-left:18px}
.drawer li{margin:3px 0}
.drawer .k{font-family:var(--font-mono);font-size:13px;font-weight:600;color:var(--color-action-primary);text-decoration:none}
.drawer .ok{color:var(--color-status-success);margin:0}
.drawer .why{color:var(--color-text-secondary)}
/* 8. Экспорт JSON и таблица связей (включаются из меню «Ещё») */
.export{display:flex;flex-direction:column;gap:var(--space-2);margin:0 0 var(--space-2)}
.export__row{display:flex;align-items:center;flex-wrap:wrap;gap:var(--space-2)}
.export__hint{font-size:var(--fs-caption);line-height:var(--lh-caption);color:var(--color-text-secondary)}
.export textarea{font-family:var(--font-mono);font-size:11.5px;width:100%;box-sizing:border-box;height:180px;border:1px solid var(--color-border-default);border-radius:var(--radius-sm);background:var(--color-bg-surface);color:var(--color-text-primary);padding:8px;resize:vertical}
.link-table{margin-top:var(--space-3)}
.tbl{max-width:100%;overflow-x:auto;margin-top:var(--space-2)}
table{border-collapse:collapse;font-size:var(--fs-body);min-width:520px}
th,td{text-align:left;padding:6px 10px;border-bottom:1px solid var(--color-border-default);vertical-align:top}
th{font-size:var(--fs-caption);font-weight:600;color:var(--color-text-secondary)}
td.k{font-family:var(--font-mono);font-size:12px;white-space:nowrap;color:var(--color-action-primary)}
/* 9. Движение и узкие экраны */
@media (prefers-reduced-motion:no-preference){.card{transition:border-color .15s}}
@media (prefers-reduced-motion:reduce){.card .grip,.fold svg{transition:none}}
@media (max-width:900px){.stage{flex-direction:column}.drawer{flex:none;max-width:100%;max-height:none;position:static}}
@media (max-width:640px){.sticky{position:static}.dates-bar{position:static}}
@media (max-width:640px){.board-controls__sep,.legend .sep{display:none}}
/* «Открыть карточку» в заголовке карточки (R-1) */
.card .open-card{margin-left:6px;color:var(--color-text-secondary);text-decoration:none;display:inline-flex;align-items:center;border-radius:var(--radius-xs)}
.card .open-card:hover{color:var(--color-action-primary)}
/* слой измерения: карточки шириной CW с высотой по содержимому, невидим */
.measure{position:absolute;left:-100000px;top:0;visibility:hidden;pointer-events:none}
.measure .card{position:static;height:auto}
.measure .card .title{-webkit-line-clamp:unset}