/* Certflow diagrams — see certflow.js */

@font-face {
  font-display: swap;
  font-family: "Virgil";
  src: url("Virgil.woff2") format("woff2");
}

body > article > figure.certflow, body > article > figure.cf-levels {
  --cf-bg: #f9fafb;
  --cf-blue: #4a9be8;
  --cf-border: #e6e8eb;
  --cf-ink: #1e1e1e;
  --cf-muted: #6b7280;
  --cf-revoke: #e03131;
  margin: 1.5rem 0 2rem;
  position: relative;
}

/* Notation legend: a small drawn example beside each item, in place of the bullet */

ul.cf-legend {
  list-style: none;
  margin-left: 0;
  padding-left: 0;
}

.cf-legend li {
  align-items: center;
  display: grid;
  gap: 1rem;
  grid-template-columns: 6.5rem 1fr;
}

.cf-legend li + li {
  margin-top: 0.75rem;
}

.cf-legend svg {
  display: block;
  height: auto;
  width: 100%;
}

.cf-legend text {
  dominant-baseline: central;
  fill: #1e1e1e;
  font-family: "Virgil", "Comic Sans MS", cursive;
  font-size: 18px;
  text-anchor: middle;
}

/* Access levels as nested boxes: each level contains the ones it implies. The stack
   hugs its longest row rather than stretching across wide windows */

.cf-nest {
  max-width: 100%;
  width: fit-content;
}

