/* ImpromptBrü — /connections: the circos plot and the adjacency matrix.
   Loads after graph.css, which owns the panel and the force view.

   ---------- THE SEVEN ARCS ARE ONE RAMP, NOT SEVEN COLOURS ----------
   This property owns exactly one accent. Seven arbitrary hues would make it look
   like seven brands, which is the thing the brand-relationship card is most
   explicit about. So the arcs run along a single axis: jade — the note colour — to
   violet — the post colour. Nothing else. Reading clockwise the hue advances with
   how finished the material is, so the colour is saying the same thing the arc
   ORDER is saying, twice, which is what lets it be this quiet.

   Constant lightness and chroma per theme (the house rule for accents), hue is the
   only variable, and it comes in as --h from graph-data.js. The one terminal arc —
   Uncreated — takes no hue at all, because it is not material.

   Values: 74% / .105 on night paper and 47% / .12 on paper bracket --ib-jade and
   --color-primary, so the two ends of the ramp ARE the note and post marks in both
   themes. Chroma is above the token values (.058 / .09) on purpose — five hues at
   token chroma are indistinguishable from each other, which defeats the whole ramp.
   These are non-text marks against a 3:1 bar, so the saturation is spendable here and
   nowhere else in the property.

   ---------- LIGHT MODE: TRANSPARENT INK, NOT A PALE COLOUR ----------
   On paper an arc is NOT filled with a pale colour. It is filled with the SAME ink the
   matrix uses (47% / .12) at 22% alpha, with a 1.5px hairline of that ink at full
   strength on its edge. Two earlier attempts and why they failed:

   1. Full-strength fill (47% / .12 solid): six saturated mid-lightness slabs read heavy
      and inky on cream, nothing like the table underneath them.
   2. Pale fill (82% / .085 solid): milky. That is what a pale colour looks like when
      its chroma is too low for its lightness — a tint of grey with a hue attached
      rather than a pale jade, and the warm paper makes it read dusty.

   Transparent ink has neither problem, because the hue is never desaturated: the paper
   shows THROUGH it. The edge hairline is what keeps the shape crisp at 14px of band.
   And it means the ring and the matrix are now coloured by one mechanism instead of two
   that happen to match — the light ramp is one pair of values again, used both ways.

   The hairlines cannot follow the fills up. A 0.75px stroke at .19 alpha needs to be
   darker than a fill does, so line work — ribbons and ticks — takes a separate INK pair
   (--ci / --cci) and the resting ribbon alpha (--crest) is higher on paper than on
   night paper for the same reason.

   ABSENCE IS NEVER THE DARKEST INK. --color-text-faint is #635C78 on paper, which made
   the "Not written yet" arc the darkest object on a light page — the eye landed on what
   is missing first, which is the exact thing the copy was changed to stop doing. On
   paper that arc gets the same 14%-alpha treatment and its dead ribbons go light.

   SCOPED TO THE BRAND, not to a class. An earlier draft hung these on a .cd class the
   page had to remember to carry, and the page that forgot rendered every arc BLACK —
   an invalid oklch() with an empty custom property is not a fallback, it is a dropped
   declaration. data-brand and data-theme both sit on <html> (the tokens file requires
   it), so this cannot be forgotten. */
[data-brand="impromptbru"]{--cl:74%;--cc:.105;--ci:74%;--cci:.105;--crest:.14}
[data-brand="impromptbru"][data-theme="light"]{--cl:47%;--cc:.12;--ci:52%;--cci:.12;--crest:.19}

.cwrap{position:relative;background:var(--color-bg-page);border:var(--border-hair) solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden}
/* flex, NOT grid + place-items:center — a centred grid item sizes to its content, so
   the SVG's width:100% resolved against max-content and the plot rendered at a third
   of the field.
   THE PLOT IS CLAMPED TO THE VIEWPORT, and that is not cosmetic. At a full-width
   square the ring was 843px tall, so on any laptop the bottom half of it sat below
   the fold — and because the card is anchored to the top of the plot, clicking a tick
   down there opened a card the reader could not see. Capping the square against vh
   keeps the whole ring AND its card on one screen, which is the whole point of the
   freeze. aspect-ratio holds it square while max-width does the clamping. */
.cstage{position:relative;display:flex;justify-content:center;padding:var(--space-4)}
.csvg{display:block;width:100%;max-width:min(900px,72vh);aspect-ratio:1;height:auto;margin-inline:auto}

/* ---------- arcs ---------- */
.carcg{cursor:pointer}
.carcg:focus{outline:none}
.carcg:focus-visible .carc{stroke:var(--color-ring);stroke-width:2}
.carc{fill:oklch(var(--cl) var(--cc) var(--h,158))}
.carcg.neutral .carc{fill:var(--color-text-faint)}
/* Night paper fills solid; paper fills with transparent ink and an edge. See the note
   at the top of this file for why a pale solid fill was wrong twice. */
