/* The obstacle graph and the obstacle detail. Every value comes from tokens.css;
   the numbers the graph writes into style attributes are positions worked out at
   runtime from these. */

/* The layout reads these back, so they are declared as lengths and resolve to
   real pixels rather than to the text of a calc. Each one is a whole multiple of
   a spacing step: the graph never invents a size of its own. */
@property --graph-gap-x {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
}
@property --graph-gap-y {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
}
@property --graph-gap-stack {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
}
@property --graph-step {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
}
@property --graph-column {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
}
@property --graph-column-max {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
}
@property --graph-arrow {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
}
@property --graph-corner {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
}
@property --graph-spine {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
}
@property --graph-lane {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
}
@property --graph-entry {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
}
@property --graph-fan {
    syntax: '<length>';
    inherits: true;
    initial-value: 0px;
}

.graph {
    --graph-gap-x: var(--space-10);
    --graph-gap-y: var(--space-5);
    --graph-gap-stack: var(--space-4);
    --graph-step: var(--space-9);
    /* The narrowest a column may be, and the widest. A layer is sized to the
       longest name in it between the two, so a short name and a long one do not
       have to share a width. A chain that cannot hold the narrower of them in
       columns cascades instead, where every card is as wide as what is left of
       the surface. */
    --graph-column: calc(var(--space-10) * 6);
    --graph-column-max: calc(var(--space-10) * 8);
    /* The marks an edge is made of: the arrowhead that ends it, the radius of
       the corner it turns when the chain is stepped down the page, how far
       inside a card its line drops, and how far apart two lines leaving the
       same layer are held. */
    --graph-arrow: var(--space-3);
    --graph-corner: var(--space-4);
    --graph-spine: var(--space-4);
    --graph-lane: var(--space-4);
    /* Where several edges reach one card, they land this far apart on its edge,
       and the card is given the room for them — never past this. */
    --graph-entry: var(--space-5);
    --graph-fan: calc(var(--row-height) * 3);

    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: var(--space-8);
}

/* Once the window is narrower than the content it can hold (--content-max), the
   columns close up before they give way. */
@media (max-width: 1180px) {
    .graph {
        --graph-gap-x: var(--space-8);
    }
}

.graph-surface {
    position: relative;
    min-width: 0;
}

/* Nothing is placed until the width is known, so no node is ever seen in the
   wrong place. */
.graph-surface:not([data-painted]) {
    visibility: hidden;
}

.graph-edges {
    position: absolute;
    top: 0;
    left: 0;
    pointer-events: none;
}

/* A line and the arrow that ends it are one mark, in one grey. */
.graph-edge {
    fill: none;
    stroke: var(--span-strong);
    stroke-width: var(--stroke-hair);
    stroke-linecap: round;
}

.graph-arrow {
    fill: var(--span-strong);
}

/* A node ---------------------------------------------------------------- */

.graph-node {
    position: absolute;
    display: flex;
    align-items: center;
    gap: var(--space-4);
    min-height: var(--row-height);
    padding: var(--space-4) var(--space-5);
    background: var(--surface);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius);
    font-size: var(--text-base);
    line-height: var(--leading-tight);
    color: var(--ink);
    transition: border-color var(--duration) ease, color var(--duration) ease,
        background var(--duration) ease;
}

.graph-node-name {
    min-width: 0;
    overflow-wrap: break-word;
}

/* The two kinds are told apart by the node itself: an Obstacle is a solid card
   with a bar down the side it blocks from, a Key Result is a recessed card
   carrying a filled round mark. Neither is labelled. */
.graph-node-obstacle {
    border-left: var(--space-2) solid var(--ink-secondary);
    padding-left: var(--space-4);
    font-weight: var(--weight-medium);
}

.graph-node-key-result {
    background: var(--surface-sunken);
    border-color: var(--line);
    color: var(--ink-secondary);
}

