/* semgit — the history map (#95, docs/ui-pass.md §8): the whole desk as
   the canvas for a document's map, drawn by history.js from the model in
   #map. Linked after presence.css. Everything here hangs off .desk--map or
   .map, which only history.html has, so no other page is touched. */

/* ----------------------------------------------------------- the desk ---

   The map takes the desk whole: no paper, no panel, no padding. The desk
   itself scrolls, both ways, when the map is bigger than the window; the
   hint, the legend and the zoom are fixed and stay out of the scroll. */

.desk--map { display: block; padding: 0; }
.desk--map .paper { width: max-content; min-width: 100%; min-height: 100%; }

/* The account menu's choices for the paper do nothing here. */
body:has(.desk--map) .menu.view :is([data-clean], [data-notes-toggle], .zoom) { display: none; }

/* ------------------------------------------------------------ the map ---

   --zoom is the map's own, on its root (the sheet's is shell.js's, on
   <html>); `zoom` rather than a transform, so the scrollable size follows
   the scale. history.js sizes the canvas and places everything in it. */

.map { position: relative; --zoom: 1; outline: none; }
.map-canvas { position: relative; zoom: var(--zoom); }
.map-svg { position: absolute; inset: 0; display: block; overflow: visible; }
.map-layer { position: absolute; inset: 0; }

/* The grey of the baseline and the wording arcs: --ink-3 thinned, so it is
   the same grey on both grounds without a hex of its own. */
.map, .map-legend { --map-grey: color-mix(in srgb, var(--ink-3) 50%, transparent); }

/* Beyond the last version the line is a prospect, not history. */
.map-svg .baseline.pending { stroke-dasharray: 2 6; opacity: .55; }
.baseline { stroke: var(--map-grey); stroke-width: 3; }

/* The arcs, by state (UI-BRIEF §2.1: the semantic colours mean the same
   thing here as on the cards and the marks). The legend's samples are the
   same paths under the same rules. */
.arc { fill: none; stroke-width: 2; stroke-linecap: round; }
.arc[data-state="merged"] { stroke: var(--wording); }
.arc[data-state="merged"][data-kind="wording"] { stroke: var(--map-grey); stroke-dasharray: 6 6; }
.arc[data-state="reviewing"] { stroke: var(--meaning); stroke-width: 2.5; stroke-dasharray: 0.1 6; }
.arc[data-state="disagreement"],
.arc[data-state="declined"] { stroke: var(--blocked); }
.arc[data-state="draft"] { stroke: var(--map-grey); stroke-dasharray: 6 6; }

/* Where an open change is heading: a version that is not one yet, hollow,
   as the panel's reviewing row is. */
.arc-end { fill: var(--surface); stroke-width: 2; }
.arc-end[data-state="reviewing"] { stroke: var(--meaning); }
.arc-end[data-state="disagreement"] { stroke: var(--blocked); }

/* --------------------------------------------------------- a version ---

   A page icon on the baseline — a small white sheet with two grey rules —
   and its labels under it, centred. A link to that version of the page. */

.map-version {
  position: absolute;
  width: 160px;
  display: flex; flex-direction: column; align-items: center;
  color: var(--ink);
  text-align: center;
  border-radius: var(--r2);
}
.map-version:hover { text-decoration: none; }
.map-version:hover .map-vlabel { text-decoration: underline; }
.map-page {
  display: block;
  width: 46px; height: 58px;
  background:
    linear-gradient(var(--line) 0 0) 50% 15px / 22px 2px no-repeat,
    linear-gradient(var(--line) 0 0) 50% 22px / 22px 2px no-repeat,
    var(--surface);
  border: 1px solid var(--line);
  border-radius: 2px;
  box-shadow: var(--e3);
}
.map-version[data-current] .map-page { border-color: var(--ink); }
.map-vlabel { margin-top: 22px; font-size: var(--t-sm); font-weight: 650; line-height: 1.3; }
.map-vsub { font-size: var(--t-xs); line-height: 1.4; color: var(--ink-3); }

/* ------------------------------------------------------------ a card ---

   At the apex of its arc: the avatar, who did what in bold, a badge when
   there is a state to say, and one line — the title and how it stands.
   The whole card is the link to the submission or the branch. --e3, as a
   card lifted off the desk is. No motion (UI-BRIEF §3). */