[data-brand="impromptbru"][data-theme="light"] .carc{fill:color-mix(in oklab,oklch(var(--cl) var(--cc) var(--h,158)) 22%,transparent);stroke:oklch(var(--cl) var(--cc) var(--h,158));stroke-width:1.5}
[data-brand="impromptbru"][data-theme="light"] .carcg.neutral .carc{fill:color-mix(in oklab,var(--color-text-faint) 14%,transparent);stroke:oklch(70% .012 250)}
/* One tick per page, inside the band, length scaled by how connected that page is.
   This is what makes an arc a ruler rather than a coloured slab. */
.cticks{stroke:oklch(var(--ci) var(--cci) var(--h,158));stroke-width:1;opacity:.62}
.carcg.neutral .cticks{stroke:var(--color-text-faint);opacity:.5}
/* --clabsz / --clabnsz are set by circos.js from the MEASURED scale of the SVG, so
   these land at 13px and 10px on screen at any render size. A literal font-size here is
   in viewBox units and shrinks with the ring — at the min(900px,72vh) clamp that put
   the labels at 5.8px on a laptop. The fallbacks are the no-JS sizes. */
.clab{font-family:var(--font-sans);font-size:var(--clabsz,17px);font-weight:var(--weight-semibold);fill:var(--color-heading);dominant-baseline:middle;pointer-events:none;letter-spacing:-.01em}
.clabn{font-family:var(--font-mono);font-size:var(--clabnsz,12px);font-weight:var(--weight-regular);fill:var(--color-text-faint);letter-spacing:var(--tracking-micro)}
.chit{fill:transparent;stroke:none;cursor:pointer}
/* The frozen page keeps a mark on the ring while its card is open, so the reader can
   see WHICH tick the card belongs to — without it the freeze is invisible the moment
   the pointer moves and the card looks unattached. */
.chit.held{fill:var(--color-accent);opacity:.5}

/* ---------- ribbons ----------
   One path per link, at the real count. Resting opacity is deliberately near the
   floor: at 451 chords anything higher is a grey disc, and the full-density picture
   is the establishing shot, not the working view. */
.cribbons{pointer-events:none}
.crib{fill:none;stroke:oklch(var(--ci) var(--cci) var(--h,158));stroke-width:.75;opacity:var(--crest)}
.crib.neutral{stroke:var(--color-text-faint)}
/* A dead link takes the grey of where it lands, not the colour of where it starts:
   the interesting fact about it is that it goes nowhere. */
.crib.dead{stroke:var(--color-text-faint);opacity:calc(var(--crest) * .72)}
[data-brand="impromptbru"][data-theme="light"] .crib.dead{stroke:oklch(82% .008 250)}
.cwrap[data-iso] .crib{opacity:.025}
.cwrap[data-iso] .crib.hi{opacity:.5;stroke-width:1.1}
.cwrap[data-iso] .crib.dead.hi{opacity:.42}
.cwrap[data-iso] .carcg.lo .carc{opacity:.3}
.cwrap[data-iso] .carcg.lo .cticks{opacity:.18}
.cwrap[data-iso] .carcg.lo .clab{opacity:.4}
/* Frozen reads slightly stronger than a hover preview: the reader has committed, and
   the card beside it is listing exactly these chords. */
.cwrap[data-iso="lock"] .crib.hi{opacity:.62;stroke-width:1.3}

.cctl{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-4);padding:var(--space-3) var(--space-4);border-bottom:var(--border-hair) solid var(--color-border);background:var(--color-bg-surface)}
.creadout{font-family:var(--font-mono);font-size:var(--text-2xs);letter-spacing:var(--tracking-micro);text-transform:uppercase;color:var(--color-text-faint)}
/* The readout is the diagram's caption and it changes on hover, so it must not move
   the layout when the string gets longer. */
.creadout{min-height:1.2em}

/* ---------- the matrix ----------
   A table, not SVG. The cells are numbers and the headers are words; a table gets
   both right for free — selectable, screen-readable, printable, and it needs no
   legend at all, which is the whole argument for it. */
