/* ==========================================================================
   ParticleLabeler - labeling workspace

   The screen lives inside the normal application shell: same brand bar, same
   navigation column, same controls. Only the stage keeps a dark ground, and
   for a reason rather than a mood - microscopy frames are dark and low in
   contrast, and a bright surface around them measurably degrades how well
   faint particles can be judged.
   ========================================================================== */

/* The workspace is the one page that fills the viewport instead of flowing.
   Selecting on the shell rather than a route keeps the rule where the layout
   decision actually is. */
.app-shell:has(.workspace-shell) { height: 100vh; }
.app-main:has(> .workspace-shell) {
    max-width: none;
    min-height: 0;
    padding: 0;
    gap: 0;
    overflow: hidden;
}

.workspace-shell {
    display: grid;
    grid-template-columns: minmax(0, 1fr) var(--workspace-aside, 320px);
    grid-template-rows: auto auto minmax(0, 1fr);
    grid-template-areas:
        "header  header"
        "toolbar toolbar"
        "stage   aside";
    height: 100%;
    min-height: 0;
    background: var(--surface-canvas);
    overflow: hidden;
}
.workspace-shell.is-aside-hidden { grid-template-columns: minmax(0, 1fr) 0; }
.workspace-shell.is-aside-hidden .workspace-aside { display: none; }

/* --------------------------------------------------------------------------
   Header - what am I working on, how far along, and the way out
   -------------------------------------------------------------------------- */
.workspace-header {
    grid-area: header;
    display: flex;
    align-items: center;
    gap: var(--space-5);
    padding: var(--space-3) var(--space-5);
    background: var(--surface-raised);
    border-bottom: 1px solid var(--border-subtle);
}
.workspace-header .spacer { flex: 1; }

.workspace-identity { display: flex; flex-direction: column; min-width: 0; }
.workspace-identity strong {
    font-size: var(--text-lg);
    font-weight: var(--weight-semibold);
    color: var(--text-strong);
    font-variant-numeric: tabular-nums;
    letter-spacing: -.01em;
    line-height: 1.15;
}
.workspace-identity span {
    font-size: var(--text-xs);
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.workspace-progress { display: flex; flex-direction: column; gap: var(--space-1); min-width: 200px; max-width: 300px; }
.workspace-progress-label {
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
    font-size: var(--text-xs);
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.workspace-submit {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-5);
    min-height: 38px;
    border: 0;
    border-radius: var(--radius-md);
    background: var(--success-500);
    color: #fff;
    font: inherit;
    font-size: var(--text-base);
    font-weight: var(--weight-semibold);
    white-space: nowrap;
    cursor: pointer;
    box-shadow: var(--shadow-sm);
    transition: background var(--duration-fast) var(--ease-out), transform var(--duration-fast) var(--ease-out);
}
.workspace-submit:hover:not(:disabled) { background: var(--success-600); }
.workspace-submit:active:not(:disabled) { transform: translateY(1px); }
.workspace-submit:disabled { opacity: .45; cursor: not-allowed; }
.workspace-submit svg { width: 17px; height: 17px; stroke: currentColor; fill: none; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.workspace-submit kbd { background: rgba(0, 0, 0, .22); border: 0; color: inherit; }

/* --------------------------------------------------------------------------
   Toolbar - what the pointer does and how the frame is shown
   -------------------------------------------------------------------------- */
/* The shared viewer toolbar sits in the toolbar row of the workspace grid. */
.workspace-shell > .viewer-toolbar { grid-area: toolbar; }

.workspace-toolgroup {
    display: flex;
    align-items: center;
    gap: 2px;
    padding: 3px;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    background: var(--surface-raised);
}
.workspace-tool {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-3);
    min-height: 28px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: none;
    color: var(--text-muted);
    font: inherit;
    font-size: var(--text-xs);
    font-weight: var(--weight-medium);
    white-space: nowrap;
    cursor: pointer;
    transition: background var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}
.workspace-tool:hover:not(:disabled) { background: var(--surface-hover); color: var(--text-default); }
.workspace-tool.is-active { background: var(--pm-navy-800); color: #fff; }

/* The position through the doubtful centres counts upwards while the button stays put.
   Proportional digits would make the label breathe in and out at every step. */
.workspace-tool .tabular { font-variant-numeric: tabular-nums; }
.workspace-tool:disabled { opacity: .4; cursor: not-allowed; }
.workspace-tool svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/* A tool that stands on its own carries the border its group would have given it. */
.workspace-tool.is-standalone {
    border-color: var(--border-default);
    background: var(--surface-raised);
    min-height: 34px;
}
.workspace-tool.is-standalone:hover { background: var(--surface-hover); border-color: var(--border-strong); }

/* --------------------------------------------------------------------------
   Stage - the only dark surface on the screen
   -------------------------------------------------------------------------- */
.workspace-stage {
    grid-area: stage;
    position: relative;
    min-height: 0;
    overflow: hidden;
    background: var(--surface-canvas);
    cursor: crosshair;
    touch-action: none;
}
.workspace-stage.is-panning { cursor: grabbing; }
.workspace-stage.is-dragging-point { cursor: grabbing; }
.workspace-stage.is-over-point { cursor: pointer; }
.workspace-stage.is-erasing { cursor: cell; }
.workspace-stage canvas { position: absolute; inset: 0; width: 100%; height: 100%; }

.workspace-hud {
    position: absolute;
    left: var(--space-4);
    bottom: var(--space-4);
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--surface-raised) 84%, transparent);
    backdrop-filter: blur(8px);
    font-size: var(--text-xs);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
    pointer-events: none;
}
.workspace-hud strong { color: var(--text-strong); font-weight: var(--weight-semibold); }
.workspace-hud .hud-divider { width: 1px; height: 14px; background: var(--border-default); }
.workspace-hud .hud-state.is-dirty { color: var(--warning-600); }
.workspace-hud .hud-state.is-saved { color: var(--success-600); }


