:root {
    --kanban-ink: #111827;
    --kanban-ink-soft: #374151;
    --kanban-muted: #6b7280;
    --kanban-muted-light: #9ca3af;
    --kanban-border: #e5e7eb;
    --kanban-border-strong: #d1d5db;
    --kanban-soft: #f7f8fa;
    --kanban-surface: #ffffff;
    --kanban-blue: #2563eb;
    --kanban-blue-dark: #1d4ed8;
    --kanban-blue-soft: #eef2ff;
    --kanban-danger: #b42318;
    --kanban-danger-soft: #fee2e2;
    --kanban-danger-soft-hover: #fecaca;
    --kanban-danger-ink: #991b1b;
    --kanban-success-soft: #dcfce7;
    --kanban-success-ink: #166534;
    --kanban-focus: #fef08a; /* the person's pick, see FOCUS_COLORS in kanban.js -- one soft color for both themes */
}

html,
body {
    background-color: #fafafa;
    background-image: radial-gradient(circle, var(--kanban-border) 1px, transparent 1px);
    background-size: 18px 18px;
    /* Kanban columns scroll horizontally; without this, a trackpad/touch
       swipe that runs out of columns to scroll falls through to the
       browser's swipe-to-go-back/forward navigation gesture. */
    overscroll-behavior-x: none;
}

body {
    margin-left: 0;
    margin-right: 0;
}

main.kanban-page {
    /* No cap, unlike the shared main { max-width: var(--body-max-width) } rule every other yzy page still
       gets from style-template.css -- this class is what already beats that rule's lower specificity, so
       widening kanban is just dropping the min(1440px, ...) ceiling this class was adding on top, not
       touching that shared rule at all. Still calc(100vw - 32px), the same formula narrow viewports
       (< 1440px + 32px) already got before this change -- so this only changes anything on a wide one,
       where it now keeps that same 16px-a-side gutter instead of centering a fixed 1440px column with
       empty margin beyond it. That gutter matters beyond looks: the swimlane label gutter (see
       positionSwimlaneLabels) sizes itself to exactly this container's own inset from the browser edge,
       so it needs that inset to still exist at every width, not just be however much space is left over
       once a capped-width column stops growing. */
    width: calc(100vw - 32px);
    max-width: none;
    min-width: 0;
    margin: 0 auto;
    /* top padding must clear the fixed 40px header (see header { height:
       40px; position: fixed } in style-template.css) or its bottom edge
       overlaps the toolbar; 44px matches that rule's own top clearance. */
    padding: 44px 0 56px;
    box-sizing: border-box;
}

.kanban-toolbar,
.kanban-board-nav,
.kanban-dialog-heading,
.kanban-dialog-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}

.kanban-toolbar {
    padding-bottom: 20px;
    border-bottom: 1px solid var(--kanban-border);
}

.kanban-toolbar h1,
.kanban-dialog-heading h2 {
    margin: 0;
    color: var(--kanban-ink);
    font-weight: 650;
}

.kanban-eyebrow {
    margin: 0 0 4px;
    color: var(--kanban-muted);
    font-size: 12px;
    font-weight: 650;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.kanban-project-controls,
.kanban-board-actions,
.kanban-dialog-footer > div {
    display: flex;
    align-items: center;
    gap: 10px;
}

.kanban-project-controls label {
    color: var(--kanban-muted);
    font-size: 13px;
}

.kanban-workspace-trigger {
    color: var(--kanban-muted);
    font-size: 13px;
    padding: 6px 8px;
    margin-left: -8px;
    border-radius: 6px;
}

.kanban-workspace-trigger:hover,
.kanban-workspace-trigger[aria-expanded="true"] {
    background: var(--kanban-soft);
    color: var(--kanban-ink);
}

.kanban-workspace-trigger:focus-visible {
    outline: 2px solid var(--kanban-blue);
    outline-offset: 1px;
}

.kanban-project-controls select,
.kanban-search {
    min-height: 38px;
    border: 1px solid var(--kanban-border-strong);
    border-radius: 8px;
    background: var(--kanban-surface);
    color: var(--kanban-ink);
    padding: 7px 10px;
    font: inherit;
}

.kanban-project-controls select {
    min-width: 220px;
}

#kanban-workspace-select {
    appearance: none;
    border-color: transparent;
    background: transparent;
    padding: 7px 8px;
    cursor: pointer;
}

#kanban-workspace-select:hover {
    background: var(--kanban-soft);
}

#kanban-workspace-select:focus {
    border-color: var(--kanban-border-strong);
    background: var(--kanban-surface);
}

#kanban-workspace-select:focus-visible {
    outline: 2px solid var(--kanban-blue);
    outline-offset: 1px;
}

.kanban-project-controls {
    flex-wrap: wrap;
}

/* The projects and settings buttons wrap as one unit, so on a narrow screen
   they stay side by side instead of one dropping to its own line. */
.kanban-project-actions {
    display: flex;
    align-items: center;
    gap: 10px;
}

.kanban-text-link {
    color: var(--kanban-blue);
    font-size: 13px;
    text-decoration: none;
}

.kanban-text-link:hover,
.kanban-text-link:focus-visible {
    text-decoration: underline;
}

.kanban-button,
.kanban-icon-button,
.kanban-board-tab,
.kanban-column-action,
.kanban-menu-item,
.kanban-picker-list,
.kanban-workspace-trigger,
.kanban-tab,
.kanban-swimlane-label-text {
    appearance: none;
    border: 1px solid transparent;
    background: none;
    color: inherit;
    font: inherit;
    cursor: pointer;
}

.kanban-button {
    min-height: 36px;
    border-radius: 8px;
    background: var(--kanban-ink);
    color: var(--kanban-surface);
    padding: 7px 13px;
    font-size: 13px;
    font-weight: 600;
}

.kanban-button:hover {
    background: var(--kanban-ink-soft);
}

.kanban-button--quiet {
    border-color: var(--kanban-border-strong);
    background: var(--kanban-surface);
    color: var(--kanban-ink-soft);
}

.kanban-button--quiet:hover {
    background: var(--kanban-soft);
}

.kanban-button--danger {
    border-color: var(--kanban-danger-soft-hover);
    background: var(--kanban-surface);
    color: var(--kanban-danger);
}

.kanban-button:disabled,
.kanban-column-action:disabled {
    cursor: not-allowed;
    opacity: 0.45;
}

.kanban-feedback {
    position: fixed;
    left: 50%;
    bottom: 28px;
    transform: translateX(-50%);
    z-index: 30;
    max-width: min(640px, calc(100vw - 32px));
    padding: 10px 16px;
    border-radius: 10px;
    background: var(--kanban-surface);
    color: var(--kanban-ink-soft);
    font-size: 13px;
    text-align: center;
    box-shadow: 0 10px 24px rgba(17, 24, 39, 0.14);
    cursor: pointer;
}

.kanban-feedback:hover {
    filter: brightness(0.97);
}

.kanban-feedback[hidden] {
    display: none;
}

.kanban-feedback[data-variant="error"] {
    background: var(--kanban-danger-soft);
    color: var(--kanban-danger-ink);
}

.kanban-empty {
    margin-top: 56px;
    padding: 48px 24px;
    border: 1px dashed var(--kanban-border-strong);
    border-radius: 12px;
    text-align: center;
}

.kanban-empty-icon {
    display: flex;
    justify-content: center;
    margin-bottom: 16px;
    color: var(--kanban-muted-light);
}

.kanban-empty h2,
.kanban-empty p {
    margin: 0;
}

.kanban-empty p {
    margin-top: 7px;
    color: var(--kanban-muted);
}

.kanban-board-nav {
    padding: 8px 0;
    border-bottom: 1px solid var(--kanban-border);
}

.kanban-board-tabs-wrap {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    flex: 1 1 auto;
}

.kanban-board-tabs-wrap .kanban-icon-button,
.kanban-board-tabs-wrap .kanban-menu-wrap {
    flex: 0 0 auto;
}

.kanban-board-tabs {
    display: flex;
    align-items: center;
    gap: 4px;
    min-width: 0;
    flex: 0 1 auto;
    /* Tabs shrink first (see .kanban-board-tab's min-width: 0) so this only
       needs to scroll in the extreme case where even every non-selected tab
       at its floor plus the selected tab's full name still don't fit. Stays
       scrollable rather than hidden for that case -- just with no visible
       bar, per this app's usual scrollbar treatment below. */
    overflow-x: auto;
    scrollbar-width: none;
    -ms-overflow-style: none;
}

.kanban-board-tab {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: 0 1 auto;
    /* 0, not a fixed floor like 60px -- a flex item's default automatic
       minimum keeps it from ever shrinking below its own (nowrap) content
       width, which would block truncation entirely. This is only a ceiling
       removal: with room to spare each tab still sizes to its own content,
       exactly as it did before shrinking was possible; min-width: 0 just
       lets that content size give way once tabs are actually crowded. */
    min-width: 0;
    max-width: 180px;
    border-radius: 7px;
    color: var(--kanban-muted);
    padding: 8px 12px;
    font-size: 13px;
}

