/* =====================================================================
   Playground — tools & games (one stylesheet, namespaced `pg-`).
   Everything is built on the theme's CSS vars, so the same rules render
   correctly in BOTH the Mocha (dark) default and the Light theme. Loaded
   only on template-tools.php / template-games.php / template-pg-item.php.
   ===================================================================== */

.pg-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ---------------------------------------------------------------------
   Landing pages (Tools / Games): heading + card grid
   --------------------------------------------------------------------- */
.pg-land-head{padding-top:54px;padding-bottom:8px}
@media (max-width:720px){.pg-land-head{padding-top:34px}}
.pg-land-meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:18px}
.pg-land-badge{font-family:var(--mono);font-size:.72rem;color:var(--text-dim);background:rgba(var(--accent-rgb),.07);
  border:1px solid var(--border);border-radius:999px;padding:6px 12px;transition:border-color var(--dur-fast),background var(--dur-fast)}
.pg-land-badge b{color:var(--blue);font-weight:800}
.pg-land-grid-sec{padding-top:8px}

/* auto-flow so the grid fills cleanly (3 games → one row of 3; 7 tools → 4+3) with no lone orphan card */
.pg-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:18px}
.pg-qr-dls{display:flex;gap:10px;flex-wrap:wrap;margin-top:4px}
.pg-qr-dls .btn{flex:1 1 auto;justify-content:center}
/* password/passphrase mode toggle — same tokens as the shared .pg-seg */
.pg-mode{display:inline-flex;border:1px solid var(--border-2);border-radius:9px;overflow:hidden;background:var(--bg-2);margin-bottom:16px}
.pg-mode-btn{font:600 .78rem/1 var(--mono);color:var(--text-dim);background:transparent;border:0;padding:8px 14px;cursor:pointer;transition:background var(--dur-fast),color var(--dur-fast)}
.pg-mode-btn+.pg-mode-btn{border-left:1px solid var(--border)}
.pg-mode-btn:hover{color:var(--text)}
.pg-mode-btn.is-active,.pg-mode-btn[aria-pressed="true"]{background:rgba(var(--accent-rgb),.16);color:var(--blue)}
.pg-mode-btn:focus-visible{outline:2px solid var(--blue);outline-offset:-2px}
.pg-mini-select{font-family:var(--mono);font-size:.78rem;background:var(--bg);color:var(--text);border:1px solid var(--border-2);border-radius:6px;padding:3px 6px;margin-left:6px}
/* fullscreen game cards (.is-fs is toggled in JS on fullscreenchange) */
.pg-fs-btn{cursor:pointer}
.pg-card.is-fs{width:100vw;height:100vh;max-width:none;border-radius:0;display:flex;flex-direction:column;background:var(--bg)}
.pg-card.is-fs .win-bar{flex:0 0 auto}
.pg-card.is-fs .pg-body{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;align-items:center;justify-content:center;overflow:auto;padding:18px}
.pg-card.is-fs .pg-canvas-wrap{max-width:min(96vw,150vh)}
.pg-card.is-fs .pg-game-bar,.pg-card.is-fs .pg-dpad{flex:0 0 auto}
/* Star Defender: keep aspect in fullscreen (its canvas is normally width:100%) — width follows the JS-set height */
.pg-card.is-fs #sdCanvas{width:auto;max-width:96vw;margin-left:auto;margin-right:auto}
.pg-cardlink{position:relative;display:grid;grid-template-columns:44px minmax(0,1fr) auto;
  grid-template-areas:"icon title arrow" "desc desc desc" "best best best";
  column-gap:14px;row-gap:10px;align-items:center;overflow:hidden;
  padding:18px 18px;border:1px solid var(--border);border-radius:var(--radius);text-decoration:none;color:inherit;
  background:linear-gradient(180deg,var(--panel),var(--bg-2));box-shadow:0 2px 10px -7px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.03);
  transition:transform var(--dur-base) var(--ease-premium), border-color var(--dur-base) var(--ease-premium), box-shadow var(--dur-base) var(--ease-premium)}
html[data-theme="latte"] .pg-cardlink{background:linear-gradient(180deg,#ffffff,#fbfcff)}
.pg-cardlink:hover{transform:translateY(-6px);border-color:var(--blue);
  box-shadow:0 22px 50px -24px rgba(0,0,0,.7), 0 0 46px -28px var(--blue)}
html[data-theme="latte"] .pg-cardlink:hover{box-shadow:0 20px 46px -22px rgba(40,60,110,.30), 0 0 0 1px rgba(var(--accent-rgb),.14)}
.pg-cardlink:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
/* running border-sheen on hover, matching the rest of the cards */
.pg-cardlink::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;z-index:4;padding:1px;opacity:0;transition:opacity var(--dur-mid);
  background:linear-gradient(115deg,transparent 0 42%,rgba(var(--accent-rgb),.55) 50%,transparent 58% 100%);background-size:260% 100%;
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;
  mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);mask-composite:exclude;
  animation:borderSheen 7s ease-in-out infinite}