.graph-node-key-result::before {
    content: '';
    flex: none;
    width: var(--space-4);
    height: var(--space-4);
    background: var(--span-strong);
    border-radius: 50%;
}

/* The ring follows the card it is drawn around rather than the smaller radius
   the page uses for everything else. */
.graph-node:focus-visible {
    border-radius: var(--radius);
}

.graph-node:hover {
    border-color: var(--accent);
    color: var(--accent-strong);
    background: var(--surface);
}

.graph-node-obstacle:hover {
    border-left-color: var(--accent);
}

.graph-node-key-result:hover::before {
    background: var(--accent);
}

.graph-node-archived {
    color: var(--ink-muted);
    border-left-color: var(--span-strong);
}

/* A node left with no edge — whatever it blocked is archived or filtered out —
   is not in a chain, so it is not drawn inside one. It sits below, sized to its
   own name, where no arrow can be read as leaving it. */
.graph-loose {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-5);
}

.graph-loose:not(:first-child) {
    margin-top: var(--space-9);
    padding-top: var(--space-8);
    border-top: 1px solid var(--line);
}

.graph-loose .graph-node {
    position: static;
    max-width: var(--graph-column);
}

.graph-bare {
    padding: var(--space-6) var(--space-8);
}

.graph-none {
    font-size: var(--text-base);
    color: var(--ink-muted);
}

/* Naming an obstacle happens under the chain it will join, in its own band. */
.obstacles-create {
    margin-top: var(--space-5);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.obstacles-create .create-row {
    border-top: 0;
}

@media (max-width: 720px) {
    .graph {
        padding: var(--space-5);
    }

    /* Nothing on a phone screen scrolls sideways, the graph least of all. */
    .toolbar-obstacles {
        flex-wrap: wrap;
    }

    }

/* The detail ------------------------------------------------------------ */

.obstacle-action {
    display: inline-flex;
    align-items: center;
    height: var(--control-height);
    padding: 0 var(--space-5);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius);
    background: var(--surface);
    font-size: var(--text-base);
    color: var(--ink-secondary);
    cursor: pointer;
    transition: border-color var(--duration) ease, color var(--duration) ease,
        background var(--duration) ease;
}

.obstacle-action:hover {
    border-color: var(--line-strong);
    color: var(--ink);
    background: var(--surface-hover);
}

/* A write is in the air. The button that started it says so by not offering
   itself a second time. */
.obstacle-action[disabled] {
    opacity: 0.55;
    cursor: default;
}

.obstacle-action[disabled]:hover {
    border-color: var(--line-strong);
    color: var(--ink-secondary);
    background: var(--surface);
}

.obstacle-action-strong[disabled]:hover {
    border-color: var(--accent);
    color: var(--surface);
    background: var(--accent);
}

.obstacle-action-strong {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--surface);
    font-weight: var(--weight-medium);
}

.obstacle-action-strong:hover {
    background: var(--accent-strong);
    border-color: var(--accent-strong);
    color: var(--surface);
}

.obstacle-actions {
    display: flex;
    gap: var(--space-3);
}

/* A bar for an Obstacle, a filled round mark for a Key Result — the same pair
   the graph uses. The two kinds never appear in a list together without them. */
.blocks-mark {
    flex: none;
}

.blocks-mark-obstacle {
    width: var(--space-2);
    height: var(--space-6);
    border-radius: var(--radius-mark);
    background: var(--ink-secondary);
}

.blocks-mark-key-result {
    width: var(--space-4);
    height: var(--space-4);
    margin: 0 var(--space-1);
    background: var(--span-strong);
    border-radius: 50%;
}

/* The detail sits on one measured rail: its actions stand over the record they
   act on, and no hairline runs on past the text it separates. */
.obstacle-screen .screen-head,
.obstacle-detail,
.obstacle-none {
    max-width: var(--measure);
}

.obstacle-detail {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
}

.obstacle-archived .obstacle-fact-value,
.obstacle-archived .obstacle-link-name {
    color: var(--ink-muted);
}