/* Lets non-selected tabs shrink together as more boards are added,
   truncating each name with an ellipsis so every board keeps fitting on
   this one line for as long as possible before .kanban-board-tabs' own
   (invisible) scrolling has to take over. The floor keeps at least a few
   characters of each name legible -- without it min-width:0 lets a crowded
   tab shrink to nothing. 6ch, not 3ch: the ellipsis glyph itself eats into
   the box, so a 3ch floor only left room for a single letter plus "…" once
   verified on a narrow (mobile) width with several boards -- 6ch is what it
   actually takes to keep 3+ letters visible before the ellipsis. */
.kanban-board-tab-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 6ch;
}

.kanban-board-tab:hover {
    background: var(--kanban-soft);
    color: var(--kanban-ink);
}

.kanban-board-tab[aria-selected="true"] {
    background: var(--kanban-blue-soft);
    color: var(--kanban-blue-dark);
    font-weight: 650;
    /* The board you're looking at should always read in full -- only the
       other tabs give up width when the strip is crowded. */
    flex-shrink: 0;
    max-width: none;
}

/* A board added to the combined overview (see toggleExtraBoard) alongside
   the primary one above -- outlined rather than filled so it stays clearly
   secondary to the single filled/active tab. */
.kanban-board-tab[data-extra="true"] {
    border: 1px solid var(--kanban-blue);
    color: var(--kanban-blue-dark);
    font-weight: 650;
}

.kanban-board-tab[data-extra="true"]:hover {
    background: var(--kanban-blue-soft);
}

/* A column focus (see columnFocusActive) makes every other board inert rather than switchable -- same
   disabled language as .kanban-button:disabled, reused here since these tabs are plain divs and get no
   native :disabled. The hover override keeps it from lighting up as if a click would do something. */
.kanban-board-tab[aria-disabled="true"] {
    cursor: not-allowed;
    opacity: 0.45;
}

.kanban-board-tab[aria-disabled="true"]:hover {
    background: none;
    color: var(--kanban-muted);
}

.kanban-board-tab-icon {
    flex: 0 0 auto;
    font-size: 12px;
    line-height: 1;
}

.kanban-columns {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    width: 100%;
    margin-top: 16px;
    padding-bottom: 24px;
    overflow-x: auto;
    /* `contain` still lets a trackpad/touch swipe past the scroll edge fall
       through to the browser's own swipe-to-go-back gesture; `none` suppresses
       that default action outright, not just chaining to ancestor scrollers. */
    overscroll-behavior-inline: none;
    scrollbar-width: none;
    -ms-overflow-style: none;
}

/* This app doesn't show scrollbars. For a horizontal browsing strip like this
   one -- where the next column/tab already peeks in at the edge as its own
   "there's more" cue -- that means hidden outright: content still scrolls
   (wheel, trackpad, touch, keyboard), the bar itself just never renders. A
   new strip like these two should join this selector list. Scrollable lists
   *inside* a dialog or panel (nothing peeking at an edge to hint at more
   content) instead get the minimal transparent-track treatment a bit further
   down, since hiding those away would leave no clue they scroll at all. */
.kanban-columns::-webkit-scrollbar,
.kanban-board-tabs::-webkit-scrollbar {
    display: none;
}

/* A dialog/panel's scrollable list (item picker, template list, project
   search results, history, people roster) stays visibly scrollable -- unlike
   the strips above, there's no edge-peeking content to hint that more exists
   below the fold, so hiding it away entirely would make it look cut off
   rather than scrollable. It still never gets the browser's default opaque
   bar: thin, transparent track. Firefox honors this outright; Safari has a
   history of ignoring webkit scrollbar color overrides and drawing its own
   accent-colored thumb regardless (see the page-level scrollbar note in
   kanban-dark.css), so treat this as best-effort there, not a guarantee. */
.kanban-picker-items,
.kanban-history-list,
.kanban-resources-panel {
    scrollbar-width: thin;
    scrollbar-color: var(--kanban-border-strong) transparent;
}

.kanban-picker-items::-webkit-scrollbar,
.kanban-history-list::-webkit-scrollbar,
.kanban-resources-panel::-webkit-scrollbar {
    width: 6px;
    background: transparent;
}

.kanban-picker-items::-webkit-scrollbar-track,
.kanban-history-list::-webkit-scrollbar-track,
.kanban-resources-panel::-webkit-scrollbar-track {
    background: transparent;
}

.kanban-picker-items::-webkit-scrollbar-thumb,
.kanban-history-list::-webkit-scrollbar-thumb,
.kanban-resources-panel::-webkit-scrollbar-thumb {
    background: var(--kanban-border-strong);
    border-radius: 999px;
}

/* On a touch device the thin-track treatment above is dropped in favor of no bar at all: touch scrolling
   is already self-evident (a swipe, a bounce at the end), so the hint a mouse/trackpad user needs here has
   nothing left to do except sit there -- and some mobile browsers don't auto-hide a scrollbar an author
   has explicitly styled the way they do the native one, which would leave it visibly parked over these
   popups' content the whole time. (hover: none), not a width breakpoint: this is about the input, a touch
   phone or tablet, not the window size -- a narrow desktop browser window still has a mouse and keeps its
   thin scrollbar. */
@media (hover: none) {
    .kanban-picker-items,
    .kanban-history-list,
    .kanban-resources-panel {
        scrollbar-width: none;
        -ms-overflow-style: none;
    }

    .kanban-picker-items::-webkit-scrollbar,
    .kanban-history-list::-webkit-scrollbar,
    .kanban-resources-panel::-webkit-scrollbar {
        display: none;
    }
}

.kanban-column {
    position: relative;
    flex: 0 0 292px;
    width: 292px;
    border: 1px solid var(--kanban-border);
    border-radius: 12px;
    background: var(--kanban-soft);
    overflow: hidden;
    transition: background 150ms ease, border-color 150ms ease, box-shadow 150ms ease;
}

.kanban-column:hover:not(.kanban-column--selected) {
    box-shadow: inset 0 0 0 1px var(--kanban-border-strong);
}

.kanban-column[data-completion="true"] {
    background: #eaf7ee;
}

.kanban-column[data-completion="true"]::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: var(--kanban-success-ink);
}

.kanban-column--accent::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: var(--bucket-accent);
}

.kanban-column--selected {
    background: var(--kanban-border-strong);
    border-color: var(--kanban-muted-light);
}

.kanban-column--selected[data-completion="true"] {
    background: #d7ecdf;
}

.kanban-column--synthetic {
    cursor: default;
}

.kanban-column[data-overdue="true"] {
    background: var(--kanban-danger-soft);
    border-color: var(--kanban-danger);
}

/* Selecting an overdue column would otherwise be invisible -- its own red tint already fills the
   background the selected state would use to show itself. Keep the red border (still the overdue cue)
   but drop the background back to the ordinary selected one. */
.kanban-column--selected[data-overdue="true"] {
    background: var(--kanban-border-strong);
}

.kanban-bucket-swatch {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex: 0 0 auto;
}

.kanban-column-header {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 48px;
    padding: 8px 10px;
    border-bottom: 1px solid var(--kanban-border);
}

.kanban-column-drag,
.kanban-card-drag,
.kanban-resource-drag {
    color: var(--kanban-muted-light);
    cursor: grab;
    user-select: none;
    border-radius: 4px;
}

.kanban-column-drag:focus,
.kanban-card-drag:focus {
    outline: none;
}

.kanban-column-drag:focus-visible,
.kanban-card-drag:focus-visible {
    outline: 2px solid var(--kanban-blue);
    outline-offset: 1px;
}

.kanban-column-drag {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(3, 1fr);
    gap: 3px;
    padding: 3px;
}

/* Project columns never reorder (see setupProjectSortables), so this handle is collapse-only -- swap the
   base rule's grab cursor, which implies dragging, for a plain pointer. */
.kanban-column-drag--collapse-only {
    cursor: pointer;
}

.kanban-column-drag-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
    transition: background-color 0.15s ease;
}

.kanban-column--collapsed .kanban-column-drag-dot--present {
    background: var(--dot-color);
}

.kanban-column-title {
    min-width: 0;
    margin: 0;
    overflow: hidden;
    color: var(--kanban-ink);
    font-size: 14px;
    font-weight: 650;
    text-overflow: ellipsis;
    white-space: nowrap;
}

a.kanban-column-title {
    text-decoration: none;
}

a.kanban-column-title:hover,
a.kanban-column-title:focus-visible {
    color: var(--kanban-blue);
    text-decoration: underline;
}