.pg-cardlink:hover::after{opacity:1}
.pg-cardlink-bar{position:absolute;top:0;left:0;height:3px;width:100%;background:var(--blue);opacity:0;transition:opacity var(--dur-base)}
.pg-cardlink:hover .pg-cardlink-bar{opacity:1}
.pg-cardlink-icon{flex:0 0 auto;width:44px;height:44px;border-radius:11px;display:flex;align-items:center;justify-content:center;
  background:rgba(var(--accent-rgb),.1);border:1px solid var(--border-2);transition:transform var(--dur-base) var(--ease-premium), box-shadow var(--dur-base) var(--ease-premium)}
.pg-cardlink-icon svg{width:22px;height:22px;stroke:var(--blue)}
.pg-cardlink:hover .pg-cardlink-icon{transform:scale(1.1) rotate(-5deg);box-shadow:0 6px 18px -8px var(--blue)}
.pg-cardlink-body{display:contents}
.pg-cardlink-icon{grid-area:icon}
.pg-cardlink-title{grid-area:title;font-size:1.02rem;font-weight:700;letter-spacing:-.3px;color:var(--text);line-height:1.3}
.pg-cardlink:hover .pg-cardlink-title{color:var(--blue)}
.pg-cardlink-desc{grid-area:desc;font-size:.875rem;color:var(--text-dim);line-height:1.55}
.pg-best{grid-area:best;justify-self:start;align-self:end;font-family:var(--mono);font-size:.72rem;font-weight:600;line-height:1;padding:3px 8px;border-radius:999px;border:1px solid var(--border);color:var(--text-mut);background:rgba(255,255,255,.02)}
.pg-best.has-best{color:var(--green);border-color:color-mix(in srgb, var(--green) 40%, transparent)}
.pgs-row{display:flex;gap:8px;justify-content:center;flex-wrap:wrap;margin-top:12px}
.pgs-wrap{display:flex;flex-direction:column;align-items:center;gap:11px;margin-top:12px}
.pgs-preview{width:100%;max-width:340px;height:auto;border-radius:10px;border:1px solid var(--border);box-shadow:0 16px 40px -20px rgba(0,0,0,.7);display:block}
.pgs-actions{display:flex;gap:8px;justify-content:center;flex-wrap:wrap}
.pgs-btn{font-family:var(--mono);font-size:.76rem;font-weight:600;padding:7px 13px;border-radius:8px;border:1px solid var(--border);background:rgba(255,255,255,.03);color:var(--text-dim);cursor:pointer;transition:color var(--dur-fast),border-color var(--dur-fast),background var(--dur-fast)}
.pgs-btn:hover{color:var(--text);border-color:var(--blue);background:rgba(137,180,250,.08)}
.pgs-btn.is-done{color:var(--green);border-color:var(--green)}
.pg-cardlink-arrow{grid-area:arrow;font-family:var(--mono);color:var(--text-mut);align-self:center;transition:transform var(--dur-fast) var(--ease-premium), color var(--dur-fast)}
.pg-cardlink:hover .pg-cardlink-arrow{transform:translateX(4px);color:var(--blue)}
.pg-cardlink:active{transform:translateY(-2px) scale(.992)}
/* "More tools / More games" block under a single item page */
.pg-more-sec{padding-top:18px}
.pg-more-sec .sec-title{font-size:1.35rem}
.pg-more-cards{}
.pg-item-bridge{margin:22px 0 0;text-align:center;font-family:var(--mono);font-size:.78rem;color:var(--text-mut)}
.pg-item-bridge a{color:var(--green);text-decoration:none}
.pg-item-bridge a:hover{text-decoration:underline;text-underline-offset:3px}
/* the deliberate "all →" ghost card that fills the 4th slot */
.pg-ghostlink{display:flex;align-items:center;justify-content:center;border-style:dashed;background:transparent;min-height:96px;padding-top:18px}
.pg-ghostlink::after{display:none}
.pg-ghostlink-label{font-family:var(--mono);font-size:.95rem;font-weight:700;color:var(--text-dim)}
.pg-ghostlink:hover .pg-ghostlink-label{color:var(--text)}
.pg-ghostlink .arrow{display:inline-block;transition:transform var(--dur-base) var(--ease-premium)}
.pg-ghostlink:hover .arrow{transform:translateX(4px)}

/* ---------------------------------------------------------------------
   Item page: breadcrumb + single-tool layout
   --------------------------------------------------------------------- */
/* SLIM header band — the tool itself is the hero of this page; a full hero
   band pushed the actual tool below the fold (visitors had to scroll to use it) */