.cf-nest .lvl {
  background: color-mix(in srgb, var(--cf-blue) calc(var(--h) * 4%), #fff);
  border: 2px solid color-mix(in srgb, var(--cf-ink) calc(12% + var(--h) * 8%), #fff);
  border-radius: 14px;
  padding: 0.4rem 0.75rem 0.55rem;
}

.cf-nest .lvl > .lvl {
  margin-top: 0.35rem;
}

.cf-nest .head {
  align-items: baseline;
  display: grid;
  font-family: "Merriweather Sans", sans-serif;
  font-size: 0.85rem;
  gap: 0.4rem;
  grid-template-columns: 1.5rem 4.2rem 1fr;
  line-height: 1.3;
}

.cf-nest .tag {
  font-family: "Virgil", "Comic Sans MS", cursive;
  font-size: 1.05rem;
}

.cf-nest small {
  color: var(--cf-muted);
  font-size: 0.85em;
  margin-left: 0.3rem;
}

/* Implied levels: a certificate's level contains the ones below it, and a later
   delegation can draw on just the inner part. Colour is the level here, not the subject.
   A supporting illustration, not a main figure: it stays in the text column (the
   article's default padding) and has no canvas frame */

body > article > figure.cf-inline {
  margin: 1rem 0 1.5rem;
}

.cf-implied {
  display: block;
  height: auto;
  overflow: visible;
  width: 100%;
}

.cf-implied text {
  dominant-baseline: central;
  fill: #1e1e1e;
  font-family: "Virgil", "Comic Sans MS", cursive;
  font-size: 20px;
  text-anchor: middle;
}

.cf-implied text.tag { font-size: 18px; text-anchor: start; }
.cf-implied text.small { font-size: 17px; }
.cf-implied .agent { fill: #fff; stroke: #1e1e1e; stroke-width: 2.6; }
.cf-implied .line { fill: none; stroke: #1e1e1e; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2.6; }
.cf-implied .edit { fill: #e3f2e6; stroke: #46a35a; stroke-width: 2.6; }
.cf-implied .read { fill: #fdf2e4; stroke: #f0a24a; stroke-width: 2.6; }
.cf-implied .relay { fill: #fbe4d6; stroke: #e0661f; stroke-width: 2.6; }
.cf-implied .cf-flow { stroke-dasharray: 7 7; stroke-width: 2.6; }

/* Narrowest pipe: the stream that reaches the end is only as wide as the narrowest
   delegation it passed through. It's the doc's authority, so it's in the doc's colour
   and marches like the dashed flows in the diagrams */

.cf-pipes {
  background: var(--cf-bg);
  border: 1px solid var(--cf-border);
  border-radius: 6px;
  display: block;
  height: auto;
  width: 100%;
}

.cf-pipes text {
  dominant-baseline: central;
  fill: var(--cf-ink);
  font-family: "Virgil", "Comic Sans MS", cursive;
  text-anchor: middle;
}

.cf-pipes .emo { font-size: 56px; }
.cf-pipes .pipe { fill: #fff; stroke: var(--cf-ink); stroke-width: 3; }
.cf-pipes .flange { fill: var(--cf-bg); stroke: var(--cf-ink); stroke-width: 3; }
.cf-pipes .hop { fill: #fff; stroke: var(--cf-ink); stroke-width: 3; }
.cf-pipes .hop-label { font-size: 26px; }
.cf-pipes .pipe-tag { font-size: 30px; }
.cf-pipes .sub { fill: var(--cf-muted); font-size: 24px; }
.cf-pipes .pipe-out { font-size: 28px; font-weight: 700; }

/* One dashed stream, the same style all the way along; only its width changes */
.cf-pipes .flow {
  animation: cf-pipe-flow 1.2s linear infinite;
  stroke: var(--cf-blue);
  stroke-dasharray: 26 14;
  stroke-linecap: butt;
  stroke-width: 16;
}

/* Alice's pipe runs full, wall to wall; the stream that carries on is Read-sized */
.cf-pipes .flow.wide {
  stroke-width: 90;
}

@keyframes cf-pipe-flow {
  to { stroke-dashoffset: -40; }
}

/* Just the diagram canvas, not the icons inside buttons */
.cf-stage > svg {
  background: var(--cf-bg);
  border: 1px solid var(--cf-border);
  border-radius: 6px;
  display: block;
  height: auto;
  user-select: none;
  width: 100%;
}

/* Only nodes swallow touches, so the page still scrolls from empty canvas */
.cf-agent, .cf-cert {
  touch-action: none;
}

/* Before the script runs, the step captions read as a plain list */
.certflow.cf-ready .certflow-steps {
  display: none;
}

/* Strokes */

.certflow text {
  dominant-baseline: central;
  fill: var(--cf-ink);
  font-family: "Virgil", "Comic Sans MS", cursive;
  pointer-events: none;
  text-anchor: middle;
}

.cf-stroke {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 3.2;
}

.cf-flow {
  animation: cf-march 1.1s linear infinite;
  fill: none;
  stroke-dasharray: 10 10;
  stroke-linecap: round;
  stroke-width: 3.2;
}

/* A revocation's provenance: dashed like any authority flow, but red, and ending in
   the ✗ through the revoked certificate */
.cf-revflow {
  animation: cf-march 1.1s linear infinite;
  fill: none;
  stroke: var(--cf-revoke);
  stroke-dasharray: 10 10;
  stroke-linecap: round;
  stroke-width: 3.2;
}

@keyframes cf-march {
  to { stroke-dashoffset: -20; }
}

.cf-backdrop {
  fill: var(--cf-bg);
}

/* The ✗ a revocation's line ends in, sitting on the certificate it crosses out */
.cf-revmark {
  stroke-width: 4;
}

/* The revocation itself: a red certificate, with red "who signed what" lines from the
   revoker, through it, to the certificate it crosses out */
.cf-revsolid, .cf-revbox {
  stroke: var(--cf-revoke);
}

.cf-revfill {
  fill: var(--cf-revoke);
  fill-opacity: 0.14;
}

.cf-revocation {
  cursor: grab;
  touch-action: none;
}

.cf-inert {
  opacity: 0.4;
}

.cf-rubber {
  pointer-events: none;
  stroke: var(--cf-muted);
  stroke-dasharray: 4 8;
  stroke-linecap: round;
  stroke-width: 3;
}

/* State */

.cf-agent, .cf-cert {
  outline: none;
}

.cf-agent, .cf-cert {
  cursor: grab;
}

.cf-dragging, .cf-dragging * {
  cursor: grabbing;
}

.cf-agent:focus-visible .cf-stroke, .cf-cert:focus-visible .cf-stroke {
  stroke-width: 6;
}

.cf-selected .cf-stroke, .cf-drop .cf-stroke {
  stroke-width: 6;
}

.cf-revoked {
  opacity: 0.55;
}

.cf-invalid {
  opacity: 0.25;
}

.cf-enter {
  animation: cf-enter 0.6s ease-out both;
}

/* `animation` doesn't stack across classes, so new flows need both spelled out */
.cf-flow.cf-enter, .cf-revflow.cf-enter {
  animation: cf-enter 0.6s ease-out both, cf-march 1.1s linear infinite;
}

@keyframes cf-enter {
  from { opacity: 0; }
}

/* Focus: dim everything that isn't part of the current trace or provenance. Only
   opacity changes, so authority keeps its own colours (red is reserved for revocation) */

[data-key] {
  transition: opacity 0.2s;
}

.cf-focus [data-key]:not(.cf-lit) {
  opacity: 0.12;
}

@media (prefers-reduced-motion: reduce) {
  .cf-flow, .cf-revflow, .cf-enter, .cf-flow.cf-enter, .cf-revflow.cf-enter, .cf-pipes .flow {
    animation: none;
  }
  [data-key] {
    transition: none;
  }
}

/* Controls */

.cf-toolbar, .cf-controls {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  font-family: "Merriweather Sans", sans-serif;
  font-size: 0.8rem;
  gap: 0.5rem 1rem;
  margin-top: 0.5rem;
}

.cf-toolbar {
  margin: 0 0 0.5rem;
}

.certflow button {
  background: #fff;
  border: 1px solid var(--cf-border);
  border-radius: 999px;
  color: var(--cf-ink);
  cursor: pointer;
  font: inherit;
  padding: 0.2rem 0.75rem;
}

.certflow button:hover:not(:disabled) {
  border-color: var(--cf-muted);
}

.certflow button:disabled {
  cursor: default;
  opacity: 0.35;
}

.certflow button[aria-checked="true"] {
  background: var(--cf-ink);
  border-color: var(--cf-ink);
  color: #fff;
}

.cf-stepper, .cf-segmented, .cf-adders {
  align-items: center;
  display: flex;
  gap: 0.35rem;
}

.cf-count {
  color: var(--cf-muted);
  font-variant-numeric: tabular-nums;
  min-width: 3.5em;
  text-align: center;
}

.cf-label {
  color: var(--cf-muted);
  margin-right: 0.15rem;
}

.certflow button.cf-play {
  display: grid;
  height: 1.9rem;
  padding: 0;
  place-items: center;
  width: 1.9rem;
}

.cf-play svg {
  height: 0.85rem;
  width: 0.85rem;
}

.cf-counter {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

/* Autoplay countdown: fills over the step's dwell time, then advances. It's a progress
   indicator rather than decoration, so it runs even with reduced motion */
.cf-timer {
  background: var(--cf-border);
  border-radius: 2px;
  height: 3px;
  overflow: hidden;
}

.cf-timer > span {
  animation: cf-timer var(--cf-dwell, 6s) linear forwards paused;
  background: var(--cf-ink);
  display: block;
  height: 100%;
  transform-origin: left;
}

.cf-playing:not(.cf-offscreen) .cf-timer > span {
  animation-play-state: running;
}

@keyframes cf-timer {
  from { transform: scaleX(0); }
}

.cf-reset {
  margin-left: auto;
}

.cf-caption {
  font-size: 0.95rem;
  margin-top: 0.6rem;
  min-height: 3em;
}

/* How to interact with a figure: a regular article aside, pinned beside the top of the
   canvas in the margin. The figure sits one --padding inside the article, so shift by
   that to line up with the other asides. On narrow screens asides rejoin the flow under
   the figure; article.css pulls them up 1em (!important) to tuck under a paragraph, but
   the step caption has no bottom margin to absorb that, so put a gap back */
body > article > figure.certflow > aside.cf-hint {
  right: calc(var(--padding) * -1);
  top: 0;
}

@media only screen and (max-width: 40rem) {
  body > article > figure.certflow > aside.cf-hint {
    margin-top: 0.75rem !important;
    right: inherit;
    top: auto;
  }
}

/* What the traced agent can reach, floating in the canvas's top-left corner. Only the
   rows take the pointer, so the card never blocks dragging or hovering behind it */
.cf-trace {
  background: rgb(255 255 255 / 0.94);
  border: 1px solid var(--cf-border);
  border-radius: 10px;
  box-shadow: 0 2px 10px rgb(0 0 0 / 0.08);
  color: var(--cf-muted);
  font-family: "Merriweather Sans", sans-serif;
  font-size: 0.75rem;
  left: 0.6rem;
  max-width: min(24rem, calc(100% - 1.2rem));
  padding: 0.45rem 0.6rem 0.55rem;
  pointer-events: none;
  position: absolute;
  top: 0.6rem;
}

.cf-trace[hidden] {
  display: none;
}

.cf-trace p {
  margin: 0 0 0.35rem;
}

.cf-trace .cf-reach li {
  pointer-events: auto;
}

.cf-reach {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  list-style: none;
  margin: 0;
  max-width: none;
  padding: 0;
}

.cf-reach li {
  align-items: center;
  background: #fff;
  border: 1px solid var(--cf-border);
  border-radius: 999px;
  color: var(--cf-ink);
  cursor: default;
  display: flex;
  gap: 0.4rem;
  margin: 0;
  padding: 0.15rem 0.7rem;
}

.cf-reach li:hover, .cf-reach li:focus {
  border-color: var(--cf-ink);
  outline: none;
}

.cf-via {
  color: var(--cf-muted);
}

.cf-swatch {
  border-radius: 50%;
  display: inline-block;
  flex: none;
  height: 0.65rem;
  width: 0.65rem;
}

.cf-menu {
  background: #fff;
  border: 1px solid var(--cf-border);
  border-radius: 8px;
  box-shadow: 0 6px 20px rgb(0 0 0 / 0.12);
  display: flex;
  flex-direction: column;
  font-family: "Merriweather Sans", sans-serif;
  font-size: 0.8rem;
  gap: 0.25rem;
  padding: 0.5rem;
  position: absolute;
  transform: translate(-50%, 8px);
  z-index: 10;
}

.cf-menu p {
  color: var(--cf-muted);
  margin: 0 0 0.2rem;
}

.cf-menu-row {
  align-items: center;
  display: flex;
  gap: 0.3rem;
}

.cf-menu .cf-subject {
  align-items: center;
  display: flex;
  flex: 1;
  gap: 0.4rem;
  margin-right: 0.5rem;
  white-space: nowrap;
}

.cf-menu button {
  border-radius: 6px;
  white-space: nowrap;
  padding: 0.2rem 0.55rem;
}

.cf-menu button:focus-visible {
  outline: 2px solid #4c3fb8;
  outline-offset: 1px;
}

/* Builder tool palette, floating over the bottom of the canvas */

.cf-stage {
  position: relative;
}

.cf-palette {
  align-items: center;
  background: #fff;
  border: 1px solid var(--cf-border);
  border-radius: 10px;
  bottom: 0.6rem;
  box-shadow: 0 2px 10px rgb(0 0 0 / 0.08);
  display: flex;
  font-family: "Merriweather Sans", sans-serif;
  font-size: 0.75rem;
  gap: 0.25rem;
  left: 50%;
  padding: 0.25rem;
  position: absolute;
  transform: translateX(-50%);
}

.certflow .cf-tool {
  align-items: center;
  border-color: transparent;
  border-radius: 7px;
  display: flex;
  height: 2rem;
  justify-content: center;
  padding: 0;
  width: 2rem;
}

.certflow .cf-tool[aria-pressed="true"] {
  background: #ece8ff;
  color: #4c3fb8;
}


.cf-tool-delegate .cf-agent {
  cursor: crosshair;
}

.certflow .cf-menu button.cf-menu-row {
  text-align: left;
  width: 100%;
}