.kanban-column-title-group {
    display: flex;
    flex-direction: column;
    min-width: 0;
    gap: 1px;
}

.kanban-column-title-group .kanban-column-title {
    min-width: 0;
}

.kanban-column-subtitle {
    overflow: hidden;
    color: var(--kanban-muted);
    font-size: 11px;
    font-weight: 500;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.kanban-column-count {
    margin-left: auto;
    color: var(--kanban-muted);
    font-size: 12px;
}

.kanban-completion-label {
    border-radius: 999px;
    background: var(--kanban-success-soft);
    color: var(--kanban-success-ink);
    padding: 2px 6px;
    font-size: 10px;
    font-weight: 650;
    text-transform: uppercase;
}

.kanban-column-actions {
    display: flex;
    gap: 2px;
}

.kanban-column-action,
.kanban-icon-button {
    width: 28px;
    height: 28px;
    border-radius: 6px;
    color: var(--kanban-muted);
    line-height: 1;
}

.kanban-column-action:hover,
.kanban-icon-button:hover {
    background: var(--kanban-border);
    color: var(--kanban-ink);
}

.kanban-column--collapsed {
    flex: 0 0 40px;
    width: 40px;
    align-self: stretch;
}

.kanban-column--collapsed .kanban-column-header {
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    height: 100%;
    min-height: 100%;
    gap: 10px;
    padding: 10px 0;
    border-bottom: none;
}

.kanban-column--collapsed .kanban-column-count,
.kanban-column--collapsed .kanban-column-actions,
.kanban-column--collapsed .kanban-completion-label,
.kanban-column--collapsed .kanban-card-list,
.kanban-column--collapsed .kanban-column-swimlanes,
.kanban-column--collapsed .kanban-unavailable-label {
    display: none;
}

.kanban-column--collapsed .kanban-column-title {
    writing-mode: vertical-rl;
    text-orientation: mixed;
    transform: rotate(180deg);
    max-height: 100%;
    white-space: nowrap;
}

.kanban-menu-wrap {
    position: relative;
    display: inline-flex;
}

.kanban-menu {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    z-index: 20;
    display: flex;
    flex-direction: column;
    min-width: 190px;
    padding: 6px;
    border: 1px solid var(--kanban-border);
    border-radius: 10px;
    background: var(--kanban-surface);
    box-shadow: 0 10px 24px rgba(17, 24, 39, 0.14);
}

.kanban-menu[hidden] {
    display: none;
}

.kanban-menu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 8px 10px;
    border-radius: 7px;
    font-size: 13px;
    font-weight: 600;
    text-align: left;
    white-space: nowrap;
}

.kanban-menu-item:hover {
    background: var(--kanban-soft);
}

.kanban-menu-item:disabled {
    cursor: not-allowed;
    opacity: 0.45;
}

.kanban-menu-item:disabled:hover {
    background: none;
}

.kanban-menu-icon {
    display: inline-flex;
    flex: 0 0 auto;
    width: 18px;
    align-items: center;
    justify-content: center;
    color: var(--kanban-muted);
}

.kanban-menu-item--danger {
    color: var(--kanban-danger);
}

.kanban-menu-item--danger .kanban-menu-icon {
    color: var(--kanban-danger);
}

.kanban-card-list {
    min-height: 82px;
    padding: 9px;
}

/* Swimlanes: a column's card list splits into one band per swimlane line
   instead of a single list. .kanban-column already clips its content to
   its own border-radius (see its `overflow: hidden` above), so these bands
   -- which carry no border or radius of their own, only the divider
   between them -- never interrupt the column's rounded top/bottom corners;
   equalizeSwimlaneBands sets each band's height to match its row's tallest
   column, which is what turns the per-column dividers into one continuous
   horizontal line across the board. */
.kanban-column-swimlanes {
    display: flex;
    flex-direction: column;
}

.kanban-swimlane-band {
    box-sizing: border-box;
    /* --swimlane-hue is set inline per line (see swimlaneLineHue) so a
       band's tint and its label's (below) always match; the lightness/
       saturation baked into this rule (not the JS) is what kanban-dark.css
       overrides for the theme, same split as every other color token here. */
    background: hsl(var(--swimlane-hue, 217) 50% 97%);
}

.kanban-swimlane-band + .kanban-swimlane-band {
    border-top: 1px solid var(--kanban-border-strong);
}

/* Collapsed via the line's own gutter label (see toggleSwimlaneLineCollapse) -- every column's band for
   this line shares the class, so equalizeSwimlaneBands measures the same small height in each and the row
   stays one continuous thin strip across the board, exactly like an expanded row already does. 28px, not
   0 -- positionSwimlaneLabels mirrors this height onto the gutter label box, and a 0-height label would
   take its own collapse/expand control down with it. Matches .kanban-icon-button/.kanban-column-action's
   own 28px, this app's usual "compact control" size. */
.kanban-swimlane-band--collapsed {
    min-height: 28px;
}

.kanban-swimlane-band--collapsed .kanban-card-list--band {
    display: none;
}

.kanban-card-list--band {
    min-height: 48px;
}

/* Its children are position: fixed and don't contribute to its size, so
   this wrapper itself renders at 0x0 -- but as a real flex child of
   #kanban-columns it would still hold one gap's worth of space before the
   first column even at zero width, pushing every column right for no
   visual reason. display: contents removes it from that flex layout
   entirely (its children's own position: fixed is unaffected either way),
   which is what actually keeps the columns from being pushed. */
.kanban-swimlane-labels {
    display: contents;
}

/* Both the colored box per line and its text are position: fixed, pinned
   flush to the literal browser window edge (left: 0, a flat constant), and
   fully placed by positionSwimlaneLabels (JS) -- including width, which is
   *not* constant: main.kanban-page's own centering inset from that edge
   grows on a wide window, so the label's width is kept equal to it every
   time, spanning the full gap with nothing left over against the column
   either. Neither is laid out by this wrapper or by normal document flow,
   which is what keeps them out of #kanban-columns' flex flow entirely (the
   columns are never pushed right) while still tracking the page's scroll. */
.kanban-swimlane-label {
    position: fixed;
    left: 0;
    z-index: 4;
    box-sizing: border-box;
    cursor: pointer;
}

/* Shared with .kanban-swimlane-mobile-tab below -- different controls for
   the same line, so they always carry the exact same tint. */
.kanban-swimlane-label,
.kanban-swimlane-mobile-tab {
    background: hsl(var(--swimlane-hue, 217) 45% 92%);
}

/* box-shadow, not filter/transform/opacity -- this box has a position: fixed child (.kanban-swimlane-
   label-text) pinned to the viewport, and any of those would make this element a new containing block for
   it instead, shifting it the moment the label is hovered. box-shadow doesn't. */
.kanban-swimlane-label:hover {
    box-shadow: inset 0 0 0 1px var(--kanban-border-strong);
}

.kanban-swimlane-label:focus-visible {
    outline: 2px solid var(--kanban-blue);
    outline-offset: -2px;
}

/* Marks which line new cards land in (see selectSwimlaneLine/placeNewCardInSelectedLine) -- a border, not
   a text or background color, since this box's own background already varies per line (the hue cycle
   below) and a solid accent bar at its edge reads clearly regardless of which hue it's drawn against,
   unlike text color did. On the right -- the seam between the gutter and the column it labels -- rather
   than the left (the page's own outer edge). box-sizing: border-box keeps the border from changing this
   element's own width (already set explicitly, in positionSwimlaneLabels) regardless of which side it's
   on -- and being position: fixed, changing it can never reflow anything else on the page either. */
.kanban-swimlane-label--selected {
    border-right: 2px solid var(--kanban-blue);
}

/* A line with a color of its own (--swimlane-color, set inline) mixes it
   into the surface rather than going through the hue formulas above, so the
   exact pick -- saturation and all -- is honored in either theme (the dark
   ratios live in kanban-dark.css). Later than the base rules so it wins. */
.kanban-swimlane-band--custom {
    background: color-mix(in srgb, var(--swimlane-color) 9%, var(--kanban-surface));
}

.kanban-swimlane-label--custom,
.kanban-swimlane-mobile-tab--custom {
    background: color-mix(in srgb, var(--swimlane-color) 18%, var(--kanban-surface));
}