.pg-item-head{padding-top:40px;padding-bottom:0}
@media (max-width:720px){.pg-item-head{padding-top:30px}}
.pg-item-head .sec-head{margin-bottom:0;max-width:none;display:flex;align-items:baseline;gap:6px 16px;flex-wrap:wrap}
.pg-item-head .sec-title{font-size:1.55rem;letter-spacing:-.5px;margin:0}
.pg-item-head .sec-desc{font-size:1rem}
.pg-crumb{display:flex;align-items:center;gap:8px;font-family:var(--mono);font-size:.76rem;color:var(--text-mut);margin-bottom:8px}
.pg-crumb a{color:var(--blue);text-decoration:none}
.pg-crumb a:hover{text-decoration:underline;text-underline-offset:2px}
.pg-crumb-sep{color:var(--gutter)}
.pg-crumb-cur{color:var(--text-dim)}
.pg-item-body-sec{padding-top:30px;padding-bottom:40px}
.pg-item-wrap{max-width:720px}
.pg-item-wrap.pg-item-tool{max-width:1000px}
.pg-item-wrap .pg-card{display:flex;flex-direction:column}
/* wide two-column layout for tools that opt in via .pg-2col on the .pg-body
   (.pg-body.pg-2col doubled so the grid beats the later .pg-body flex rule) */
.pg-2col,.pg-body.pg-2col{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);gap:20px;align-items:start}
@media (max-width:820px){ .pg-2col,.pg-body.pg-2col{grid-template-columns:1fr} }

/* ---------------------------------------------------------------------
   Shared card body + form primitives
   --------------------------------------------------------------------- */
.pg-card{display:flex;flex-direction:column}
.pg-body{padding:20px;display:flex;flex-direction:column;gap:14px}
.pg-field{display:flex;flex-direction:column;gap:7px}
.pg-label{font-family:var(--mono);font-size:.72rem;color:var(--text-mut);text-transform:uppercase;letter-spacing:.6px}
.pg-label-row{display:flex;align-items:center;justify-content:space-between;gap:10px}
.pg-clear{flex:0 0 auto}
.pg-val{color:var(--blue);font-weight:700}
.pg-lead{font-size:.9rem;color:var(--text-dim);margin:0;line-height:1.55}

/* shared compact button variant — the ONE sanctioned .btn size override for tight toolbars */
.btn.btn-sm{padding:9px 15px;font-size:.8rem}

/* shared micro section heading — mono uppercase + hairline ornament */
.pg-sec-h{font:700 .7rem/1 var(--mono);letter-spacing:.12em;text-transform:uppercase;color:var(--text-mut);display:flex;align-items:center;gap:9px}
.pg-sec-h::after{content:"";flex:1;height:1px;background:var(--border)}

/* shared segmented control */
.pg-seg{display:inline-flex;border:1px solid var(--border-2);border-radius:9px;overflow:hidden;background:var(--bg-2)}
.pg-seg button{background:transparent;border:0;color:var(--text-dim);font:600 .78rem/1 var(--mono);padding:8px 14px;cursor:pointer;transition:background var(--dur-fast),color var(--dur-fast)}
.pg-seg button+button{border-left:1px solid var(--border)}
.pg-seg button:hover{color:var(--text)}
.pg-seg button[aria-pressed="true"]{background:rgba(var(--accent-rgb),.16);color:var(--blue)}
.pg-seg button:focus-visible{outline:2px solid var(--blue);outline-offset:-2px}

.pg-input{width:100%;background:var(--bg-2);border:1px solid var(--border-2);border-radius:9px;color:var(--text);
  font-family:var(--mono);font-size:.88rem;padding:10px 12px;outline:none;transition:border-color var(--dur-fast), box-shadow var(--dur-fast)}
.pg-input:focus{border-color:var(--blue);box-shadow:0 0 0 3px rgba(var(--accent-rgb),.16)}
.pg-input::placeholder{color:var(--text-mut)}
.pg-input[readonly]{color:var(--green);background:rgba(var(--accent-rgb),.05)}
.pg-textarea{resize:vertical;line-height:1.6;min-height:84px}

/* range slider (themed) */
.pg-range{-webkit-appearance:none;appearance:none;width:100%;height:6px;border-radius:4px;background:var(--border-2);outline:none;cursor:pointer}
.pg-range::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:18px;height:18px;border-radius:50%;
  background:var(--blue);border:2px solid var(--panel);box-shadow:0 2px 8px -2px rgba(0,0,0,.5);cursor:pointer}
.pg-range::-moz-range-thumb{width:18px;height:18px;border-radius:50%;background:var(--blue);border:2px solid var(--panel);cursor:pointer}
.pg-range:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 3px rgba(var(--accent-rgb),.3)}

/* select with caret */
.pg-selectwrap{position:relative}
.pg-select{width:100%;appearance:none;-webkit-appearance:none;-moz-appearance:none;cursor:pointer;
  background:var(--bg-2);border:1px solid var(--border-2);border-radius:9px;color:var(--text);
  font-family:var(--mono);font-size:.86rem;padding:10px 36px 10px 12px;outline:none;transition:border-color var(--dur-fast), box-shadow var(--dur-fast)}
