/* THE INFRASTRUCTURE MAP (infraMap.mjs). Greys and sizes are the shared tokens; the one thing this file adds is a colour for what a node IS, one token per kind. The
   kind is always said in words as well (the node's second line, the legend, the panel): a colour never carries it alone. Light and dark both come from the shared surface and ink tokens. */
:root {
  --map-domain: var(--ink);
  --map-app: #7FB2E5;
  --map-tab: #B8B8C2;
  --map-group: var(--surface-3);
  --map-cloud: #E5A86A;
  --map-store: #B69AE0;
  --map-mac: #69D3B0;
  --map-ext: #E08FA8;
}

.im-bar { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: var(--card-detail-gap); }
.im-btn { padding: 7px 14px; font-size: var(--type-small); }

/* The viewport. touch-action: none is what lets one finger drag and two pinch inside it; the page around it still scrolls, and the rest of the card (the bar, the legend, the panel) is where a finger can leave the map. */
.im-view {
  position: relative;
  height: min(62vh, 520px);
  min-height: 340px;
  border: .5px solid var(--line);
  border-radius: 18px;
  background: var(--surface);
  overflow: hidden;
  touch-action: none;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.im-view.is-dragging { cursor: grabbing; }
.im-svg { display: block; width: 100%; height: 100%; }
.im-svg text { pointer-events: none; font-family: inherit; }

.im-edge { fill: none; stroke: var(--line); stroke-width: 1; }

.im-node { cursor: pointer; outline: none; }
.im-box { fill: var(--surface-2); stroke: var(--line); stroke-width: .6; }
.im-node.im-group .im-box { stroke-dasharray: 5 4; }
.im-node.is-selected .im-box { stroke: var(--ink); stroke-width: 1.2; }
.im-node:focus-visible .im-box { stroke: var(--focus); stroke-width: 1.5; }
.im-name { font-size: var(--type-label); font-weight: 300; fill: var(--ink); }
.im-sub { font-size: var(--type-tag); font-weight: 200; fill: var(--muted); }
.im-badge { fill: var(--surface); stroke: var(--line); stroke-width: .6; }
.im-count { font-size: var(--type-tag); font-weight: 300; fill: var(--ink); }

/* A node's kind: the pip on the node and the dot in the legend and the panel are the same colour. */
.im-node.im-domain .im-pip, .im-dot.im-domain { fill: var(--map-domain); background: var(--map-domain); }
.im-node.im-app .im-pip, .im-dot.im-app { fill: var(--map-app); background: var(--map-app); }
.im-node.im-tab .im-pip, .im-dot.im-tab { fill: var(--map-tab); background: var(--map-tab); }
.im-node.im-group .im-pip, .im-dot.im-group { fill: var(--map-group); background: var(--map-group); }
.im-node.im-cloud .im-pip, .im-dot.im-cloud { fill: var(--map-cloud); background: var(--map-cloud); }
.im-node.im-store .im-pip, .im-dot.im-store { fill: var(--map-store); background: var(--map-store); }
.im-node.im-mac .im-pip, .im-dot.im-mac { fill: var(--map-mac); background: var(--map-mac); }
.im-node.im-ext .im-pip, .im-dot.im-ext { fill: var(--map-ext); background: var(--map-ext); }

.im-legend { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: var(--card-detail-gap) 0 0; padding: 0; list-style: none; font-size: var(--type-label); color: var(--muted); }
.im-key { display: inline-flex; align-items: center; gap: 6px; }
.im-dot { display: inline-block; flex: none; width: 10px; height: 10px; border-radius: 50%; }

/* The panel under the map: what the selected node is and what it stands on. */
.im-detail { margin-top: var(--card-box-gap); padding-top: var(--card-detail-gap); border-top: .5px solid var(--line); min-height: 4.5em; }
.im-d-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.im-d-title { font-size: var(--type-lead); font-weight: 300; color: var(--ink); }
.im-d-kind { font-size: var(--type-label); color: var(--muted); }
.im-d-sub { margin-top: 3px; font-size: var(--type-small); color: var(--muted); }
.im-d-label { font-size: var(--type-label); color: var(--muted); }
.im-facts { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 6px 14px; margin: var(--card-detail-gap) 0 0; font-size: var(--type-small); }
.im-facts dt { color: var(--muted); }
.im-facts dd { margin: 0; color: var(--ink); overflow-wrap: anywhere; }
.im-also { margin: 4px 0 0; padding: 0; list-style: none; }
.im-link { padding: 3px 0; border: 0; background: none; font: inherit; font-size: var(--type-small); color: var(--ink); text-align: left; text-decoration: underline; text-decoration-color: var(--line); cursor: pointer; }
.im-link:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.im-d-src { margin-top: var(--card-detail-gap); overflow-wrap: anywhere; }

/* A flow chart (flowChart.mjs) takes the whole row, centred, bare: no card around it. The picture is its real size and shrinks to fit a narrow screen; the panel under it is as wide as reads well. */
.fl { grid-column: 1 / -1; display: flex; flex-direction: column; align-items: center; gap: var(--card-detail-gap); }
.fl-svg { display: block; flex: none; max-width: 100%; height: auto; }
/* The data-flow chart at its natural size, on a page that scrolls as a whole (owner, 2026-11-02): never shrunk, never in a box of its own. The host is as wide as the drawing, so the document scrolls sideways;
   the stamp and the detail panel stick to the left edge of the view so they are never scrolled out of sight. */
.fl.fl-wide { align-items: flex-start; width: max-content; min-width: 100%; }
.fl-svg.fl-natural { max-width: none; width: auto; height: auto; }
.fl-wide .fl-legend, .fl-wide .fl-stamp, .fl-wide .fl-detail { position: sticky; left: var(--page-gutter, 24px); width: min(720px, calc(100vw - 2 * var(--page-gutter, 24px))); box-sizing: border-box; }
.fl-svg text { font-family: inherit; pointer-events: none; }
.fl-svg .im-box { stroke: none; fill: var(--surface-2); }
.fl-svg .im-edge { stroke-width: 1; }
.fl-node { cursor: pointer; outline: none; }
.fl-node:focus-visible .im-box { stroke: var(--focus); stroke-width: 1.2; }
/* The state of a piece is the TINT OF ITS OWN BOX (owner, 2026-11-01: "leverage the colour of the card itself"): dark, with a wash of green, amber or red. The word (OK, Late, Down, Silent,
   Unknown) is always written inside the box as well, so the colour is never the only carrier. Unknown has no tint at all: nothing is known, so nothing is claimed. Silent is a cool grey-blue:
   the Mac stopped talking, which is not the same as a failure. A touched box is told from the rest by being brighter, not by an outline. */
.fl-svg .im-box { fill: var(--surface-2); }
.fl-svg .st-ok .im-box { fill: color-mix(in srgb, var(--status-ok) 22%, var(--surface-2)); }
.fl-svg .st-late .im-box { fill: color-mix(in srgb, var(--status-warn) 30%, var(--surface-2)); }
.fl-svg .st-down .im-box { fill: color-mix(in srgb, var(--status-bad) 34%, var(--surface-2)); }
.fl-svg .st-silent .im-box { fill: color-mix(in srgb, #6C8FB8 30%, var(--surface-2)); }
.fl-node.is-selected .im-box { filter: brightness(1.4); }
.fl-chip { display: inline-block; padding: 1px 10px; border-radius: 99px; font-size: var(--type-label); color: var(--ink); background: var(--surface-2); }
.fl-chip.st-ok { background: color-mix(in srgb, var(--status-ok) 30%, var(--surface-2)); }
.fl-chip.st-late { background: color-mix(in srgb, var(--status-warn) 38%, var(--surface-2)); }
.fl-chip.st-down { background: color-mix(in srgb, var(--status-bad) 42%, var(--surface-2)); }
.fl-chip.st-silent { background: color-mix(in srgb, #6C8FB8 38%, var(--surface-2)); }
/* The lines of a data-flow chart: straight, with a head at the end the data goes to. A wide invisible stroke under each is what a finger lands on. */
.fl-edge { cursor: pointer; outline: none; }
.fl-hit { fill: none; stroke: transparent; stroke-width: 16; }
.fl-line { fill: none; stroke: var(--muted); stroke-width: .4; }                /* hairline-thin (owner, 2026-11-01: "extremely thinner") */
.fl-head { fill: var(--muted); stroke: none; }
.fl-edge:hover .fl-line, .fl-edge.is-selected .fl-line, .fl-edge:focus-visible .fl-line { stroke: var(--ink); stroke-width: .7; }
.fl-edge:hover .fl-head, .fl-edge.is-selected .fl-head, .fl-edge:focus-visible .fl-head { fill: var(--ink); }
.fl-edge-label { font-size: var(--type-body); font-weight: 100; fill: var(--muted); pointer-events: none; paint-order: stroke; stroke: var(--bg, #000); stroke-width: 3px; stroke-linejoin: round; }
.fl-edge.is-selected .fl-edge-label { fill: var(--ink); }
.fl-root-title { font-size: var(--type-display); font-weight: 100; fill: var(--ink); }
.fl-root-site { font-size: var(--type-label); font-weight: 200; fill: var(--muted); }
.fl-tab-title { font-size: var(--type-heading); font-weight: 100; fill: var(--ink); }
.fl-sub { font-size: var(--type-caption); font-weight: 200; fill: var(--muted); }
.fl-name { font-size: var(--type-small); font-weight: 200; fill: var(--ink); }
.fl-where { fill: var(--muted); }
/* A Pages box is a rack of two units on two feet (flowChart.mjs rackPair): the units take the state's tint through .im-box above, the lamps its colour. */
.fl-slot { fill: var(--muted); opacity: .45; }
.fl-foot { fill: var(--muted); opacity: .35; }
.fl-lamp { fill: var(--muted); }
.fl-svg .st-ok .fl-lamp { fill: var(--status-ok); }
.fl-svg .st-late .fl-lamp { fill: var(--status-warn); }
.fl-svg .st-down .fl-lamp { fill: var(--status-bad); }
.fl-svg .st-silent .fl-lamp { fill: #6C8FB8; }
.fl-state { fill: var(--ink); }
/* The Pages server on the data-flow chart (flowChart.mjs serverNode): one tower of five drawers with a dashed base, names above it. The dots in the drawers are its lights (owner, 2026-11-02): the colour is the state's own and each
   state blinks the way a real machine does, every dot at its own rate. Working: activity lights flickering. Late: all blink slowly together. Down: steady on, nothing moving. Silent: a slow dim breathing.
   Unknown: the dots stay a quiet grey: nothing is known, so nothing is claimed. */
.fl-hitbox { fill: transparent; stroke: none; }
.fl-svg .fl-body { fill: var(--surface-2); stroke: var(--ink); stroke-width: .25; }               /* a thin outline in the tower's own units (scaled to .75px) */
.fl-svg .fl-slotbox { fill: none; stroke: var(--muted); stroke-width: .4; }
.fl-divider { fill: none; stroke: var(--muted); stroke-width: .4; }
.fl-vent { fill: none; stroke: var(--muted); stroke-width: .55; stroke-linecap: round; }
.fl-led { fill: var(--muted); }
.fl-node.is-selected .fl-body { filter: brightness(1.4); }
.fl-node:focus-visible .fl-body { stroke: var(--focus); stroke-width: 1.5; }
.fl-svg .st-ok .fl-led { fill: var(--status-ok); animation: fl-flicker var(--d, 1.5s) linear infinite; animation-delay: var(--dl, 0s); }
.fl-svg .st-late .fl-led { fill: var(--status-warn); animation: fl-blink 1.6s step-end infinite; }
.fl-svg .st-down .fl-led { fill: var(--status-bad); }
.fl-svg .st-silent .fl-led { fill: #6C8FB8; animation: fl-breathe 4s ease-in-out infinite; }
@keyframes fl-flicker { 0%, 100% { fill-opacity: 1; } 8% { fill-opacity: .15; } 14% { fill-opacity: 1; } 38% { fill-opacity: 1; } 44% { fill-opacity: .2; } 52% { fill-opacity: 1; } 71% { fill-opacity: .1; } 76% { fill-opacity: 1; } }
@keyframes fl-blink { 0%, 49% { fill-opacity: 1; } 50%, 100% { fill-opacity: .12; } }
@keyframes fl-breathe { 0%, 100% { fill-opacity: .15; } 50% { fill-opacity: .7; } }
@media (prefers-reduced-motion: reduce) {
  .fl-svg .st-ok .fl-led, .fl-svg .st-late .fl-led, .fl-svg .st-silent .fl-led { animation: none; }
  .fl-svg .st-silent .fl-led { fill-opacity: .45; }
}
.fl-dash { fill: none; stroke: var(--ink); stroke-width: .5; stroke-linecap: round; }
.fl-node.is-selected .fl-body { filter: brightness(1.4); }
.fl-node:focus-visible .fl-body { stroke: var(--focus); stroke-width: 1.5; }
.fl-stamp { font-size: var(--type-label); color: var(--muted); text-align: center; }
.fl-detail { width: 100%; max-width: 720px; padding: var(--card-detail-gap) 4px 0; }
.fl-why { margin-bottom: var(--card-detail-gap); }
.fl-logs { margin-top: 4px; padding: 10px 12px; border-radius: 12px; background: var(--surface-2); font-family: var(--font-mono); font-size: var(--type-caption); line-height: 1.5; color: var(--ink); white-space: pre-wrap; overflow-wrap: anywhere; max-height: 240px; overflow-y: auto; scrollbar-width: thin; }
.fl-logs:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

@media (max-width: 480px) {
  .im-facts { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .im-facts dd { margin-bottom: 6px; }
}
@media (min-width: 900px) {
  /* The map takes the whole row: it is the one card on the page that is a picture of all the others. */
  .page:not(.page-sub) .card.map-card { grid-column: 1 / -1; max-width: none; width: 100%; }
  .im-view { height: min(66vh, 640px); }
}

/* MOCK-UP panel of an outside service (flowChart.mjs mockUsagePanel): three layouts, A / B / C. */
.fl-mockbar { display: flex; align-items: center; gap: 6px; margin-top: var(--card-detail-gap); flex-wrap: wrap; }
.fl-mocktag { font-size: var(--type-caption); color: var(--status-warn); margin-right: 6px; }
.fl-vtab { font: inherit; font-size: var(--type-caption); color: var(--muted); background: var(--surface-2); border: 0; border-radius: 99px; padding: 2px 12px; cursor: pointer; }
.fl-vtab.is-on { color: var(--ink); background: var(--surface-3, var(--surface-2)); box-shadow: inset 0 0 0 .5px var(--line); }
.fl-calls { display: grid; gap: 4px; margin-top: 6px; font-size: var(--type-small); }
.fl-call { display: grid; grid-template-columns: 92px 150px minmax(0, 1fr); gap: 10px; color: var(--ink); }
.fl-call-when, .fl-call-why { color: var(--muted); }
.fl-call.is-bad .fl-call-what { color: var(--status-bad); }
.fl-sumline { margin-top: var(--card-detail-gap); font-size: var(--type-small); color: var(--ink); }
.fl-strip { display: block; margin-top: 8px; max-width: 100%; }
.fl-bar { fill: var(--muted); opacity: .75; }
.fl-bar.is-bad { fill: var(--status-bad); opacity: 1; }
.fl-failcard { margin-top: 10px; padding: 8px 12px; border-radius: 12px; background: color-mix(in srgb, var(--status-bad) 16%, var(--surface-2)); }
.fl-failwhy { font-size: var(--type-small); color: var(--ink); overflow-wrap: anywhere; }

/* An API card (flowChart.mjs apiCard): a folded, rounded card with curly braces; the fold is a touch lighter than the body, the braces are the ink colour. */
.fl-apifold { fill: color-mix(in srgb, var(--ink) 14%, var(--surface-2)); stroke: color-mix(in srgb, var(--ink) 14%, var(--surface-2)); stroke-width: 7; stroke-linejoin: round; }
.fl-apibrace { font-size: 26px; font-weight: 100; fill: var(--ink); }
.fl-apiname { font-weight: 300; }

/* The card IS the device (flowChart.mjs deviceCard): hairline frames, the screen tinted by the state (green online), the browser's bar or the home-screen app's icon drawn on it. */
.fl-devframe { fill: var(--surface); stroke: var(--ink); stroke-width: .8; stroke-linejoin: round; stroke-linecap: round; }
.fl-devframe.is-dashed { stroke-dasharray: 4 3; }
.fl-devscreen { stroke: none; }
.fl-devink { fill: var(--ink); stroke: none; }
.fl-devcut { fill: var(--bg, #000); stroke: var(--ink); stroke-width: .5; }
.fl-devbar { fill: none; stroke: var(--muted); stroke-width: .7; stroke-linecap: round; stroke-linejoin: round; }
.fl-devq { font-size: 34px; font-weight: 100; fill: var(--ink); }

/* The engine folder (a laptop with the folder on its screen) and a script card with its status dot. */
.fl-svg .fl-lapframe { fill: var(--surface-2); stroke: color-mix(in srgb, var(--ink) 45%, transparent); stroke-width: 1; stroke-linejoin: round; }
.fl-svg .fl-folder { fill: color-mix(in srgb, var(--ink) 12%, var(--surface-2)); stroke: color-mix(in srgb, var(--ink) 55%, transparent); stroke-width: 1; stroke-linejoin: round; }
.fl-svg .fl-scrdot { fill: color-mix(in srgb, var(--ink) 35%, transparent); }
.fl-svg .st-ok .fl-scrdot { fill: var(--ok, #6fb58f); }
.fl-svg .st-down .fl-scrdot { fill: var(--bad, #e08a7a); }

/* A Worker: a hexagon with a clock on its left point. */
.fl-svg .fl-hex { stroke-linejoin: round; }
.fl-svg .fl-clock { fill: none; stroke: color-mix(in srgb, var(--ink) 55%, transparent); stroke-width: 1.1; stroke-linecap: round; stroke-linejoin: round; }

/* Lines that only watch (Nini's checks, a clock's "I ran" note) are dashed, so the working lines of the app stand out from the monitoring. */
.fl-edge.is-watch .fl-line { stroke-dasharray: 3 4; stroke-width: .6; opacity: .55; }
.fl-edge.is-watch .fl-head { opacity: .55; }
.fl-svg.fl-curved .fl-line { stroke-width: .9; }
.fl-svg.fl-curved .fl-edge:hover .fl-line, .fl-svg.fl-curved .fl-edge.is-selected .fl-line { stroke-width: 1.4; }

/* THE SWIMLANES, FOCUS AND THE KEY (owner, 2026-11-04). A lane is a quiet panel with its name in small capitals; the watchers' column is outlined by a dashed line, like their lines. */
.fl-svg .fl-zone { fill: color-mix(in srgb, var(--ink) 3.5%, transparent); stroke: color-mix(in srgb, var(--ink) 9%, transparent); stroke-width: 1; }
.fl-svg .fl-zone.is-watchzone { stroke-dasharray: 4 5; fill: transparent; }
.fl-svg .fl-zone-title { font-size: var(--type-caption); font-weight: 200; letter-spacing: .08em; text-transform: uppercase; fill: var(--muted); }
.fl-edge, .fl-node { transition: opacity .15s ease; }
.fl-edge.is-dim, .fl-node.is-dim { opacity: .2; }
.fl-edge.is-lit .fl-line { stroke: var(--ink); stroke-width: 1.2; }
.fl-edge.is-lit .fl-head { fill: var(--ink); }
.fl-edge.is-lit .fl-edge-label { fill: var(--ink); }
.fl-edge.is-plain .fl-line { stroke-dasharray: 1 4; stroke-linecap: round; }
.fl-legend { display: flex; flex-wrap: wrap; gap: 6px 22px; align-items: center; margin: 0 0 12px; font-size: var(--type-caption); font-weight: 200; color: var(--muted); }
.fl-key { display: inline-flex; align-items: center; gap: 8px; }
.fl-key .fl-line { fill: none; stroke: var(--muted); stroke-width: 1.1; }
.fl-key .fl-line.is-watchline { stroke-dasharray: 3 4; opacity: .7; }
.fl-key .fl-line.is-plainline { stroke-dasharray: 1 4; stroke-linecap: round; }
.fl-key .fl-head { fill: var(--muted); }
.fl-key-hint { margin-left: auto; }

/* THE WORDS ARE ON DEMAND (owner, 2026-11-04: "extremely confusing and unreadable"): with 40 lines, a label on each buried the picture. A line's words show when it is lit, touched or selected, or when "Show all words" is on.
   Lines that only watch recede far back, and a sync is one line with a head at each end. */
.fl-svg.fl-curved .fl-edge-label { opacity: 0; transition: opacity .12s ease; }
.fl-edge.is-lit .fl-edge-label, .fl-edge:hover .fl-edge-label, .fl-edge.is-selected .fl-edge-label, .fl-showwords .fl-svg.fl-curved .fl-edge-label { opacity: 1; }
.fl-showwords .fl-edge.is-dim .fl-edge-label { opacity: .5; }
.fl-svg.fl-curved .fl-edge.is-watch:not(.is-lit):not(.is-selected) .fl-line { opacity: .3; stroke-width: .5; }
.fl-svg.fl-curved .fl-edge.is-watch:not(.is-lit):not(.is-selected) .fl-head { opacity: .3; }
.fl-words { font: inherit; color: var(--ink); background: var(--surface-2); border: 0; border-radius: 99px; padding: 3px 12px; cursor: pointer; }
.fl-words[aria-pressed="true"] { background: color-mix(in srgb, var(--ink) 22%, var(--surface-2)); }

/* A link box: a dashed pill, the doorway to the other page. */
.fl-svg .im-box.fl-link { fill: transparent; stroke: color-mix(in srgb, var(--ink) 40%, transparent); stroke-width: 1; stroke-dasharray: 4 4; }
.fl-svg .fl-linkarrow { fill: none; stroke: var(--muted); stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.fl-node:hover .im-box.fl-link { stroke: var(--ink); }