/* A second, easier-to-hit pair of controls for the gutter's own two actions
   above (see .kanban-swimlane-label / .kanban-swimlane-label-text and
   renderSwimlaneLabels) -- that gutter's own width is only ever as wide as
   the page's centering inset (see the comment on .kanban-swimlane-label
   above), which can shrink to a few px on a narrow phone: too thin to read
   the line's name on, let alone tap. This floats over the board instead,
   flush with its row's own bottom border (positionSwimlaneLabels sets `top`
   only) and centered in the viewport by a static left/transform here, so it
   stays reachable regardless of how far the board itself is scrolled
   horizontally -- the same idea as .kanban-resources-tab's handle on the
   opposite edge, just attached to a row's bottom instead of the viewport's
   side, and tinted to match its own line instead of the app's neutral
   accent. Hidden outside touch/narrow widths -- the same breakpoint
   .kanban-resources-tab itself uses below for its own touch handling -- the
   gutter is plenty usable with a mouse.

   Two segments, same split as the gutter itself: kanban-swimlane-mobile-
   tab-select picks the line, kanban-swimlane-mobile-tab-toggle collapses/
   expands it and carries the line's actual name. Two separate buttons, not
   one nested in the other -- unlike the gutter's own nesting, where the
   text button is small relative to the box around it, here the text segment
   would swallow nearly all of a merged control, leaving almost nothing of
   the select action left to tap. overflow: hidden on the shared pill is
   safe here (unlike .kanban-view-group elsewhere), since neither segment
   anchors a popup that clipping would break. */
.kanban-swimlane-mobile-tab {
    display: none;
    position: fixed;
    left: 50%;
    z-index: 4;
    align-items: stretch;
    border: 1px solid var(--kanban-border-strong);
    border-bottom: none;
    border-top-left-radius: 6px;
    border-top-right-radius: 6px;
    overflow: hidden;
    transform: translateX(-50%);
}

.kanban-swimlane-mobile-tab-select,
.kanban-swimlane-mobile-tab-toggle {
    margin: 0;
    padding: 0;
    border: none;
    background: transparent;
    cursor: pointer;
}

/* 28px, not the gutter's own arbitrary rotated-text height -- this app's
   usual compact-control size (.kanban-icon-button, .kanban-swimlane-band--
   collapsed), and plenty for a thumb regardless of what the name segment's
   own content needs. */
.kanban-swimlane-mobile-tab-select {
    width: 28px;
    height: 28px;
}

.kanban-swimlane-mobile-tab-select:hover {
    box-shadow: inset 0 0 0 1px var(--kanban-border-strong);
}

.kanban-swimlane-mobile-tab-select:focus-visible,
.kanban-swimlane-mobile-tab-toggle:focus-visible {
    outline: 2px solid var(--kanban-blue);
    outline-offset: -2px;
}

/* Mirrors .kanban-swimlane-label--selected's own accent -- same line, same
   meaning -- but on the top edge (this segment's free edge, the bottom one
   being flush against its row) rather than the right. */
.kanban-swimlane-mobile-tab-select--selected {
    border-top: 2px solid var(--kanban-blue);
}

.kanban-swimlane-mobile-tab-toggle {
    display: flex;
    align-items: center;
    gap: 4px;
    height: 28px;
    padding: 0 10px;
    border-left: 1px solid var(--kanban-border-strong);
    max-width: 150px;
    color: var(--kanban-ink-soft);
    font-size: 12px;
    font-weight: 650;
}

.kanban-swimlane-mobile-tab-toggle:hover,
.kanban-swimlane-mobile-tab-toggle:focus-visible {
    color: var(--kanban-ink);
}

.kanban-swimlane-mobile-tab-arrow {
    flex: 0 0 auto;
    font-size: 14px;
    line-height: 1;
}

.kanban-swimlane-mobile-tab-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* writing-mode swaps which axis align-items/justify-content control (main
   axis becomes vertical here), and the 180deg rotation below then flips
   that axis again -- so flex-end (bottom, pre-rotation) is what lands at
   the visual top post-rotation, not flex-start. */
.kanban-swimlane-label-text {
    position: fixed;
    left: 0;
    z-index: 5;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding-bottom: 4px;
    overflow: hidden;
    writing-mode: vertical-rl;
    text-orientation: mixed;
    transform: rotate(180deg);
    color: var(--kanban-ink-soft);
    font-size: 12px;
    font-weight: 650;
    white-space: nowrap;
}

/* Ink, not the accent color (--kanban-blue*) -- that family sits behind this label's own per-line tint
   (--swimlane-hue/--swimlane-color, see applySwimlaneLineTint), which cycles through hues including red
   and pink, so a fixed accent color reads fine on some lines and badly on others. Ink is already the app's
   general-purpose "readable on whatever surface" text color (see .kanban-column-title and friends), which
   is what the plain, unhovered state above already relies on -- this just switches to its stronger, non
   -soft variant, matching .kanban-board-tab:hover's own ink-not-accent hover treatment. */
.kanban-swimlane-label-text:hover,
.kanban-swimlane-label-text:focus-visible {
    color: var(--kanban-ink);
}

.kanban-swimlane-label-text:focus-visible {
    outline: 2px solid var(--kanban-blue);
    outline-offset: -2px;
}

/* The chevron never shrinks -- it's the one part of this control guaranteed to stay visible (and legible
   as a click target) at any height, including the 28px collapsed one below, where there's rarely room
   left for any of the name. Bigger than the label's own 12px text (and line-height: 1, so that increase
   doesn't also push the box taller) so it reads clearly as its own small icon rather than just another
   character in the name. */
.kanban-swimlane-label-arrow {
    flex: 0 0 auto;
    font-size: 16px;
    line-height: 1;
}

.kanban-swimlane-label-name {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* .kanban-swimlane-label-text has no explicit height normally -- it's sized by its own (rotated) text
   content, independently of the band it's pinned over (see positionSwimlaneLabels' sticky-clamp comment).
   Collapsed, it needs one: without a bounded cross size the flex column above never actually shrinks, so
   .kanban-swimlane-label-name's overflow/ellipsis would have nothing to clip against. Matches the band's
   own 28px so the two stay the same size the person just asked for. */
.kanban-swimlane-label-text--collapsed {
    height: 28px;
}

.kanban-card {
    margin-bottom: 9px;
    border: 1px solid var(--kanban-border);
    border-radius: 9px;
    background: var(--kanban-surface);
    padding: 11px;
    box-shadow: 0 1px 2px rgba(17, 24, 39, 0.04);
    transition: box-shadow 150ms ease, border-color 150ms ease;
}

.kanban-card:hover {
    border-color: var(--kanban-border-strong);
    box-shadow: 0 4px 14px rgba(17, 24, 39, 0.10);
}

.kanban-card:last-child {
    margin-bottom: 0;
}

.kanban-card[data-available="false"] {
    border-style: dashed;
    background: #fffafa;
}

/* A card from a board merged into this view (see toggleExtraBoard) --
   dashed like [data-available="false"] above, this app's existing "not a
   normal interactive card here" cue, and no hover lift since nothing
   happens on interaction. */
.kanban-card--readonly {
    border-style: dashed;
    cursor: default;
}

.kanban-card--readonly:hover {
    border-color: var(--kanban-border);
    box-shadow: 0 1px 2px rgba(17, 24, 39, 0.04);
}

.kanban-card--done {
    opacity: 0.4;
}

/* Focus mode (kanban-focus-toggle): a picked card takes the focus color as its background and keeps its
   own color border. The focus colors are all light, so the card's text and lines are set dark for them
   here, in either theme -- the theme's own values are for a card surface, not for one of these. */
.kanban-card--focus,
.kanban-card--focus[data-available="false"] {
    --kanban-ink: #1f2937;
    --kanban-ink-soft: #374151;
    --kanban-muted: #4b5563;
    --kanban-muted-light: #6b7280;
    --kanban-soft: rgba(17, 24, 39, 0.08);
    --kanban-surface: #ffffff;
    --kanban-border: rgba(17, 24, 39, 0.16);
    --kanban-border-strong: rgba(17, 24, 39, 0.3);
    background: var(--kanban-focus);
}

.kanban-page--focus .kanban-card {
    cursor: pointer;
}

.kanban-card-topline {
    display: flex;
    align-items: flex-start;
    gap: 7px;
}

.kanban-card-list-name {
    min-width: 0;
    color: var(--kanban-muted);
    font-size: 11px;
    font-weight: 600;
    overflow-wrap: break-word;
}

.kanban-card-name {
    color: var(--kanban-ink);
    font-size: 13px;
    font-weight: 650;
    text-decoration: none;
}

.kanban-editable {
    cursor: text;
    border-radius: 4px;
}

.kanban-editable:hover {
    background: var(--kanban-soft);
}

.kanban-editable:focus-visible {
    outline: 1px solid var(--kanban-blue);
    outline-offset: 1px;
}

.kanban-editing {
    flex: 1 1 auto;
    min-width: 0;
}

.kanban-inline-edit {
    display: block;
    box-sizing: border-box;
    width: 100%;
    border: 1px solid var(--kanban-blue);
    border-radius: 4px;
    background: var(--kanban-surface);
    color: var(--kanban-ink);
    font: inherit;
    padding: 2px 6px;
}

textarea.kanban-inline-edit {
    min-height: 64px;
    overflow: hidden;
    resize: none;
}

