diff --git a/.vscode/settings.json b/.vscode/settings.json index a21033b..b3d8d89 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { + "editor.rulers": [100], "editor.scrollBeyondLastLine": false, "editor.tabSize": 3, "files.insertFinalNewline": true, diff --git a/dist/blogger-tweaks.min.css b/dist/blogger-tweaks.min.css index 4338d02..a2d25c5 100644 --- a/dist/blogger-tweaks.min.css +++ b/dist/blogger-tweaks.min.css @@ -1,4 +1,4 @@ -/*! web-ignition v2.2.0 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ +/*! web-ignition v2.2.1 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ #header-container #header .header-bar .title h3{border-bottom:2px solid transparent;margin-left:20px;transition:all 400ms}#header-container #header .header-bar .title h3:hover{border-color:#000}#header-container #header .header-drawer{top:35px;box-shadow:none}#header-container #header .header-drawer #views.menu{display:none;visibility:hidden;max-width:0;max-height:0;opacity:0;z-index:-10000}#main #sidebar{width:340px;margin-top:-30px;box-shadow:none}#main #sidebar .items .item{box-shadow:none;transition:400ms background-color}#main #sidebar .items .item:hover{background-color:#fff}#main #sidebar .items .item h3.title{font-size:1rem}#main #content{margin-left:360px}#main #content .article .article-header h1.title{font-size:2rem;font-weight:700;padding-right:0}#main #content .article .article-content{font-size:1.2rem;text-align:left;word-break:normal;margin-bottom:40px}#main #content .article .article-content table{border-collapse:collapse;margin-bottom:20px}#main #content .article .article-content table caption{font-size:.9rem;font-weight:700;text-transform:uppercase;letter-spacing:.16em;color:#696969;margin:.4rem 0}#main #content .article .article-content table thead tr{border-bottom:3px solid #4682b4}#main #content .article .article-content table thead tr th{text-align:left;padding:4px 10px}#main #content .article .article-content table tbody tr{border-bottom:1px solid #4682b4;transition:all 400ms}#main #content .article .article-content table tbody tr:hover{background-color:#f0f8ff}#main #content .article .article-content table tbody tr th[colspan]{font-size:.9rem;text-align:center;text-transform:uppercase;color:#fff;background-color:#4682b4}#main #content .article .article-content table tbody tr td{vertical-align:top;padding:4px 10px}#main #content .article .article-content output{display:block;background-color:#f0fff0;border:3px solid #8fbc8f;padding:0 10px 5px;margin-bottom:20px;overflow:hidden}#main #content .article .article-content output>h2{font-size:1.3rem;color:#fff;background-color:#8fbc8f;padding:0 10px 3px;margin:0-10px 5px}#main #content .article .article-content output>pre{margin:0 0-1.2em -3.3em;overflow-x:scroll;overflow-y:hidden}#attribution-container,#main #content .article .article-content .hide-me,body>.viewitem-panel{display:none;visibility:hidden;max-width:0;max-height:0;opacity:0;z-index:-10000}#main #content .article .article-content .indent{display:block;margin-left:30px}#main #content .article .article-content .framed,#main #content .article .article-content .framed-padded{border:15px solid silver}#main #content .article .article-content .framed-padded{padding:15px}#main #content .article .article-content .highlight{background-color:#ffffe0;padding:0 3px}#main #content .article .article-content .highlight2{padding:0 3px;background-color:#ffe4e1}#main #content .article .article-content *{box-sizing:border-box}#main #content .article .article-content h2{font-size:1.2rem;font-weight:100;letter-spacing:.08rem;text-align:center;color:gray;margin:-10px 0 20px}#main #content .article .article-content h3{margin-bottom:5px}#main #content .article .article-content nav{clear:both;border:1px solid silver;padding:10px 20px;background-color:#f5f5f5;margin-bottom:20px}#main #content .article .article-content nav ol,#main #content .article .article-content nav ul{margin:0}#main #content .article .article-content p{margin-top:0}#main #content .article .article-content ol,#main #content .article .article-content ul{padding-left:3em;margin:0 0 1em}#main #content .article .article-content pre{word-break:normal;word-wrap:normal}#main #content .article .article-content img{max-width:100%;border-image:none;border-width:0;padding:0;margin:0}#main #content .article .article-content figure{text-align:center;margin:0 0 20px}#main #content .article .article-content figure.full-width img{max-height:none}#main #content .article .article-content figure.small-image img{max-height:120px}#main #content .article .article-content figure figcaption{font-weight:700}#main #content .article .article-content figure img{max-height:200px}#main #content .article .article-content figure.hljs-enhance{clear:both;text-align:left}#main #content .article .article-content figure.hljs-enhance figcaption{font-size:1.1rem}#main #content .article .article-content aside{float:right;max-width:150px;margin:0 0 15px 20px}#main #content .article .article-content aside.left{float:left;margin:0 20px 15px 0}#main #content .article .article-content>footer{text-align:center;border-top:1px solid silver;padding-top:35px;margin-top:40px}#main #content .article .article-content>footer>i{font-weight:lighter}#main #content .article .article-footer{border-top:1px solid silver} /* diff --git a/dist/layouts/block-duo.css b/dist/layouts/block-duo.css index 14ce391..73c8632 100644 --- a/dist/layouts/block-duo.css +++ b/dist/layouts/block-duo.css @@ -1,4 +1,4 @@ -/*! web-ignition v2.2.0 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ +/*! web-ignition v2.2.1 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ /* Block Duo layout -- Two big columns followed by a single footer diff --git a/dist/layouts/color-blocks.css b/dist/layouts/color-blocks.css index 199a0ec..2df626c 100644 --- a/dist/layouts/color-blocks.css +++ b/dist/layouts/color-blocks.css @@ -1,4 +1,4 @@ -/*! web-ignition v2.2.0 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ +/*! web-ignition v2.2.1 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ /* Color Blocks layout -- Two columns of colorful blocks diff --git a/dist/layouts/color-slide.css b/dist/layouts/color-slide.css index a8cfa10..0f18abe 100644 --- a/dist/layouts/color-slide.css +++ b/dist/layouts/color-slide.css @@ -1,4 +1,4 @@ -/*! web-ignition v2.2.0 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ +/*! web-ignition v2.2.1 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ /* Color Slide layout -- Top to botttom color transition diff --git a/dist/layouts/letterbox.css b/dist/layouts/letterbox.css index 52b3aa2..9a335e2 100644 --- a/dist/layouts/letterbox.css +++ b/dist/layouts/letterbox.css @@ -1,4 +1,4 @@ -/*! web-ignition v2.2.0 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ +/*! web-ignition v2.2.1 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ /* Letterbox layout -- Edge-to-edge semi-opaque bar over cover background image diff --git a/dist/layouts/modern.css b/dist/layouts/modern.css index 5b39871..9b5c066 100644 --- a/dist/layouts/modern.css +++ b/dist/layouts/modern.css @@ -1,4 +1,4 @@ -/*! web-ignition v2.2.0 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ +/*! web-ignition v2.2.1 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ /* Modern layout -- Clean blog post page diff --git a/dist/layouts/neon.css b/dist/layouts/neon.css index e3ec629..5207d29 100644 --- a/dist/layouts/neon.css +++ b/dist/layouts/neon.css @@ -1,4 +1,4 @@ -/*! web-ignition v2.2.0 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ +/*! web-ignition v2.2.1 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ /* Neon layout -- For hackers and space junkies diff --git a/dist/layouts/neon.min.js b/dist/layouts/neon.min.js index f18a62e..4f10df5 100644 --- a/dist/layouts/neon.min.js +++ b/dist/layouts/neon.min.js @@ -1,2 +1,2 @@ -//! web-ignition v2.2.0 ~~ https://github.com/center-key/web-ignition ~~ MIT License +//! web-ignition v2.2.1 ~~ https://github.com/center-key/web-ignition ~~ MIT License const numNeonImages=8;const randomImage=Date.now()%numNeonImages+1;globalThis.document.body.classList.add("neon-image-"+String(randomImage)); diff --git a/dist/layouts/vertical-bars.css b/dist/layouts/vertical-bars.css index 578a82f..168b962 100644 --- a/dist/layouts/vertical-bars.css +++ b/dist/layouts/vertical-bars.css @@ -1,4 +1,4 @@ -/*! web-ignition v2.2.0 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ +/*! web-ignition v2.2.1 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ /* Vertical Bars layout -- traditional boring old-school webpage diff --git a/dist/layouts/zebra-sections.css b/dist/layouts/zebra-sections.css index 8493021..1c581a2 100644 --- a/dist/layouts/zebra-sections.css +++ b/dist/layouts/zebra-sections.css @@ -1,4 +1,4 @@ -/*! web-ignition v2.2.0 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ +/*! web-ignition v2.2.1 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ /* Zebra Sections layout -- Edge-to-edge blocks with alternating background colors @@ -20,7 +20,10 @@ HTML (
): section h2 img + p div + blockquote + cite footer */ body { @@ -138,9 +141,31 @@ main >section >div { /* centered flow box */ display: flex; flex-wrap: wrap; justify-content: center; + column-gap: 40px; + row-gap: 20px; } -main >section >div >* { - margin: 0px 20px 20px 20px; +main >section >div >blockquote { + display: block; + width: 100%; + font-size: 1.2rem; + font-style: italic; + text-align: left; + border: 1px solid silver; + padding: 10px 25px; + margin: 0px; + } +main >section >div >blockquote >cite { + display: block; + font-size: 0.8rem; + font-weight: 100; + font-style: normal; + letter-spacing: 0.05em; + text-align: right; + padding-top: 5px; + } +main >section >div >blockquote >cite::before { + content: "\2014"; /* character: — (em dash) */ + margin-right: 0.4em; } main >section >ul { width: 80%; @@ -167,10 +192,13 @@ main >section figure img.popup-image:hover { main >section figure figcaption { font-style: italic; } -main >section >blockquote { +main >section code { + white-space: normal; + } +main >section >blockquote { /* deprecated */ font-style: italic; } -main >section >blockquote cite { +main >section >blockquote cite { /* deprecated */ display: block; font-size: 0.8rem; font-weight: 100; diff --git a/dist/lib-x.d.ts b/dist/lib-x.d.ts index 6108392..7ddecc9 100644 --- a/dist/lib-x.d.ts +++ b/dist/lib-x.d.ts @@ -1,4 +1,4 @@ -//! web-ignition v2.2.0 ~~ https://github.com/center-key/web-ignition ~~ MIT License +//! web-ignition v2.2.1 ~~ https://github.com/center-key/web-ignition ~~ MIT License export type GlobalKey = keyof typeof globalThis; export type Json = string | number | boolean | null | undefined | JsonObject | Json[]; diff --git a/dist/lib-x.dev.js b/dist/lib-x.dev.js index 52728bf..df7cf87 100644 --- a/dist/lib-x.dev.js +++ b/dist/lib-x.dev.js @@ -1,4 +1,4 @@ -//! web-ignition v2.2.0 ~~ https://github.com/center-key/web-ignition ~~ MIT License +//! web-ignition v2.2.1 ~~ https://github.com/center-key/web-ignition ~~ MIT License const libXDom = { stateDepot: [], @@ -826,7 +826,7 @@ const libXExtra = { }, }; const libX = { - version: '2.2.0', + version: '2.2.1', dom: libXDom, ui: libXUi, util: libXUtil, diff --git a/dist/lib-x.js b/dist/lib-x.js index c729273..95561c0 100644 --- a/dist/lib-x.js +++ b/dist/lib-x.js @@ -1,4 +1,4 @@ -//! web-ignition v2.2.0 ~~ https://github.com/center-key/web-ignition ~~ MIT License +//! web-ignition v2.2.1 ~~ https://github.com/center-key/web-ignition ~~ MIT License const libXDom = { stateDepot: [], @@ -826,7 +826,7 @@ const libXExtra = { }, }; const libX = { - version: '2.2.0', + version: '2.2.1', dom: libXDom, ui: libXUi, util: libXUtil, diff --git a/dist/lib-x.min.js b/dist/lib-x.min.js index c798761..51f4080 100644 --- a/dist/lib-x.min.js +++ b/dist/lib-x.min.js @@ -1,2 +1,2 @@ -//! web-ignition v2.2.0 ~~ https://github.com/center-key/web-ignition ~~ MIT License -const libXDom={stateDepot:[],state(elem){const data=elem.dataset;elem.classList.add("libx-state");if(!data.libXState)data.libXState=String(libX.dom.stateDepot.push({})-1);return libX.dom.stateDepot[Number(data.libXState)]},cloneState(clone){const copy=elem=>{const data=elem.dataset;const newState={...libX.dom.stateDepot[Number(data.libXState)]};data.libXState=String(libX.dom.stateDepot.push(newState)-1)};if(clone.classList.contains("libx-state"))copy(clone);libX.dom.forEach(clone.getElementsByClassName("libx-state"),copy);return clone},create(tag,options){const elem=globalThis.document.createElement(tag);if(options?.id)elem.id=options.id;if(options?.class)elem.classList.add(options.class);if(options?.href)elem.href=options.href;if(options?.html)elem.innerHTML=options.html;if(options?.name)elem.name=options.name;if(options?.rel)elem.rel=options.rel;if(options?.src)elem.src=options.src;if(options?.text)elem.textContent=options.text;if(options?.type)elem.type=options.type;if(options?.subTags)options.subTags.forEach(subTag=>elem.appendChild(globalThis.document.createElement(subTag)));return elem},removeState(elem){const data=elem.dataset;if(data.libXState)libX.dom.stateDepot[Number(data.libXState)]={};return elem},select(selector){return globalThis.document.body.querySelector(selector)},selectAll(selector){return[...globalThis.document.body.querySelectorAll(selector)]},hasClass(elems,className){return Array.prototype.some.call(elems,elem=>elem.classList.contains(className))},toggleClass(elem,className,state){if(state===undefined?!elem.classList.contains(className):state)elem.classList.add(className);else elem.classList.remove(className);return elem},replaceClass(elem,oldName,newName){elem.classList.remove(oldName);elem.classList.add(newName);return elem},addClass(elems,className){Array.prototype.forEach.call(elems,elem=>elem.classList.add(className));return elems},forEach(elems,fn){Array.prototype.forEach.call(elems,fn);return elems},map(elems,fn){return Array.prototype.map.call(elems,fn)},filter(elems,fn){return Array.prototype.filter.call(elems,fn)},filterBySelector(elems,selector){return Array.prototype.filter.call(elems,elem=>elem.matches(selector))},filterByClass(elems,...classNames){const hasClass=elem=>elem.classList.contains(classNames[0]);const filtered=Array.prototype.filter.call(elems,hasClass);return classNames.length===1?filtered:libX.dom.filterByClass(filtered,...classNames.splice(1))},find(elems,fn){return Array.prototype.find.call(elems,fn)??null},index(elem){let index=0;let prev=elem.previousElementSibling;while(prev){index++;prev=prev.previousElementSibling}return index},indexOf(elems,elem){return Array.prototype.indexOf.call(elems,elem)},findIndex(elems,selector){return Array.prototype.findIndex.call(elems,elem=>elem.matches(selector))},isElem(elem){return!!elem&&typeof elem==="object"&&!!elem.nodeName},getAttrs(elem){return elem?Object.values(elem.attributes):[]},toElem(elemOrEvent){return libX.dom.isElem(elemOrEvent)?elemOrEvent:elemOrEvent.target},on(type,listener,options){const defaults={keyFilter:null,selector:null};const settings={...defaults,...options};const noFilter=!settings.keyFilter;const noSelector=!settings.selector;const delegator=event=>{const target=event.target;const elem=!target||noSelector?target:target.closest(settings.selector);if(elem&&(noFilter||settings.keyFilter===event.key))listener(elem,event,settings.selector)};globalThis.document.addEventListener(type,delegator)},onClick(listener,selector){libX.dom.on("click",listener,{selector:selector??null})},onChange(listener,selector){libX.dom.on("change",listener,{selector:selector??null})},onInput(listener,selector){libX.dom.on("input",listener,{selector:selector??null})},onKeyDown(listener,selector){libX.dom.on("keydown",listener,{selector:selector??null})},onKeyUp(listener,selector){libX.dom.on("keyup",listener,{selector:selector??null})},onEnterKey(listener,selector){libX.dom.on("keypress",listener,{selector:selector??null,keyFilter:"Enter"})},onFocusIn(listener,selector){libX.dom.on("focusin",listener,{selector:selector??null})},onFocusOut(listener,selector){libX.dom.on("focusin",listener,{selector:selector??null})},onCut(listener,selector){libX.dom.on("cut",listener,{selector:selector??null})},onPaste(listener,selector){libX.dom.on("paste",listener,{selector:selector??null})},onTouchStart(listener,selector){libX.dom.on("touchstart",listener,{selector:selector??null})},onTouchEnd(listener,selector){libX.dom.on("touchend",listener,{selector:selector??null})},onSubmit(listener,selector){libX.dom.on("submit",listener,{selector:selector??null})},onHoverIn(listener,selector){let ready=true;const delegator=event=>{const target=event.target?.closest(selector);if(target!==null&&ready)listener(target,event,selector);ready=target===null};globalThis.document.addEventListener("pointerover",delegator)},onHoverOut(listener,selector){let ready=false;let prevTarget=null;const delegator=event=>{const target=event.target?.closest(selector);prevTarget=target??prevTarget;if(target===null&&ready)listener(prevTarget,event,selector);ready=target!==null};globalThis.document.addEventListener("pointerover",delegator)},onReady(callback,options){const state=globalThis.document?globalThis.document.readyState:"browserless";if(state==="browserless"&&!options?.quiet)console.log((new Date).toISOString(),"Callback run in browserless context");if(["complete","browserless"].includes(state))callback();else globalThis.window.addEventListener("DOMContentLoaded",callback);return state}};const libXUi={isHidden(elem){const computed=globalThis.getComputedStyle(elem);return computed.display==="none"||computed.visibility==="hidden"||computed.visibility==="collapse"||computed.opacity==="0"||elem.clientHeight===0},isVisible(elem){return!libX.ui.isHidden(elem)},show(elem){const style=elem.style;style.removeProperty("display");style.removeProperty("opacity");style.removeProperty("visibility");const computed=globalThis.getComputedStyle(elem);const override=(prop,values,standIn)=>values.includes(computed.getPropertyValue(prop))&&style.setProperty(prop,standIn);override("display",["none"],"block");override("opacity",["0"],"1");override("visibility",["collapse","hidden"],"visible");return elem},hide(elem){elem.style.display="none";return elem},toggle(elem,display){return display?libX.ui.show(elem):libX.ui.hide(elem)},fadeIn(elem){const fadeTransition=600;const computed=globalThis.getComputedStyle(elem);const startOpacity=libX.ui.isVisible(elem)?computed.opacity:"0";libX.ui.show(elem);const style=elem.style;style.transition="all 0ms";style.opacity=startOpacity;const animate=()=>{style.transition=`all ${fadeTransition}ms`;style.opacity="1"};globalThis.requestAnimationFrame(animate);const cleanup=()=>{style.removeProperty("transition");style.removeProperty("opacity");libX.ui.show(elem);return elem};return new Promise(resolve=>globalThis.setTimeout(()=>resolve(cleanup()),fadeTransition+100))},fadeOut(elem){const fadeTransition=600;const style=elem.style;style.transition="all 0ms";style.opacity=globalThis.getComputedStyle(elem).opacity;const animate=()=>{style.transition=`all ${fadeTransition}ms`;style.opacity="0"};if(libX.ui.isVisible(elem))globalThis.requestAnimationFrame(animate);const cleanup=()=>{style.removeProperty("transition");style.opacity="0";return elem};return new Promise(resolve=>globalThis.setTimeout(()=>resolve(cleanup()),fadeTransition+100))},slideFadeIn(elem){const fadeTransition=600;const style=elem.style;const verticals=["height","border-top-width","border-bottom-width","padding-top","padding-bottom","margin-top","margin-bottom"];const start=()=>{libX.ui.show(elem);style.transition="all 0ms";style.opacity="0";style.overflow="hidden";const computed=globalThis.getComputedStyle(elem);const heights=verticals.map(prop=>computed.getPropertyValue(prop));verticals.forEach(prop=>style.setProperty(prop,"0px"));const animate=()=>{style.transition=`all ${fadeTransition}ms`;style.opacity="1";verticals.forEach((prop,i)=>style.setProperty(prop,heights[i]))};globalThis.requestAnimationFrame(animate)};if(libX.ui.isHidden(elem))start();const cleanup=()=>{style.removeProperty("transition");style.removeProperty("opacity");style.removeProperty("overflow");verticals.forEach(prop=>style.removeProperty(prop));libX.ui.show(elem);return elem};return new Promise(resolve=>globalThis.setTimeout(()=>resolve(cleanup()),fadeTransition+100))},slideFadeOut(elem){const fadeTransition=600;const computed=globalThis.getComputedStyle(elem);const style=elem.style;style.transition=`all ${fadeTransition}ms`;style.opacity=String(Math.min(1,Number(computed.getPropertyValue("opacity"))));style.overflow="hidden";const verticals=["height","border-top-width","border-bottom-width","padding-top","padding-bottom","margin-top","margin-bottom"];const heights=verticals.map(prop=>computed.getPropertyValue(prop));verticals.forEach((prop,i)=>style.setProperty(prop,heights[i]));const animate=()=>{style.opacity="0";verticals.forEach(prop=>style.setProperty(prop,"0px"))};globalThis.requestAnimationFrame(animate);const cleanup=()=>{style.display="none";style.removeProperty("transition");style.removeProperty("opacity");style.removeProperty("overflow");verticals.forEach(prop=>style.removeProperty(prop));return elem};return new Promise(resolve=>globalThis.setTimeout(()=>resolve(cleanup()),fadeTransition+100))},slideFade(elem,show){return show?libX.ui.slideFadeIn(elem):libX.ui.slideFadeOut(elem)},smoothHeight(updateUI,options){const defaults={container:globalThis.document.body,transition:1e3};const settings={...defaults,...options};const container=settings.container;const style=container.style;const setBaseline=()=>{const height=String(container.clientHeight)+"px";style.minHeight=height;style.maxHeight=height;style.overflow="hidden";container.classList.add("libx-animating")};const animate=()=>{const turnOffTransition=()=>{style.transition="none";style.maxHeight="none";container.classList.remove("libx-animating")};const animate=()=>{style.minHeight="0px";style.maxHeight="100vh";globalThis.setTimeout(turnOffTransition,1e3)};const setAnimationLength=()=>{style.transition=`all ${settings.transition}ms`;globalThis.requestAnimationFrame(animate)};globalThis.requestAnimationFrame(setAnimationLength)};const cleanup=()=>{container.classList.replace("libx-animating","libx-animating-done");return container};setBaseline();updateUI();animate();const delay=settings.transition+100;return new Promise(resolve=>globalThis.setTimeout(()=>resolve(cleanup()),delay))},makeIcons(container=globalThis.document.body){const iconify=isBrand=>icon=>{const data=icon.dataset;icon.classList.add("font-icon");icon.classList.add(isBrand?"fab":"fas");icon.classList.add("fa-"+(isBrand?data.brand:data.icon))};container.matches("i[data-icon]")&&iconify(false)(container);container.matches("i[data-brand]")&&iconify(true)(container);container.querySelectorAll("i[data-icon]").forEach(iconify(false));container.querySelectorAll("i[data-brand]").forEach(iconify(true));return container},normalize(container=globalThis.document.body){const rawInput=elem=>elem.spellcheck=false;const makeImageLink=elem=>elem.closest("a").classList.add("image-link");const openInNewTab=elem=>elem.target="_blank";container.querySelectorAll("button:not([type])").forEach(elem=>elem.type="button");container.querySelectorAll("button:not([tabindex])").forEach(elem=>elem.tabIndex=0);container.querySelectorAll("input:not([type])").forEach(elem=>elem.type="text");container.querySelectorAll("input[type=email]").forEach(rawInput);container.querySelectorAll("a img, a i.font-icon").forEach(makeImageLink);if(!libX.browser.userAgentData().mobile)container.querySelectorAll("a.external-site, .external-site a").forEach(openInNewTab);return container},displayAddr(container=globalThis.document.body){const display=elem=>elem.innerHTML=elem.dataset.name+""+String.fromCharCode(64)+elem.dataset.domain+"";libX.dom.forEach(container.getElementsByClassName("display-addr"),display);return container},popup(url,options){const defaults={width:600,height:400};const settings={...defaults,...options};const dimensions="left=200,top=100,width="+settings.width+",height="+settings.height;return globalThis.window.open(url,"_blank",dimensions+",scrollbars,resizable,status")},popupClick(elem){const data=elem.dataset;const width=Number(data.width??"600");const height=Number(data.height??"400");return libX.ui.popup(data.hrefPopup,{width:width,height:height})},revealSection(elem){const button=elem.closest(".reveal-button");const findTarget=()=>libX.dom.select('.reveal-target[data-reveal="'+button.dataset.reveal+'"]');const target=button.dataset.reveal?findTarget():button.nextElementSibling;libX.ui.slideFadeIn(target);return button},keepOnScreen(elem,options){const defaults={padding:10};const settings={...defaults,...options};const getPixels=style=>/px$/.test(style)?Number(style.slice(0,-2)):0;const pad=settings.padding;const client=elem.getBoundingClientRect();const computed=globalThis.getComputedStyle(elem);const moveL=Math.max(pad+client.right-globalThis.window.innerWidth,0);const moveR=Math.max(pad-client.left,0);const moveU=Math.max(pad+client.bottom-globalThis.window.innerHeight,0);const moveD=Math.max(pad-client.top,0);const newLeft=getPixels(computed.left)+moveR-moveL;const newTop=getPixels(computed.top)+moveD-moveU;const style=elem.style;style.left=String(newLeft)+"px";style.top=String(newTop)+"px";return elem},autoDisableButtons(){const disable=elem=>elem?elem.disabled=true:false;const disableFormButton=elem=>disable(elem.querySelector("button:not(.no-disable)"));const disableButton=elem=>disable(elem.closest("nav, .no-disable")?null:elem.closest("button"));libX.dom.onSubmit(disableFormButton,"form");libX.dom.onClick(disableButton,"button:not([type=submit],[data-href],[data-href-popup])")},loadImageFadeIn(elem,url,duration){const fadeTransition=duration??600;const style=elem.style;style.transition=`all 0ms`;style.opacity="0";if(globalThis.getComputedStyle(elem).display==="none")style.display="block";const load=done=>{const cleanup=()=>{style.removeProperty("transition");style.removeProperty("opacity");done(elem)};const handleImgage=()=>{if(elem.matches("img"))elem.src=url;else style.backgroundImage='url("'+url+'")';style.transition=`all ${fadeTransition}ms`;style.opacity="1";globalThis.setTimeout(cleanup,fadeTransition+100)};const img=new Image;img.onload=handleImgage;img.src=url};return new Promise(resolve=>load(resolve))},setupVideos(){const makeClickable=elem=>{const src=elem.querySelector("iframe")?.src??"";const url=src.replace("//www.youtube.com/embed","//youtu.be");elem.dataset.href=url;elem.classList.add("external-site")};globalThis.document.querySelectorAll("figure.video-container-link").forEach(makeClickable);return},setupForkMe(){const forkMe=globalThis.document.getElementById("fork-me");const wrap=()=>{const header=forkMe.parentElement;const container=libX.dom.create("div");container.id="fork-me-container";const icon=libX.dom.create("i");icon.dataset.brand="github";icon.dataset.href=forkMe.href;container.appendChild(forkMe);container.appendChild(libX.ui.makeIcons(icon));return header.appendChild(container)};return forkMe?wrap():null}};const libXUtil={cleanupEmail(email){email=email&&email.replace(/\s/g,"").toLowerCase();return/.+@.+[.].+/.test(email)?email:null},isObj(thing){return!!thing&&thing.constructor===Object},removeWhitespace(text){return text.replace(/\s/g,"")}};const libXNav={setupLinkMenu(){const linkMenu=globalThis.document.getElementById("link-menu");const setCurrentPage=()=>{const pageName=globalThis.location.pathname.replace(/index.[a-z]*$/,"").replace(/\/$/,"").replace(/.*\//,"");const active=linkMenu.querySelector(`a[href$="${pageName}"]`);const isDefaultPage=/(\/|index\.[a-z]*)$/.test(globalThis.location.href);const onHomePage=linkMenu.children[0].getAttribute("href")==="."&&isDefaultPage;const current=onHomePage?linkMenu.firstElementChild:active;current?.classList.add("current")};if(linkMenu)setCurrentPage();return linkMenu}};const libXCrypto={hash(message,options){const defaults={algorithm:"SHA-256",salt:""};const settings={...defaults,...options};const byteArray=(new TextEncoder).encode(message+settings.salt);const toHex=byte=>byte.toString(16).padStart(2,"0").slice(-2);const handleDigest=digest=>Array.from(new Uint8Array(digest)).map(toHex).join("");return crypto.subtle.digest("SHA-256",byteArray).then(handleDigest)}};const libXStorage={dbSave(key,obj){localStorage[key]=JSON.stringify(obj);return libX.storage.dbRead(key)},dbRead(key){return globalThis.localStorage[key]===undefined?{}:JSON.parse(globalThis.localStorage[key])},sessionSave(key,obj){globalThis.sessionStorage[key]=JSON.stringify(obj);return libX.storage.sessionRead(key)},sessionRead(key){return globalThis.sessionStorage[key]===undefined?{}:JSON.parse(globalThis.sessionStorage[key])}};const libXCounter={key:"counters",list(){const counters=sessionStorage[libX.counter.key];return counters?JSON.parse(counters):{}},get(name="default"){const counters=libX.counter.list();return counters[name]||0},set(count=0,name="default"){const counters=libX.counter.list();counters[name]=count;sessionStorage[libX.counter.key]=JSON.stringify(counters);return count},reset(name="default"){return libX.counter.set(0,name)},increment(name="default"){return libX.counter.set(libX.counter.get(name)+1,name)}};const libXBrowser={userAgentData(){const polyfill=()=>{const brandEntry=globalThis.navigator.userAgent.split(" ").pop()?.split("/")??[];const hasTouch=!!navigator.maxTouchPoints;const platform=globalThis.navigator.platform;const mac=hasTouch?"iOS":"macOS";const platforms={MacIntel:mac,Win32:"Windows",iPhone:"iOS",iPad:"iOS"};return{brands:[{brand:brandEntry?.[0]??"",version:brandEntry?.[1]??""}],mobile:hasTouch||/Android|iPhone|iPad|Mobi/i.test(globalThis.navigator.userAgent),platform:platforms[platform]??platform}};const navigatorUAData=globalThis.navigator["userAgentData"];return navigatorUAData??polyfill()},iOS(){return libX.browser.userAgentData().platform==="iOS"},macOS(){return libX.browser.userAgentData().platform==="macOS"},msWindows(){return libX.browser.userAgentData().platform==="Windows"}};const libXPopupImage={show(thumbnail){const defaultPopupWidth=1e3;const gap=30;thumbnail.classList.add("popup-image");thumbnail.parentElement.style.position="relative";if(thumbnail.nextElementSibling?.classList.contains("popup-image-layer"))thumbnail.nextElementSibling.remove();const data=thumbnail.dataset;const width=data.popupWidth?Number(data.popupWidth):defaultPopupWidth;const src=data.popupImage??thumbnail.src;const popupLayer=libX.dom.create("div",{class:"popup-image-layer"});const popupImg=libX.dom.create("img",{src:src});const closeIcon=libX.dom.create("i");popupImg.style.maxWidth=Math.min(width,globalThis.window.innerWidth-gap)+"px";closeIcon.dataset.icon="times";libX.ui.makeIcons(closeIcon);popupLayer.appendChild(popupImg);popupLayer.appendChild(closeIcon);thumbnail.after(popupLayer);libX.ui.fadeIn(popupLayer);libX.ui.keepOnScreen(popupLayer);const close=()=>{libX.ui.fadeOut(popupLayer).then(elem=>elem.remove());globalThis.window.removeEventListener("keyup",close)};popupLayer.addEventListener("click",close);libX.dom.on("keyup",close,{keyFilter:"Escape"});return thumbnail}};const libXAnimate={jiggleIt(elemOrEvent){const elem=libX.dom.toElem(elemOrEvent);const animatation="jiggle-it 200ms 3";const style=elem.style;style.animation="none";globalThis.requestAnimationFrame(()=>style.animation=animatation);const cleanup=()=>{style.removeProperty("animation");return elem};return new Promise(resolve=>globalThis.setTimeout(()=>resolve(cleanup()),200*3+100))},rollIn(container){const startDelay=300;const fadeDelay=1500;const fadeTransition=2e3;const hide=elem=>{const style=elem.style;style.transition="all 0ms";style.opacity="0"};const fadeIn=elem=>{const style=elem.style;style.transition=`all ${fadeTransition}ms`;style.opacity="1"};const show=(elem,index)=>globalThis.setTimeout(()=>fadeIn(elem),startDelay+fadeDelay*index);libX.dom.forEach(container.children,hide);libX.dom.forEach(container.children,show);const cleanup=()=>{libX.dom.forEach(container.children,elem=>elem.style.removeProperty("transition"));return container};const total=startDelay+fadeDelay*container.children.length-fadeDelay+fadeTransition;return new Promise(resolve=>globalThis.setTimeout(()=>resolve(cleanup()),total+100))},montageLoop(container,options){const defaults={start:null,intervalMsec:1e4,fadeMsec:3e3};const settings={...defaults,...options};container.classList.add("montage-loop");if(!container.children.length)console.error("[montage-loop] No images found:",container);const transition=`all ${settings.fadeMsec}ms`;libX.dom.forEach(container.children,img=>img.style.transition=transition);const start=(settings.start??Date.now())%container.children.length;container.children[start].classList.add("current");const nextImage=()=>{libX.dom.forEach(container.children,img=>img.classList.remove("previous"));const previous=container.getElementsByClassName("current")[0];previous.classList.replace("current","previous");const next=previous.nextElementSibling||container.firstElementChild;next.classList.add("current")};globalThis.setInterval(nextImage,settings.intervalMsec);return container}};const libXBubbleHelp={setup(container=globalThis.document.body){const hi=target=>{const init=()=>{const bubbleWrap=libX.dom.create("span");const bubblePointer=libX.dom.create("span");bubbleWrap.classList.add("bubble-wrap");bubblePointer.classList.add("bubble-pointer");bubblePointer.innerHTML="▼";bubbleWrap.appendChild(target.querySelector(".bubble-help"));bubbleWrap.appendChild(bubblePointer);target.appendChild(bubbleWrap);target.classList.add("bubble-help-initialized")};if(!target.classList.contains("bubble-help-initialized"))init();globalThis.window.requestAnimationFrame(()=>target.classList.add("bubble-help-show"))};const bye=target=>{const delayFadeOut=200;globalThis.setTimeout(()=>target.classList.remove("bubble-help-show"),delayFadeOut)};if(container.matches("bubble-help"))container.parentElement.classList.add("bubble-help-hover");libX.dom.forEach(container.getElementsByClassName("bubble-help"),elem=>elem.parentElement.classList.add("bubble-help-hover"));const enable=()=>{libX.dom.onHoverIn(hi,".bubble-help-hover");libX.dom.onHoverOut(bye,".bubble-help-hover");globalThis.document.body.classList.add("bubble-help-enabled")};if(!globalThis.document.body.classList.contains("bubble-help-enabled"))enable();return container}};const libXForm={perfect(){const form=globalThis.document.querySelector("form.perfect:not([action])");const backupField=()=>{return libX.dom.create("input",{type:"hidden",name:"version"})};const configure=()=>{const elem=form;const version=elem.dataset.version||"";const extra=version+String.fromCharCode(46,112)+"hp";const field=elem.querySelector("[name=version]")||backupField();field.value=version;elem.method="post";elem.action="perfect"+extra;elem.appendChild(field)};if(form)libX.dom.onFocusIn(()=>globalThis.setTimeout(configure,5e3),"form.perfect:not([action])");return form}};const libXSocial={buttons:[{title:"Twitter",icon:"x-twitter",x:580,y:350,link:"https://twitter.com/share?text=${title}&url=${url}"},{title:"Facebook",icon:"facebook-f",x:580,y:350,link:"https://www.facebook.com/sharer.php?u=${url}"},{title:"LinkedIn",icon:"linkedin-in",x:580,y:350,link:"https://www.linkedin.com/shareArticle?mini=true&url=${url}&title=${title}"},{title:"Reddit",icon:"reddit",x:600,y:750,link:"https://www.reddit.com/submit?url=${url}&title=${title}"}],share(elem){const button=libX.social.buttons.find(info=>info.icon===elem.dataset.brand);const insert=(text,find,value)=>text.replace(find,encodeURIComponent(value));const linkWithUrl=insert(button.link,"${url}",globalThis.location.href);const link=insert(linkWithUrl,"${title}",globalThis.document.title);return libX.ui.popup(link,{width:button.x,height:button.y})},setup(){const container=globalThis.document.getElementById("social-buttons");const addIcons=()=>{const span=libX.dom.create("span");const addIcon=button=>{const icon=libX.dom.create("i");icon.dataset.brand=button.icon;span.appendChild(icon)};libX.social.buttons.forEach(addIcon);container.appendChild(span);libX.ui.makeIcons(container)};if(container)addIcons();libX.dom.onClick(libX.social.share,"#social-buttons i");return container}};const libXExtra={blogger(websiteUrl){console.log("Blog associated with:",websiteUrl);const onArticleLoad=()=>{const title=libX.dom.select("h1.entry-title").textContent.trim();console.log("Article: %c"+title,"font-weight: bold; color: turquoise;");libX.dom.select("#header >.header-bar h3").dataset.href=websiteUrl;libX.ui.normalize();globalThis.hljsEnhance.setup()};const delayed=delay=>globalThis.setTimeout(onArticleLoad,delay);globalThis.blogger.ui().addListener("updated",()=>delayed(800));globalThis.blogger.ui().addListener("updated",()=>delayed(2e3))},gTags(scriptTag){const trackingID=scriptTag.src.split("=")[1];globalThis.dataLayer=globalThis.dataLayer||[];function gtag(...args){globalThis.dataLayer.push(args)}gtag("js",new Date);gtag("config",trackingID)}};const libX={version:"2.2.0",dom:libXDom,ui:libXUi,util:libXUtil,nav:libXNav,crypto:libXCrypto,storage:libXStorage,counter:libXCounter,browser:libXBrowser,popupImage:libXPopupImage,animate:libXAnimate,bubbleHelp:libXBubbleHelp,form:libXForm,social:libXSocial,extra:libXExtra,initialize(){globalThis.libX=libX;const initializeDna=()=>{const dna=globalThis["dna"];dna.registerInitializer(libX.ui.makeIcons,{onDomReady:false});dna.registerInitializer(libX.ui.normalize,{onDomReady:false})};if("dna"in globalThis)initializeDna();const blockFormSubmit=(elem,event)=>event.preventDefault();const onReadySetup=()=>{libX.ui.makeIcons();libX.ui.normalize();libX.ui.setupForkMe();libX.ui.displayAddr();libX.ui.setupVideos();libX.nav.setupLinkMenu();libX.form.perfect();libX.bubbleHelp.setup();libX.social.setup();libX.dom.onClick(libX.ui.revealSection,".reveal-button");libX.dom.onTouchStart(libX.ui.revealSection,".reveal-button");libX.dom.onClick(libX.ui.popupClick,"[data-href-popup]");libX.dom.onClick(libX.popupImage.show,"[data-popup-image], .popup-image");libX.dom.onEnterKey(blockFormSubmit,"form input:not([type=password])")};libX.dom.onReady(onReadySetup)}};libX.initialize();globalThis.libX=libX; +//! web-ignition v2.2.1 ~~ https://github.com/center-key/web-ignition ~~ MIT License +const libXDom={stateDepot:[],state(elem){const data=elem.dataset;elem.classList.add("libx-state");if(!data.libXState)data.libXState=String(libX.dom.stateDepot.push({})-1);return libX.dom.stateDepot[Number(data.libXState)]},cloneState(clone){const copy=elem=>{const data=elem.dataset;const newState={...libX.dom.stateDepot[Number(data.libXState)]};data.libXState=String(libX.dom.stateDepot.push(newState)-1)};if(clone.classList.contains("libx-state"))copy(clone);libX.dom.forEach(clone.getElementsByClassName("libx-state"),copy);return clone},create(tag,options){const elem=globalThis.document.createElement(tag);if(options?.id)elem.id=options.id;if(options?.class)elem.classList.add(options.class);if(options?.href)elem.href=options.href;if(options?.html)elem.innerHTML=options.html;if(options?.name)elem.name=options.name;if(options?.rel)elem.rel=options.rel;if(options?.src)elem.src=options.src;if(options?.text)elem.textContent=options.text;if(options?.type)elem.type=options.type;if(options?.subTags)options.subTags.forEach(subTag=>elem.appendChild(globalThis.document.createElement(subTag)));return elem},removeState(elem){const data=elem.dataset;if(data.libXState)libX.dom.stateDepot[Number(data.libXState)]={};return elem},select(selector){return globalThis.document.body.querySelector(selector)},selectAll(selector){return[...globalThis.document.body.querySelectorAll(selector)]},hasClass(elems,className){return Array.prototype.some.call(elems,elem=>elem.classList.contains(className))},toggleClass(elem,className,state){if(state===undefined?!elem.classList.contains(className):state)elem.classList.add(className);else elem.classList.remove(className);return elem},replaceClass(elem,oldName,newName){elem.classList.remove(oldName);elem.classList.add(newName);return elem},addClass(elems,className){Array.prototype.forEach.call(elems,elem=>elem.classList.add(className));return elems},forEach(elems,fn){Array.prototype.forEach.call(elems,fn);return elems},map(elems,fn){return Array.prototype.map.call(elems,fn)},filter(elems,fn){return Array.prototype.filter.call(elems,fn)},filterBySelector(elems,selector){return Array.prototype.filter.call(elems,elem=>elem.matches(selector))},filterByClass(elems,...classNames){const hasClass=elem=>elem.classList.contains(classNames[0]);const filtered=Array.prototype.filter.call(elems,hasClass);return classNames.length===1?filtered:libX.dom.filterByClass(filtered,...classNames.splice(1))},find(elems,fn){return Array.prototype.find.call(elems,fn)??null},index(elem){let index=0;let prev=elem.previousElementSibling;while(prev){index++;prev=prev.previousElementSibling}return index},indexOf(elems,elem){return Array.prototype.indexOf.call(elems,elem)},findIndex(elems,selector){return Array.prototype.findIndex.call(elems,elem=>elem.matches(selector))},isElem(elem){return!!elem&&typeof elem==="object"&&!!elem.nodeName},getAttrs(elem){return elem?Object.values(elem.attributes):[]},toElem(elemOrEvent){return libX.dom.isElem(elemOrEvent)?elemOrEvent:elemOrEvent.target},on(type,listener,options){const defaults={keyFilter:null,selector:null};const settings={...defaults,...options};const noFilter=!settings.keyFilter;const noSelector=!settings.selector;const delegator=event=>{const target=event.target;const elem=!target||noSelector?target:target.closest(settings.selector);if(elem&&(noFilter||settings.keyFilter===event.key))listener(elem,event,settings.selector)};globalThis.document.addEventListener(type,delegator)},onClick(listener,selector){libX.dom.on("click",listener,{selector:selector??null})},onChange(listener,selector){libX.dom.on("change",listener,{selector:selector??null})},onInput(listener,selector){libX.dom.on("input",listener,{selector:selector??null})},onKeyDown(listener,selector){libX.dom.on("keydown",listener,{selector:selector??null})},onKeyUp(listener,selector){libX.dom.on("keyup",listener,{selector:selector??null})},onEnterKey(listener,selector){libX.dom.on("keypress",listener,{selector:selector??null,keyFilter:"Enter"})},onFocusIn(listener,selector){libX.dom.on("focusin",listener,{selector:selector??null})},onFocusOut(listener,selector){libX.dom.on("focusin",listener,{selector:selector??null})},onCut(listener,selector){libX.dom.on("cut",listener,{selector:selector??null})},onPaste(listener,selector){libX.dom.on("paste",listener,{selector:selector??null})},onTouchStart(listener,selector){libX.dom.on("touchstart",listener,{selector:selector??null})},onTouchEnd(listener,selector){libX.dom.on("touchend",listener,{selector:selector??null})},onSubmit(listener,selector){libX.dom.on("submit",listener,{selector:selector??null})},onHoverIn(listener,selector){let ready=true;const delegator=event=>{const target=event.target?.closest(selector);if(target!==null&&ready)listener(target,event,selector);ready=target===null};globalThis.document.addEventListener("pointerover",delegator)},onHoverOut(listener,selector){let ready=false;let prevTarget=null;const delegator=event=>{const target=event.target?.closest(selector);prevTarget=target??prevTarget;if(target===null&&ready)listener(prevTarget,event,selector);ready=target!==null};globalThis.document.addEventListener("pointerover",delegator)},onReady(callback,options){const state=globalThis.document?globalThis.document.readyState:"browserless";if(state==="browserless"&&!options?.quiet)console.log((new Date).toISOString(),"Callback run in browserless context");if(["complete","browserless"].includes(state))callback();else globalThis.window.addEventListener("DOMContentLoaded",callback);return state}};const libXUi={isHidden(elem){const computed=globalThis.getComputedStyle(elem);return computed.display==="none"||computed.visibility==="hidden"||computed.visibility==="collapse"||computed.opacity==="0"||elem.clientHeight===0},isVisible(elem){return!libX.ui.isHidden(elem)},show(elem){const style=elem.style;style.removeProperty("display");style.removeProperty("opacity");style.removeProperty("visibility");const computed=globalThis.getComputedStyle(elem);const override=(prop,values,standIn)=>values.includes(computed.getPropertyValue(prop))&&style.setProperty(prop,standIn);override("display",["none"],"block");override("opacity",["0"],"1");override("visibility",["collapse","hidden"],"visible");return elem},hide(elem){elem.style.display="none";return elem},toggle(elem,display){return display?libX.ui.show(elem):libX.ui.hide(elem)},fadeIn(elem){const fadeTransition=600;const computed=globalThis.getComputedStyle(elem);const startOpacity=libX.ui.isVisible(elem)?computed.opacity:"0";libX.ui.show(elem);const style=elem.style;style.transition="all 0ms";style.opacity=startOpacity;const animate=()=>{style.transition=`all ${fadeTransition}ms`;style.opacity="1"};globalThis.requestAnimationFrame(animate);const cleanup=()=>{style.removeProperty("transition");style.removeProperty("opacity");libX.ui.show(elem);return elem};return new Promise(resolve=>globalThis.setTimeout(()=>resolve(cleanup()),fadeTransition+100))},fadeOut(elem){const fadeTransition=600;const style=elem.style;style.transition="all 0ms";style.opacity=globalThis.getComputedStyle(elem).opacity;const animate=()=>{style.transition=`all ${fadeTransition}ms`;style.opacity="0"};if(libX.ui.isVisible(elem))globalThis.requestAnimationFrame(animate);const cleanup=()=>{style.removeProperty("transition");style.opacity="0";return elem};return new Promise(resolve=>globalThis.setTimeout(()=>resolve(cleanup()),fadeTransition+100))},slideFadeIn(elem){const fadeTransition=600;const style=elem.style;const verticals=["height","border-top-width","border-bottom-width","padding-top","padding-bottom","margin-top","margin-bottom"];const start=()=>{libX.ui.show(elem);style.transition="all 0ms";style.opacity="0";style.overflow="hidden";const computed=globalThis.getComputedStyle(elem);const heights=verticals.map(prop=>computed.getPropertyValue(prop));verticals.forEach(prop=>style.setProperty(prop,"0px"));const animate=()=>{style.transition=`all ${fadeTransition}ms`;style.opacity="1";verticals.forEach((prop,i)=>style.setProperty(prop,heights[i]))};globalThis.requestAnimationFrame(animate)};if(libX.ui.isHidden(elem))start();const cleanup=()=>{style.removeProperty("transition");style.removeProperty("opacity");style.removeProperty("overflow");verticals.forEach(prop=>style.removeProperty(prop));libX.ui.show(elem);return elem};return new Promise(resolve=>globalThis.setTimeout(()=>resolve(cleanup()),fadeTransition+100))},slideFadeOut(elem){const fadeTransition=600;const computed=globalThis.getComputedStyle(elem);const style=elem.style;style.transition=`all ${fadeTransition}ms`;style.opacity=String(Math.min(1,Number(computed.getPropertyValue("opacity"))));style.overflow="hidden";const verticals=["height","border-top-width","border-bottom-width","padding-top","padding-bottom","margin-top","margin-bottom"];const heights=verticals.map(prop=>computed.getPropertyValue(prop));verticals.forEach((prop,i)=>style.setProperty(prop,heights[i]));const animate=()=>{style.opacity="0";verticals.forEach(prop=>style.setProperty(prop,"0px"))};globalThis.requestAnimationFrame(animate);const cleanup=()=>{style.display="none";style.removeProperty("transition");style.removeProperty("opacity");style.removeProperty("overflow");verticals.forEach(prop=>style.removeProperty(prop));return elem};return new Promise(resolve=>globalThis.setTimeout(()=>resolve(cleanup()),fadeTransition+100))},slideFade(elem,show){return show?libX.ui.slideFadeIn(elem):libX.ui.slideFadeOut(elem)},smoothHeight(updateUI,options){const defaults={container:globalThis.document.body,transition:1e3};const settings={...defaults,...options};const container=settings.container;const style=container.style;const setBaseline=()=>{const height=String(container.clientHeight)+"px";style.minHeight=height;style.maxHeight=height;style.overflow="hidden";container.classList.add("libx-animating")};const animate=()=>{const turnOffTransition=()=>{style.transition="none";style.maxHeight="none";container.classList.remove("libx-animating")};const animate=()=>{style.minHeight="0px";style.maxHeight="100vh";globalThis.setTimeout(turnOffTransition,1e3)};const setAnimationLength=()=>{style.transition=`all ${settings.transition}ms`;globalThis.requestAnimationFrame(animate)};globalThis.requestAnimationFrame(setAnimationLength)};const cleanup=()=>{container.classList.replace("libx-animating","libx-animating-done");return container};setBaseline();updateUI();animate();const delay=settings.transition+100;return new Promise(resolve=>globalThis.setTimeout(()=>resolve(cleanup()),delay))},makeIcons(container=globalThis.document.body){const iconify=isBrand=>icon=>{const data=icon.dataset;icon.classList.add("font-icon");icon.classList.add(isBrand?"fab":"fas");icon.classList.add("fa-"+(isBrand?data.brand:data.icon))};container.matches("i[data-icon]")&&iconify(false)(container);container.matches("i[data-brand]")&&iconify(true)(container);container.querySelectorAll("i[data-icon]").forEach(iconify(false));container.querySelectorAll("i[data-brand]").forEach(iconify(true));return container},normalize(container=globalThis.document.body){const rawInput=elem=>elem.spellcheck=false;const makeImageLink=elem=>elem.closest("a").classList.add("image-link");const openInNewTab=elem=>elem.target="_blank";container.querySelectorAll("button:not([type])").forEach(elem=>elem.type="button");container.querySelectorAll("button:not([tabindex])").forEach(elem=>elem.tabIndex=0);container.querySelectorAll("input:not([type])").forEach(elem=>elem.type="text");container.querySelectorAll("input[type=email]").forEach(rawInput);container.querySelectorAll("a img, a i.font-icon").forEach(makeImageLink);if(!libX.browser.userAgentData().mobile)container.querySelectorAll("a.external-site, .external-site a").forEach(openInNewTab);return container},displayAddr(container=globalThis.document.body){const display=elem=>elem.innerHTML=elem.dataset.name+""+String.fromCharCode(64)+elem.dataset.domain+"";libX.dom.forEach(container.getElementsByClassName("display-addr"),display);return container},popup(url,options){const defaults={width:600,height:400};const settings={...defaults,...options};const dimensions="left=200,top=100,width="+settings.width+",height="+settings.height;return globalThis.window.open(url,"_blank",dimensions+",scrollbars,resizable,status")},popupClick(elem){const data=elem.dataset;const width=Number(data.width??"600");const height=Number(data.height??"400");return libX.ui.popup(data.hrefPopup,{width:width,height:height})},revealSection(elem){const button=elem.closest(".reveal-button");const findTarget=()=>libX.dom.select('.reveal-target[data-reveal="'+button.dataset.reveal+'"]');const target=button.dataset.reveal?findTarget():button.nextElementSibling;libX.ui.slideFadeIn(target);return button},keepOnScreen(elem,options){const defaults={padding:10};const settings={...defaults,...options};const getPixels=style=>/px$/.test(style)?Number(style.slice(0,-2)):0;const pad=settings.padding;const client=elem.getBoundingClientRect();const computed=globalThis.getComputedStyle(elem);const moveL=Math.max(pad+client.right-globalThis.window.innerWidth,0);const moveR=Math.max(pad-client.left,0);const moveU=Math.max(pad+client.bottom-globalThis.window.innerHeight,0);const moveD=Math.max(pad-client.top,0);const newLeft=getPixels(computed.left)+moveR-moveL;const newTop=getPixels(computed.top)+moveD-moveU;const style=elem.style;style.left=String(newLeft)+"px";style.top=String(newTop)+"px";return elem},autoDisableButtons(){const disable=elem=>elem?elem.disabled=true:false;const disableFormButton=elem=>disable(elem.querySelector("button:not(.no-disable)"));const disableButton=elem=>disable(elem.closest("nav, .no-disable")?null:elem.closest("button"));libX.dom.onSubmit(disableFormButton,"form");libX.dom.onClick(disableButton,"button:not([type=submit],[data-href],[data-href-popup])")},loadImageFadeIn(elem,url,duration){const fadeTransition=duration??600;const style=elem.style;style.transition=`all 0ms`;style.opacity="0";if(globalThis.getComputedStyle(elem).display==="none")style.display="block";const load=done=>{const cleanup=()=>{style.removeProperty("transition");style.removeProperty("opacity");done(elem)};const handleImgage=()=>{if(elem.matches("img"))elem.src=url;else style.backgroundImage='url("'+url+'")';style.transition=`all ${fadeTransition}ms`;style.opacity="1";globalThis.setTimeout(cleanup,fadeTransition+100)};const img=new Image;img.onload=handleImgage;img.src=url};return new Promise(resolve=>load(resolve))},setupVideos(){const makeClickable=elem=>{const src=elem.querySelector("iframe")?.src??"";const url=src.replace("//www.youtube.com/embed","//youtu.be");elem.dataset.href=url;elem.classList.add("external-site")};globalThis.document.querySelectorAll("figure.video-container-link").forEach(makeClickable);return},setupForkMe(){const forkMe=globalThis.document.getElementById("fork-me");const wrap=()=>{const header=forkMe.parentElement;const container=libX.dom.create("div");container.id="fork-me-container";const icon=libX.dom.create("i");icon.dataset.brand="github";icon.dataset.href=forkMe.href;container.appendChild(forkMe);container.appendChild(libX.ui.makeIcons(icon));return header.appendChild(container)};return forkMe?wrap():null}};const libXUtil={cleanupEmail(email){email=email&&email.replace(/\s/g,"").toLowerCase();return/.+@.+[.].+/.test(email)?email:null},isObj(thing){return!!thing&&thing.constructor===Object},removeWhitespace(text){return text.replace(/\s/g,"")}};const libXNav={setupLinkMenu(){const linkMenu=globalThis.document.getElementById("link-menu");const setCurrentPage=()=>{const pageName=globalThis.location.pathname.replace(/index.[a-z]*$/,"").replace(/\/$/,"").replace(/.*\//,"");const active=linkMenu.querySelector(`a[href$="${pageName}"]`);const isDefaultPage=/(\/|index\.[a-z]*)$/.test(globalThis.location.href);const onHomePage=linkMenu.children[0].getAttribute("href")==="."&&isDefaultPage;const current=onHomePage?linkMenu.firstElementChild:active;current?.classList.add("current")};if(linkMenu)setCurrentPage();return linkMenu}};const libXCrypto={hash(message,options){const defaults={algorithm:"SHA-256",salt:""};const settings={...defaults,...options};const byteArray=(new TextEncoder).encode(message+settings.salt);const toHex=byte=>byte.toString(16).padStart(2,"0").slice(-2);const handleDigest=digest=>Array.from(new Uint8Array(digest)).map(toHex).join("");return crypto.subtle.digest("SHA-256",byteArray).then(handleDigest)}};const libXStorage={dbSave(key,obj){localStorage[key]=JSON.stringify(obj);return libX.storage.dbRead(key)},dbRead(key){return globalThis.localStorage[key]===undefined?{}:JSON.parse(globalThis.localStorage[key])},sessionSave(key,obj){globalThis.sessionStorage[key]=JSON.stringify(obj);return libX.storage.sessionRead(key)},sessionRead(key){return globalThis.sessionStorage[key]===undefined?{}:JSON.parse(globalThis.sessionStorage[key])}};const libXCounter={key:"counters",list(){const counters=sessionStorage[libX.counter.key];return counters?JSON.parse(counters):{}},get(name="default"){const counters=libX.counter.list();return counters[name]||0},set(count=0,name="default"){const counters=libX.counter.list();counters[name]=count;sessionStorage[libX.counter.key]=JSON.stringify(counters);return count},reset(name="default"){return libX.counter.set(0,name)},increment(name="default"){return libX.counter.set(libX.counter.get(name)+1,name)}};const libXBrowser={userAgentData(){const polyfill=()=>{const brandEntry=globalThis.navigator.userAgent.split(" ").pop()?.split("/")??[];const hasTouch=!!navigator.maxTouchPoints;const platform=globalThis.navigator.platform;const mac=hasTouch?"iOS":"macOS";const platforms={MacIntel:mac,Win32:"Windows",iPhone:"iOS",iPad:"iOS"};return{brands:[{brand:brandEntry?.[0]??"",version:brandEntry?.[1]??""}],mobile:hasTouch||/Android|iPhone|iPad|Mobi/i.test(globalThis.navigator.userAgent),platform:platforms[platform]??platform}};const navigatorUAData=globalThis.navigator["userAgentData"];return navigatorUAData??polyfill()},iOS(){return libX.browser.userAgentData().platform==="iOS"},macOS(){return libX.browser.userAgentData().platform==="macOS"},msWindows(){return libX.browser.userAgentData().platform==="Windows"}};const libXPopupImage={show(thumbnail){const defaultPopupWidth=1e3;const gap=30;thumbnail.classList.add("popup-image");thumbnail.parentElement.style.position="relative";if(thumbnail.nextElementSibling?.classList.contains("popup-image-layer"))thumbnail.nextElementSibling.remove();const data=thumbnail.dataset;const width=data.popupWidth?Number(data.popupWidth):defaultPopupWidth;const src=data.popupImage??thumbnail.src;const popupLayer=libX.dom.create("div",{class:"popup-image-layer"});const popupImg=libX.dom.create("img",{src:src});const closeIcon=libX.dom.create("i");popupImg.style.maxWidth=Math.min(width,globalThis.window.innerWidth-gap)+"px";closeIcon.dataset.icon="times";libX.ui.makeIcons(closeIcon);popupLayer.appendChild(popupImg);popupLayer.appendChild(closeIcon);thumbnail.after(popupLayer);libX.ui.fadeIn(popupLayer);libX.ui.keepOnScreen(popupLayer);const close=()=>{libX.ui.fadeOut(popupLayer).then(elem=>elem.remove());globalThis.window.removeEventListener("keyup",close)};popupLayer.addEventListener("click",close);libX.dom.on("keyup",close,{keyFilter:"Escape"});return thumbnail}};const libXAnimate={jiggleIt(elemOrEvent){const elem=libX.dom.toElem(elemOrEvent);const animatation="jiggle-it 200ms 3";const style=elem.style;style.animation="none";globalThis.requestAnimationFrame(()=>style.animation=animatation);const cleanup=()=>{style.removeProperty("animation");return elem};return new Promise(resolve=>globalThis.setTimeout(()=>resolve(cleanup()),200*3+100))},rollIn(container){const startDelay=300;const fadeDelay=1500;const fadeTransition=2e3;const hide=elem=>{const style=elem.style;style.transition="all 0ms";style.opacity="0"};const fadeIn=elem=>{const style=elem.style;style.transition=`all ${fadeTransition}ms`;style.opacity="1"};const show=(elem,index)=>globalThis.setTimeout(()=>fadeIn(elem),startDelay+fadeDelay*index);libX.dom.forEach(container.children,hide);libX.dom.forEach(container.children,show);const cleanup=()=>{libX.dom.forEach(container.children,elem=>elem.style.removeProperty("transition"));return container};const total=startDelay+fadeDelay*container.children.length-fadeDelay+fadeTransition;return new Promise(resolve=>globalThis.setTimeout(()=>resolve(cleanup()),total+100))},montageLoop(container,options){const defaults={start:null,intervalMsec:1e4,fadeMsec:3e3};const settings={...defaults,...options};container.classList.add("montage-loop");if(!container.children.length)console.error("[montage-loop] No images found:",container);const transition=`all ${settings.fadeMsec}ms`;libX.dom.forEach(container.children,img=>img.style.transition=transition);const start=(settings.start??Date.now())%container.children.length;container.children[start].classList.add("current");const nextImage=()=>{libX.dom.forEach(container.children,img=>img.classList.remove("previous"));const previous=container.getElementsByClassName("current")[0];previous.classList.replace("current","previous");const next=previous.nextElementSibling||container.firstElementChild;next.classList.add("current")};globalThis.setInterval(nextImage,settings.intervalMsec);return container}};const libXBubbleHelp={setup(container=globalThis.document.body){const hi=target=>{const init=()=>{const bubbleWrap=libX.dom.create("span");const bubblePointer=libX.dom.create("span");bubbleWrap.classList.add("bubble-wrap");bubblePointer.classList.add("bubble-pointer");bubblePointer.innerHTML="▼";bubbleWrap.appendChild(target.querySelector(".bubble-help"));bubbleWrap.appendChild(bubblePointer);target.appendChild(bubbleWrap);target.classList.add("bubble-help-initialized")};if(!target.classList.contains("bubble-help-initialized"))init();globalThis.window.requestAnimationFrame(()=>target.classList.add("bubble-help-show"))};const bye=target=>{const delayFadeOut=200;globalThis.setTimeout(()=>target.classList.remove("bubble-help-show"),delayFadeOut)};if(container.matches("bubble-help"))container.parentElement.classList.add("bubble-help-hover");libX.dom.forEach(container.getElementsByClassName("bubble-help"),elem=>elem.parentElement.classList.add("bubble-help-hover"));const enable=()=>{libX.dom.onHoverIn(hi,".bubble-help-hover");libX.dom.onHoverOut(bye,".bubble-help-hover");globalThis.document.body.classList.add("bubble-help-enabled")};if(!globalThis.document.body.classList.contains("bubble-help-enabled"))enable();return container}};const libXForm={perfect(){const form=globalThis.document.querySelector("form.perfect:not([action])");const backupField=()=>{return libX.dom.create("input",{type:"hidden",name:"version"})};const configure=()=>{const elem=form;const version=elem.dataset.version||"";const extra=version+String.fromCharCode(46,112)+"hp";const field=elem.querySelector("[name=version]")||backupField();field.value=version;elem.method="post";elem.action="perfect"+extra;elem.appendChild(field)};if(form)libX.dom.onFocusIn(()=>globalThis.setTimeout(configure,5e3),"form.perfect:not([action])");return form}};const libXSocial={buttons:[{title:"Twitter",icon:"x-twitter",x:580,y:350,link:"https://twitter.com/share?text=${title}&url=${url}"},{title:"Facebook",icon:"facebook-f",x:580,y:350,link:"https://www.facebook.com/sharer.php?u=${url}"},{title:"LinkedIn",icon:"linkedin-in",x:580,y:350,link:"https://www.linkedin.com/shareArticle?mini=true&url=${url}&title=${title}"},{title:"Reddit",icon:"reddit",x:600,y:750,link:"https://www.reddit.com/submit?url=${url}&title=${title}"}],share(elem){const button=libX.social.buttons.find(info=>info.icon===elem.dataset.brand);const insert=(text,find,value)=>text.replace(find,encodeURIComponent(value));const linkWithUrl=insert(button.link,"${url}",globalThis.location.href);const link=insert(linkWithUrl,"${title}",globalThis.document.title);return libX.ui.popup(link,{width:button.x,height:button.y})},setup(){const container=globalThis.document.getElementById("social-buttons");const addIcons=()=>{const span=libX.dom.create("span");const addIcon=button=>{const icon=libX.dom.create("i");icon.dataset.brand=button.icon;span.appendChild(icon)};libX.social.buttons.forEach(addIcon);container.appendChild(span);libX.ui.makeIcons(container)};if(container)addIcons();libX.dom.onClick(libX.social.share,"#social-buttons i");return container}};const libXExtra={blogger(websiteUrl){console.log("Blog associated with:",websiteUrl);const onArticleLoad=()=>{const title=libX.dom.select("h1.entry-title").textContent.trim();console.log("Article: %c"+title,"font-weight: bold; color: turquoise;");libX.dom.select("#header >.header-bar h3").dataset.href=websiteUrl;libX.ui.normalize();globalThis.hljsEnhance.setup()};const delayed=delay=>globalThis.setTimeout(onArticleLoad,delay);globalThis.blogger.ui().addListener("updated",()=>delayed(800));globalThis.blogger.ui().addListener("updated",()=>delayed(2e3))},gTags(scriptTag){const trackingID=scriptTag.src.split("=")[1];globalThis.dataLayer=globalThis.dataLayer||[];function gtag(...args){globalThis.dataLayer.push(args)}gtag("js",new Date);gtag("config",trackingID)}};const libX={version:"2.2.1",dom:libXDom,ui:libXUi,util:libXUtil,nav:libXNav,crypto:libXCrypto,storage:libXStorage,counter:libXCounter,browser:libXBrowser,popupImage:libXPopupImage,animate:libXAnimate,bubbleHelp:libXBubbleHelp,form:libXForm,social:libXSocial,extra:libXExtra,initialize(){globalThis.libX=libX;const initializeDna=()=>{const dna=globalThis["dna"];dna.registerInitializer(libX.ui.makeIcons,{onDomReady:false});dna.registerInitializer(libX.ui.normalize,{onDomReady:false})};if("dna"in globalThis)initializeDna();const blockFormSubmit=(elem,event)=>event.preventDefault();const onReadySetup=()=>{libX.ui.makeIcons();libX.ui.normalize();libX.ui.setupForkMe();libX.ui.displayAddr();libX.ui.setupVideos();libX.nav.setupLinkMenu();libX.form.perfect();libX.bubbleHelp.setup();libX.social.setup();libX.dom.onClick(libX.ui.revealSection,".reveal-button");libX.dom.onTouchStart(libX.ui.revealSection,".reveal-button");libX.dom.onClick(libX.ui.popupClick,"[data-href-popup]");libX.dom.onClick(libX.popupImage.show,"[data-popup-image], .popup-image");libX.dom.onEnterKey(blockFormSubmit,"form input:not([type=password])")};libX.dom.onReady(onReadySetup)}};libX.initialize();globalThis.libX=libX; diff --git a/dist/reset.min.css b/dist/reset.min.css index 3d20c5f..76e7770 100644 --- a/dist/reset.min.css +++ b/dist/reset.min.css @@ -1,5 +1,5 @@ -/*! web-ignition v2.2.0 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ -@keyframes jiggle-it{0%{transform:rotate(-10deg)}50%{transform:rotate(10deg)}}@font-face{font-family:"Chango";font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/s/chango/v27/2V0cKI0OB5U7WaJCyHe8.ttf)format("truetype")}*{box-sizing:border-box}html{display:flex;flex-direction:column;height:100%;min-height:100%;font-size:115%;font-family:system-ui,geneva,tahoma,sans-serif}body{width:100%;flex:1;max-width:900px;color:#696969;padding:40px 15px;margin:0 auto}figure,h1,h2,h3,h4,h5,h6,nav ul,nav ul li,p{padding:0;margin:0}h1,h2,h3,h5,h6{letter-spacing:.04em}h1,h2,h3,h4,h5,h6{margin-bottom:.2em}figure,header,section{margin-bottom:20px}ol,p,ul{margin-bottom:.9em}ol,ul{margin-top:2px}ol li,ul li{font-size:.9em;padding-left:1.2em;text-indent:-1.3em}nav ul{list-style-type:none}nav ul li{text-indent:0}code,pre{font-family:menlo,consolas,monospace;font-style:normal;font-weight:700;line-height:1.3em;margin:0}figure figcaption code,ol code,p a,p code,p span,ul code{white-space:nowrap}p code{padding:0 3px}body>header,figure{text-align:center}figure img{max-width:100%;max-height:100%}figcaption{font-weight:700;padding:3px 0}hr,iframe,img,table.data-box tr{border:0}hr{border-top:1px solid silver}sub,sup{font-size:.7rem}main{min-height:300px}aside{float:right;clear:right;font-size:.9rem;margin:0 0 20px 20px}aside.left{float:left;clear:left;margin:0 20px 20px 0}main section aside{max-width:35%;background-color:#f5f5f5;border:1px solid silver;padding:10px}main section aside.simple{background-color:transparent;border:0;padding:0}main section aside h2{font-size:1.1rem}main section aside img{width:100%;max-width:100%}main section aside p:last-child{margin-bottom:0}.float-endgame:after,section:after{content:" ";display:table;clear:both}body>footer{display:flex;justify-content:space-between;align-items:center;clear:both;text-align:center;font-size:.9rem;color:#a9a9a9;padding:30px 0}body>footer>div{min-width:20%}body>footer>div:first-child:last-child{width:100%}body>footer>div:first-child:not(:last-child){text-align:left}body>footer>div:last-child:not(:first-child){text-align:right}body>footer a img[alt=logo]{height:50px}h1{font-size:2.5rem;font-family:Chango,system-ui,sans-serif}h2{font-size:1.5rem}h3{font-size:1.2rem}h4{font-size:.9rem;font-weight:400;text-transform:uppercase;letter-spacing:.14em}h1+h2{font-weight:lighter;text-shadow:0 0 .2em #fff;margin:-.2em 0 .4em}quoteblock:before{content:open-quote}quoteblock:after{content:close-quote}i.font-icon{font-size:1.5em}a{color:#696969;text-decoration:none;border-bottom:1px dotted;outline:2px solid transparent;transition:all 500ms}a:visited{color:#a9a9a9}a:hover,img.popup-image+.popup-image-layer i[data-icon]:hover{color:#fff}a[title]{cursor:pointer}a i.font-icon,a img,i.font-icon[data-click],i.font-icon[data-href]{opacity:.9;transition:all 500ms}.bubble-help-hover.bubble-help-show>.bubble-wrap,.plain a img,a i.font-icon:hover,a img.plain,a img:hover,a.plain img,i.font-icon[data-click]:hover,i.font-icon[data-href]:hover{opacity:1}a figure figcaption{text-align:center;transition:all 500ms}a figure:hover figcaption{color:#000}.plain a,.plain-tables table tr,a.image-link,a.plain,nav a{border-bottom:none}.plain a:visited,a.image-link:visited,a.plain:visited,nav a:visited{color:inherit}.plain a:hover,a.image-link:hover,a.plain:hover,nav a:hover{color:inherit;background-color:transparent;outline-color:transparent}fieldset,form,label{display:block;max-width:25em;margin-bottom:1em}label>span:first-child{display:block}fieldset>aside,input,select,textarea{width:100%;max-width:25em;font-size:1.1em}input,textarea{background-color:#f5fffa;border:1px solid silver;border-radius:5px;padding:.3em}textarea{height:4.1em}label:has(input[type=checkbox],input[type=radio]){display:flex;align-items:center;padding-left:1.2em;margin-bottom:.1em}label:has(input:disabled)::target-text{opacity:.5}form.perfect fieldset label input,input[type=checkbox],input[type=radio]{width:auto;margin-right:.3em}input[type=range]{appearance:none;height:1.2em;padding:0;cursor:grab}input[type=range]:active{cursor:grabbing}button,input[type=checkbox],input[type=file],input[type=radio],select{cursor:pointer}input,optgroup,option,select,textarea{transition:all 500ms}:disabled{opacity:.5;cursor:not-allowed;pointer-events:none}input:out-of-range{background-color:pink}fieldset nav,form nav{text-align:right;margin-bottom:1em}fieldset nav button,form nav button{margin-left:.5em}button{font-size:1.1rem;font-weight:700;white-space:nowrap;color:#fff;border:0;border-radius:.4em;padding:.6em 1.2em;outline:0;transition:all 500ms}button i.font-icon{font-size:1.2em;vertical-align:top;padding-right:.4em}button:disabled{background-color:silver}label:has(select){position:relative;text-align:left;padding:0}label:has(select)::after{content:"❯";position:absolute;right:.4em;bottom:.03em;font-size:1.5em;transform:rotate(90deg);pointer-events:none}label:has(select) select{appearance:none;color:#000;background-color:#f5fffa;border:1px solid silver;padding:.3em 2em .3em .5em;margin:0}label:has(select) select:focus{background-color:#f0fff0}label:has(select) select:invalid{color:#b22222}fieldset,form.perfect fieldset{border:0;padding:0}fieldset:not(:has(>label>input[type=checkbox],>label>input[type=radio])){border:1px solid silver;border-radius:5px;padding:.8em 1em 0}fieldset:not(:has(>label>input[type=checkbox],>label>input[type=radio]))>legend{font-size:1.1em;font-weight:700;border:1px solid silver;border-radius:1000px;padding:.3em 1em}table{border-collapse:collapse;border-spacing:0;margin:0 auto 20px}table caption{caption-side:bottom;font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.16em;margin-top:.4rem}table tr{border-bottom:1px solid #4682b4;transition:all 500ms}table thead tr{border-bottom-width:3px}table tbody tr:hover,table.data-box{background-color:#f0f8ff}table tbody tr th[colspan]{font-size:.8rem;font-weight:400;text-align:center;text-transform:uppercase;color:#fff;background-color:#4682b4;padding:3px 0}table tbody tr td{font-size:.9rem;vertical-align:top;text-align:center}table tbody tr td.num{text-align:right}table td,table th{padding:6px 15px}table.data-box{border:3px solid #dcdcdc}table.data-box td,table.data-box th{font-size:.9rem;text-align:left;padding:4px 15px}table.data-box thead tr{background-color:#dcdcdc}table.data-box tbody tr:nth-child(odd){background-color:#f5fffa}table.data-box tbody tr:hover{background-color:#fffaf0}table.data-box tbody tr th[colspan]{background-color:#a9a9a9}.plain-tables table tbody td{text-align:left}.plain-tables table tbody tr:hover{background-color:transparent}@media (max-width:667px){table td,table th{padding:6px}}.flex-columns{display:flex;margin-bottom:20px}.flex-columns>*{flex:1;padding:0 15px;margin-bottom:20px}.flex-columns>:first-child{padding-left:0}.flex-columns>:last-child{padding-right:0}@media (max-width:667px){.flex-columns{flex-direction:column}.flex-columns>*{padding:0}}.keep-together{white-space:nowrap}.hide-me{display:none;visibility:hidden;padding:0;margin:0;opacity:0;z-index:-10000}.separator:after{content:"|";padding:0 5px}.hover-glow{transition:all 500ms}.hover-glow:hover{box-shadow:0 0 .2em #00bfff}.box-glow{box-shadow:0 0 2em #00bfff}.bullseye,.centered-flow-box{display:flex;justify-content:center}.centered-flow-box{flex-wrap:wrap}.bullseye{align-items:center}.framed img,img.framed{border:3px solid silver;border-radius:2px;transition:all 500ms}.framed img:hover,img.framed:hover{border-color:#696969}.modal-layer{display:none;position:fixed;top:0;left:0;width:100%;height:100vh;text-align:center}ul.simple-text{list-style-type:none;padding:0}ul.simple-text li{font-size:1rem;text-indent:0;padding:0}figure.video-container,figure.video-container-link{position:relative;width:100%;aspect-ratio:16/9;display:flex;align-items:stretch;align-content:stretch;background-color:#000;border:10px solid silver;margin:0 0 20px;overflow:hidden;transition:all 500ms}figure.video-container-link:hover,figure.video-container:hover{border-color:gray}figure.video-container-link>iframe,figure.video-container>iframe{width:100%;align-self:stretch;border:0}figure.video-container-link>iframe+figcaption,figure.video-container>iframe+figcaption{opacity:0}figure.video-container-link>a,figure.video-container>a{align-self:stretch;width:100%;cursor:pointer}figure.video-container-link>a>img,figure.video-container>a>img{display:block;width:100%;height:100%;object-fit:cover}figure.video-container-link>figcaption,figure.video-container>figcaption{position:absolute;top:5px;left:5px;font-weight:400;text-align:left;color:#fff;background-color:rgba(0,0,0,.4);border-radius:4px;padding:6px 16px;margin-right:30px;z-index:100;pointer-events:none}figure.video-container-link>iframe{pointer-events:none}form.perfect{display:flex;flex-direction:column;max-width:25em;background-color:#f5f5f5;color:#696969;border:1px solid;border-radius:2px;padding:0;margin:0 auto 20px}form.perfect>*{margin:0 20px 20px}form.perfect h2{font-size:1.2rem;text-align:center;color:#fff;padding:.3em;margin:0 0 20px}form.perfect label{display:block;font-size:1rem;text-align:left;margin-bottom:20px}form.perfect input,form.perfect select,form.perfect textarea{width:100%;max-width:100%;font-size:1.2rem;margin:0}form.perfect textarea{height:4.1em}form.perfect input,form.perfect textarea{box-sizing:border-box;border:1px solid silver;border-radius:5px;padding:.3em}form.perfect fieldset legend{font-size:1em}form.perfect fieldset label{display:flex;align-items:center;padding-left:1.2em;margin-bottom:.1em}form.perfect nav{display:flex;justify-content:space-between;align-items:flex-end}form.perfect nav button{font-size:1.1rem;font-weight:700;color:#fff;background-color:#696969;border:0;border-radius:.4em;padding:.6em 1.2em;cursor:pointer;transition:all 500ms}form.perfect nav button:focus,form.perfect nav button:hover:not(:disabled){background-color:#000}form.perfect nav small{font-size:.6rem;color:gray}form.perfect nav small a{color:gray;background-color:transparent;text-decoration:none;border:0;outline:0}.reveal-button{display:inline-block;border:1px solid;padding:3px 10px;margin-bottom:20px;transition:all 500ms;cursor:pointer}.reveal-button:hover{color:#fff;border-color:transparent}.reveal-target{display:none;margin-bottom:20px}[data-href-popup]{cursor:pointer}.json-key{color:brown}.json-value{color:navy}.json-boolean{color:teal}.json-string{color:olive}#fork-me,.bubble-help{display:none}.bubble-help-hover,.montage-loop{position:relative}.bubble-help-hover>.bubble-wrap{position:absolute;top:5px;left:0;transform:translateY(-100%);font-family:system-ui,sans-serif;font-size:.8rem;font-weight:700;pointer-events:none;z-index:200;opacity:0;transition:opacity 600ms 300ms}.bubble-help-hover>.bubble-wrap>.bubble-help{display:block;white-space:nowrap;border-radius:5px;padding:10px 20px}.bubble-help-hover>.bubble-wrap>.bubble-pointer{display:block;font-size:120%;text-align:left;padding-left:12px;margin-top:-.4em}body>header>#fork-me-container{position:absolute;top:0;right:0;width:200px;height:200px;overflow:hidden;z-index:150;pointer-events:none}body>header>#fork-me-container>a#fork-me{display:block;height:30px;line-height:30px;text-align:center;font-size:14px;font-weight:700;color:#fff;background-color:rgba(180,180,180,.8);border:1px solid #696969;transform:rotate(45deg);margin:60px -50px 0 0;transition:all 500ms;pointer-events:auto}body>header>#fork-me-container>a#fork-me:hover{color:#fff;background-color:#b4b4b4;outline:0}body>header>#fork-me-container>i.font-icon{display:none;position:absolute;top:10px;right:10px;font-size:40px;color:#696969;pointer-events:auto}@media (max-width:667px){body>header>#fork-me-container>a#fork-me{display:none}body>header>#fork-me-container>i.font-icon{display:block}}#social-buttons span i.font-icon{display:inline-block;width:24px;height:24px;line-height:24px;font-size:18px;vertical-align:top;text-align:center;color:#696969;background-color:#fff;border:1px solid silver;border-radius:.2em;transition:all 500ms}#social-buttons span i.font-icon:not(:last-child){margin-right:8px}#social-buttons span i.font-icon:hover{color:#6495ed;box-shadow:0 0 .4em #87ceeb}img.popup-image,img[data-popup-image]{max-width:120px;max-height:120px;opacity:.9;transition:all 500ms;cursor:pointer}img.popup-image:hover,img[data-popup-image]:hover{opacity:1}img.popup-image+.popup-image-layer{position:absolute;top:10px;left:10px;background-color:#fff;z-index:5000;opacity:0}img.popup-image+.popup-image-layer i[data-icon]{position:absolute;right:-.7em;top:-.7em;width:1.6em;height:1.6em;font-size:1.8rem;text-align:center;color:gray;background-color:silver;border-radius:1000px;padding-top:.3em;transition:all 500ms}img.popup-image+.popup-image-layer img{display:block;width:auto;height:auto;border:20px solid silver}.montage-loop>img{position:absolute;display:block;object-fit:cover;width:100%;height:100%;opacity:0}.montage-loop>img.previous{opacity:1;z-index:1000}.montage-loop>img.current{opacity:1;z-index:2000}.dna-panels .dna-panel::after{content:"";display:block;clear:both}@media (max-width:667px){h1{font-size:2rem}h1+h2{font-size:1.3rem}main section aside,main section aside.left{clear:both;float:none;max-width:none;text-align:center;margin:0 0 20px}main section aside img{width:auto;max-height:200px}body{padding:20px 10px}body>footer{flex-direction:column;padding:20px 2px}body>footer>div{text-align:center!important}body>footer>:not(:last-child){margin-bottom:15px}} +/*! web-ignition v2.2.1 ~~ https://github.com/center-key/web-ignition ~~ MIT License */ +@keyframes jiggle-it{0%{transform:rotate(-10deg)}50%{transform:rotate(10deg)}}@font-face{font-family:"Chango";font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/s/chango/v27/2V0cKI0OB5U7WaJCyHe8.ttf)format("truetype")}*{box-sizing:border-box}html{display:flex;flex-direction:column;height:100%;min-height:100%;font-size:115%;font-family:system-ui,geneva,tahoma,sans-serif}body{width:100%;flex:1;max-width:900px;color:#696969;padding:40px 15px;margin:0 auto}figure,h1,h2,h3,h4,h5,h6,nav ul,nav ul li,p{padding:0;margin:0}h1,h2,h3,h5,h6{letter-spacing:.04em}h1,h2,h3,h4,h5,h6{margin-bottom:.2em}figure,header,section{margin-bottom:20px}ol,p,ul{margin-bottom:.9em}ol,ul{margin-top:2px}ol li,ul li{font-size:.9em;padding-left:1.2em;text-indent:-1.3em}nav ul{list-style-type:none}nav ul li{text-indent:0}code,pre{font-family:menlo,consolas,monospace;font-style:normal;font-weight:700;line-height:1.3em;margin:0}figure figcaption code,ol code,p a,p code,p span,ul code{white-space:nowrap}p code{padding:0 3px}body>header,figure{text-align:center}figure img{max-width:100%;max-height:100%}figcaption{font-weight:700;padding:3px 0}hr,iframe,img,table.data-box tr{border:0}hr{border-top:1px solid silver}sub,sup{font-size:.7rem}main{min-height:300px}aside{float:right;clear:right;font-size:.9rem;margin:0 0 20px 20px}aside.left{float:left;clear:left;margin:0 20px 20px 0}main section aside{max-width:35%;background-color:#f5f5f5;border:1px solid silver;padding:10px}main section aside.simple{background-color:transparent;border:0;padding:0}main section aside h2{font-size:1.1rem}main section aside img{width:100%;max-width:100%}main section aside p:last-child{margin-bottom:0}.float-endgame:after,section:after{content:" ";display:table;clear:both}body>footer{display:flex;justify-content:space-between;align-items:center;clear:both;text-align:center;font-size:.9rem;color:#a9a9a9;padding:30px 0}body>footer>div{min-width:20%}body>footer>div:first-child:last-child{width:100%}body>footer>div:first-child:not(:last-child){text-align:left}body>footer>div:last-child:not(:first-child){text-align:right}body>footer a img[alt=logo]{height:50px}h1{font-size:2.5rem;font-family:Chango,system-ui,sans-serif}h2{font-size:1.5rem}h3{font-size:1.2rem}h4{font-size:.9rem;font-weight:400;text-transform:uppercase;letter-spacing:.14em}h1+h2{font-weight:lighter;text-shadow:0 0 .2em #fff;margin:-.2em 0 .4em}quoteblock:before{content:open-quote}quoteblock:after{content:close-quote}i.font-icon{font-size:1.5em}a{color:#696969;text-decoration:none;border-bottom:1px dotted;outline:2px solid transparent;transition:all 500ms}a:visited{color:#a9a9a9}a:hover,img.popup-image+.popup-image-layer i[data-icon]:hover{color:#fff}a[title]{cursor:pointer}a i.font-icon,a img,i.font-icon[data-click],i.font-icon[data-href]{opacity:.9;transition:all 500ms}.bubble-help-hover.bubble-help-show>.bubble-wrap,.plain a img,a i.font-icon:hover,a img.plain,a img:hover,a.plain img,i.font-icon[data-click]:hover,i.font-icon[data-href]:hover{opacity:1}a figure figcaption{text-align:center;transition:all 500ms}a figure:hover figcaption{color:#000}.plain a,.plain-tables table tr,a.image-link,a.plain,nav a{border-bottom:none}.plain a:visited,a.image-link:visited,a.plain:visited,nav a:visited{color:inherit}.plain a:hover,a.image-link:hover,a.plain:hover,nav a:hover{color:inherit;background-color:transparent;outline-color:transparent}fieldset,form,label{display:block;max-width:25em;margin-bottom:1em}label>span:first-child{display:block}fieldset>aside,input,select,textarea{width:100%;max-width:25em;font-size:1.1em}input,textarea{border:1px solid silver;border-radius:5px;padding:.3em}textarea{height:4.1em}label:has(input[type=checkbox],input[type=radio]){display:flex;align-items:center;padding-left:1.2em;margin-bottom:.1em}label:has(input:disabled)::target-text{opacity:.5}form.perfect fieldset label input,input[type=checkbox],input[type=radio]{width:auto;margin-right:.3em}input[type=range]{appearance:none;height:1.2em;padding:0;cursor:grab}input[type=range]:active{cursor:grabbing}button,input[type=checkbox],input[type=file],input[type=radio],select{cursor:pointer}input,optgroup,option,select,textarea{transition:all 500ms}:disabled{opacity:.5;cursor:not-allowed;pointer-events:none}input:out-of-range{background-color:pink}fieldset nav,form nav{text-align:right;margin-bottom:1em}fieldset nav button,form nav button{margin-left:.5em}input,textarea{background-color:#f5fffa}button{font-size:1.1rem;font-weight:700;white-space:nowrap;color:#fff;border:0;border-radius:.4em;padding:.6em 1.2em;outline:0;transition:all 500ms}button i.font-icon{font-size:1.2em;vertical-align:top;padding-right:.4em}button:disabled{background-color:silver}label:has(select){position:relative;text-align:left;padding:0}label:has(select)::after{content:"❯";position:absolute;right:.4em;bottom:.03em;font-size:1.5em;transform:rotate(90deg);pointer-events:none}label:has(select) select{appearance:none;color:#000;background-color:#f5fffa;border:1px solid silver;padding:.3em 2em .3em .5em;margin:0}label:has(select) select:focus{background-color:#f0fff0}label:has(select) select:invalid{color:#b22222}fieldset,form.perfect fieldset{border:0;padding:0}fieldset:not(:has(>label>input[type=checkbox],>label>input[type=radio])){border:1px solid silver;border-radius:5px;padding:.8em 1em 0}fieldset:not(:has(>label>input[type=checkbox],>label>input[type=radio]))>legend{font-size:1.1em;font-weight:700;border:1px solid silver;border-radius:1000px;padding:.3em 1em}table{border-collapse:collapse;border-spacing:0;margin:0 auto 20px}table caption{caption-side:bottom;font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.16em;margin-top:.4rem}table tr{border-bottom:1px solid #4682b4;transition:all 500ms}table thead tr{border-bottom-width:3px}table tbody tr:hover,table.data-box{background-color:#f0f8ff}table tbody tr th[colspan]{font-size:.8rem;font-weight:400;text-align:center;text-transform:uppercase;color:#fff;background-color:#4682b4;padding:3px 0}table tbody tr td{font-size:.9rem;vertical-align:top;text-align:center}table tbody tr td.num{text-align:right}table td,table th{padding:6px 15px}table.data-box{border:3px solid #dcdcdc}table.data-box td,table.data-box th{font-size:.9rem;text-align:left;padding:4px 15px}table.data-box thead tr{background-color:#dcdcdc}table.data-box tbody tr:nth-child(odd){background-color:#f5fffa}table.data-box tbody tr:hover{background-color:#fffaf0}table.data-box tbody tr th[colspan]{background-color:#a9a9a9}.plain-tables table tbody td{text-align:left}.plain-tables table tbody tr:hover{background-color:transparent}@media (max-width:667px){table td,table th{padding:6px}}.flex-columns{display:flex;margin-bottom:20px}.flex-columns>*{flex:1;padding:0 15px;margin-bottom:20px}.flex-columns>:first-child{padding-left:0}.flex-columns>:last-child{padding-right:0}@media (max-width:667px){.flex-columns{flex-direction:column}.flex-columns>*{padding:0}}.keep-together{white-space:nowrap}.hide-me{display:none;visibility:hidden;padding:0;margin:0;opacity:0;z-index:-10000}.separator:after{content:"|";padding:0 5px}.hover-glow{transition:all 500ms}.hover-glow:hover{box-shadow:0 0 .2em #00bfff}.box-glow{box-shadow:0 0 2em #00bfff}.bullseye,.centered-flow-box{display:flex;justify-content:center}.centered-flow-box{flex-wrap:wrap}.bullseye{align-items:center}.framed img,img.framed{border:3px solid silver;border-radius:2px;transition:all 500ms}.framed img:hover,img.framed:hover{border-color:#696969}.modal-layer{display:none;position:fixed;top:0;left:0;width:100%;height:100vh;text-align:center}ul.simple-text{list-style-type:none;padding:0}ul.simple-text li{font-size:1rem;text-indent:0;padding:0}figure.video-container,figure.video-container-link{position:relative;width:100%;aspect-ratio:16/9;display:flex;align-items:stretch;align-content:stretch;background-color:#000;border:10px solid silver;margin:0 0 20px;overflow:hidden;transition:all 500ms}figure.video-container-link:hover,figure.video-container:hover{border-color:gray}figure.video-container-link>iframe,figure.video-container>iframe{width:100%;align-self:stretch;border:0}figure.video-container-link>iframe+figcaption,figure.video-container>iframe+figcaption{opacity:0}figure.video-container-link>a,figure.video-container>a{align-self:stretch;width:100%;cursor:pointer}figure.video-container-link>a>img,figure.video-container>a>img{display:block;width:100%;height:100%;object-fit:cover}figure.video-container-link>figcaption,figure.video-container>figcaption{position:absolute;top:5px;left:5px;font-weight:400;text-align:left;color:#fff;background-color:rgba(0,0,0,.4);border-radius:4px;padding:6px 16px;margin-right:30px;z-index:100;pointer-events:none}figure.video-container-link>iframe{pointer-events:none}form.perfect{display:flex;flex-direction:column;max-width:25em;background-color:#f5f5f5;color:#696969;border:1px solid;border-radius:2px;padding:0;margin:0 auto 20px}form.perfect>*{margin:0 20px 20px}form.perfect h2{font-size:1.2rem;text-align:center;color:#fff;padding:.3em;margin:0 0 20px}form.perfect label{display:block;font-size:1rem;text-align:left;margin-bottom:20px}form.perfect input,form.perfect select,form.perfect textarea{width:100%;max-width:100%;font-size:1.2rem;margin:0}form.perfect textarea{height:4.1em}form.perfect input,form.perfect textarea{box-sizing:border-box;border:1px solid silver;border-radius:5px;padding:.3em}form.perfect fieldset legend{font-size:1em}form.perfect fieldset label{display:flex;align-items:center;padding-left:1.2em;margin-bottom:.1em}form.perfect nav{display:flex;justify-content:space-between;align-items:flex-end}form.perfect nav button{font-size:1.1rem;font-weight:700;color:#fff;background-color:#696969;border:0;border-radius:.4em;padding:.6em 1.2em;cursor:pointer;transition:all 500ms}form.perfect nav button:focus,form.perfect nav button:hover:not(:disabled){background-color:#000}form.perfect nav small{font-size:.6rem;color:gray}form.perfect nav small a{color:gray;background-color:transparent;text-decoration:none;border:0;outline:0}.reveal-button{display:inline-block;border:1px solid;padding:3px 10px;margin-bottom:20px;transition:all 500ms;cursor:pointer}.reveal-button:hover{color:#fff;border-color:transparent}.reveal-target{display:none;margin-bottom:20px}[data-href-popup]{cursor:pointer}.json-key{color:brown}.json-value{color:navy}.json-boolean{color:teal}.json-string{color:olive}#fork-me,.bubble-help{display:none}.bubble-help-hover,.montage-loop{position:relative}.bubble-help-hover>.bubble-wrap{position:absolute;top:5px;left:0;transform:translateY(-100%);font-family:system-ui,sans-serif;font-size:.8rem;font-weight:700;pointer-events:none;z-index:200;opacity:0;transition:opacity 600ms 300ms}.bubble-help-hover>.bubble-wrap>.bubble-help{display:block;white-space:nowrap;border-radius:5px;padding:10px 20px}.bubble-help-hover>.bubble-wrap>.bubble-pointer{display:block;font-size:120%;text-align:left;padding-left:12px;margin-top:-.4em}body>header>#fork-me-container{position:absolute;top:0;right:0;width:200px;height:200px;overflow:hidden;z-index:150;pointer-events:none}body>header>#fork-me-container>a#fork-me{display:block;height:30px;line-height:30px;text-align:center;font-size:14px;font-weight:700;color:#fff;background-color:rgba(180,180,180,.8);border:1px solid #696969;transform:rotate(45deg);margin:60px -50px 0 0;transition:all 500ms;pointer-events:auto}body>header>#fork-me-container>a#fork-me:hover{color:#fff;background-color:#b4b4b4;outline:0}body>header>#fork-me-container>i.font-icon{display:none;position:absolute;top:10px;right:10px;font-size:40px;color:#696969;pointer-events:auto}@media (max-width:667px){body>header>#fork-me-container>a#fork-me{display:none}body>header>#fork-me-container>i.font-icon{display:block}}#social-buttons span i.font-icon{display:inline-block;width:24px;height:24px;line-height:24px;font-size:18px;vertical-align:top;text-align:center;color:#696969;background-color:#fff;border:1px solid silver;border-radius:.2em;transition:all 500ms}#social-buttons span i.font-icon:not(:last-child){margin-right:8px}#social-buttons span i.font-icon:hover{color:#6495ed;box-shadow:0 0 .4em #87ceeb}img.popup-image,img[data-popup-image]{max-width:120px;max-height:120px;opacity:.9;transition:all 500ms;cursor:pointer}img.popup-image:hover,img[data-popup-image]:hover{opacity:1}img.popup-image+.popup-image-layer{position:absolute;top:10px;left:10px;background-color:#fff;z-index:5000;opacity:0}img.popup-image+.popup-image-layer i[data-icon]{position:absolute;right:-.7em;top:-.7em;width:1.6em;height:1.6em;font-size:1.8rem;text-align:center;color:gray;background-color:silver;border-radius:1000px;padding-top:.3em;transition:all 500ms}img.popup-image+.popup-image-layer img{display:block;width:auto;height:auto;border:20px solid silver}.montage-loop>img{position:absolute;display:block;object-fit:cover;width:100%;height:100%;opacity:0}.montage-loop>img.previous{opacity:1;z-index:1000}.montage-loop>img.current{opacity:1;z-index:2000}.dna-panels .dna-panel::after{content:"";display:block;clear:both}@media (max-width:667px){h1{font-size:2rem}h1+h2{font-size:1.3rem}main section aside,main section aside.left{clear:both;float:none;max-width:none;text-align:center;margin:0 0 20px}main section aside img{width:auto;max-height:200px}body{padding:20px 10px}body>footer{flex-direction:column;padding:20px 2px}body>footer>div{text-align:center!important}body>footer>:not(:last-child){margin-bottom:15px}} /******************************************************************************/ /****************************************/ diff --git a/package.json b/package.json index e14b743..08dfaba 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "web-ignition", "description": "Start a fire", - "version": "2.2.0", + "version": "2.2.1", "license": "MIT", "type": "module", "module": "dist/lib-x.js", @@ -119,7 +119,7 @@ "rimraf": "~5.0", "run-scripts-util": "~1.2", "typescript": "~5.4", - "typescript-eslint": "~7.11", + "typescript-eslint": "~7.12", "uglify-js": "~3.17", "w3c-html-validator": "~1.8" }