<!-- SOLID CITY · part 80 -->
0-10, the King: "photograph the menu too").
   A small self-contained DOM-to-canvas renderer (no third-party code): every visible HUD layer / open panel is cloned
   with its computed styles inlined, images/canvases/fonts inlined as data: URLs, ::before/::after turned into real
   spans, scroll positions kept, then drawn through an SVG <foreignObject> at the TARGET scale, so text stays sharp.
   Glass (backdrop-filter: blur) is reproduced by blurring the world pixels under the glass before the layer is drawn.
   One layer that cannot render is skipped (reported), never the whole shot. window.CityDomShot.compose(ctx, W, H, opts). */
(function () {
'use strict';
var SVGNS = 'http://www.w3.org/2000/svg', XHTML = 'http://www.w3.org/1999/xhtml';
var PROPS = ['display', 'box-sizing', 'width', 'height', 'min-width', 'min-height', 'max-width', 'max-height',
  'padding-top', 'padding-right', 'padding-bottom', 'padding-left', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
  'border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width', 'border-top-style', 'border-right-style', 'border-bottom-style', 'border-left-style',
  'border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color', 'border-top-left-radius', 'border-top-right-radius', 'border-bottom-right-radius', 'border-bottom-left-radius',
  'background-color', 'background-image', 'background-size', 'background-position', 'background-repeat', 'background-clip', 'background-origin', '-webkit-background-clip', '-webkit-text-fill-color',
  'color', 'font-family', 'font-size', 'font-weight', 'font-style', 'font-stretch', 'font-variant-numeric', 'line-height', 'letter-spacing', 'word-spacing', 'text-align', 'text-transform', 'text-indent',
  'text-decoration-line', 'text-decoration-color', 'text-decoration-style', 'text-shadow', 'white-space', 'word-break', 'overflow-wrap', 'text-overflow', 'overflow-x', 'overflow-y',
  'opacity', 'box-shadow', 'transform', 'transform-origin', 'filter', 'position', 'left', 'top', 'right', 'bottom', 'z-index', 'float', 'clear',
  'flex-direction', 'flex-wrap', 'justify-content', 'justify-items', 'align-items', 'align-self', 'align-content', 'row-gap', 'column-gap', 'flex-grow', 'flex-shrink', 'flex-basis', 'order',
  'grid-template-columns', 'grid-template-rows', 'grid-column-start', 'grid-column-end', 'grid-row-start', 'grid-row-end', 'grid-auto-flow', 'grid-auto-rows', 'grid-auto-columns', 'place-items',
  'vertical-align', 'list-style-type', 'list-style-position', 'object-fit', 'object-position', 'visibility', 'clip-path', 'mix-blend-mode', 'isolation',
  '-webkit-line-clamp', '-webkit-box-orient', 'table-layout', 'border-collapse', 'border-spacing', 'caption-side', 'empty-cells', 'accent-color', 'appearance', '-webkit-appearance',
  'fill', 'stroke', 'stroke-width', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'tab-size', 'direction', 'unicode-bidi', 'writing-mode'];
var SKIP = { SCRIPT: 1, STYLE: 1, NOSCRIPT: 1, TEMPLATE: 1, LINK: 1, META: 1, AUDIO: 1, VIDEO: 1, IFRAME: 1 };
var dataCache = {};
function toDataURL(url) {
  if (!url || /^data:/.test(url)) return Promise.resolve(url);
  if (dataCache[url]) return dataCache[url];
  return (dataCache[url] = fetch(url, { credentials: 'same-origin', cache: 'force-cache' }).then(function (r) { if (!r.ok) throw new Error(r.status); return r.blob(); })
    .then(function (b) { return new Promise(function (res, rej) { var fr = new FileReader(); fr.onload = function () { res(fr.result); }; fr.onerror = rej; fr.readAsDataURL(b); }); })
    .catch(function () { return ''; }));
}
function shown(el, cs) { cs = cs || getComputedStyle(el); if (el.hidden || cs.display === 'none' || cs.visibility === 'hidden' || +cs.opacity < 0.01) return false; var r = el.getBoundingClientRect(); return r.width > 0 && r.height > 0 && r.right > 0 && r.bottom > 0 && r.left < innerWidth && r.top < innerHeight; }
function copyStyle(cs, dst, extra) {
  var s = '';
  for (var i = 0; i < PROPS.length; i++) { var v = cs.getPropertyValue(PROPS[i]); if (v !== '' && v != null) { if ((PROPS[i] === 'overflow-x' || PROPS[i] === 'overflow-y') && (v === 'auto' || v === 'scroll')) v = 'hidden'; s += PROPS[i] + ':' + v + ';'; } }
  s += 'scrollbar-width:none;';
  s += 'backdrop-filter:none;-webkit-backdrop-filter:none;transition:none;animation:none;caret-color:transparent;' + (extra || '');
  dst.setAttribute('style', s);
}
function pseudo(el, which, job) {
  var cs = getComputedStyle(el, which), c = cs.getPropertyValue('content');
  if (!c || c === 'none' || c === 'normal') return null;
  var span = document.createElement('span'), txt = '';
  if (/^["']/.test(c)) txt = c.slice(1, -1).replace(/\\([0-9a-f]{1,6}) ?/gi, function (m, h) { return String.fromCodePoint(parseInt(h, 16)); }).replace(/\\(.)/g, '$1');
  else if (!/^(url|counter|attr)/.test(c) && c !== '""') return null;
  span.textContent = txt; copySty