.kanban-inline-edit:disabled {
    opacity: 0.6;
}

/* The card's real column, shown when it's sitting in a synthetic bucket (a grouped view, or the
   multi-board combined overview) instead of that column -- see cardOriginTagNeeded. Same pill language as
   .kanban-card-assignee/.kanban-card-due below, placed right under the title instead of down in the meta
   row so it reads before the description, on every card that needs it regardless of whether that card
   also has a due date or an assignee. */
.kanban-card-origin {
    display: inline-flex;
    max-width: 100%;
    margin: 2px 0 8px;
    border-radius: 999px;
    background: var(--kanban-success-soft);
    color: var(--kanban-success-ink);
    padding: 3px 9px;
    font-size: 10px;
    font-weight: 650;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

a.kanban-card-name:hover,
a.kanban-card-name:focus-visible {
    color: var(--kanban-blue);
    text-decoration: underline;
}

.kanban-card-actions {
    display: flex;
    align-items: center;
    gap: 2px;
    margin-left: auto;
}

.kanban-card-description {
    display: -webkit-box;
    margin: 6px 0 0;
    overflow: hidden;
    color: var(--kanban-muted);
    font-size: 12px;
    line-height: 1.45;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    border-radius: 4px;
}

.kanban-card-description--expanded {
    -webkit-line-clamp: unset;
    overflow: visible;
}

.kanban-card-description--empty {
    color: transparent;
    font-style: italic;
}

.kanban-card-description--empty:hover {
    color: var(--kanban-muted-light);
}

.kanban-expandable {
    cursor: pointer;
}

.kanban-expandable:hover {
    background: var(--kanban-soft);
}

.kanban-expandable:focus-visible {
    outline: 2px solid var(--kanban-blue);
    outline-offset: 1px;
}

.kanban-card-footer {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
}

.kanban-card-checklist {
    min-width: 0;
    overflow: hidden;
    color: var(--kanban-muted);
    font-size: 12px;
    font-weight: 600;
    text-decoration: none;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.kanban-card-checklist::before {
    content: '☑';
    margin-right: 6px;
}

a.kanban-card-checklist:hover,
a.kanban-card-checklist:focus-visible {
    color: var(--kanban-blue);
    text-decoration: underline;
}

/* To-do list embedded in a custom card. Reads as an extension of the
   description: same size and color, no header or box, with the remove and
   "Add item" affordances only revealed on hover/focus. */
.kanban-todos {
    margin-top: 6px;
    color: var(--kanban-muted);
    font-size: 12px;
    line-height: 1.45;
}

.kanban-todo {
    display: flex;
    align-items: flex-start;
    gap: 6px;
}

.kanban-todo-check {
    flex: 0 0 auto;
    width: 13px;
    height: 13px;
    margin: 2px 0 0;
    accent-color: var(--kanban-blue);
    cursor: pointer;
}

.kanban-todo-check:disabled {
    cursor: default;
}

.kanban-todo-text {
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: anywhere;
}

.kanban-todo--done .kanban-todo-text {
    color: var(--kanban-muted-light);
    text-decoration: line-through;
}

.kanban-todo .kanban-inline-edit {
    padding: 0 4px;
    font-size: inherit;
    line-height: inherit;
}

.kanban-todo-remove {
    flex: 0 0 auto;
    border: 0;
    background: none;
    padding: 0 3px;
    color: var(--kanban-muted-light);
    font: inherit;
    font-size: 14px;
    line-height: 1.3;
    cursor: pointer;
    opacity: 0;
}

.kanban-todo:hover .kanban-todo-remove,
.kanban-todo-remove:focus-visible {
    opacity: 1;
}

.kanban-todo-remove:hover {
    color: var(--kanban-danger);
}

.kanban-todo-add {
    display: block;
    box-sizing: border-box;
    width: 100%;
    margin: 0;
    border: 0;
    border-radius: 4px;
    background: transparent;
    padding: 0 0 0 19px;
    color: var(--kanban-ink);
    font: inherit;
    outline: none;
}

.kanban-todo-add[hidden] {
    display: none;
}

.kanban-todo-add::placeholder {
    color: transparent;
    font-style: italic;
}

.kanban-card:hover .kanban-todo-add::placeholder,
.kanban-todo-add:focus::placeholder {
    color: var(--kanban-muted-light);
}

.kanban-todo-add:focus {
    background: var(--kanban-soft);
}

.kanban-todos-toggle {
    display: block;
    border: 0;
    background: none;
    padding: 0 0 0 19px;
    color: var(--kanban-muted-light);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}

.kanban-todos-toggle[hidden] {
    display: none;
}

.kanban-todos-toggle:hover,
.kanban-todos-toggle:focus-visible {
    color: var(--kanban-blue);
}

/* No hover on touch screens, so keep the affordances (faintly) visible. */
@media (hover: none) {
    .kanban-todo-remove {
        opacity: 0.6;
    }

    .kanban-todo-add::placeholder {
        color: var(--kanban-muted-light);
    }
}

.kanban-template-list {
    height: min(320px, 45vh);
    margin-top: 14px;
}

.kanban-menu-move {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 10px;
    border-bottom: 1px solid var(--kanban-border);
    margin-bottom: 4px;
}

.kanban-menu-move-select {
    flex: 1 1 auto;
    min-width: 0;
    border: 1px solid var(--kanban-border-strong);
    border-radius: 6px;
    background: var(--kanban-surface);
    color: var(--kanban-ink);
    padding: 6px 8px;
    font: inherit;
    font-size: 13px;
    cursor: pointer;
}

.kanban-menu-move-select:disabled {
    cursor: not-allowed;
    opacity: 0.45;
}

.kanban-menu-colors {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 8px 10px;
    border-bottom: 1px solid var(--kanban-border);
    margin-bottom: 4px;
}

/* The compact swatch: the card menu's color row, and the swimlane line color
   popover (same picker, same size). */
.kanban-menu-colors .kanban-color-swatch,
.kanban-color-popover .kanban-color-swatch {
    width: 20px;
    height: 20px;
    border-radius: 6px;
}

/* The "automatic" cross is drawn for the 26px swatch; scale it to fit. */
.kanban-color-popover .kanban-color-swatch--none::before,
.kanban-color-popover .kanban-color-swatch--none::after {
    width: 13px;
}

.kanban-menu-colors .kanban-color-swatch:disabled {
    cursor: not-allowed;
    opacity: 0.45;
}

.kanban-menu-colors .kanban-color-swatch:disabled:hover {
    transform: none;
}

.kanban-checked-label,
.kanban-unavailable-label {
    flex: 0 0 auto;
    border-radius: 999px;
    padding: 3px 7px;
    font-size: 10px;
    font-weight: 650;
}

.kanban-checked-label {
    background: var(--kanban-success-soft);
    color: var(--kanban-success-ink);
}

.kanban-unavailable-label {
    background: var(--kanban-danger-soft);
    color: var(--kanban-danger-ink);
}

.kanban-card-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-top: 10px;
}

.kanban-card-created {
    min-width: 0;
    overflow: hidden;
    color: var(--kanban-muted);
    font-size: 11px;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.kanban-card-assignee {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    border-radius: 999px;
    background: var(--kanban-soft);
    color: var(--kanban-ink-soft);
    padding: 3px 9px;
    font-size: 11px;
    font-weight: 650;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.kanban-card-photos {
    flex: 0 0 auto;
    border-radius: 999px;
    background: var(--kanban-soft);
    color: var(--kanban-muted);
    padding: 3px 9px;
    font-size: 11px;
    font-weight: 650;
}

.kanban-card-due {
    flex: 0 0 auto;
    border: none;
    border-radius: 999px;
    background: var(--kanban-soft);
    color: var(--kanban-muted);
    padding: 3px 9px;
    font: inherit;
    font-size: 11px;
    font-weight: 650;
    cursor: pointer;
    appearance: none;
}

.kanban-card-due:hover {
    background: var(--kanban-border);
    color: var(--kanban-ink);
}

.kanban-card-due:disabled {
    cursor: default;
}

.kanban-card-due--overdue {
    background: var(--kanban-danger-soft);
    color: var(--kanban-danger-ink);
}

.kanban-card-due--overdue:hover {
    background: var(--kanban-danger-soft-hover);
}

.kanban-card-ghost {
    opacity: 0.35;
}

.kanban-card-chosen {
    box-shadow: 0 8px 22px rgba(17, 24, 39, 0.12);
}

.kanban-dialog {
    position: fixed;
    top: 50%;
    left: 50%;
    margin: 0;
    transform: translate(-50%, -50%);
    width: min(840px, calc(100vw - 32px));
    max-height: min(720px, calc(100vh - 32px));
    padding: 0;
    border: 1px solid var(--kanban-border);
    border-radius: 14px;
    background: var(--kanban-surface);
    color: var(--kanban-ink);
}

.kanban-dialog::backdrop {
    background: rgba(17, 24, 39, 0.35);
}

/* Same dimming a native <dialog> gets from its ::backdrop, applied behind
   the lightweight menus/panels (column, card, board, filter, people) since
   those aren't <dialog> elements and get no backdrop of their own. */
.kanban-popup-overlay {
    position: fixed;
    inset: 0;
    z-index: 15;
    background: rgba(17, 24, 39, 0.35);
}

/* A small handle pinned to the viewport's right edge, top-aligned with the
   columns row. That offset depends on the toolbar's height -- which wraps
   at narrow widths -- so it isn't a fixed value; positionResourcesPanel
   sets `top` from the columns row's own rect instead. The handle keeps the
   same position and a higher z-index than the panel, so once open it still
   sits at the panel's top-right corner and doubles as the close control. */
.kanban-resources-tab {
    position: fixed;
    right: 0;
    width: 8px;
    height: 48px;
    margin: 0;
    padding: 0;
    border: 1px solid var(--kanban-border-strong);
    border-right: none;
    border-top-left-radius: 4px;
    border-bottom-left-radius: 4px;
    background: var(--kanban-border-strong);
    cursor: pointer;
    z-index: 20;
}

.kanban-resources-tab:hover,
.kanban-resources-tab[aria-expanded="true"] {
    background: var(--kanban-blue);
    border-color: var(--kanban-blue);
}

/* A touch screen can't hover to light the handle up, and at rest it is an 8px sliver in the border colour --
   about 1.4:1 (light) to 1.8:1 (dark) against the page -- and far too thin to hit with a finger. On touch and
   narrow screens it gets a readable colour, a slightly wider pill, and an invisible extension of its hit area
   (still the same button) to the left and above/below. The extension is dropped while the panel is open: it
   would sit on top of the panel header's own buttons, and the open handle is already easy to see. */
@media (hover: none), (max-width: 820px) {
    .kanban-resources-tab {
        width: 14px;
        background: var(--kanban-muted);
        border-color: var(--kanban-muted);
    }

    .kanban-resources-tab:not([aria-expanded="true"])::before {
        content: '';
        position: absolute;
        inset: -10px 0 -10px -30px;
    }

    .kanban-swimlane-mobile-tab {
        display: flex;
    }
}

.kanban-resources-panel {
    position: fixed;
    right: 0;
    bottom: 24px;
    width: 300px;
    padding: 14px;
    background: var(--kanban-surface);
    border: 1px solid var(--kanban-border-strong);
    border-right: none;
    border-top-left-radius: 10px;
    border-bottom-left-radius: 10px;
    box-shadow: -8px 0 24px rgba(17, 24, 39, 0.10);
    overflow-y: auto;
    z-index: 18;
}

.kanban-dialog--narrow {
    width: min(360px, calc(100vw - 32px));
}

.kanban-dialog--medium {
    width: min(480px, calc(100vw - 32px));
}

.kanban-dialog-shell {
    padding: 20px;
}

.kanban-tabs {
    display: flex;
    gap: 4px;
    margin-top: 16px;
    border-bottom: 1px solid var(--kanban-border);
}

.kanban-tabs[hidden] {
    display: none;
}

.kanban-tab {
    border-radius: 8px 8px 0 0;
    padding: 9px 14px;
    color: var(--kanban-muted);
    font-size: 13px;
    font-weight: 600;
}

.kanban-tab:hover {
    background: var(--kanban-soft);
    color: var(--kanban-ink);
}

.kanban-tab[aria-selected="true"] {
    background: var(--kanban-soft);
    color: var(--kanban-ink);
}

.kanban-search-label {
    display: block;
    margin: 18px 0 6px;
    color: var(--kanban-muted);
    font-size: 12px;
    font-weight: 600;
}

.kanban-search,
.kanban-textarea {
    width: 100%;
    box-sizing: border-box;
}

.kanban-search::placeholder,
.kanban-textarea::placeholder {
    color: var(--kanban-muted-light);
    opacity: 1;
}

.kanban-textarea {
    min-height: 120px;
    border: 1px solid var(--kanban-border-strong);
    border-radius: 8px;
    background: var(--kanban-surface);
    color: var(--kanban-ink);
    padding: 9px 10px;
    font: inherit;
    resize: vertical;
}

.kanban-color-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.kanban-color-swatch {
    position: relative;
    width: 26px;
    height: 26px;
    border: 2px solid transparent;
    border-radius: 7px;
    background: var(--kanban-border-strong);
    box-shadow: inset 0 0 0 1px rgba(17, 24, 39, 0.08);
    cursor: pointer;
    padding: 0;
}

.kanban-color-swatch:hover {
    transform: scale(1.08);
}

.kanban-color-swatch[aria-checked="true"],
.kanban-color-swatch[aria-pressed="true"] {
    border-color: var(--kanban-ink);
}

.kanban-color-swatch--none {
    background: var(--kanban-surface);
}

.kanban-color-swatch--none::before,
.kanban-color-swatch--none::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 18px;
    height: 2px;
    background: var(--kanban-border-strong);
    transform: translate(-50%, -50%) rotate(45deg);
}

.kanban-color-swatch--none::after {
    transform: translate(-50%, -50%) rotate(-45deg);
}

.kanban-projects-results {
    margin-top: 14px;
    max-height: min(360px, 55vh);
}

.kanban-projects-result {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}

.kanban-picker-items {
    overflow-y: auto;
    border: 1px solid var(--kanban-border);
    border-radius: 10px;
}

.kanban-picker-list {
    display: block;
    width: 100%;
    border-bottom: 1px solid var(--kanban-border);
    padding: 11px 12px;
    text-align: left;
}

.kanban-picker-list:last-child {
    border-bottom: 0;
}

.kanban-picker-list[aria-selected="true"] {
    background: var(--kanban-blue-soft);
    color: var(--kanban-blue-dark);
    font-weight: 650;
}

.kanban-picker-item {
    display: grid;
    grid-template-columns: 20px 1fr;
    gap: 10px;
    padding: 12px;
    border-bottom: 1px solid var(--kanban-border);
    cursor: pointer;
}

.kanban-picker-item:last-child {
    border-bottom: 0;
}

.kanban-picker-item input {
    width: 17px;
    height: 17px;
    margin-top: 2px;
}

.kanban-picker-item strong,
.kanban-picker-item span {
    display: block;
}

.kanban-picker-item strong {
    font-size: 13px;
}

.kanban-picker-item span {
    margin-top: 3px;
    color: var(--kanban-muted);
    font-size: 12px;
    line-height: 1.4;
}

.kanban-picker-placeholder {
    padding: 24px;
    color: var(--kanban-muted);
    text-align: center;
}

/* The Add card dialog's From template tab. Each row is one saved card
   template: its left side adds a card from it, the small rename/delete
   actions (shared with the people rows) sit on the right. */
.kanban-card-template-list {
    max-height: min(320px, 45vh);
    margin-top: 14px;
}

.kanban-card-template {
    display: flex;
    align-items: center;
    gap: 6px;
    padding-right: 10px;
    border-bottom: 1px solid var(--kanban-border);
}

.kanban-card-template:last-child {
    border-bottom: 0;
}

.kanban-card-template:hover {
    background: var(--kanban-soft);
}

.kanban-card-template-use {
    appearance: none;
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    border: 0;
    background: none;
    padding: 12px 0 12px 12px;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.kanban-card-template-use:focus-visible {
    outline: 2px solid var(--kanban-blue);
    outline-offset: -2px;
}

.kanban-card-template-dot {
    flex: 0 0 auto;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--kanban-border-strong);
}

.kanban-card-template-text {
    min-width: 0;
}

.kanban-card-template-text strong,
.kanban-card-template-text span {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.kanban-card-template-text strong {
    font-size: 13px;
}

.kanban-card-template-text span {
    margin-top: 3px;
    color: var(--kanban-muted);
    font-size: 12px;
}

.kanban-history-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-top: 16px;
    max-height: 60vh;
    overflow-y: auto;
}

.kanban-history-entry {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 12px;
    border: 1px solid var(--kanban-border);
    border-radius: 8px;
    background: var(--kanban-soft);
}

.kanban-history-when {
    color: var(--kanban-muted);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

.kanban-history-message {
    color: var(--kanban-ink);
    font-size: 13px;
}

.kanban-history-diffs {
    margin: 4px 0 0;
    padding-left: 18px;
    color: var(--kanban-muted);
    font-size: 12px;
}

.kanban-history-diffs li {
    margin-top: 2px;
}

.kanban-toggle {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--kanban-muted);
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    user-select: none;
}

.kanban-toggle[hidden] {
    display: none;
}

.kanban-toggle input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
}

.kanban-toggle-track {
    position: relative;
    flex: 0 0 auto;
    width: 34px;
    height: 20px;
    border-radius: 999px;
    background: var(--kanban-border-strong);
    transition: background 0.15s ease;
}

.kanban-toggle-track::after {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--kanban-surface);
    box-shadow: 0 1px 2px rgba(17, 24, 39, 0.25);
    transition: transform 0.15s ease;
}