.pg-select:focus{border-color:var(--blue);box-shadow:0 0 0 3px rgba(var(--accent-rgb),.16)}
.pg-select option{background:var(--panel);color:var(--text)}
.pg-select-caret{position:absolute;right:13px;top:50%;transform:translateY(-50%);pointer-events:none;color:var(--text-mut);font-size:.75rem}

/* checkboxes */
.pg-checks{border:1px solid var(--border-2);border-radius:11px;padding:12px 14px;margin:0;display:flex;flex-direction:column;gap:8px}
.pg-checks legend{padding:0 6px;margin-left:-6px}
.pg-check-inline{display:flex;align-items:center;gap:10px;font-size:.88rem;color:var(--text-dim);cursor:pointer}
.pg-check-inline input[type="checkbox"]{flex:0 0 auto;width:17px;height:17px;accent-color:var(--green);cursor:pointer}

/* copy row + output chip */
.pg-copyrow{display:flex;gap:8px;align-items:stretch}
.pg-output{flex:1;min-width:0;background:rgba(var(--accent-rgb),.06);border:1px solid var(--border-2);border-radius:9px;
  font-family:var(--mono);font-size:.85rem;color:var(--green);padding:10px 12px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;display:flex;align-items:center}
.pg-copy,.pg-regen,.pg-swap{flex:0 0 auto}
.pg-copy.copied{color:var(--green);border-color:var(--green)}