.map-card {
  position: absolute;
  display: grid; row-gap: 5px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: 10px;
  box-shadow: var(--e3);
  color: var(--ink);
  font-size: var(--t-sm); line-height: 1.4;
}
.map-card:hover { text-decoration: none; border-color: var(--line); }
.map-card-head { display: flex; align-items: flex-start; gap: 8px; min-width: 0; }
.map-card-head .avatar { flex: none; }
.map-card-title {
  flex: 1 1 auto;
  padding-top: 2px;
  font-size: var(--t-md); font-weight: 650; line-height: 1.35;
}
/* Wraps, as the mock's do (`being / reviewed`), so the title keeps its room. */
.map-badge {
  flex: none;
  max-width: 80px;
  margin-top: 2px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--sunken);
  color: var(--ink-2);
  font-size: var(--t-3xs); font-weight: 500; line-height: 1.3;
  letter-spacing: .01em;
  text-align: center;
}
.map-card[data-state="reviewing"] .map-badge { background: var(--warn-wash); color: var(--meaning); }
.map-card[data-state="disagreement"] .map-badge,
.map-card[data-state="declined"] .map-badge { background: var(--danger-wash); color: var(--blocked); }
.map-card-desc { color: var(--ink-2); }

/* ------------------------------------------ the hint, the legend, zoom ---

   Fixed to the window, as the presence pill is (presence.css), so the map
   scrolls under them. */