.kanban-toggle input:checked ~ .kanban-toggle-track {
    background: var(--kanban-blue);
}

.kanban-toggle input:checked ~ .kanban-toggle-track::after {
    transform: translateX(14px);
}

.kanban-toggle:has(input:disabled) {
    opacity: 0.5;
    cursor: default;
}

.kanban-toggle input:focus-visible ~ .kanban-toggle-track {
    outline: 2px solid var(--kanban-blue);
    outline-offset: 2px;
}

.kanban-dialog-footer {
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid var(--kanban-border);
    color: var(--kanban-muted);
    font-size: 12px;
}

/* A segmented pill: one shared border/background around the whole group
   instead of tinting each button, so the group reads clearly regardless of
   theme or state. No overflow: hidden here -- People/Filter's segments wrap
   their trigger in a position:relative .kanban-filter-wrap so their dropdown
   panel can anchor to it, and clipping the group would clip that panel too
   (it did: the popups still opened, just invisibly). The end segments are
   rounded directly instead, below. The border-reset + divider rules (after
   the hover/pressed block, so they win the specificity tie on border-color)
   turn off each button's individual border in favor of a single hairline
   between segments. */
.kanban-view-group {
    display: flex;
    align-items: center;
    border: 1px solid var(--kanban-border-strong);
    border-radius: 8px;
}