/* char-counter / strength meter */
.pg-meter{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.pg-meter-bar{flex:1;min-width:120px;height:6px;border-radius:4px;background:var(--border-2);overflow:hidden}
.pg-meter-bar i{display:block;height:100%;width:100%;transform:scaleX(0);transform-origin:left center;border-radius:4px;background:var(--text-mut);transition:transform var(--dur-base) var(--ease-premium), background var(--dur-base) var(--ease-premium)}
.pg-meter-txt{font-family:var(--mono);font-size:.74rem;color:var(--text-mut);white-space:nowrap}
.pg-flag{font-weight:700}
.pg-meter[data-state="weak"]   .pg-meter-bar i{background:var(--red)}
.pg-meter[data-state="fair"]   .pg-meter-bar i{background:var(--yellow)}
.pg-meter[data-state="good"]   .pg-meter-bar i{background:var(--teal)}
.pg-meter[data-state="strong"] .pg-meter-bar i{background:var(--green)}
.pg-meter[data-state="weak"]   .pg-flag{color:var(--red)}
.pg-meter[data-state="fair"]   .pg-flag{color:var(--yellow)}
.pg-meter[data-state="good"]   .pg-flag{color:var(--teal)}
.pg-meter[data-state="strong"] .pg-flag{color:var(--green)}

/* ---------------------------------------------------------------------
   Word & Character Counter
   --------------------------------------------------------------------- */
.pg-statgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.pg-stat{display:flex;flex-direction:column;gap:4px;padding:14px 12px;border:1px solid var(--border-2);border-radius:11px;
  background:rgba(var(--accent-rgb),.04);text-align:center}
.pg-stat-num{font-family:var(--mono);font-size:clamp(1.2rem,3.4vw,1.6rem);font-weight:800;color:var(--text);letter-spacing:-.5px;line-height:1}
.pg-stat-lab{font-family:var(--mono);font-size:.7rem;color:var(--text-mut);text-transform:uppercase;letter-spacing:.5px}

/* ---------------------------------------------------------------------
   Password Generator
   --------------------------------------------------------------------- */
.pg-pwd-output{font-size:1rem;letter-spacing:.5px;color:var(--green) !important}
.pg-generate{align-self:flex-start}

/* ---------------------------------------------------------------------
   Color Converter
   --------------------------------------------------------------------- */
.pg-color-top{display:flex;align-items:flex-end;gap:14px}
.pg-color-pickwrap{display:flex;flex-direction:column;gap:7px}
.pg-color-pickwrap input[type="color"]{width:64px;height:64px;padding:0;border:1px solid var(--border-2);border-radius:12px;background:var(--bg-2);cursor:pointer}
.pg-color-pickwrap input[type="color"]::-webkit-color-swatch-wrapper{padding:4px}
.pg-color-pickwrap input[type="color"]::-webkit-color-swatch{border:none;border-radius:8px}
.pg-color-preview{flex:1;align-self:stretch;min-height:64px;border:1px solid var(--border-2);border-radius:12px;background:#89b4fa;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.06)}
.pg-hex{text-transform:lowercase}

/* ---------------------------------------------------------------------
   Image Resizer & Compressor
   --------------------------------------------------------------------- */
.pg-drop{display:flex;align-items:center;justify-content:center;text-align:center;cursor:pointer;
  border:1.5px dashed var(--border-2);border-radius:14px;padding:34px 20px;background:rgba(var(--accent-rgb),.03);
  transition:border-color var(--dur-fast), background var(--dur-fast)}
.pg-drop:hover,.pg-drop.dragover{border-color:var(--blue);background:rgba(var(--accent-rgb),.08)}
.pg-drop-inner{display:flex;flex-direction:column;align-items:center;gap:8px}
.pg-drop-inner svg{width:34px;height:34px;color:var(--blue)}
.pg-drop-txt{font-size:.95rem;color:var(--text);font-weight:600}
.pg-drop-sub{font-family:var(--mono);font-size:.74rem;color:var(--text-mut)}
.pg-ir-panel{display:grid;grid-template-columns:1fr 1fr;gap:18px;align-items:start}
.pg-ir-preview{border:1px solid var(--border-2);border-radius:12px;overflow:hidden;background:var(--bg);
  display:flex;align-items:center;justify-content:center;min-height:160px;
  background-image:linear-gradient(45deg,var(--border-2) 25%,transparent 25%),linear-gradient(-45deg,var(--border-2) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,var(--border-2) 75%),linear-gradient(-45deg,transparent 75%,var(--border-2) 75%);
  background-size:18px 18px;background-position:0 0,0 9px,9px -9px,-9px 0}
.pg-ir-preview img{display:block;max-width:100%;height:auto}
.pg-ir-controls{display:flex;flex-direction:column;gap:13px}
.pg-ir-dims{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.pg-ir-size{font-family:var(--mono);font-size:.8rem;color:var(--text-dim);line-height:1.6}
.pg-ir-size b{color:var(--green)}
.pg-ir-download{font-size:.88rem}

/* ---------------------------------------------------------------------
   QR Code Generator
   --------------------------------------------------------------------- */
.pg-qr-body{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:24px;align-items:center}
.pg-qr-controls{display:flex;flex-direction:column;gap:13px}
.pg-qr-stage{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;align-self:stretch}
#qr-canvas{width:100%;max-width:320px;height:auto;image-rendering:pixelated;border:1px solid var(--border-2);border-radius:12px;
  background:#fff;padding:10px}
.pg-qr-msg{font-family:var(--mono);font-size:.78rem;color:var(--text-mut);margin:0;text-align:center;min-height:1.2em}
.pg-qr-msg.err{color:var(--red)}

/* ---------------------------------------------------------------------
   Games — shared chrome (canvas/board, overlay, controls, d-pad)
   --------------------------------------------------------------------- */
.pg-game-body{gap:14px}
.pg-canvas-wrap,.pg-2048-wrap,.pg-mem-wrap{position:relative;width:100%;max-width:420px;margin:0 auto}
.pg-canvas-wrap{max-width:600px;aspect-ratio:24/15;border:1px solid var(--border);border-radius:12px;overflow:hidden;background:var(--bg);box-shadow:inset 0 0 0 1px rgba(var(--accent-rgb),.05)}
#snakeCanvas{display:block;width:100%;height:100%;touch-action:none}

.pg-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;border-radius:12px;
  background:rgba(13,17,23,.74);backdrop-filter:blur(3px);text-align:center;padding:18px;transition:opacity var(--dur-base)}
html[data-theme="latte"] .pg-overlay{background:rgba(243,246,252,.8)}
.pg-overlay.hidden{opacity:0;pointer-events:none}
.pg-overlay-card{max-width:300px;display:flex;flex-direction:column;gap:10px;align-items:center}
.pg-overlay-title{font-family:var(--mono);font-weight:800;font-size:1.5rem;letter-spacing:-.5px;color:var(--text)}
.pg-overlay-msg{font-size:.88rem;color:var(--text-dim);margin:0;line-height:1.5}
.pg-start{font-size:.9rem;padding:11px 20px}

.pg-game-bar{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.pg-game-hint{font-family:var(--mono);font-size:.72rem;color:var(--text-mut);margin-left:auto}

.pg-dpad{display:grid;grid-template-columns:repeat(3,46px);grid-template-rows:repeat(2,46px);gap:6px;justify-content:center;margin:2px auto 0}
/* mono filename chip — the cards are an `ls` of executables, say so */
.pg-cardlink{position:relative}
.pg-cardlink-file{position:absolute;top:8px;right:12px;font-family:var(--mono);font-size:.62rem;color:var(--text-mut);opacity:.7;pointer-events:none;max-width:46%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pg-cardlink{padding-top:28px}
.pg-cardlink-arrow::before{content:"run ";font-family:var(--mono);font-size:.72rem;color:var(--green);opacity:0;transition:opacity var(--dur-fast)}
.pg-cardlink:hover .pg-cardlink-arrow::before{opacity:1}
@media (prefers-reduced-motion:reduce){.pg-cardlink-arrow::before{transition:none}}

/* touch controls are for touch — mouse+keyboard players don't need an on-screen D-pad */
@media (hover:hover) and (pointer:fine){.pg-dpad{display:none}}

/* ---------------------------------------------------------------------
   Landing-card VIGNETTES — every icon "runs" on hover ("everything on this
   site is a running program"). Pure transform/opacity/stroke keyframes on
   the inline SVG children; gated to hover devices; silenced by the
   reduced-motion block at the end of this file.
   --------------------------------------------------------------------- */
@media (hover:hover){
  .pg-cardlink svg *{transform-box:fill-box;transform-origin:center}
  /* snake: the body slithers, the food blinks */
  .pg-card--snake:is(:hover,.pg-attract) svg path{stroke-dasharray:34 10;animation:pgvSlither 1.2s linear infinite}
  .pg-card--snake:is(:hover,.pg-attract) svg circle{animation:pgvBlink 1.2s steps(2) infinite}
  @keyframes pgvSlither{to{stroke-dashoffset:-44}}
  @keyframes pgvBlink{50%{opacity:.25}}
  /* star defender: the ship lifts off on its thrusters */
  .pg-card--star-defender:is(:hover,.pg-attract) svg{animation:pgvLift .7s var(--ease-back) infinite alternate}
  .pg-card--star-defender:is(:hover,.pg-attract) svg path:last-of-type{animation:pgvFlicker .18s steps(2) infinite}
  @keyframes pgvLift{from{transform:translateY(1.5px)}to{transform:translateY(-2px)}}
  @keyframes pgvFlicker{50%{opacity:.35}}
  /* bubble shooter: the bubbles pop one by one */
  .pg-card--bubble-shooter:is(:hover,.pg-attract) svg circle{animation:pgvPop 1.4s ease-in-out infinite}
  .pg-card--bubble-shooter:is(:hover,.pg-attract) svg circle:nth-of-type(2){animation-delay:.25s}
  .pg-card--bubble-shooter:is(:hover,.pg-attract) svg circle:nth-of-type(3){animation-delay:.5s}
  @keyframes pgvPop{0%,100%{transform:scale(1);opacity:1}12%{transform:scale(1.35);opacity:.15}24%{transform:scale(1);opacity:1}}
  /* typing test: keystrokes ripple across the board */
  .pg-card--typing-test:is(:hover,.pg-attract) svg path{stroke-dasharray:3 4;animation:pgvType .8s linear infinite}
  @keyframes pgvType{to{stroke-dashoffset:-7}}
  /* password: the key turns */
  .pg-card--password-generator:is(:hover,.pg-attract) svg path{animation:pgvKeyTurn 1s var(--ease-back) infinite}
  @keyframes pgvKeyTurn{0%,100%{transform:rotate(0)}40%{transform:rotate(-14deg)}}
  /* qr: the modules shuffle */
  .pg-card--qr-code:is(:hover,.pg-attract) svg rect{animation:pgvBlink .6s steps(2) infinite}
  .pg-card--qr-code:is(:hover,.pg-attract) svg rect:nth-of-type(2){animation-delay:.2s}
  .pg-card--qr-code:is(:hover,.pg-attract) svg rect:nth-of-type(3){animation-delay:.4s}
  .pg-card--qr-code:is(:hover,.pg-attract) svg path{animation:pgvFlicker .45s steps(2) infinite}
  /* color palette: the swatches fan out */
  .pg-card--color-palette:is(:hover,.pg-attract) svg rect{animation:pgvFan 1.1s var(--ease-back) infinite}
  .pg-card--color-palette:is(:hover,.pg-attract) svg rect:nth-of-type(1){--fanx:-1.6px;--fany:-1.6px}
  .pg-card--color-palette:is(:hover,.pg-attract) svg rect:nth-of-type(2){--fanx:1.6px;--fany:-1.6px}
  .pg-card--color-palette:is(:hover,.pg-attract) svg rect:nth-of-type(3){--fanx:-1.6px;--fany:1.6px}
  .pg-card--color-palette:is(:hover,.pg-attract) svg rect:nth-of-type(4){--fanx:1.6px;--fany:1.6px}
  @keyframes pgvFan{0%,100%{transform:translate(0,0)}45%{transform:translate(var(--fanx,0),var(--fany,0))}}
  /* image tools: the picture pans inside its frame */
  .pg-card--image-resizer:is(:hover,.pg-attract) svg path,.pg-card--image-to-webp:is(:hover,.pg-attract) svg path:last-of-type,.pg-card--og-preview:is(:hover,.pg-attract) svg path:last-of-type{animation:pgvPan 1.3s ease-in-out infinite}
  @keyframes pgvPan{0%,100%{transform:translateX(0)}50%{transform:translateX(-1.8px)}}
  /* favicon: the star pops */
  .pg-card--favicon-generator:is(:hover,.pg-attract) svg path{animation:pgvStar 1s var(--ease-back) infinite}
  @keyframes pgvStar{0%,100%{transform:scale(1) rotate(0)}45%{transform:scale(1.18) rotate(18deg)}}
  /* word counter: the lines type themselves, the counter lens pulses */
  .pg-card--word-counter:is(:hover,.pg-attract) svg path{stroke-dasharray:12 5;animation:pgvType .7s linear infinite}
  .pg-card--word-counter:is(:hover,.pg-attract) svg circle{animation:pgvPulse 1s ease-in-out infinite}
  @keyframes pgvPulse{0%,100%{transform:scale(1)}50%{transform:scale(1.18)}}
  /* json formatter: the braces breathe apart */
  .pg-card--json-formatter:is(:hover,.pg-attract) svg path:first-of-type{animation:pgvBraceL 1.1s ease-in-out infinite}
  .pg-card--json-formatter:is(:hover,.pg-attract) svg path:last-of-type{animation:pgvBraceR 1.1s ease-in-out infinite}
  @keyframes pgvBraceL{0%,100%{transform:translateX(0)}50%{transform:translateX(-1.6px)}}
  @keyframes pgvBraceR{0%,100%{transform:translateX(0)}50%{transform:translateX(1.6px)}}
  /* diff checker: the two sides compare (alternating blink) */
  .pg-card--diff-checker:is(:hover,.pg-attract) svg path:first-of-type{animation:pgvBlink 1s steps(2) infinite}
  .pg-card--diff-checker:is(:hover,.pg-attract) svg path:last-of-type{animation:pgvBlink 1s steps(2) .5s infinite}
  /* css gradient: the diagonals sweep */
  .pg-card--css-gradient:is(:hover,.pg-attract) svg path{stroke-dasharray:8 6;animation:pgvType 1s linear infinite}
  /* invoice: the receipt rocks gently */
  .pg-card--invoice-generator:is(:hover,.pg-attract) svg{animation:pgvRock 1.2s ease-in-out infinite}
  @keyframes pgvRock{0%,100%{transform:rotate(-2deg)}50%{transform:rotate(2deg)}}
}
.pg-dbtn{font-size:1rem;color:var(--text-dim);background:rgba(var(--accent-rgb),.07);border:1px solid var(--border-2);border-radius:10px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;user-select:none;-webkit-user-select:none;touch-action:manipulation;transition:var(--dur-fast)}
.pg-dbtn{transition:color var(--dur-fast), border-color var(--dur-fast), background var(--dur-fast), transform var(--dur-fast)}
.pg-dbtn:hover,.pg-dbtn:active{color:var(--text);border-color:var(--blue);background:rgba(var(--accent-rgb),.14)}
.pg-dbtn:active{transform:scale(.92)}
.pg-up{grid-column:2;grid-row:1}
.pg-left{grid-column:1;grid-row:2}
.pg-down{grid-column:2;grid-row:2}
.pg-right{grid-column:3;grid-row:2}

/* ---------------------------------------------------------------------
   Typing Speed Test
   --------------------------------------------------------------------- */
.pg-type-target{font-family:var(--mono);font-size:.92rem;line-height:1.9;background:var(--bg);border:1px solid var(--border-2);
  border-radius:11px;padding:14px 16px;white-space:pre-wrap;word-break:break-word;color:var(--text-mut);min-height:84px}
.pg-type-target .tc{transition:color .05s, background .05s;border-radius:2px}
.pg-type-target .tc.ok{color:var(--green)}
.pg-type-target .tc.bad{color:var(--red);background:rgba(243,139,168,.18)}
html[data-theme="latte"] .pg-type-target .tc.bad{background:rgba(207,34,46,.12)}
.pg-type-target .tc.cur{background:rgba(var(--accent-rgb),.28);color:var(--text);box-shadow:inset 0 -2px 0 var(--blue)}
.pg-type-target .tc.nl::after{content:"\21B5";color:var(--gutter);font-size:.8em}
.pg-type-input{width:100%;background:var(--bg-2);border:1px solid var(--border-2);border-radius:9px;color:var(--text);
  font-family:var(--mono);font-size:.88rem;line-height:1.7;padding:12px 14px;outline:none;resize:vertical;transition:border-color var(--dur-fast), box-shadow var(--dur-fast)}
.pg-type-input:focus{border-color:var(--peach);box-shadow:0 0 0 3px rgba(250,179,135,.16)}
.pg-type-input.done{border-color:var(--green);box-shadow:0 0 0 3px rgba(166,227,161,.16)}
.pg-type-stats{display:flex;gap:18px;flex-wrap:wrap;font-family:var(--mono)}
.pg-type-stats b{font-size:1.3rem;font-weight:800;color:var(--text);letter-spacing:-.5px}
.pg-type-stats .pg-stat-cap{font-size:.74rem;color:var(--text-mut);margin-left:4px}

/* ---------------------------------------------------------------------
   Responsive
   --------------------------------------------------------------------- */
@media (max-width:1000px){
  .pg-cards{grid-template-columns:repeat(auto-fill,minmax(220px,1fr))}
}
@media (max-width:680px){
  .pg-cards{grid-template-columns:1fr}
  .pg-statgrid{grid-template-columns:repeat(2,1fr)}
  .pg-qr-body,.pg-ir-panel{grid-template-columns:1fr}
  .pg-caseout{grid-template-columns:96px 1fr auto}
  .pg-uc-row{grid-template-columns:1fr;gap:10px}
  .pg-swap{justify-self:center;transform:rotate(90deg)}
}
@media (prefers-reduced-motion:reduce){
  .pg-cardlink,.pg-cardlink-icon,.pg-cardlink-arrow,.pg-meter-bar i,.pg-overlay,.pg-type-target .tc,.pg-2048-tile,.pg-dbtn{transition:none}
  .pg-cardlink::after{animation:none}
  .pg-cardlink svg,.pg-cardlink svg *{animation:none!important}
  .pg-2048-tile.spawn,.pg-2048-tile.merge,.pg-mem-inner{animation:none;transition:none}
  .pg-cardlink:hover,.pg-cardlink:active,.pg-dbtn:active,.pg-mem-card:active .pg-mem-inner{transform:none}
  .pg-mem-card.flip:active .pg-mem-inner,.pg-mem-card.matched .pg-mem-inner{transform:rotateY(180deg)}
}

/* ---------------------------------------------------------------------
   Exit-code micro-feedback — one grammar across every tool. A tiny mono
   stamp injected after the action button by window.pgExit (pg-exit.js):
   "exit 0 ✓" (green) / "exit 1 — msg" (red), fades in, auto-fades ~1.2s.
   .pg-shake = one-shot 4px horizontal shake for error emphasis
   (transform-only; both silenced by the reduced-motion block above).
   --------------------------------------------------------------------- */
.pg-exit{font-family:var(--mono);font-size:.72rem;opacity:0;transform:translateY(2px);
  transition:opacity var(--dur-fast),transform var(--dur-fast);white-space:nowrap;flex:0 0 auto;align-self:center}
.pg-exit.show{opacity:1;transform:none}
.pg-exit.ok{color:var(--green)}
.pg-exit.err{color:var(--red)}
.pg-shake{animation:pgShake .3s linear}
@keyframes pgShake{0%,100%{transform:translateX(0)}25%{transform:translateX(-4px)}55%{transform:translateX(4px)}80%{transform:translateX(-3px)}}

/* Word Counter — stat-tile value tick + word-goal pop (transform-only) */
.pg-stat-num.wc-tick{animation:wcTick .15s ease-out}
@keyframes wcTick{0%{transform:translateY(2px) scale(1.07)}100%{transform:translateY(0) scale(1)}}
.wc-goal-pop .pg-meter-bar{animation:wcGoalPop .4s var(--ease-back)}
@keyframes wcGoalPop{0%{transform:scaleY(1)}40%{transform:scaleY(1.8)}100%{transform:scaleY(1)}}
/* reduced-motion gate for the rules above (after them so it wins the cascade) */
@media (prefers-reduced-motion:reduce){
  .pg-exit{transition:none;transform:none}
  .pg-shake{animation:none}
  .pg-stat-num.wc-tick,.wc-goal-pop .pg-meter-bar{animation:none}
}

/* Game overlays (Play / Play again) sit on the always-dark game canvas. In latte the
   ghost-blue primary button is low-contrast on that dark backdrop, so give these
   game buttons a solid accent fill in the light theme. */
html[data-theme="latte"] .sd-btn,
html[data-theme="latte"] .bs-btn,
html[data-theme="latte"] .sk-btn{background:var(--blue);color:#fff;border-color:var(--blue)}
html[data-theme="latte"] .sd-btn:hover,
html[data-theme="latte"] .bs-btn:hover,
html[data-theme="latte"] .sk-btn:hover{background:#0b5cc4;border-color:#0b5cc4;color:#fff}

/* Latte: give the best-score chip a faint blue fill so it reads on white cards */
html[data-theme="latte"] .pg-best{background:rgba(9,105,218,.04)}

/* Visible keyboard focus ring on every tool/game control (buttons, inputs, ranges,
   selects) — main.css only covers .btn/.bar-btn, so tool-specific controls like
   the palette Regenerate button + range sliders had no focus indicator. */
.pg-card button:focus-visible,.pg-card input:focus-visible,.pg-card select:focus-visible,
.pg-card textarea:focus-visible,.pg-card [tabindex="0"]:focus-visible,
.cp-btn:focus-visible,.cp-range:focus-visible,input[type="range"]:focus-visible{outline:2px solid var(--blue);outline-offset:2px;border-radius:6px}

.pg-seg button:active,.pg-mode-btn:active,.pgs-btn:active{transform:scale(.95)}
@media (prefers-reduced-motion:reduce){.pg-seg button:active,.pg-mode-btn:active,.pgs-btn:active{transform:none}}
