/* Copyright ExaOps Pty Ltd 2026. All rights reserved. */

/* The roadmap canvas. Geometry is set inline from pxPerDay by the component; this file carries
   only what does not depend on the scale. */

/* Labels beside the canvas, not on top of it.
 *
 * The first draft rendered each lane's label inside the lane as a sticky inline block. At Sprint
 * zoom that looked fine because the bars happened to start further right; at Quarter zoom, where a
 * day is 1.4px, every bar lands under the label and the label — having a background and a z-index —
 * paints straight over them. A Gantt needs a gutter, so this is one. */
.exa-gantt-wrap {
    display: flex;
    align-items: flex-start;
    width: 100%;
}

.exa-gantt-gutter {
    flex: 0 0 auto;
    width: 190px;
    border-right: 1px solid var(--mud-palette-lines-default);
}

.exa-gantt-gutter-spacer {
    height: 32px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

.exa-gantt-gutter-label {
    height: 44px;
    line-height: 44px;
    padding: 0 8px;
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--mud-palette-text-primary);
    border-bottom: 1px solid var(--mud-palette-lines-default);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.exa-gantt-root {
    position: relative;
    flex: 1 1 auto;
    min-width: 0;
    overflow-x: auto;
    overflow-y: hidden;
    user-select: none;

    /* Without this the browser claims horizontal drags for its own scrolling on touch and the
       gesture never reaches pointermove. */
    touch-action: pan-y;
}

.exa-gantt-ruler {
    position: relative;
    height: 32px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
    white-space: nowrap;
}

.exa-gantt-tick {
    position: absolute;
    top: 0;
    bottom: 0;
    border-left: 1px solid var(--mud-palette-lines-default);
    padding-left: 4px;
    font-size: 0.72rem;
    color: var(--mud-palette-text-secondary);
    pointer-events: none;
}

/* A sprint boundary is the thing bars snap to, so it is drawn more strongly than a date tick. */
.exa-gantt-tick-sprint {
    border-left-style: solid;
    border-left-color: var(--mud-palette-primary);
    opacity: 0.55;
}

/* Sprint boundaries, faint, behind everything. Bars snap to these, so showing them is what
   makes the snap legible rather than mysterious. */
.exa-gantt-sprintline {
    position: absolute;
    top: 0;
    width: 1px;
    background: var(--mud-palette-lines-default);
    opacity: 0.5;
    pointer-events: none;
    z-index: 0;
}

.exa-gantt-today {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 2px;
    background: var(--mud-palette-error);
    opacity: 0.7;
    pointer-events: none;
    z-index: 3;
}

.exa-gantt-lane {
    position: relative;
    height: 44px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

/* Bars sit above the lane background but below the milestone diamonds and the link overlay. */
.exa-gantt-bar { z-index: 1; }

.exa-gantt-bar {
    position: absolute;
    top: 8px;
    height: 26px;
    border-radius: 4px;
    padding: 0 8px;
    font-size: 0.78rem;
    line-height: 26px;
    color: #fff;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    cursor: grab;

    /* The drag writes transform, never left, so nothing here may transition transform - a
       transition would lag the cursor by its own duration on every frame. */
    transition: box-shadow 120ms ease;
}

.exa-gantt-bar:hover {
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}

/* The grab zone at each end, matching handleWidth() in gantt.js — the two must agree or the
   cursor promises a resize the code then treats as a move, or worse the reverse.
 *
 * min(8px, 33%) rather than a flat 8px: on a 12px bar two 8px handles cover the whole thing, so
 * the cursor said "resize" everywhere and there was no middle to move by. A third each end always
 * leaves a third in the middle. */
.exa-gantt-bar::before,
.exa-gantt-bar::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    width: min(8px, 33%);
    cursor: ew-resize;
}

.exa-gantt-bar::before { left: 0; }
.exa-gantt-bar::after { right: 0; }

.exa-gantt-bar[data-gantt-readonly="true"] {
    cursor: default;
    opacity: 0.62;

    /* A portfolio release seen from inside one project. Hatched so it reads as "not yours to
       move" before the user tries and finds nothing happens. */
    background-image: repeating-linear-gradient(
        45deg,
        rgba(255, 255, 255, 0.18) 0 6px,
        transparent 6px 12px
    );
}

.exa-gantt-bar[data-gantt-readonly="true"]::before,
.exa-gantt-bar[data-gantt-readonly="true"]::after {
    cursor: default;
}

.exa-gantt-dragging {
    cursor: grabbing;
    opacity: 0.85;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
    z-index: 5;
}

.exa-gantt-active {
    cursor: grabbing;
}

/* Milestones sit on the ruler as diamonds. */
.exa-gantt-milestone {
    position: absolute;
    top: 8px;
    width: 14px;
    height: 14px;
    transform: rotate(45deg);
    background: var(--mud-palette-secondary);
    border: 1px solid var(--mud-palette-surface);
    cursor: grab;
    z-index: 4;
}

.exa-gantt-milestone-risk {
    background: var(--mud-palette-warning);
}

.exa-gantt-milestone-external {
    background: var(--mud-palette-info);
}

/* The rubber band drawn when dragging across empty lane background. */
.exa-gantt-draw {
    position: absolute;
    top: 0;
    bottom: 0;
    background: var(--mud-palette-primary);
    opacity: 0.22;
    pointer-events: none;
    z-index: 1;
}

/* Dependency arrows (Phase 5) draw into this overlay, in the same coordinate space as the bars. */
.exa-gantt-links {
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 3;
}

.exa-gantt-link {
    stroke: var(--mud-palette-text-secondary);
    stroke-width: 1.5;
    fill: none;
    opacity: 0.75;
}

/* A dependency pointing backwards in time - the blocker finishing after the thing it blocks.
   Coloured, never auto-resolved: one drag silently relaying forty bars is what makes people
   distrust Gantt tools. */
.exa-gantt-link-backwards {
    stroke: var(--mud-palette-error);
    stroke-dasharray: 4 3;
    opacity: 1;
}

/* ---------------------------------------------------------------------------
 * The people grid: rows are people, columns are time blocks.
 *
 * A table rather than flex, because the thing being read is a grid — a person's
 * row across, a block's column down — and a table gives that alignment for free
 * and keeps it when a cell grows to hold four cards.
 * ------------------------------------------------------------------------- */

.exa-people-grid {
    overflow-x: auto;
}

.exa-people-table {
    width: 100%;
    border-collapse: collapse;
}

.exa-people-table th,
.exa-people-table td {
    border: 1px solid var(--mud-palette-lines-default);
    vertical-align: top;
    padding: 6px;
}

.exa-people-table th {
    text-align: left;
    background: var(--mud-palette-background-grey);
}

.exa-people-block-name {
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--mud-palette-text-primary);
}