.kanban-view-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 1px solid var(--kanban-border-strong);
    border-radius: 8px;
    background: var(--kanban-surface);
    color: var(--kanban-muted);
    appearance: none;
    padding: 0;
    cursor: pointer;
}

/* An author rule's `display` always beats the UA stylesheet's `[hidden] { display: none }`, even at equal
   specificity (see the .kanban-view-group[hidden] note below, which needs the same override for the same
   reason) -- so every board-only toggle setProjectChromeHidden hides in project view (sortByDueDate,
   viewCalendar, viewColor, organizeWorkflow, organizeSwimlane, hideCompleted, plus focus's own
   workspace-closed case -- collapseColumns stays shown there, see setProjectChromeHidden) needs this
   spelled out, or it stays fully visible and clickable with just its `hidden` attribute set and nothing
   actually hidden. */
.kanban-view-toggle[hidden] {
    display: none;
}

.kanban-view-toggle:hover {
    background: var(--kanban-soft);
    color: var(--kanban-ink);
}

.kanban-view-toggle[aria-pressed="true"],
.kanban-view-toggle[aria-expanded="true"] {
    border-color: var(--kanban-blue);
    background: var(--kanban-blue-soft);
    color: var(--kanban-blue-dark);
}

/* People and search stand apart from the rest of the toolbar's neutral
   icons, using the same accent color the pressed/expanded state already
   uses elsewhere rather than a new one-off hue. */
.kanban-view-toggle--accent {
    color: var(--kanban-blue);
}

.kanban-view-toggle--accent:hover {
    background: var(--kanban-blue-soft);
    color: var(--kanban-blue-dark);
}

/* Focus mode's own button: in the focus color while on, matching the cards it picks. Held down it opens
   the color chooser, so the browser's own long-press behavior (text selection, callout) stays out of the
   way. */
.kanban-view-toggle--focus {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
    touch-action: manipulation;
}

.kanban-view-toggle--focus[aria-pressed="true"] {
    border-color: rgba(17, 24, 39, 0.35);
    background: var(--kanban-focus);
    color: #1f2937;
}

.kanban-view-group .kanban-view-toggle {
    border: none;
    border-radius: 0;
}

/* Round the two end segments to match the group's own border-radius, the
   same "group vs. actual flex item" child-combinator reasoning as the
   divider below: whichever element is first/last -- a bare button or a
   .kanban-filter-wrap around one -- gets rounded, and if that's a wrap, the
   button inside it picks up the same rounding via the second selector. */
.kanban-view-group > :first-child,
.kanban-view-group > :first-child .kanban-view-toggle {
    border-top-left-radius: 7px;
    border-bottom-left-radius: 7px;
}

.kanban-view-group > :last-child,
.kanban-view-group > :last-child .kanban-view-toggle {
    border-top-right-radius: 7px;
    border-bottom-right-radius: 7px;
}

/* Project view hides Hide-completed (setProjectChromeHidden) but not Focus -- focus mode also works
   there, on the project's own item cards -- so :last-child above, which only looks at DOM position and
   not [hidden], leaves Focus's right edge square while it's the only segment actually showing. Give it
   the last-child rounding too whenever that's the case. */
.kanban-view-group > #kanban-focus-toggle:has(+ #kanban-hide-completed[hidden]) {
    border-top-right-radius: 7px;
    border-bottom-right-radius: 7px;
}

/* On the divider, the child combinator (not descendant) so a segment that's
   a bare button -- and one wrapped, like a filter trigger, in its own
   position:relative .kanban-filter-wrap for its dropdown panel -- both get
   exactly one hairline, on the group's actual flex item rather than
   reaching into a wrap for the button inside it. */
.kanban-view-group > :not(:first-child) {
    border-left: 1px solid var(--kanban-border-strong);
}

.kanban-view-toggle:disabled {
    cursor: not-allowed;
    opacity: 0.45;
}

.kanban-view-icon {
    width: 16px;
    height: 16px;
}

.kanban-theme-icon {
    width: 16px;
    height: 16px;
}

.kanban-theme-icon--sun {
    display: none;
}

.kanban-theme-icon--moon {
    display: block;
}

/* Three-state "hide completed" toggle (all / hide completed / only
   completed) -- one icon per mode, swapped by the data-mode attribute
   syncHideCompletedButton keeps in sync with state.completedFilter. */
.kanban-completed-icon {
    display: none;
}

#kanban-hide-completed[data-mode="all"] .kanban-completed-icon--all,
#kanban-hide-completed[data-mode="hide"] .kanban-completed-icon--hide,
#kanban-hide-completed[data-mode="only"] .kanban-completed-icon--only {
    display: block;
}

.kanban-filter-wrap {
    position: relative;
    display: inline-flex;
}

/* Same fix, same reason as .kanban-view-toggle[hidden] above: this wrap's own `display` is an author rule
   tying (and beating, on source order) the UA stylesheet's `[hidden] { display: none }`, so setting
   `hidden` on #kanban-people-wrap/#kanban-filter-wrap in project view (setProjectChromeHidden) left both
   fully visible and clickable without this. */
.kanban-filter-wrap[hidden] {
    display: none;
}

.kanban-filter-badge {
    position: absolute;
    top: -2px;
    right: -2px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--kanban-blue);
    border: 2px solid var(--kanban-surface);
}

.kanban-filter-badge[hidden] {
    display: none;
}

.kanban-filter-panel {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 20;
    width: 260px;
    padding: 14px;
    border: 1px solid var(--kanban-border);
    border-radius: 10px;
    background: var(--kanban-surface);
    box-shadow: 0 10px 24px rgba(17, 24, 39, 0.14);
}

.kanban-filter-panel[hidden] {
    display: none;
}

.kanban-filter-panel .kanban-search-label:first-child {
    margin-top: 0;
}

.kanban-filter-date-range {
    display: flex;
    align-items: center;
    gap: 6px;
}

.kanban-filter-date-range input[type="date"] {
    flex: 1 1 0;
    min-width: 0;
    border: 1px solid var(--kanban-border-strong);
    border-radius: 8px;
    background: var(--kanban-surface);
    color: var(--kanban-ink);
    padding: 6px 8px;
    font: inherit;
    font-size: 12px;
}

.kanban-filter-date-range span {
    color: var(--kanban-muted-light);
}

.kanban-filter-clear {
    width: 100%;
    margin-top: 16px;
}

/* The tabs in the resources panel's People view sit right under its heading. */
.kanban-resources-panel .kanban-tabs {
    margin-top: 0;
}

.kanban-people-group-btn {
    width: 100%;
    margin: 10px 0;
    justify-content: center;
}

.kanban-people-group-btn[aria-pressed="true"] {
    border-color: var(--kanban-blue);
    background: var(--kanban-blue-soft);
    color: var(--kanban-blue-dark);
}

.kanban-people-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.kanban-people-empty {
    margin: 4px 0;
    color: var(--kanban-muted);
    font-size: 12px;
}

.kanban-people-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    padding: 4px 2px;
    border-radius: 6px;
}

.kanban-people-row:hover {
    background: var(--kanban-soft);
}

.kanban-people-row-label {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    font-size: 13px;
    cursor: pointer;
}