.workspace-loading {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    background: var(--surface-canvas);
    color: var(--text-muted);
    font-size: var(--text-sm);
    gap: var(--space-3);
}
.workspace-spinner {
    width: 30px; height: 30px;
    border: 2.5px solid var(--border-default);
    border-top-color: var(--pm-orange-500);
    border-radius: 50%;
    animation: workspace-spin .8s linear infinite;
}
@keyframes workspace-spin { to { transform: rotate(360deg); } }

/* Magnifier follows the pointer while L is held. */
.workspace-magnifier {
    position: absolute;
    width: 190px; height: 190px;
    margin: -95px 0 0 -95px;
    border: 2px solid var(--marker-selected);
    border-radius: 50%;
    box-shadow: var(--shadow-lg), inset 0 0 0 1px rgba(0, 0, 0, .5);
    pointer-events: none;
    opacity: 0;
    overflow: hidden;
    transition: opacity var(--duration-fast) var(--ease-out);
}
.workspace-magnifier.is-visible { opacity: 1; }
.workspace-magnifier canvas { position: absolute; inset: 0; width: 100%; height: 100%; }

/* --------------------------------------------------------------------------
   Side column
   -------------------------------------------------------------------------- */
.workspace-aside {
    grid-area: aside;
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    padding: var(--space-4);
    background: var(--surface-raised);
    border-left: 1px solid var(--border-subtle);
    overflow: hidden auto;
    scrollbar-width: thin;
}
.workspace-aside section { display: flex; flex-direction: column; gap: var(--space-3); }
.workspace-aside h2 {
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.workspace-counts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-2); }
.workspace-count {
    display: flex; flex-direction: column; gap: 2px;
    padding: var(--space-3);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
}
.workspace-count .count-value { font-size: var(--text-xl); font-weight: var(--weight-semibold); color: var(--text-strong); font-variant-numeric: tabular-nums; line-height: 1.1; }
.workspace-count .count-label { font-size: var(--text-xs); color: var(--text-muted); }
.workspace-count.is-total { grid-column: 1 / -1; border-color: var(--pm-orange-400); background: var(--pm-orange-100); }
.workspace-count.is-added .count-value { color: var(--success-600); }
.workspace-count.is-removed .count-value { color: var(--danger-600); }
.workspace-count.is-moved .count-value { color: var(--warning-600); }

.workspace-slider { display: flex; flex-direction: column; gap: var(--space-1); }
.workspace-slider .slider-head { display: flex; justify-content: space-between; font-size: var(--text-xs); color: var(--text-muted); font-variant-numeric: tabular-nums; }
.workspace-slider input[type="range"] { width: 100%; accent-color: var(--pm-orange-500); min-height: 0; padding: 0; border: 0; background: none; }

.workspace-legend { display: flex; flex-direction: column; gap: var(--space-2); font-size: var(--text-xs); color: var(--text-muted); }
.workspace-legend div { display: flex; align-items: center; gap: var(--space-2); }
/* The swatches carry the marker colours from the canvas, which are deliberately not
   brand colours - they have to stay legible on top of grey microscopy data. */