.mx{border-collapse:separate;border-spacing:2px;font-family:var(--font-mono);font-size:var(--text-2xs);letter-spacing:var(--tracking-micro);color:var(--color-text);width:100%}
.mx th,.mx td{padding:0;font-weight:var(--weight-regular)}
.mxc{width:96px}
.mxfrom,.mxto{display:block;font-size:9px;color:var(--color-text-faint);text-transform:uppercase;text-align:left}
.mxh{height:76px;vertical-align:bottom;padding-bottom:5px !important;color:oklch(var(--cl) var(--cc) var(--h,158))}
.mxh[data-neutral]{color:var(--color-text-faint)}
.mxh span{display:inline-block;writing-mode:vertical-rl;transform:rotate(180deg);text-transform:uppercase;white-space:nowrap}
.mxr{text-align:left;padding-right:9px !important;white-space:nowrap;text-transform:uppercase;color:oklch(var(--cl) var(--cc) var(--h,158))}
.mxr[data-neutral]{color:var(--color-text-faint)}
.mxn{margin-left:7px;color:var(--color-text-faint);letter-spacing:0}
/* Cell fill is sqrt-scaled AND capped near 0.53. A linear ramp against a max near
   110 leaves everything under 20 looking empty; a ramp run all the way to 1 walks the
   cell through a dead band (roughly --o 0.60 to 0.70) where the composited wash is too
   dark for --color-heading and too light for --color-on-accent, so NEITHER ink clears
   AA on 10px mono. Capping under it means one ink for every cell. */
.mxv{text-align:center;height:34px;border-radius:var(--radius-sm);position:relative;color:var(--color-heading);background:color-mix(in oklab,oklch(var(--cl) var(--cc) var(--h,158)) calc(var(--o,0) * 100%),transparent)}
.mxv[data-neutral]{background:color-mix(in oklab,var(--color-text-faint) calc(var(--o,0) * 100%),transparent)}
.mxv.zero{color:var(--color-text-faint);background:none}
/* The diagonal is links INSIDE a category, which is a different fact from links
   between two, so it is outlined rather than just shaded. */
.mxv.self{outline:var(--border-hair) solid var(--color-border-strong);outline-offset:-1px}
.mxt{text-align:center;color:var(--color-text-faint);font-size:9px;text-transform:uppercase}
.mxfoot .mxr{color:var(--color-text-faint)}

@media (max-width:760px){
  .mxc{width:74px}
  .mxr{font-size:9px}
  .clab{font-size:11px}
}

/* ---------- the page ---------- */
.cnhead{padding-bottom:var(--space-2)}
.cnlede{margin:var(--space-2) 0 0;max-width:62ch;font-size:var(--text-lg);line-height:1.5;color:var(--color-text-lead);text-wrap:pretty}
/* The stats bar, unchanged from the study: the one element that works under any
   visualisation, and the first thing a reader with no vault context can use. */
/* ONE LINE, always. auto-fit + minmax made equal columns and therefore wrapped as
   soon as six × 150px exceeded the measure. This is a single row of max-content
   columns spread with space-between: each stat is exactly as wide as its own label, so
   "posts" takes 40px and "topics · 24 bulk-made" takes what it needs, and the row
   cannot break. white-space:nowrap on the label is what makes max-content honest.
   Below 760px one line would mean six ~55px columns, so it becomes 3×2 there — a
   readable grid beats an unreadable line. */
.cnstats{display:grid;grid-auto-flow:column;grid-auto-columns:max-content;justify-content:space-between;gap:var(--space-4) var(--space-5);padding:var(--space-4) 0;border-top:var(--border-hair) solid var(--color-border);border-bottom:var(--border-hair) solid var(--color-border);margin:var(--space-5) 0}
.cnstat{display:flex;flex-direction:column;gap:3px}
.cnstatn{font-family:var(--font-display);font-weight:var(--weight-extrabold);font-size:var(--text-xl);color:var(--color-heading);line-height:1;letter-spacing:-.02em;white-space:nowrap}
.cnstatl{font-family:var(--font-mono);font-size:var(--text-2xs);letter-spacing:var(--tracking-micro);text-transform:uppercase;color:var(--color-text-faint);white-space:nowrap}
/* One view. The Circos/Web toggle is gone — .cnviews survives only as a wrapper, and
   the force view's styles stay in graph.css, which this page still needs for the card. */
.cnviews{position:relative}
.cnsec{margin-top:var(--space-7)}
.cnsech{font-family:var(--font-display);font-weight:var(--weight-extrabold);font-size:var(--text-xl);color:var(--color-heading);margin:0 0 var(--space-1);letter-spacing:-.015em}
.cnsecl{margin:0 0 var(--space-4);max-width:72ch;font-size:var(--text-base);color:var(--color-text-muted);text-wrap:pretty}
.cnframe{border:var(--border-hair) solid var(--color-border);border-radius:var(--radius-lg);padding:var(--space-5);overflow-x:auto}
.cnnote{margin:var(--space-3) 0 0;font-family:var(--font-mono);font-size:var(--text-2xs);letter-spacing:var(--tracking-micro);text-transform:uppercase;color:var(--color-text-faint)}
@media (max-width:760px){
  .cnstats{grid-auto-flow:row;grid-template-columns:repeat(3,1fr);gap:var(--space-4) var(--space-3);justify-content:start}
}