.kanban-people-row-label span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.kanban-people-row-actions {
    flex: 0 0 auto;
    display: flex;
    gap: 2px;
}

.kanban-people-row-action {
    appearance: none;
    border: none;
    border-radius: 4px;
    background: none;
    color: var(--kanban-muted);
    width: 20px;
    height: 20px;
    font-size: 12px;
    line-height: 1;
    cursor: pointer;
}

.kanban-people-row-action:hover {
    background: var(--kanban-border);
    color: var(--kanban-ink);
}

.kanban-people-row-action--danger:hover {
    background: var(--kanban-danger-soft);
    color: var(--kanban-danger);
}

.kanban-resources-heading {
    margin: 0 0 10px;
    color: var(--kanban-ink);
    font-size: 13px;
    font-weight: 650;
}

/* A panel heading with an add action pinned to its right edge. The button's
   negative margins keep the row as short as the bare heading, so the title
   sits where it does in a panel without one, and pull the plus in line with
   the row × buttons below it. */
.kanban-resources-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin: 0 0 10px;
}

.kanban-resources-header .kanban-resources-heading {
    margin: 0;
}

.kanban-resources-header .kanban-icon-button {
    flex: 0 0 auto;
    margin: -6px -2px -6px 0;
    font-size: 18px;
}

.kanban-swimlane-row {
    padding: 4px 0;
}

/* The color chip on a swimlane line's row: a small square showing the line's
   color that opens the popover below. */
.kanban-color-chip {
    flex: 0 0 auto;
    width: 14px;
    height: 14px;
    padding: 0;
    border: 1px solid var(--kanban-border-strong);
    border-radius: 3px;
    background: var(--kanban-border-strong);
    cursor: pointer;
}

.kanban-color-chip:disabled {
    cursor: default;
}

.kanban-color-chip:focus-visible {
    outline: 2px solid var(--kanban-blue);
    outline-offset: 1px;
}

/* Reuses .kanban-color-row / .kanban-color-swatch (the card color picker's
   own). Fixed, placed by openColorPopover, so the resources panel's
   scrolling can't clip it. */
.kanban-color-popover {
    position: fixed;
    z-index: 22;
    gap: 6px;
    padding: 8px 10px;
    border: 1px solid var(--kanban-border);
    border-radius: 10px;
    background: var(--kanban-surface);
    box-shadow: 0 10px 24px rgba(17, 24, 39, 0.14);
}

/* The "custom" swatch: an eyedropper on a neutral swatch, so it reads as
   "pick your own", and stays that way once a non-preset color is chosen --
   its own color then fills the swatch (inline) and the eyedropper's color
   flips for contrast (see openColorPopover). It also hosts the native color
   input, invisible, purely so the system picker opens anchored to it. */
.kanban-color-swatch--custom {
    color: var(--kanban-ink);
}

.kanban-color-swatch--custom::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 12px;
    height: 12px;
    transform: translate(-50%, -50%);
    background-color: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M20.71 5.63l-2.34-2.34a.9959.9959 0 0 0-1.41 0l-3.12 3.12-1.93-1.91-1.41 1.41 1.42 1.42L3 16.25V21h4.75l8.92-8.92 1.42 1.42 1.41-1.41-1.92-1.92 3.12-3.12c.4-.4.4-1.03.01-1.42zM6.92 19L5 17.08l8.06-8.06 1.92 1.92L6.92 19z'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M20.71 5.63l-2.34-2.34a.9959.9959 0 0 0-1.41 0l-3.12 3.12-1.93-1.91-1.41 1.41 1.42 1.42L3 16.25V21h4.75l8.92-8.92 1.42 1.42 1.41-1.41-1.92-1.92 3.12-3.12c.4-.4.4-1.03.01-1.42zM6.92 19L5 17.08l8.06-8.06 1.92 1.92L6.92 19z'/%3E%3C/svg%3E") center / contain no-repeat;
    pointer-events: none;
}

.kanban-color-native {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    padding: 0;
    border: none;
    opacity: 0;
    pointer-events: none;
}

.kanban-swimlane-lines-list {
    margin: 6px 0 0 22px;
    border-left: 1px solid var(--kanban-border);
    padding-left: 8px;
}

.kanban-workflow-rule-label {
    flex: 0 0 auto;
    font-size: 13px;
    color: var(--kanban-ink);
}

.kanban-workflow-rules-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    margin-top: 6px;
    padding: 6px 2px 2px;
    border-top: 1px solid var(--kanban-border);
    color: var(--kanban-muted);
    font-size: 11px;
    font-weight: 650;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.kanban-undo-toast {
    position: fixed;
    left: 50%;
    bottom: 28px;
    transform: translateX(-50%);
    z-index: 40;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 16px;
    border-radius: 10px;
    background: var(--kanban-ink);
    color: var(--kanban-surface);
    box-shadow: 0 10px 24px rgba(17, 24, 39, 0.25);
    font-size: 13px;
}

.kanban-undo-toast[hidden] {
    display: none;
}

.kanban-undo-button {
    appearance: none;
    border: none;
    border-radius: 4px;
    background: none;
    color: var(--kanban-surface);
    font: inherit;
    font-weight: 700;
    padding: 2px 4px;
    cursor: pointer;
    text-decoration: underline;
}

.kanban-undo-button:hover {
    background: rgba(255, 255, 255, 0.14);
}

.kanban-undo-button:focus-visible {
    outline: 2px solid var(--kanban-surface);
    outline-offset: 2px;
}

@media (max-width: 820px) {
    main.kanban-page {
        width: calc(100vw - 20px);
        padding-top: 44px;
    }

    .kanban-toolbar,
    .kanban-board-nav {
        align-items: flex-start;
        flex-direction: column;
    }

    /* One line, always: the icon buttons never drop to a second row. The workspace name gives up width
       first (it truncates), then, only if that's not enough, the "Workspace:" label. */
    .kanban-project-controls {
        width: 100%;
        flex-wrap: nowrap;
    }

    .kanban-project-controls select {
        flex: 1 1 0;
        min-width: 0;
        text-overflow: ellipsis;
    }

    .kanban-project-controls .kanban-menu-wrap {
        min-width: 0;
    }

    .kanban-workspace-trigger {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .kanban-project-actions {
        flex: 0 0 auto;
    }

    .kanban-board-nav,
    .kanban-board-tabs-wrap,
    .kanban-board-tabs {
        width: 100%;
    }

    .kanban-column {
        flex-basis: min(84vw, 292px);
        width: min(84vw, 292px);
    }

    .kanban-column--collapsed {
        flex-basis: 40px;
        width: 40px;
    }

    .kanban-dialog-footer {
        align-items: flex-start;
        flex-direction: column;
    }
}

/* Phone widths: the toolbar's separate button groups plus its two standalone
   buttons (collapse columns, add column) stop reading as one row -- the lone
   "+" ends up stranded far right of everything else. Fold every top-level
   piece into a single bordered pill instead, mirroring .kanban-view-group's
   own look above (reset each piece's own border/radius, add one hairline
   divider between pieces, round only the merged pill's true outer edges),
   and center that pill in the row. */
@media (max-width: 640px) {
    .kanban-board-actions {
        flex-wrap: wrap;
        justify-content: center;
        width: 100%;
        gap: 8px 0;
        border: 1px solid var(--kanban-border-strong);
        border-radius: 8px;
    }

    .kanban-board-actions .kanban-view-group,
    .kanban-board-actions > .kanban-view-toggle {
        border: none;
        border-radius: 0;
    }

    /* Undo each group's own end-rounding (desktop rule above) -- those ends
       are now interior seams, not the merged pill's actual edges. */
    .kanban-board-actions .kanban-view-group > :first-child,
    .kanban-board-actions .kanban-view-group > :first-child .kanban-view-toggle,
    .kanban-board-actions .kanban-view-group > :last-child,
    .kanban-board-actions .kanban-view-group > :last-child .kanban-view-toggle {
        border-radius: 0;
    }

    /* One hairline between every top-level piece -- the piece itself gets the
       border, whether it's a bare button or a group div. */
    .kanban-board-actions > :not(:first-child) {
        border-left: 1px solid var(--kanban-border-strong);
    }

    /* Round only the merged pill's true outer edges. */
    .kanban-board-actions > .kanban-view-toggle:first-child,
    .kanban-board-actions > .kanban-view-group:first-child > :first-child,
    .kanban-board-actions > .kanban-view-group:first-child > :first-child .kanban-view-toggle {
        border-top-left-radius: 7px;
        border-bottom-left-radius: 7px;
    }

    .kanban-board-actions > .kanban-view-toggle:last-child,
    .kanban-board-actions > .kanban-view-group:last-child > :last-child,
    .kanban-board-actions > .kanban-view-group:last-child > :last-child .kanban-view-toggle {
        border-top-right-radius: 7px;
        border-bottom-right-radius: 7px;
    }
}