.legend-swatch { width: 12px; height: 12px; border-radius: 50%; border: 2px solid currentColor; flex: 0 0 12px; }
.legend-swatch.is-preannotated { color: var(--marker-detection); }
.legend-swatch.is-manual { color: var(--marker-manual); }
.legend-swatch.is-moved { color: var(--marker-adjusted); }
.legend-swatch.is-selected { color: var(--marker-selected); background: var(--marker-selected); }

.shortcut-list { display: flex; flex-direction: column; gap: var(--space-1); }
.shortcut-list div { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); font-size: var(--text-xs); color: var(--text-muted); }
/* Alternatives for one action, wrapping together and staying right-aligned so the
   column of keys keeps its edge. */
.shortcut-list .shortcut-keys {
    display: flex; flex-wrap: wrap; align-items: center;
    justify-content: flex-end; gap: var(--space-1);
}
.shortcut-list .shortcut-keys em { font-style: normal; color: var(--text-subtle); }
.shortcut-list strong { color: var(--text-default); font-weight: var(--weight-medium); text-align: right; }
kbd {
    display: inline-block;
    padding: 1px var(--space-2);
    min-width: 20px;
    border: 1px solid var(--border-default);
    border-bottom-width: 2px;
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
    color: var(--text-default);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    text-align: center;
    white-space: nowrap;
}

.workspace-note {
    padding: var(--space-3);
    border-left: 2px solid var(--pm-orange-500);
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
    font-size: var(--text-xs);
    line-height: var(--leading-snug);
    color: var(--text-muted);
}

/* Below this width the side column costs more stage than it returns. */
@media (max-width: 1280px) {
    .workspace-shell { grid-template-columns: minmax(0, 1fr) 0; }
    .workspace-aside { display: none; }
}
@media (max-width: 900px) {
    .workspace-header { flex-wrap: wrap; gap: var(--space-3); }
    .workspace-progress { order: 3; flex-basis: 100%; max-width: none; }
}

/* A frame somebody else already refined and handed back. Deliberately not styled as an
   error - nothing is wrong, but what is on screen is a person's judgement rather than the
   detector's proposal, and that changes how it should be read. */
.workspace-prior {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--space-3);
    border-left: 3px solid var(--marker-adjusted, var(--warning-600));
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
    font-size: var(--text-xs);
    line-height: var(--leading-snug);
    color: var(--text-muted);
}
.workspace-prior strong { color: var(--text-strong); font-weight: var(--weight-semibold); }
.workspace-prior span { font-variant-numeric: tabular-nums; }

/* Measuring mode: the frame is read, not edited. The crosshair means "place a point here",
   so it has to change - pointing at something and asking about it is a different gesture. */
.workspace-stage.is-measuring { cursor: default; }
.workspace-stage.is-measuring.is-over-point { cursor: zoom-in; }

/* What a scan could not vouch for. A ring rather than a colour: colour already means
   provenance here, and the legend says so - a verdict is a different question about the
   same marker and needs its own channel. Dashed, like the marker it describes. */
.legend-swatch.is-doubtful {
    color: var(--marker-uncertain, #eea448);
    background: none;
    border-style: dashed;
}

/* The buttons that sweep a whole band away, side by side, wrapping when the dialog is narrow
   rather than pushing the note out of view. */
.frame-scan-actions { display: flex; flex-direction: column; gap: var(--space-2); }
.frame-scan-buttons { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* The ring that centre wears on the frame, on the button that removes it - amber dashed for
   uncertain, red dotted for unlikely. Two channels, so it survives colour blindness. */
.verdict-dot {
    display: inline-block;
    width: 0.75em;
    height: 0.75em;
    margin-inline-end: 0.4em;
    border-radius: 50%;
    border: 2px solid currentColor;
    vertical-align: -0.05em;
}
.verdict-dot.is-uncertain { color: var(--marker-uncertain, #eea448); border-style: dashed; }
.verdict-dot.is-unlikely  { color: var(--marker-unlikely, #f2617a); border-style: dotted; }

/* The other half of the same question, and deliberately unlike it: colour and pattern both
   differ, so the two are still distinguishable when the colours are not. */
.legend-swatch.is-unlikely {
    color: var(--marker-unlikely, #f2617a);
    background: none;
    border-style: dotted;
}