.obstacle-none {
    font-size: var(--text-base);
    color: var(--ink-muted);
}

/* Two facts, two halves of the measure, a hairline between them: the band is
   filled by what it holds rather than framing space. */
.obstacle-facts {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    border-bottom: 1px solid var(--line);
}

.obstacle-fact {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-width: 0;
    padding: var(--space-6);
    border-right: 1px solid var(--line);
}

.obstacle-fact:last-child {
    border-right: 0;
}

.obstacle-fact-label {
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    color: var(--ink-muted);
}

.obstacle-fact-value {
    font-size: var(--text-base);
    color: var(--ink);
}

.obstacle-block {
    padding: var(--space-6);
    border-bottom: 1px solid var(--line);
}

.obstacle-block:last-child {
    border-bottom: 0;
}

.obstacle-block-title {
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    color: var(--ink-muted);
    margin-bottom: var(--space-3);
}

.obstacle-links {
    display: flex;
    flex-direction: column;
}

.obstacle-link {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    min-height: var(--row-height);
    padding: var(--space-2) 0;
    font-size: var(--text-base);
    color: var(--ink);
    border-bottom: 1px solid var(--line);
}

.obstacle-link:last-child {
    border-bottom: 0;
}

.obstacle-link-archived .obstacle-link-name {
    color: var(--ink-muted);
}

.obstacle-link:hover .obstacle-link-name {
    color: var(--accent-strong);
}

.obstacle-link:hover .blocks-mark-obstacle {
    background: var(--accent);
}

.obstacle-link:hover .blocks-mark-key-result {
    background: var(--accent);
}

/* Editing in place ------------------------------------------------------ */

.obstacle-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
    padding: var(--space-6);
}

.obstacle-form-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-5);
}

.obstacle-field {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-width: 0;
}

.obstacle-field-wide {
    flex: 1;
    min-width: var(--sidebar-width);
}

.obstacle-label {
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    color: var(--ink-muted);
    padding: 0;
}

.obstacle-input {
    height: var(--control-height);
    padding: 0 var(--space-4);
    background: var(--surface);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius);
    font-size: var(--text-base);
    color: var(--ink);
    transition: border-color var(--duration) ease, box-shadow var(--duration) ease;
}

.obstacle-input:focus {
    border-color: var(--accent);
    box-shadow: var(--focus-glow);
}

.obstacle-select {
    padding-right: var(--space-6);
}

.obstacle-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin: 0;
    padding: 0;
    border: 0;
    min-width: 0;
}

.obstacle-choices {
    display: flex;
    flex-direction: column;
}

.obstacle-choice-set {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(calc(var(--space-10) * 8), 1fr));
    gap: var(--space-3) var(--space-6);
}

/* Obstacles are ticked apart from Key Results: a hairline between the two sets
   keeps them from reading as one run of boxes. It carries no label — naming the
   two kinds would be explaining what the marks already say. */
.obstacle-choice-set + .obstacle-choice-set {
    margin-top: var(--space-5);
    padding-top: var(--space-5);
    border-top: 1px solid var(--line);
}

.obstacle-choice {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    min-width: 0;
    font-size: var(--text-base);
    color: var(--ink);
    cursor: pointer;
}

.obstacle-check {
    flex: none;
    accent-color: var(--accent);
}

/* A name in the form is the name, never a stump of one: what is being ticked
   has to be readable. */
.obstacle-choice-name {
    min-width: 0;
    overflow-wrap: break-word;
}

.obstacle-error {
    font-size: var(--text-sm);
    color: var(--red);
}

.obstacle-form-actions {
    display: flex;
    gap: var(--space-3);
}

@media (max-width: 720px) {
    .obstacle-field-wide {
        flex: 1 0 100%;
        min-width: 0;
    }

    .obstacle-choice-set {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* The person is a link to everything that is theirs, as on every screen. */
.obstacle-owner-link:hover {
    color: var(--accent-strong);
    text-decoration: underline;
}