.map-hint {
  position: fixed;
  top: calc(var(--topbar-h) + 10px); right: 14px;
  z-index: 8;
  max-width: calc(100vw - 28px);
  padding: 5px 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: var(--e2);
  font-size: var(--t-xs); line-height: 14px;
  color: var(--ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.map-legend {
  position: fixed;
  left: 10px; bottom: 44px;
  z-index: 8;
  width: 320px; max-width: calc(100vw - 20px);
  padding: 12px 14px 10px;
  background: var(--surface);
  border-radius: 10px;
  box-shadow: var(--e3);
}
/* The mock's head uses the interface's compact uppercase label style. */
.map-legend-head {
  margin-bottom: 6px;
  font-size: var(--t-3xs); font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-3);
}
.map-legend-row {
  display: flex; align-items: center; gap: 10px;
  font-size: var(--t-xs); line-height: 22px;
  color: var(--ink);
}
.map-legend-row svg { flex: none; width: 24px; height: 8px; overflow: visible; }

.map-zoom {
  position: fixed;
  left: 10px; bottom: 10px;
  z-index: 8;
  display: inline-flex; align-items: center; gap: 4px;
  height: 26px;
  padding: 0 4px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: var(--e1);
}
.map-zoom button {
  width: 20px; height: 20px;
  border: 0; border-radius: 50%;
  background: transparent;
  color: var(--ink-2);
  font-size: 14px; line-height: 1;
  cursor: pointer;
}
.map-zoom button:hover { background: var(--sunken); color: var(--ink); }
.map-zoom output {
  min-width: 36px;
  text-align: center;
  font-size: var(--t-xs); font-variant-numeric: tabular-nums; letter-spacing: 0;
  color: var(--ink-2);
}

@media print { .map-hint, .map-zoom { display: none !important; } }

/* ================================================== the history tree (#23)

   The same route's other reading: the document's versions as stacks of
   paper on a canvas that pans downward, the tree growing from the first
   draft through every branch and every merge. history_tree.js places
   everything; this is the look. Everything hangs off `.tree`, which only
   history.html has when `view=tree`, so nothing else is touched — the map
   above is untouched too.

   Rule 12: a stack stands for a version of the document, and carries only
   the document. Who wrote it, when, on which branch and under which
   submission is in the caption beside it, on the desk. */

.desk--tree { display: block; padding: 0; }
.desk--tree .paper { width: max-content; min-width: 100%; min-height: 100%; }
body:has(.desk--tree) .menu.view :is([data-clean], [data-notes-toggle], .zoom) { display: none; }

.tree { position: relative; --zoom: 1; outline: none; }
.tree-canvas { position: relative; zoom: var(--zoom); }
.tree-svg { position: absolute; inset: 0; display: block; overflow: visible; }
/* The stacks sit over the joins, so the layer covers the whole canvas and
   would otherwise swallow every click meant for a line. Only what is drawn
   in it takes a pointer. */
.tree-layer { position: absolute; inset: 0; pointer-events: none; }
.tree-layer > * { pointer-events: auto; }
.tree, .tree-legend { --tree-grey: color-mix(in srgb, var(--ink-3) 55%, transparent); }

/* --------------------------------------------------------- the joins ---

   A line from a version to the version made out of it. Its state is the
   child's: in the document, being written now, or written and not taken.
   Dash and colour together, never colour alone (UI-BRIEF §5.5). */

/* The visible line is drawn over its own hit area, so it must not be what
   the pointer lands on, or the line would swallow every click meant for it. */
.tree-edge { fill: none; stroke-width: 2.5; stroke-linecap: round; pointer-events: none; }
.tree-edge[data-line="merged"] { stroke: var(--tree-grey); }
.tree-edge[data-line="open"] { stroke: var(--meaning); stroke-dasharray: 1 7; }
.tree-edge[data-line="abandoned"] { stroke: var(--blocked); stroke-dasharray: 6 6; opacity: .7; }
/* A join: both lines into a merge are drawn heavier, because the merge is
   the moment two drafts became one document. */
.tree-edge[data-kind="merge"] { stroke-width: 3.5; }
/* The hit area — a 2px line is not a click target. Invisible, over the line. */
.tree-hit { fill: none; stroke: transparent; stroke-width: 18px; pointer-events: stroke; cursor: pointer; }
.tree-hit:hover + .tree-edge, .tree-hit:focus-visible + .tree-edge { stroke: var(--ink); }
.tree-hit:focus-visible { outline: none; stroke: color-mix(in srgb, var(--focus) 35%, transparent); }

/* Where a line runs off the window the walk stopped at. */
.tree-beyond { stroke: var(--tree-grey); stroke-width: 2.5; stroke-dasharray: 2 6; }

/* -------------------------------------------------------- a version ---

   A stack of paper: the sheet, and one to three pages behind it, deeper
   when the document was longer. The whole stack is the link that opens
   that version. */

.tree-node {
  position: relative;
  flex: none;
  display: block;
  color: var(--ink);
  border-radius: var(--r2);
}
.tree-node:hover { text-decoration: none; }
.tree-node[data-line="abandoned"] { opacity: .62; }
.tree-node[data-line="abandoned"]:hover, .tree-node:focus-visible { opacity: 1; }

.tree-stack { position: relative; display: block; }
.tree-sheet, .tree-back {
  position: absolute; top: 0; left: 0;
  width: 100%; height: 100%;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 2px;
}
.tree-back { background: var(--sunken); }
/* The document view's own paper shadow (sheet.css), so a version reads as
   the same object shrunk. The hairline is not on the real sheet: at this
   size the shadow alone leaves the paper with no edge at all. */
.tree-sheet {
  box-shadow: var(--paper-shadow, var(--e3));
  overflow: hidden;
}
.tree-node:hover .tree-sheet { border-color: var(--ink-3); }
.tree-node[data-current] .tree-sheet { border-color: var(--ink); border-width: 1.5px; }
.tree-node[data-merge] .tree-sheet { border-color: var(--wording); }

/* The document's own first lines, once the reader has zoomed in far enough
   to read them. The manuscript serif, as the sheet is. */
.tree-text {
  position: absolute; inset: 0;
  padding: 9px 8px;
  font-family: var(--prose);
  /* Set in the canvas's own units, so the CSS zoom is what decides whether
     the words can be read: 5px at 200% is 10px on the screen. */
  font-size: 5px; line-height: 1.45;
  color: var(--ink-2);
  overflow: hidden;
}
.tree-text p { margin: 0 0 2px; }
.tree-text .h { font-weight: 650; color: var(--ink); }
/* Before the words arrive, the ruled lines the far view shows. */
.tree-rules { position: absolute; inset: 0; }
.tree-rules i { position: absolute; left: 12%; height: 1.5px; background: var(--line); }

/* ------------------------------------------------------ the caption ---

   Who made this version, when, and what it belongs to. Beside the stack,
   never on it (rule 12), and clear of the line running down through the
   stacks, which is why it sits to the right rather than under. */

.tree-box { display: flex; align-items: center; gap: 11px; }
.tree-cap {
  display: grid; row-gap: 1px;
  justify-items: start;
  line-height: 1.35;
  min-width: 0;
}
.tree-who { display: flex; align-items: center; gap: 5px; max-width: 100%; }
.tree-who .avatar { flex: none; width: 17px; height: 17px; font-size: 9px; }
.tree-handle {
  font-size: var(--t-xs); font-weight: 650;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tree-node:hover .tree-handle { text-decoration: underline; }
.tree-when { font-size: var(--t-3xs); color: var(--ink-3); }
.tree-branch {
  max-width: 100%;
  font-family: var(--mono); font-size: var(--t-3xs);
  color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* The submission a version was proposed or merged under: its number, and
   whether it changed the meaning or only the wording. A link of its own,
   so the stack still opens the version. */
.tree-sub {
  display: inline-flex; align-items: baseline; gap: 5px;
  margin-top: 2px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--sunken);
  color: var(--ink-2);
  font-size: var(--t-3xs);
}
.tree-sub:hover { text-decoration: none; background: var(--accent-wash); color: var(--ink); }
.tree-sub b { font-weight: 650; font-family: var(--mono); }
.tree-sub[data-kind="semantic"] { background: var(--warn-wash); color: var(--meaning); }
.tree-sub[data-kind="surface"] { background: var(--ok-wash); color: var(--wording); }

/* ------------------------------------------------ a collapsed stretch ---

   Zoomed out, a long run of versions nobody branched from is one marker
   rather than fourteen identical stacks. Clicking it opens the run. */

.tree-run {
  position: absolute;
  display: grid; place-items: center;
  border: 1px dashed var(--line);
  border-radius: 999px;
  background: var(--canvas);
  color: var(--ink-3);
  font-size: var(--t-xs);
  cursor: pointer;
  white-space: nowrap;
}
.tree-run:hover { border-color: var(--ink-3); color: var(--ink); }

/* -------------------------------------- the hint, the legend, controls ---

   Fixed to the window, as the map's are, so the canvas scrolls under. */

/* Bottom right: the zoom has the bottom left, the hint the top right, the
   two readings the top left, so the canvas keeps its middle. */
.tree-legend { position: fixed; left: auto; right: 10px; bottom: 10px; z-index: 8; width: 250px; }
.tree-legend .map-legend-row svg { width: 8px; height: 24px; }
/* Samples of a hairline read as nothing at 8px wide. */
.tree-legend .tree-edge { stroke-width: 3.5; }
.tree-legend .tree-edge[data-kind="merge"] { stroke-width: 5; }

.history-views {
  position: fixed;
  top: calc(var(--topbar-h) + 10px); left: 14px;
  z-index: 8;
  display: inline-flex; gap: 2px;
  padding: 2px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: var(--e1);
}
.history-views a {
  padding: 2px 11px;
  border-radius: 999px;
  color: var(--ink-3);
  font-size: var(--t-xs); line-height: 17px;
}
.history-views a:hover { color: var(--ink); text-decoration: none; }
.history-views a[aria-current] { background: var(--sunken); color: var(--ink); font-weight: 600; }

/* A phone (UI-BRIEF §5.5): a 250px card of legend over a 375px canvas hides
   the tree it explains, and the hint and the two readings cannot share the
   top of that screen. The canvas, the zoom and the switch stay. */
@media (max-width: 700px) {
  body:has(.desk--tree) .map-hint { display: none; }
  .tree-legend { display: none; }
}

@media print { .tree-legend, .history-views { display: none !important; } }

.edit-milestones { padding: 8px; font: var(--t-sm)/1.5 var(--ui); }
.edit-milestones > summary { cursor: pointer; font-weight: 600; }
.edit-milestones ol { padding-left: 18px; max-height: 45vh; overflow: auto; }
.edit-milestones li { margin-block: 10px; }
.edit-milestones small { display: block; color: var(--ink-3); }
.history-edit-activity { position: fixed; top: calc(var(--topbar-h, 48px) + 12px); right: 16px; z-index: 10; max-width: min(340px, calc(100vw - 32px)); background: var(--surface); border: 1px solid var(--line); border-radius: 14px; box-shadow: var(--e1); }
.history-edit-activity:empty { display: none; }