.exa-people-block-dates {
    font-size: 0.7rem;
    color: var(--mud-palette-text-secondary);
}

/* Sticky so a wide plan can be scrolled sideways without losing whose row it is. */
.exa-people-name {
    position: sticky;
    left: 0;
    z-index: 2;
    min-width: 150px;
    max-width: 150px;
    background: var(--mud-palette-surface);
}

.exa-people-cell {
    min-width: 190px;
}

/* Over capacity. Tinted rather than bordered so it reads at a glance down a column,
   which is how somebody scans for who is drowning. */
.exa-people-over {
    background: rgba(244, 67, 54, 0.10);
}

/* The drop target has to keep a height when empty, or a cell with no cards is a
   1px line nobody can drop onto. */
.exa-people-zone {
    min-height: 46px;
}

.exa-people-load {
    margin-top: 4px;
}

.exa-people-card {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 4px;
    padding: 4px 6px;
    border-radius: 4px;
    background: var(--mud-palette-background-grey);
    border-left: 3px solid var(--mud-palette-primary);
    font-size: 0.75rem;
    cursor: grab;
}

.exa-people-card:hover {
    background: var(--mud-palette-action-default-hover);
}

.exa-people-card-num {
    color: var(--mud-palette-text-secondary);
    flex: 0 0 auto;
}

.exa-people-card-title {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The estimate is the reason the grid exists, so it never truncates. */
.exa-people-card-effort {
    flex: 0 0 auto;
    font-weight: 500;
    color: var(--mud-palette-text-primary);
}
