packing-bingo 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,12 +1,12 @@
1
1
  import * as react from 'react';
2
2
  import { CSSProperties } from 'react';
3
3
  import { PackingBingoOptions, PackingBingoState } from './core.cjs';
4
- export { BingoEvent, BingoItem, DEFAULT_ITEMS, LINES, Messages, PackingBingoInstance, PerfectEvent, createPackingBingo, en, ja } from './core.cjs';
4
+ export { BingoEvent, BingoItem, DEFAULT_ITEMS, LINES, Messages, PackingBingoInstance, PerfectEvent, bingoLines, createPackingBingo, en, ja } from './core.cjs';
5
5
 
6
6
  interface PackingBingoProps extends Omit<PackingBingoOptions, "controlled" | "defaultChecked"> {
7
- /** Controlled state (16 booleans). Update it from `onChange`. */
7
+ /** Controlled state (one boolean per item). Update it from `onChange`. */
8
8
  checked?: readonly boolean[];
9
- /** Initial state for an uncontrolled card (16 booleans), used when nothing is saved under `storageKey`. */
9
+ /** Initial state for an uncontrolled card (one boolean per item), used when nothing is saved under `storageKey`. */
10
10
  defaultChecked?: readonly boolean[];
11
11
  className?: string;
12
12
  style?: CSSProperties;
@@ -19,7 +19,7 @@ interface PackingBingoHandle {
19
19
  getState(): PackingBingoState | null;
20
20
  }
21
21
  /**
22
- * A 4×4 packing-list bingo card. Client-only: it renders an empty <div> on the server and
22
+ * A packing-list bingo card (4×4 by default; any size from 2×2 to 10×10, optionally with a FREE center). Client-only: it renders an empty <div> on the server and
23
23
  * builds the card after mount, so it is safe in Next.js (it ships with "use client").
24
24
  */
25
25
  declare const PackingBingo: react.ForwardRefExoticComponent<PackingBingoProps & react.RefAttributes<PackingBingoHandle>>;
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import * as react from 'react';
2
2
  import { CSSProperties } from 'react';
3
3
  import { PackingBingoOptions, PackingBingoState } from './core.js';
4
- export { BingoEvent, BingoItem, DEFAULT_ITEMS, LINES, Messages, PackingBingoInstance, PerfectEvent, createPackingBingo, en, ja } from './core.js';
4
+ export { BingoEvent, BingoItem, DEFAULT_ITEMS, LINES, Messages, PackingBingoInstance, PerfectEvent, bingoLines, createPackingBingo, en, ja } from './core.js';
5
5
 
6
6
  interface PackingBingoProps extends Omit<PackingBingoOptions, "controlled" | "defaultChecked"> {
7
- /** Controlled state (16 booleans). Update it from `onChange`. */
7
+ /** Controlled state (one boolean per item). Update it from `onChange`. */
8
8
  checked?: readonly boolean[];
9
- /** Initial state for an uncontrolled card (16 booleans), used when nothing is saved under `storageKey`. */
9
+ /** Initial state for an uncontrolled card (one boolean per item), used when nothing is saved under `storageKey`. */
10
10
  defaultChecked?: readonly boolean[];
11
11
  className?: string;
12
12
  style?: CSSProperties;
@@ -19,7 +19,7 @@ interface PackingBingoHandle {
19
19
  getState(): PackingBingoState | null;
20
20
  }
21
21
  /**
22
- * A 4×4 packing-list bingo card. Client-only: it renders an empty <div> on the server and
22
+ * A packing-list bingo card (4×4 by default; any size from 2×2 to 10×10, optionally with a FREE center). Client-only: it renders an empty <div> on the server and
23
23
  * builds the card after mount, so it is safe in Next.js (it ships with "use client").
24
24
  */
25
25
  declare const PackingBingo: react.ForwardRefExoticComponent<PackingBingoProps & react.RefAttributes<PackingBingoHandle>>;
package/dist/index.js CHANGED
@@ -2,10 +2,12 @@
2
2
  import {
3
3
  DEFAULT_ITEMS,
4
4
  LINES,
5
+ bingoLines,
5
6
  createPackingBingo,
6
7
  en,
7
- ja
8
- } from "./chunk-ZDBGKPFF.js";
8
+ ja,
9
+ resolveStorageKey
10
+ } from "./chunk-Z34GMJW2.js";
9
11
 
10
12
  // src/react.tsx
11
13
  import { forwardRef, useEffect, useImperativeHandle, useRef } from "react";
@@ -20,7 +22,8 @@ var PackingBingo = forwardRef(function PackingBingo2(props, ref) {
20
22
  messagesRef.current = messages;
21
23
  const controlled = checked !== void 0;
22
24
  const latest = useRef(checked ?? defaultChecked);
23
- const latestKey = useRef(config.storageKey);
25
+ const storageKey = resolveStorageKey({ ...config, controlled });
26
+ const latestKey = useRef(storageKey);
24
27
  if (controlled) latest.current = checked;
25
28
  const messageShape = messages ? Object.fromEntries(Object.entries(messages).map(([k, v]) => [k, typeof v === "function" ? "\u0192" : v])) : null;
26
29
  const key = JSON.stringify({ ...config, messageShape, controlled });
@@ -36,7 +39,7 @@ var PackingBingo = forwardRef(function PackingBingo2(props, ref) {
36
39
  ...config,
37
40
  messages: liveMessages,
38
41
  controlled,
39
- defaultChecked: controlled || latestKey.current === config.storageKey ? latest.current : defaultChecked,
42
+ defaultChecked: controlled || latestKey.current === storageKey ? latest.current : defaultChecked,
40
43
  onChange: (next) => {
41
44
  if (!controlled) latest.current = next;
42
45
  callbacks.current.onChange?.(next);
@@ -47,7 +50,7 @@ var PackingBingo = forwardRef(function PackingBingo2(props, ref) {
47
50
  inst.current = instance;
48
51
  return () => {
49
52
  if (!controlled) latest.current = instance.getState().checked;
50
- latestKey.current = config.storageKey;
53
+ latestKey.current = storageKey;
51
54
  instance.destroy();
52
55
  if (inst.current === instance) inst.current = null;
53
56
  };
@@ -73,6 +76,7 @@ export {
73
76
  DEFAULT_ITEMS,
74
77
  LINES,
75
78
  PackingBingo,
79
+ bingoLines,
76
80
  createPackingBingo,
77
81
  en,
78
82
  ja
@@ -1,16 +1,16 @@
1
- "use strict";var PackingBingo=(()=>{var Ee=Object.defineProperty;var ct=Object.getOwnPropertyDescriptor;var bt=Object.getOwnPropertyNames;var dt=Object.prototype.hasOwnProperty;var mt=(r,n)=>{for(var k in n)Ee(r,k,{get:n[k],enumerable:!0})},ft=(r,n,k,d)=>{if(n&&typeof n=="object"||typeof n=="function")for(let m of bt(n))!dt.call(r,m)&&m!==k&&Ee(r,m,{get:()=>n[m],enumerable:!(d=ct(n,m))||d.enumerable});return r};var kt=r=>ft(Ee({},"__esModule",{value:!0}),r);var yt={};mt(yt,{DEFAULT_ITEMS:()=>Le,LINES:()=>F,createPackingBingo:()=>vt,en:()=>Ge,ja:()=>Se});var Le=[{emoji:"\u{1F4D6}",label:"\u65C5\u306E\u3057\u304A\u308A"},{emoji:"\u{1FAAA}",label:"\u751F\u5F92\u624B\u5E33"},{emoji:"\u{1F3E5}",label:"\u4FDD\u967A\u8A3C\u30B3\u30D4\u30FC"},{emoji:"\u{1F45B}",label:"\u304A\u3053\u3065\u304B\u3044"},{emoji:"\u{1F455}",label:"\u7740\u66FF\u3048"},{emoji:"\u{1F319}",label:"\u30D1\u30B8\u30E3\u30DE"},{emoji:"\u{1F9E5}",label:"\u4E0A\u7740"},{emoji:"\u{1FAA5}",label:"\u6D17\u9762\u7528\u5177"},{emoji:"\u{1F6C1}",label:"\u30BF\u30AA\u30EB"},{emoji:"\u{1F927}",label:"\u30CF\u30F3\u30AB\u30C1\u30FB\u30C6\u30A3\u30C3\u30B7\u30E5"},{emoji:"\u{1F637}",label:"\u30DE\u30B9\u30AF"},{emoji:"\u{1F48A}",label:"\u5E38\u5099\u85AC\u30FB\u9154\u3044\u6B62\u3081"},{emoji:"\u2602\uFE0F",label:"\u6298\u308A\u305F\u305F\u307F\u5098"},{emoji:"\u270F\uFE0F",label:"\u7B46\u8A18\u7528\u5177"},{emoji:"\u{1F6CD}\uFE0F",label:"\u30D3\u30CB\u30FC\u30EB\u888B"},{emoji:"\u{1F4F1}",label:"\u30B9\u30DE\u30DB\u30FB\u5145\u96FB\u5668"}];var Se={title:"\u6301\u3061\u3082\u306E\u30D3\u30F3\u30B4",tag:"\u4FEE\u5B66\u65C5\u884C",subtitle:"\u30BF\u30C3\u30D7\u3067\u30B9\u30BF\u30F3\u30D7\u3002\u30BF\u30C6\u30FB\u30E8\u30B3\u30FB\u30CA\u30CA\u30E1\u3067\u30D3\u30F3\u30B4\uFF01",packed:"\u305D\u308D\u3063\u305F",bingo:"BINGO",score:"SCORE",combo:r=>`${r} COMBO`,comboPop:r=>`${r} COMBO!`,reset:"\u30EA\u30BB\u30C3\u30C8",soundOn:"\u{1F50A} \u97F3\u3042\u308A",soundOff:"\u{1F507} \u97F3\u306A\u3057",stamp:"OK",reachBadge:"\u30EA\u30FC\u30C1",reachPop:"\u30EA\u30FC\u30C1!",bannerSingle:"BINGO!",bannerDouble:"\u30C0\u30D6\u30EB\u30D3\u30F3\u30B4!",bannerTriple:"\u30C8\u30EA\u30D7\u30EB\u30D3\u30F3\u30B4!",bannerNth:r=>`${r} \u30E9\u30A4\u30F3\u76EE\uFF01`,bannerMulti:r=>`\u4E00\u6C17\u306B ${r} \u30E9\u30A4\u30F3\uFF01`,statusStart:r=>`\u306E\u3053\u308A ${r} \u3053\u3002\u307E\u305A\u306F1\u30E9\u30A4\u30F3\u305D\u308D\u3048\u3088\u3046`,statusLines:(r,n)=>`\u30D3\u30F3\u30B4 ${r} \u30E9\u30A4\u30F3\uFF01 \u306E\u3053\u308A ${n} \u3053`,statusReach:r=>`\u30EA\u30FC\u30C1\uFF01 \u3042\u3068${r.slice(0,2).map(n=>`\u300C${n}\u300D`).join("\u304B")}${r.length>2?"\u306A\u3069":""}\u3067\u30D3\u30F3\u30B4`,statusDone:"\u{1F389} \u30D1\u30FC\u30D5\u30A7\u30AF\u30C8\uFF01\u5FD8\u308C\u7269\u30BC\u30ED\u3067\u51FA\u767A\u3067\u304D\u307E\u3059",perfectTag:"\u{1F3C6} PERFECT",perfectStamp:`\u6E96\u5099
2
- \u5B8C\u4E86`,perfectTitle:"\u30D1\u30FC\u30D5\u30A7\u30AF\u30C8\uFF01",perfectBody:`16\u3053 \u305C\u3093\u3076\u305D\u308D\u3063\u305F\uFF01
3
- \u5FD8\u308C\u7269\u30BC\u30ED\u3067\u3001\u3044\u3063\u3066\u3089\u3063\u3057\u3083\u3044\uFF01`,perfectBonus:r=>`PERFECT BONUS +${r}`,statScore:"SCORE",statCombo:"MAX COMBO",statLines:"BINGO",close:"\u3068\u3058\u308B",demoLabel:"\u30C7\u30E2\uFF1A",demoBingo:"\u25B6 \u30D3\u30F3\u30B4\u3092\u898B\u308B",demoPerfect:"\u25B6 \u30B3\u30F3\u30DC \u2192 \u30D1\u30FC\u30D5\u30A7\u30AF\u30C8",demoRestore:"\u6700\u521D\u306B\u623B\u3059"},Ge={title:"Packing Bingo",tag:"School trip",subtitle:"Tap to stamp. Rows, columns and diagonals all count!",packed:"PACKED",bingo:"BINGO",score:"SCORE",combo:r=>`${r} COMBO`,comboPop:r=>`${r} COMBO!`,reset:"Reset",soundOn:"\u{1F50A} Sound on",soundOff:"\u{1F507} Muted",stamp:"OK",reachBadge:"REACH",reachPop:"Reach!",bannerSingle:"BINGO!",bannerDouble:"DOUBLE BINGO!",bannerTriple:"TRIPLE BINGO!",bannerNth:r=>`Line ${r}!`,bannerMulti:r=>`${r} lines at once!`,statusStart:r=>`${r} to go. Finish a line first!`,statusLines:(r,n)=>`${r} bingo line${r===1?"":"s"}! ${n} to go`,statusReach:r=>`Reach! Pack ${r.slice(0,2).join(" or ")}${r.length>2?" (or more)":""} for a bingo`,statusDone:"\u{1F389} Perfect! Nothing left behind.",perfectTag:"\u{1F3C6} PERFECT",perfectStamp:`ALL
4
- SET`,perfectTitle:"Perfect!",perfectBody:`All 16 packed!
5
- Have a great trip!`,perfectBonus:r=>`PERFECT BONUS +${r}`,statScore:"SCORE",statCombo:"MAX COMBO",statLines:"BINGO",close:"Close",demoLabel:"Demo:",demoBingo:"\u25B6 Show a bingo",demoPerfect:"\u25B6 Combo \u2192 perfect",demoRestore:"Restore"};var Ue=[0,2,4,7,9,12,14,16,19,21,24,26,28,31,33,36],U=r=>523.25*Math.pow(2,r/12);function _e(r){let n=null,k=null;function d(){if(r()||typeof window>"u")return null;let c=navigator.userActivation;if(!n&&c&&!c.hasBeenActive)return null;if(!n){let b=window.AudioContext??window.webkitAudioContext;if(!b)return null;n=new b;let y=n.createDynamicsCompressor();k=n.createGain(),k.gain.value=.6,k.connect(y).connect(n.destination)}return n.state==="suspended"&&n.resume(),n}function m(c,b=0,y=.15,E="triangle",M=.2,A=0){let p=d();if(!p||!k)return;let x=p.currentTime+b,S=p.createOscillator(),C=p.createGain();S.type=E,S.frequency.setValueAtTime(c,x),A&&S.frequency.exponentialRampToValueAtTime(A,x+y),C.gain.setValueAtTime(1e-4,x),C.gain.exponentialRampToValueAtTime(M,x+.01),C.gain.exponentialRampToValueAtTime(1e-4,x+y),S.connect(C).connect(k),S.start(x),S.stop(x+y+.05)}function $(c=0,b=.3,y=.25,E=1200){let M=d();if(!M||!k)return;let A=M.currentTime+c,p=Math.ceil(M.sampleRate*b),x=M.createBuffer(1,p,M.sampleRate),S=x.getChannelData(0);for(let f=0;f<p;f++)S[f]=(Math.random()*2-1)*Math.pow(1-f/p,2.5);let C=M.createBufferSource(),W=M.createBiquadFilter(),I=M.createGain();C.buffer=x,W.type="bandpass",W.frequency.value=E,W.Q.value=.7,I.gain.value=y,C.connect(W).connect(I).connect(k),C.start(A)}let R=c=>U(Ue[Math.min(Math.max(c,0),Ue.length-1)]);return{pop(c){let b=R(c);m(b,0,.16,"triangle",.22),m(b*2,0,.08,"sine",.06),m(150,0,.09,"sine",.25,60)},off:()=>m(392,0,.1,"sine",.1,262),reach(){m(988,0,.08,"square",.05),m(1319,.09,.14,"square",.05)},bingo(c){[0,4,7,12,16,19].forEach((b,y)=>m(U(b),y*.06,.22,"square",.06)),[12,16,19].forEach(b=>m(U(b),.38,.6,"triangle",.12)),c>1&&[24,28,31].forEach(b=>m(U(b),.55,.6,"triangle",.08)),$(0,.25,.12,3e3)},perfect(){[0,4,7,12,16,19,24].forEach((c,b)=>m(U(c-12),b*.07,.25,"square",.06)),[0,4,7,12].forEach(c=>m(U(c),.55,1.2,"triangle",.12)),[12,16,19].forEach(c=>m(U(c),.55,1.2,"sawtooth",.03)),m(U(-12),.55,1.2,"sine",.2)},boom(){$(0,.5,.3,500),m(90,0,.3,"sine",.25,40)},tick:()=>m(1760,0,.03,"square",.03),note:(c,b=0)=>m(R(c),b,.12,"square",.05),close(){n&&n.close().catch(()=>{}),n=null,k=null}}}var We="https://fonts.googleapis.com/css2?family=Dela+Gothic+One&family=M+PLUS+Rounded+1c:wght@500;800&display=swap",Ve=`
6
- .pkb{--pk-sun:var(--pkb-sun,#FFD54F);--pk-ink:var(--pkb-ink,#2A1F14);--pk-paper:var(--pkb-paper,#FFFDF6);--pk-red:var(--pkb-red,#E8473B);--pk-mint:var(--pkb-mint,#BDEBD2);--pk-display:"Dela Gothic One",var(--pkb-font-fallback,sans-serif);--pk-body:"M PLUS Rounded 1c","Hiragino Maru Gothic ProN",var(--pkb-font-fallback,sans-serif);container-type:inline-size;isolation:isolate;width:100%}
1
+ "use strict";var PackingBingo=(()=>{var Pe=Object.defineProperty;var zt=Object.getOwnPropertyDescriptor;var Tt=Object.getOwnPropertyNames;var Ot=Object.prototype.hasOwnProperty;var At=(t,n)=>{for(var s in n)Pe(t,s,{get:n[s],enumerable:!0})},Pt=(t,n,s,c)=>{if(n&&typeof n=="object"||typeof n=="function")for(let b of Tt(n))!Ot.call(t,b)&&b!==s&&Pe(t,b,{get:()=>n[b],enumerable:!(c=zt(n,b))||c.enumerable});return t};var Ft=t=>Pt(Pe({},"__esModule",{value:!0}),t);var Ht={};At(Ht,{DEFAULT_ITEMS:()=>ie,LINES:()=>Rt,bingoLines:()=>Re,createPackingBingo:()=>Dt,en:()=>it,ja:()=>qe});var ie=[{emoji:"\u{1F45B}",label:"\u8CA1\u5E03"},{emoji:"\u{1F4F1}",label:"\u30B9\u30DE\u30DB"},{emoji:"\u{1F50B}",label:"\u30E2\u30D0\u30A4\u30EB\u200B\u5145\u96FB\u5668"},{emoji:"\u{1F4CB}",label:"\u5065\u5EB7\u8ABF\u67FB\u7968"},{emoji:"\u{1FAAA}",label:"\u30DE\u30A4\u30CA\u30AB\u30FC\u30C9\u200B\u307E\u305F\u306F\u4FDD\u967A\u8A3C"},{emoji:"\u{1F4D6}",label:"\u3057\u304A\u308A"},{emoji:"\u{1F637}",label:"\u30DE\u30B9\u30AF"},{emoji:"\u{1F927}",label:"\u30CF\u30F3\u30AB\u30C1"},{emoji:"\u{1F48A}",label:"\u5E38\u5099\u85AC"},{emoji:"\u{1F6CD}\uFE0F",label:"\u30D3\u30CB\u30FC\u30EB\u888B"},{emoji:"\u{1F9E4}",label:"\u8ECD\u624B\uFF08\u5B66\u6821\u652F\u7D66\uFF09"},{emoji:"\u{1F526}",label:"\u30D8\u30C3\u30C9\u30E9\u30A4\u30C8"},{emoji:"\u{1F455}",label:"\u30B8\u30E3\u30FC\u30B8"},{emoji:"\u2614",label:"\u96E8\u5177"},{emoji:"\u{1F6C1}",label:"\u30BF\u30AA\u30EB"},{emoji:"\u{1F9F4}",label:"\u65E5\u713C\u3051\u6B62\u3081"}];var xe=2,Fe=10,ve=t=>{throw new Error(`[packing-bingo] ${t}`)};function Ie(t){if(t.items)return t.items;let n=t.size;return n==null||!Number.isInteger(n)||n<xe?ie:ie.slice(0,n*n-(t.free?1:0))}function at(t,n){(!Number.isInteger(t)||t<xe||t>Fe)&&ve(`"size" must be a whole number from ${xe} to ${Fe} (got ${t}).`),n&&t%2===0&&ve(`"free" needs an odd size such as 3 or 5, so that the card has a center (got ${t}).`)}function rt(t,n){let s=k=>Array.from({length:t},(l,d)=>k(d)),c=[...s(k=>s(l=>k*t+l)),...s(k=>s(l=>l*t+k)),s(k=>k*(t+1)),s(k=>(k+1)*(t-1))],b=n?(t*t-1)/2:-1,L=k=>n&&k>b?k-1:k;return{center:b,cellLines:c,lines:c.map(k=>k.filter(l=>l!==b).map(L))}}function ot(t){let n=Ie(t),s=!!t.free,c=t.size;if(c==null){let g=n.length,M=v=>{let $=Math.round(Math.sqrt(v));return $*$===v&&$>=xe&&$<=Fe?$:0};if(c=M(g+(s?1:0)),!c){let v=M(g+(s?0:1)),$=s?v?`; ${g} items fill a ${v}\xD7${v} card without "free"`:"":v%2?`, or set "free" for a ${v}\xD7${v} card with a FREE center`:"";ve(s?`With "free", "items" must have one less than an odd square number of entries (8, 24, 48, 80)${$} (got ${g}).`:`"items" must have a square number of entries (4, 9, 16, 25, \u2026, 100)${$} (got ${g}).`)}}at(c,s);let b=c*c-(s?1:0);if(n.length!==b){let g=`a ${c}\xD7${c} card${s?" with a FREE center":""}`;ve(t.items?`"items" must have exactly ${b} entries for ${g} (got ${n.length}).`:`A ${g.slice(2)} needs ${b} items, but DEFAULT_ITEMS has only ${ie.length}. Pass "items".`)}let{center:L,cellLines:k,lines:l}=rt(c,s),d=n.map((g,M)=>s&&M>=L?M+1:M);return{size:c,free:s,items:n,itemCell:d,center:L,cellLines:k,lines:l}}function Re(t,n=!1){return at(t,n),rt(t,n).lines}var qe={title:"\u6301\u3061\u3082\u306E\u30D3\u30F3\u30B4",tag:"\u4FEE\u5B66\u65C5\u884C",subtitle:"",packed:"\u305D\u308D\u3063\u305F",bingo:"BINGO",score:"SCORE",combo:t=>`${t} COMBO`,comboPop:t=>`${t} COMBO!`,reset:"\u30EA\u30BB\u30C3\u30C8",soundOn:"\u{1F50A} \u97F3\u3042\u308A",soundOff:"\u{1F507} \u97F3\u306A\u3057",stamp:"OK",free:"FREE",reachBadge:"\u30EA\u30FC\u30C1",reachPop:"\u30EA\u30FC\u30C1!",bannerSingle:"BINGO!",bannerDouble:"\u30C0\u30D6\u30EB\u30D3\u30F3\u30B4!",bannerTriple:"\u30C8\u30EA\u30D7\u30EB\u30D3\u30F3\u30B4!",bannerNth:t=>`${t} \u30E9\u30A4\u30F3\u76EE\uFF01`,bannerMulti:t=>`\u4E00\u6C17\u306B ${t} \u30E9\u30A4\u30F3\uFF01`,statusStart:()=>"",statusLines:(t,n)=>`\u30D3\u30F3\u30B4 ${t} \u30E9\u30A4\u30F3\uFF01 \u306E\u3053\u308A ${n} \u3053`,statusReach:t=>`\u30EA\u30FC\u30C1\uFF01 \u3042\u3068${t.slice(0,2).map(n=>`\u300C${n}\u300D`).join("\u304B")}${t.length>2?"\u306A\u3069":""}\u3067\u30D3\u30F3\u30B4`,statusDone:"\u{1F389} \u30D1\u30FC\u30D5\u30A7\u30AF\u30C8\uFF01\u5FD8\u308C\u7269\u30BC\u30ED\u3067\u51FA\u767A\u3067\u304D\u307E\u3059",perfectTag:"\u{1F3C6} PERFECT",perfectStamp:`\u6E96\u5099
2
+ \u5B8C\u4E86`,perfectTitle:"\u30D1\u30FC\u30D5\u30A7\u30AF\u30C8\uFF01",perfectBody:t=>`${t}\u3053 \u305C\u3093\u3076\u305D\u308D\u3063\u305F\uFF01
3
+ \u5FD8\u308C\u7269\u30BC\u30ED\u3067\u3001\u3044\u3063\u3066\u3089\u3063\u3057\u3083\u3044\uFF01`,perfectBonus:t=>`PERFECT BONUS +${t}`,statScore:"SCORE",statCombo:"MAX COMBO",statLines:"BINGO",close:"\u3068\u3058\u308B",demoLabel:"\u30C7\u30E2\uFF1A",demoBingo:"\u25B6 \u30D3\u30F3\u30B4\u3092\u898B\u308B",demoPerfect:"\u25B6 \u30B3\u30F3\u30DC \u2192 \u30D1\u30FC\u30D5\u30A7\u30AF\u30C8",demoRestore:"\u6700\u521D\u306B\u623B\u3059"},it={title:"Packing Bingo",tag:"School trip",subtitle:"",packed:"PACKED",bingo:"BINGO",score:"SCORE",combo:t=>`${t} COMBO`,comboPop:t=>`${t} COMBO!`,reset:"Reset",soundOn:"\u{1F50A} Sound on",soundOff:"\u{1F507} Muted",stamp:"OK",free:"FREE",reachBadge:"REACH",reachPop:"Reach!",bannerSingle:"BINGO!",bannerDouble:"DOUBLE BINGO!",bannerTriple:"TRIPLE BINGO!",bannerNth:t=>`Line ${t}!`,bannerMulti:t=>`${t} lines at once!`,statusStart:()=>"",statusLines:(t,n)=>`${t} bingo line${t===1?"":"s"}! ${n} to go`,statusReach:t=>`Reach! Pack ${t.slice(0,2).join(" or ")}${t.length>2?" (or more)":""} for a bingo`,statusDone:"\u{1F389} Perfect! Nothing left behind.",perfectTag:"\u{1F3C6} PERFECT",perfectStamp:`ALL
4
+ SET`,perfectTitle:"Perfect!",perfectBody:t=>`All ${t} packed!
5
+ Have a great trip!`,perfectBonus:t=>`PERFECT BONUS +${t}`,statScore:"SCORE",statCombo:"MAX COMBO",statLines:"BINGO",close:"Close",demoLabel:"Demo:",demoBingo:"\u25B6 Show a bingo",demoPerfect:"\u25B6 Combo \u2192 perfect",demoRestore:"Restore"};var st=[0,2,4,7,9,12,14,16,19,21,24,26,28,31,33,36],V=t=>523.25*Math.pow(2,t/12);function pt(t){let n=null,s=null;function c(){if(t()||typeof window>"u")return null;let l=navigator.userActivation;if(!n&&l&&!l.hasBeenActive)return null;if(!n){let d=window.AudioContext??window.webkitAudioContext;if(!d)return null;n=new d;let g=n.createDynamicsCompressor();s=n.createGain(),s.gain.value=.6,s.connect(g).connect(n.destination)}return n.state==="suspended"&&n.resume(),n}function b(l,d=0,g=.15,M="triangle",v=.2,$=0){let F=c();if(!F||!s)return;let u=F.currentTime+d,I=F.createOscillator(),C=F.createGain();I.type=M,I.frequency.setValueAtTime(l,u),$&&I.frequency.exponentialRampToValueAtTime($,u+g),C.gain.setValueAtTime(1e-4,u),C.gain.exponentialRampToValueAtTime(v,u+.01),C.gain.exponentialRampToValueAtTime(1e-4,u+g),I.connect(C).connect(s),I.start(u),I.stop(u+g+.05)}function L(l=0,d=.3,g=.25,M=1200){let v=c();if(!v||!s)return;let $=v.currentTime+l,F=Math.ceil(v.sampleRate*d),u=v.createBuffer(1,F,v.sampleRate),I=u.getChannelData(0);for(let S=0;S<F;S++)I[S]=(Math.random()*2-1)*Math.pow(1-S/F,2.5);let C=v.createBufferSource(),H=v.createBiquadFilter(),z=v.createGain();C.buffer=u,H.type="bandpass",H.frequency.value=M,H.Q.value=.7,z.gain.value=g,C.connect(H).connect(z).connect(s),C.start($)}let k=l=>V(st[Math.min(Math.max(l,0),st.length-1)]);return{pop(l){let d=k(l);b(d,0,.16,"triangle",.22),b(d*2,0,.08,"sine",.06),b(150,0,.09,"sine",.25,60)},off:()=>b(392,0,.1,"sine",.1,262),reach(){b(988,0,.08,"square",.05),b(1319,.09,.14,"square",.05)},bingo(l){[0,4,7,12,16,19].forEach((d,g)=>b(V(d),g*.06,.22,"square",.06)),[12,16,19].forEach(d=>b(V(d),.38,.6,"triangle",.12)),l>1&&[24,28,31].forEach(d=>b(V(d),.55,.6,"triangle",.08)),L(0,.25,.12,3e3)},perfect(){[0,4,7,12,16,19,24].forEach((l,d)=>b(V(l-12),d*.07,.25,"square",.06)),[0,4,7,12].forEach(l=>b(V(l),.55,1.2,"triangle",.12)),[12,16,19].forEach(l=>b(V(l),.55,1.2,"sawtooth",.03)),b(V(-12),.55,1.2,"sine",.2)},boom(){L(0,.5,.3,500),b(90,0,.3,"sine",.25,40)},tick:()=>b(1760,0,.03,"square",.03),note:(l,d=0)=>b(k(l),d,.12,"square",.05),close(){n&&n.close().catch(()=>{}),n=null,s=null}}}function lt(t){return t.controlled?null:t.storageKey!==void 0?t.storageKey||null:t.demo?null:It(Ie(t))}function It(t){let n=t.map(c=>`${c.emoji}\0${c.label}`).join(""),s=2166136261;for(let c=0;c<n.length;c++)s^=n.charCodeAt(c),s=Math.imul(s,16777619);return`packing-bingo:${(s>>>0).toString(36)}`}var ct="https://fonts.googleapis.com/css2?family=Dela+Gothic+One&family=M+PLUS+Rounded+1c:wght@500;800&display=swap",bt=`
6
+ .pkb{--pk-sun:var(--pkb-sun,#FFD54F);--pk-ink:var(--pkb-ink,#2A1F14);--pk-paper:var(--pkb-paper,#FFFDF6);--pk-red:var(--pkb-red,#E8473B);--pk-mint:var(--pkb-mint,#BDEBD2);--pk-display:"Dela Gothic One",var(--pkb-font-fallback,sans-serif);--pk-body:"M PLUS Rounded 1c","Hiragino Maru Gothic ProN",var(--pkb-font-fallback,sans-serif);--pk-n:4;--pk-s:1;--pk-d:1;container-type:inline-size;isolation:isolate;width:100%}
7
7
  .pkb,.pkb *{box-sizing:border-box;margin:0;padding:0}
8
8
  .pkb-board{position:relative;overflow:hidden;max-width:720px;margin:0 auto;padding:22px 26px 20px;border-radius:24px;background-color:var(--pk-sun);background-image:radial-gradient(rgba(42,31,20,.12) 1.3px,transparent 1.6px);background-size:16px 16px;border:2.5px solid var(--pk-ink);color:var(--pk-ink);font-family:var(--pk-body);line-height:1.4;text-align:left}
9
9
  .pkb-board.pkb-shake{animation:pkb-shake .45s cubic-bezier(.36,.07,.19,.97)}
10
10
  @keyframes pkb-shake{10%,90%{transform:translate(-1px,1px)}20%,80%{transform:translate(3px,-2px)}30%,50%,70%{transform:translate(-6px,2px)}40%,60%{transform:translate(6px,-1px)}}
11
11
  .pkb-board.pkb-punch{animation:pkb-punch .4s cubic-bezier(.3,1.6,.5,1)}
12
12
  @keyframes pkb-punch{30%{transform:scale(1.018)}}
13
- .pkb-head{display:flex;justify-content:space-between;align-items:center;gap:16px;margin-bottom:18px}
13
+ .pkb-head{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px 16px;margin-bottom:18px}
14
14
  .pkb-tags{display:flex;gap:8px;align-items:center}
15
15
  .pkb-kicker{display:inline-block;background:var(--pk-ink);color:var(--pk-sun);font-weight:800;font-size:11px;letter-spacing:.14em;padding:4px 10px;border-radius:999px}
16
16
  .pkb-kicker.pkb-gold{color:#fff;background:linear-gradient(90deg,#E8473B,#FF9F1C,#1FA971,#2F6FED,#E8473B);background-size:200% 100%;animation:pkb-rb 2s linear infinite}
@@ -18,7 +18,7 @@ Have a great trip!`,perfectBonus:r=>`PERFECT BONUS +${r}`,statScore:"SCORE",stat
18
18
  .pkb button{font-family:var(--pk-body)}
19
19
  .pkb-snd{appearance:none;border:2px solid var(--pk-ink);background:var(--pk-paper);border-radius:999px;padding:2px 9px;font-weight:800;font-size:11px;line-height:1.4;color:var(--pk-ink);cursor:pointer}
20
20
  .pkb-title{font-family:var(--pk-display);font-weight:400;font-size:34px;line-height:1.15;margin-top:8px;letter-spacing:.02em;color:inherit}
21
- .pkb-sub{font-weight:800;font-size:13px;margin-top:4px}
21
+ .pkb-sub{font-weight:800;font-size:13px;margin-top:4px;word-break:auto-phrase}
22
22
  .pkb-side{display:flex;flex-direction:column;gap:8px;flex:none}
23
23
  .pkb-score{display:flex;gap:10px}
24
24
  .pkb-pill{min-width:78px;background:var(--pk-paper);border:2.5px solid var(--pk-ink);border-radius:14px;padding:6px 10px 5px;text-align:center;box-shadow:3px 3px 0 var(--pk-ink)}
@@ -37,16 +37,18 @@ Have a great trip!`,perfectBonus:r=>`PERFECT BONUS +${r}`,statScore:"SCORE",stat
37
37
  .pkb-combo.pkb-on .pkb-bar i{animation:pkb-drain 2.5s linear forwards}
38
38
  @keyframes pkb-drain{from{transform:scaleX(1)}to{transform:scaleX(0)}}
39
39
  .pkb-gw{position:relative}
40
- .pkb-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}
41
- .pkb-tile{position:relative;aspect-ratio:1/.82;background:var(--pk-paper);border:2.5px solid var(--pk-ink);border-radius:16px;box-shadow:4px 4px 0 var(--pk-ink);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;cursor:pointer;user-select:none;-webkit-tap-highlight-color:transparent;transition:transform .1s,box-shadow .1s,background-color .25s}
42
- .pkb-tile:active{transform:translate(3px,3px);box-shadow:1px 1px 0 var(--pk-ink)}
40
+ .pkb-grid{display:grid;grid-template-columns:repeat(var(--pk-n),minmax(0,1fr));gap:calc(12px*var(--pk-d))}
41
+ .pkb-tile{position:relative;min-width:0;place-self:stretch;aspect-ratio:1/.82;background:var(--pk-paper);border:2.5px solid var(--pk-ink);border-radius:calc(16px*var(--pk-d));box-shadow:4px 4px 0 var(--pk-ink);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:calc(6px*var(--pk-d));cursor:pointer;user-select:none;-webkit-tap-highlight-color:transparent;transition:transform .1s,box-shadow .1s,background-color .25s}
42
+ .pkb-tile:active:not(.pkb-free){transform:translate(3px,3px);box-shadow:1px 1px 0 var(--pk-ink)}
43
43
  .pkb-tile input{position:absolute;opacity:0;pointer-events:none;width:1px;height:1px}
44
44
  .pkb-tile:has(input:focus-visible){outline:3px solid var(--pk-ink);outline-offset:3px}
45
- .pkb-emo{font-size:32px;line-height:1;transition:opacity .2s}
46
- .pkb-lbl{font-weight:800;font-size:13px;line-height:1.25;text-align:center;padding:0 6px;transition:opacity .2s;word-break:keep-all;overflow-wrap:anywhere}
47
- .pkb-stamp{position:absolute;left:50%;top:50%;width:64%;aspect-ratio:1;border-radius:50%;border:3px solid var(--pk-red);box-shadow:inset 0 0 0 2px var(--pk-paper),inset 0 0 0 4px var(--pk-red);color:var(--pk-red);display:grid;place-items:center;font-family:var(--pk-display);font-size:20px;letter-spacing:.04em;opacity:0;transform:translate(-50%,-50%) rotate(-16deg) scale(1.7);transition:transform .25s cubic-bezier(.3,1.5,.5,1),opacity .15s;pointer-events:none}
45
+ .pkb-emo{font-size:max(14px,calc(32px*var(--pk-s)));line-height:1;transition:opacity .2s}
46
+ .pkb-lbl{font-weight:800;font-size:max(9px,calc(13px*var(--pk-s)));line-height:1.25;text-align:center;padding:0 calc(6px*var(--pk-d));transition:opacity .2s;word-break:keep-all;overflow-wrap:anywhere}
47
+ .pkb-stamp{position:absolute;left:50%;top:50%;width:64%;aspect-ratio:1;border-radius:50%;border:3px solid var(--pk-red);box-shadow:inset 0 0 0 2px var(--pk-paper),inset 0 0 0 4px var(--pk-red);color:var(--pk-red);display:grid;place-items:center;font-family:var(--pk-display);font-size:max(9px,calc(20px*var(--pk-s)));letter-spacing:.04em;opacity:0;transform:translate(-50%,-50%) rotate(-16deg) scale(1.7);transition:transform .25s cubic-bezier(.3,1.5,.5,1),opacity .15s;pointer-events:none}
48
48
  .pkb-tile.pkb-on .pkb-stamp{opacity:.9;transform:translate(-50%,-50%) rotate(-16deg) scale(1)}
49
49
  .pkb-tile.pkb-on .pkb-emo,.pkb-tile.pkb-on .pkb-lbl{opacity:.35}
50
+ .pkb-tile.pkb-free{cursor:default;container-type:inline-size}
51
+ .pkb-tile.pkb-free .pkb-stamp{width:72%;opacity:1;transition:none;font-size:17cqi;letter-spacing:.02em;line-height:1;text-align:center;background:var(--pk-red);color:var(--pk-paper);border-color:var(--pk-red);box-shadow:inset 0 0 0 2px var(--pk-red),inset 0 0 0 4px var(--pk-paper)}
50
52
  .pkb-tile.pkb-line{background-color:var(--pk-mint)}
51
53
  .pkb-tile.pkb-line::before{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;background:linear-gradient(110deg,transparent 30%,rgba(255,255,255,.9) 45%,transparent 60%) no-repeat;background-size:250% 100%;background-position:200% 0;animation:pkb-glint 3.2s ease-in-out var(--pkb-gd,0s) infinite}
52
54
  @keyframes pkb-glint{0%{background-position:200% 0}30%,100%{background-position:-100% 0}}
@@ -63,11 +65,11 @@ Have a great trip!`,perfectBonus:r=>`PERFECT BONUS +${r}`,statScore:"SCORE",stat
63
65
  .pkb-lines{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;overflow:visible;z-index:2;transition:opacity .4s}
64
66
  .pkb-board.pkb-all .pkb-lines{opacity:0}
65
67
  .pkb-lines line{fill:none;stroke-linecap:round;stroke-dasharray:1;stroke-dashoffset:0}
66
- .pkb-lines .pkb-u{stroke:var(--pk-paper);stroke-width:13}
67
- .pkb-lines .pkb-o{stroke:var(--pk-ink);stroke-width:6}
68
+ .pkb-lines .pkb-u{stroke:var(--pk-paper);stroke-width:calc(13px*var(--pk-d))}
69
+ .pkb-lines .pkb-o{stroke:var(--pk-ink);stroke-width:calc(6px*var(--pk-d))}
68
70
  .pkb-lines .pkb-draw line{animation:pkb-draw .45s ease-out .3s both}
69
71
  @keyframes pkb-draw{from{stroke-dashoffset:1}}
70
- .pkb-foot{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-top:18px;font-weight:800;font-size:13px}
72
+ .pkb-foot{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-top:18px;font-weight:800;font-size:13px;word-break:auto-phrase}
71
73
  .pkb-reset{appearance:none;flex:none;border:2px solid var(--pk-ink);background:transparent;border-radius:999px;padding:5px 12px;font-weight:800;font-size:12px;line-height:1.4;color:var(--pk-ink);cursor:pointer}
72
74
  .pkb-flash{position:absolute;inset:0;z-index:7;background:#fff;opacity:0;pointer-events:none}
73
75
  .pkb-flash.pkb-go{animation:pkb-flash .4s ease-out}
@@ -82,7 +84,7 @@ Have a great trip!`,perfectBonus:r=>`PERFECT BONUS +${r}`,statScore:"SCORE",stat
82
84
  .pkb-float{position:absolute;z-index:11;pointer-events:none;white-space:nowrap;font-family:var(--pk-display);font-weight:400;line-height:1;-webkit-text-stroke:4px var(--pk-ink);paint-order:stroke fill;transform:translate(-50%,-50%);animation:pkb-rise .95s cubic-bezier(.2,.9,.3,1) both}
83
85
  .pkb-float.pkb-pt{font-size:22px;color:var(--pk-paper)}
84
86
  .pkb-float.pkb-cmb{font-size:17px}
85
- .pkb-float.pkb-big{font-size:clamp(20px,6cqi,34px);color:#FFE066}
87
+ .pkb-float.pkb-big{font-size:clamp(14px,5.6cqi,34px);color:#FFE066}
86
88
  .pkb-float.pkb-rch{font-size:20px;color:var(--pk-red);-webkit-text-stroke:4px var(--pk-paper)}
87
89
  @keyframes pkb-rise{0%{opacity:0;transform:translate(-50%,-20%) scale(.4)}18%{opacity:1;transform:translate(-50%,-60%) scale(1.2)}30%{transform:translate(-50%,-70%) scale(1)}75%{opacity:1}100%{opacity:0;transform:translate(-50%,-190%) scale(1)}}
88
90
  .pkb-perfect{position:absolute;inset:0;z-index:8;display:grid;place-items:center;padding:20px;background:rgba(42,31,20,.5);opacity:0;visibility:hidden;transition:opacity .3s,visibility .3s}
@@ -93,7 +95,7 @@ Have a great trip!`,perfectBonus:r=>`PERFECT BONUS +${r}`,statScore:"SCORE",stat
93
95
  .pkb-perfect.pkb-show .pkb-medal{animation:pkb-slam .38s cubic-bezier(.5,0,.75,0) .35s forwards}
94
96
  @keyframes pkb-slam{to{opacity:1;transform:rotate(-14deg) scale(1)}}
95
97
  .pkb-ptitle{font-family:var(--pk-display);font-weight:400;font-size:30px;line-height:1.3;color:inherit}
96
- .pkb-pbody{font-weight:800;font-size:13.5px;line-height:1.6;margin:6px 0 14px;white-space:pre-line}
98
+ .pkb-pbody{font-weight:800;font-size:13.5px;line-height:1.6;margin:6px 0 14px;white-space:pre-line;word-break:auto-phrase}
97
99
  .pkb-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-bottom:16px}
98
100
  .pkb-stats>div{border:2px solid var(--pk-ink);border-radius:12px;padding:6px 4px 5px;background:#fff}
99
101
  .pkb-stats small{display:block;font-size:9.5px;font-weight:800;letter-spacing:.1em}
@@ -103,24 +105,26 @@ Have a great trip!`,perfectBonus:r=>`PERFECT BONUS +${r}`,statScore:"SCORE",stat
103
105
  .pkb-fx{position:absolute;inset:0;width:100%;height:100%;z-index:10;pointer-events:none}
104
106
  .pkb-demo{max-width:720px;margin:12px auto 4px;display:flex;flex-wrap:wrap;align-items:center;gap:8px;font-family:var(--pk-body);font-size:12px;color:#666}
105
107
  .pkb-demo button{appearance:none;border:1px solid #ccc;background:#f3f3f3;color:#222;border-radius:999px;padding:5px 12px;font-size:12px;cursor:pointer}
106
- @container (max-width:560px){.pkb-board{padding:18px 14px 16px}.pkb-head{flex-direction:column;align-items:stretch;gap:12px}.pkb-score{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.pkb-pill,.pkb-pill.pkb-sc{min-width:0;padding:5px 4px 4px}.pkb-pill b{font-size:19px}.pkb-title{font-size:26px}.pkb-grid{gap:8px}.pkb-tile{border-radius:12px;box-shadow:3px 3px 0 var(--pk-ink);gap:3px;aspect-ratio:1/1}.pkb-emo{font-size:24px}.pkb-lbl{font-size:10.5px;padding:0 2px}.pkb-stamp{font-size:14px}.pkb-tile.pkb-reach::after{font-size:9px;padding:2px 5px;top:-9px;right:-5px}.pkb-lines .pkb-u{stroke-width:10}.pkb-lines .pkb-o{stroke-width:5}.pkb-banner::before{width:380px;height:380px;margin:-190px 0 0 -190px}.pkb-banner span{font-size:12px}.pkb-medal{width:96px;height:96px;font-size:20px}.pkb-card{padding:20px 14px 16px}.pkb-ptitle{font-size:24px}.pkb-stats b{font-size:17px}.pkb-float.pkb-pt{font-size:17px}.pkb-float.pkb-cmb{font-size:13px}}
108
+ @container (max-width:560px){.pkb-board{padding:18px 14px 16px}.pkb-head{flex-direction:column;align-items:stretch;gap:12px}.pkb-score{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.pkb-pill,.pkb-pill.pkb-sc{min-width:0;padding:5px 4px 4px}.pkb-pill b{font-size:19px}.pkb-title{font-size:26px}.pkb-grid{gap:max(3px,calc(8px*var(--pk-d)))}.pkb-tile{border-radius:calc(12px*var(--pk-d));box-shadow:3px 3px 0 var(--pk-ink);gap:calc(3px*var(--pk-d));aspect-ratio:1/1}.pkb-emo{font-size:max(13px,calc(24px*var(--pk-s)))}.pkb-lbl{font-size:max(8.5px,calc(10.5px*var(--pk-s)));padding:0 calc(2px*var(--pk-d))}.pkb-stamp{font-size:max(9px,calc(14px*var(--pk-s)))}.pkb-tile.pkb-reach::after{font-size:9px;padding:2px 5px;top:-9px;right:-5px}.pkb-lines .pkb-u{stroke-width:calc(10px*var(--pk-d))}.pkb-lines .pkb-o{stroke-width:calc(5px*var(--pk-d))}.pkb-banner::before{width:380px;height:380px;margin:-190px 0 0 -190px}.pkb-banner span{font-size:12px}.pkb-medal{width:96px;height:96px;font-size:20px}.pkb-card{padding:20px 14px 16px}.pkb-ptitle{font-size:24px}.pkb-stats b{font-size:17px}.pkb-float.pkb-pt{font-size:17px}.pkb-float.pkb-cmb{font-size:13px}}
109
+ @container (max-width:400px){.pkb-board{padding:16px 10px 14px}.pkb-grid{gap:max(3px,calc(6px*var(--pk-d)))}.pkb-lbl{font-size:max(8.5px,calc(10px*var(--pk-s)));padding:0 calc(1px*var(--pk-d))}.pkb-emo{font-size:max(12px,calc(22px*var(--pk-s)))}.pkb-stamp{font-size:max(9px,calc(13px*var(--pk-s)))}.pkb-foot{margin-top:14px;font-size:12px}.pkb-perfect{padding:12px}.pkb-stats{gap:6px}.pkb-stats>div{padding:6px 2px 5px}.pkb-stats small{letter-spacing:.02em}}
110
+ @container (max-width:320px){.pkb-board{padding-inline:8px}.pkb-grid{gap:max(3px,calc(5px*var(--pk-d)))}.pkb-lbl{font-size:max(8.5px,calc(9.5px*var(--pk-s)));padding:0}}
107
111
  @media (prefers-reduced-motion:reduce){.pkb-board.pkb-shake,.pkb-board.pkb-punch,.pkb-flash.pkb-go,.pkb-tile.pkb-hop,.pkb-tile.pkb-squash,.pkb-tile.pkb-reach,.pkb-tile.pkb-line::before,.pkb-pill.pkb-hot,.pkb-bump,.pkb-tile.pkb-reach::after,.pkb-banner::before,.pkb-lines .pkb-draw line,.pkb-kicker.pkb-gold{animation:none}.pkb-banner.pkb-show{animation:pkb-fade 1.8s forwards}.pkb-float{animation:pkb-fade 1s both}.pkb-perfect.pkb-show .pkb-medal{animation:none;opacity:1;transform:rotate(-14deg)}.pkb-card{transition:none}}
108
112
  @keyframes pkb-fade{0%,100%{opacity:0}15%,80%{opacity:1}}
109
- `;var F=[[0,1,2,3],[4,5,6,7],[8,9,10,11],[12,13,14,15],[0,4,8,12],[1,5,9,13],[2,6,10,14],[3,7,11,15],[0,5,10,15],[3,6,9,12]],ut=[0,1,2,3,5,10],Ke=["#E8473B","#2F6FED","#1FA971","#FFFDF6","#2A1F14","#FF9F1C"],Ye=["#FF9F1C","#1FA971","#2F6FED","#9B5DE5","#E8473B"],gt=2500,Xe="packing-bingo-muted",g=r=>r.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n]),_=r=>Array.from({length:16},(n,k)=>!!r?.[k]),Je=()=>Array.from({length:16},(r,n)=>ut.includes(n));function Qe(r){try{return localStorage.getItem(r)}catch{return null}}function Ze(r,n){try{localStorage.setItem(r,n)}catch{}}function ht(r){if(!document.getElementById("pkb-styles")){let n=document.createElement("style");n.id="pkb-styles",n.textContent=Ve,document.head.appendChild(n)}if(r&&!document.getElementById("pkb-fonts")){let n=document.createElement("link");n.id="pkb-fonts",n.rel="stylesheet",n.href=We,document.head.appendChild(n)}}function xt(r,n,k){let d=r.map(($,R)=>`<label class="pkb-tile" data-reach="${g(n.reachBadge)}" style="--pkb-gd:${((R>>2)+(R&3))*.12}s"><input type="checkbox"><span class="pkb-emo" aria-hidden="true">${g($.emoji)}</span><span class="pkb-lbl">${g($.label).replace(/・/g,"\u30FB<wbr>")}</span><span class="pkb-stamp" aria-hidden="true">${g(n.stamp)}</span></label>`).join(""),m=k?`<div class="pkb-demo"><span>${g(n.demoLabel)}</span><button type="button" data-r="dB">${g(n.demoBingo)}</button><button type="button" data-r="dP">${g(n.demoPerfect)}</button><button type="button" data-r="dR">${g(n.demoRestore)}</button></div>`:"";return`<div class="pkb"><div class="pkb-board">
113
+ `;var Rt=Re(4),dt=["#E8473B","#2F6FED","#1FA971","#FFFDF6","#2A1F14","#FF9F1C"],mt=["#FF9F1C","#1FA971","#2F6FED","#9B5DE5","#E8473B"],qt=2500,ft="packing-bingo-muted",x=t=>t.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n]);function ut(t){try{return localStorage.getItem(t)}catch{return null}}function kt(t,n){try{localStorage.setItem(t,n)}catch{}}function Nt(t){if(!document.getElementById("pkb-styles")){let n=document.createElement("style");n.id="pkb-styles",n.textContent=bt,document.head.appendChild(n)}if(t&&!document.getElementById("pkb-fonts")){let n=document.createElement("link");n.id="pkb-fonts",n.rel="stylesheet",n.href=ct,document.head.appendChild(n)}}function jt(t,n,s){let c=t.size,b=Array.from({length:c*c},(l,d)=>{let g=`--pkb-gd:${+((Math.floor(d/c)+d%c)*.36/Math.max(1,c-1)).toFixed(3)}s`;if(d===t.center)return`<div class="pkb-tile pkb-free pkb-on" style="${g}"><span class="pkb-stamp">${x(n.free)}</span></div>`;let M=t.items[t.itemCell.indexOf(d)];return`<label class="pkb-tile" data-reach="${x(n.reachBadge)}" style="${g}"><input type="checkbox"><span class="pkb-emo" aria-hidden="true">${x(M.emoji)}</span><span class="pkb-lbl">${x(M.label).replace(/・/g,"\u30FB<wbr>")}</span><span class="pkb-stamp" aria-hidden="true">${x(n.stamp)}</span></label>`}).join(""),L=`--pk-n:${c};--pk-s:${+Math.min(1.35,4/c).toFixed(3)};--pk-d:${+Math.min(1,4/c).toFixed(3)}`,k=s?`<div class="pkb-demo"><span>${x(n.demoLabel)}</span><button type="button" data-r="dB">${x(n.demoBingo)}</button><button type="button" data-r="dP">${x(n.demoPerfect)}</button><button type="button" data-r="dR">${x(n.demoRestore)}</button></div>`:"";return`<div class="pkb" style="${L}"><div class="pkb-board">
110
114
  <div class="pkb-head"><div>
111
- <div class="pkb-tags"><span class="pkb-kicker" data-r="kick">${g(n.tag)}</span><button type="button" class="pkb-snd" data-r="snd"></button></div>
112
- <h2 class="pkb-title">${g(n.title)}</h2><p class="pkb-sub">${g(n.subtitle)}</p></div>
115
+ <div class="pkb-tags"><span class="pkb-kicker" data-r="kick">${x(n.tag)}</span><button type="button" class="pkb-snd" data-r="snd"></button></div>
116
+ <h2 class="pkb-title">${x(n.title)}</h2>${n.subtitle?`<p class="pkb-sub">${x(n.subtitle)}</p>`:""}</div>
113
117
  <div class="pkb-side"><div class="pkb-score">
114
- <div class="pkb-pill"><small>${g(n.packed)}</small><b data-r="cnt"></b></div>
115
- <div class="pkb-pill" data-r="bp"><small>${g(n.bingo)}</small><b data-r="bng"></b></div>
116
- <div class="pkb-pill pkb-sc" data-r="sp"><small>${g(n.score)}</small><b data-r="sc">0</b></div></div>
118
+ <div class="pkb-pill"><small>${x(n.packed)}</small><b data-r="cnt"></b></div>
119
+ <div class="pkb-pill" data-r="bp"><small>${x(n.bingo)}</small><b data-r="bng"></b></div>
120
+ <div class="pkb-pill pkb-sc" data-r="sp"><small>${x(n.score)}</small><b data-r="sc">0</b></div></div>
117
121
  <div class="pkb-combo" data-r="combo"><b data-r="cmbN"></b><span class="pkb-bar"><i data-r="cbar"></i></span></div></div></div>
118
- <div class="pkb-gw"><div class="pkb-grid">${d}</div><svg class="pkb-lines" aria-hidden="true"></svg>
122
+ <div class="pkb-gw"><div class="pkb-grid">${b}</div><svg class="pkb-lines" aria-hidden="true"></svg>
119
123
  <div class="pkb-banner" data-r="banner" aria-hidden="true"><b data-r="bT"></b><span data-r="bS"></span></div></div>
120
- <div class="pkb-foot"><span data-r="msg" aria-live="polite"></span><button type="button" class="pkb-reset" data-r="reset">${g(n.reset)}</button></div>
124
+ <div class="pkb-foot"><span data-r="msg" aria-live="polite"></span><button type="button" class="pkb-reset" data-r="reset">${x(n.reset)}</button></div>
121
125
  <div class="pkb-flash" data-r="flash"></div>
122
- <div class="pkb-perfect" data-r="perfect"><div class="pkb-card" role="dialog" aria-label="${g(n.perfectTitle)}">
123
- <div class="pkb-medal">${g(n.perfectStamp)}</div><h3 class="pkb-ptitle">${g(n.perfectTitle)}</h3><p class="pkb-pbody">${g(n.perfectBody)}</p>
124
- <div class="pkb-stats"><div><small>${g(n.statScore)}</small><b data-r="sScore">0</b></div><div><small>${g(n.statCombo)}</small><b data-r="sCombo">\xD70</b></div><div><small>${g(n.statLines)}</small><b data-r="sBingo">0</b></div></div>
125
- <button type="button" class="pkb-close" data-r="close">${g(n.close)}</button></div></div>
126
- <canvas class="pkb-fx"></canvas></div>${m}</div>`}function vt(r,n={}){let k=n.items??Le;if(k.length!==16)throw new Error(`[packing-bingo] "items" must have exactly 16 entries (got ${k.length}).`);let d={...Se,...n.messages};n.title!=null&&(d.title=n.title),n.tag!=null&&(d.tag=n.tag),n.subtitle!=null&&(d.subtitle=n.subtitle);let m=!!n.controlled,$=m?null:n.storageKey??null,R=!!n.demo,c=typeof matchMedia=="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches,b=!1,y=new Set,E=(e,t)=>{let a=window.setTimeout(()=>{y.delete(a),b||e()},t);y.add(a)},M=e=>new Promise(t=>window.setTimeout(t,e)),A=0;ht(n.fonts!==!1),r.innerHTML=xt(k,d,R);let p=e=>{let t=r.querySelector(`[data-r="${e}"]`);if(!t)throw new Error(`[packing-bingo] internal: missing element "${e}"`);return t},x=r.querySelector(".pkb-board"),S=r.querySelector(".pkb-gw"),C=r.querySelector(".pkb-grid"),W=r.querySelector(".pkb-lines"),I=r.querySelector(".pkb-fx"),f=I.getContext("2d"),L=Array.from(C.children),re=L.map(e=>e.querySelector("input")),Be=p("kick"),be=p("snd"),N=p("perfect"),h=_(void 0),w=[],ie=new Set,de=new Set,se=!1,Me=0,z=0,ne=0,B=0,X=0,Ce=0,me=!1,ae=new Set,J=new Set,ze=Qe(Xe),V=ze!=null?ze==="1":n.sound===!1,T=_e(()=>V),Te=()=>{be.textContent=V?d.soundOff:d.soundOn,be.setAttribute("aria-pressed",String(!V))};be.addEventListener("click",()=>{V=!V,Ze(Xe,V?"1":"0"),Te(),V||T.pop(4)}),Te();let D=[],K=0,oe=1,H=0,G=0,Pe=()=>{let e=x.getBoundingClientRect();oe=Math.min(2,window.devicePixelRatio||1),H=e.width,G=e.height,I.width=Math.round(H*oe),I.height=Math.round(G*oe)},fe=(e,t,a,o,s,i,l,v)=>({x:e,y:t,vx:a,vy:o,g:s,life:l,shape:v,w:(5+Math.random()*6)*i,h:(3+Math.random()*5)*i,r:Math.random()*6,vr:(Math.random()-.5)*.35,c:Ke[Math.random()*Ke.length|0]}),ke=()=>{!K&&f&&(K=requestAnimationFrame($e))};function Q(e,t,a,o={}){if(!c){for(let s=0;s<a;s++){let i=(o.angle??-Math.PI/2)+(Math.random()-.5)*(o.spread??Math.PI*2),l=(o.speed??10)*(.35+Math.random()*.85),v=Math.random()<(o.star??.15)?"star":Math.random()<.3?"round":"rect";D.push(fe(e,t,Math.cos(i)*l,Math.sin(i)*l,o.g??.28,o.size??1,(o.life??110)+Math.random()*40,v))}ke()}}function et(e){if(c)return;let t=performance.now()+e,a=()=>{for(let o=0;o<4;o++)D.push(fe(Math.random()*H,-12,(Math.random()-.5)*2,2+Math.random()*3,.045,1,420,Math.random()<.2?"star":"rect"));ke(),performance.now()<t&&E(a,45)};a()}function tt(e){if(c)return;let t=performance.now()+e,a=()=>{let o=fe(Math.random()*H,-30,(Math.random()-.5)*1.5,1.5+Math.random()*2,.05,1,500,"emoji");o.e=k[Math.random()*k.length|0].emoji,o.w=22+Math.random()*12,o.vr=(Math.random()-.5)*.06,D.push(o),ke(),performance.now()<t&&E(a,110)};a()}function nt(e,t){Q(e,t,80,{speed:7.5,g:.06,life:85,star:.4}),T.boom()}function at(e,t){e.beginPath();for(let a=0;a<10;a++){let o=a*Math.PI/5-Math.PI/2,s=a%2?t*.45:t;e.lineTo(Math.cos(o)*s,Math.sin(o)*s)}e.closePath(),e.fill()}function $e(){if(K=0,!(b||!f)){f.setTransform(oe,0,0,oe,0,0),f.clearRect(0,0,H,G),D=D.filter(e=>e.life>0&&e.y<G+40);for(let e of D)e.vx*=.985,e.vy=e.vy*.985+e.g,e.x+=e.vx,e.y+=e.vy,e.r+=e.vr,e.life--,f.save(),f.globalAlpha=Math.min(1,e.life/25),f.translate(e.x,e.y),f.rotate(e.r),f.fillStyle=e.c,e.shape==="round"?(f.beginPath(),f.arc(0,0,e.h/1.6,0,7),f.fill()):e.shape==="star"?at(f,e.w*.8):e.shape==="emoji"?(f.font=`${e.w}px "Apple Color Emoji","Segoe UI Emoji","Noto Color Emoji",sans-serif`,f.textAlign="center",f.textBaseline="middle",f.fillText(e.e??"",0,0)):(f.scale(1,Math.cos(e.r*2.3)),f.fillRect(-e.w/2,-e.h/2,e.w,e.h)),f.restore();D.length&&(K=requestAnimationFrame($e))}}let pe=e=>{let t=x.getBoundingClientRect(),a=e.getBoundingClientRect();return{x:a.left-t.left+a.width/2,y:a.top-t.top+a.height/2}},P=(e,t)=>{e.classList.remove(t),e.offsetWidth,e.classList.add(t)},Ae=(e,t)=>{c||(L[e].classList.remove("pkb-squash"),L[e].style.setProperty("--pkb-d",t+"ms"),P(L[e],"pkb-hop"))};C.addEventListener("animationend",e=>{let t=e.target;t.classList.contains("pkb-tile")&&(e.animationName==="pkb-hop"||e.animationName==="pkb-squash")&&t.classList.remove(e.animationName)});let ot=e=>{let t=document.createElement("span");t.className="pkb-ring",e.appendChild(t),t.addEventListener("animationend",()=>t.remove())},ue=e=>{let t=navigator.userActivation;if(!(t&&!t.hasBeenActive))try{navigator.vibrate?.(e)}catch{}},le=(e,t,a,o,s=0,i)=>{let l=document.createElement("div");l.className="pkb-float pkb-"+o,l.textContent=e,l.style.left=t+"px",l.style.top=a+"px",s&&(l.style.animationDelay=s+"ms"),i&&(l.style.color=i),x.appendChild(l),l.addEventListener("animationend",()=>l.remove())},Oe=(e,t,a)=>Math.max(0,Math.min(1,(e-t)/a)),Fe=e=>1-Math.pow(1-e,3),ce=0;function ge(){cancelAnimationFrame(ce);let e=ne,t=z,a=performance.now(),o=s=>{if(b)return;let i=Oe(s,a,450);ne=Math.round(e+(t-e)*Fe(i)),p("sc").textContent=ne.toLocaleString(),i<1&&(ce=requestAnimationFrame(o))};o(a),c||P(p("sp"),"pkb-bump")}let Re=(e,t,a,o="pt")=>{le(`+${e}`,t,a,o),ge()};function he(e,t,a,o,s,i=!1){let l=performance.now(),v=A,q=0,j=Y=>{if(b||v!==A)return;let te=Oe(Y,l,o);e.textContent=s(Math.round(t+(a-t)*Fe(te))),i&&te<1&&Y-q>55&&(T.tick(),q=Y),te<1?requestAnimationFrame(j):c||P(e,"pkb-bump")};j(l)}let qe=e=>{let t=L[e];return{x:t.offsetLeft+t.offsetWidth/2,y:t.offsetTop+t.offsetHeight/2}};function je(e=[]){W.setAttribute("viewBox",`0 0 ${S.clientWidth} ${S.clientHeight}`),W.innerHTML=w.map(t=>{let a=qe(F[t][0]),o=qe(F[t][3]),s=o.x-a.x,i=o.y-a.y,l=Math.hypot(s,i)||1,v=s/l*26,q=i/l*26,j=`x1="${a.x-v}" y1="${a.y-q}" x2="${o.x+v}" y2="${o.y+q}" pathLength="1"`;return`<g${e.includes(t)?' class="pkb-draw"':""}><line class="pkb-u" ${j}/><line class="pkb-o" ${j}/></g>`}).join("")}function rt(e,t){let a=pe(L[e]);if(!t){B=0,p("combo").classList.remove("pkb-on"),T.off();return}let o=performance.now();B=o-Ce<gt?B+1:1,Ce=o,X=Math.max(X,B),T.pop(B-1),c||(P(L[e],"pkb-squash"),ot(L[e])),Q(a.x,a.y,18,{speed:6,g:.2,life:30,size:.6,star:.5}),ae.has(e)||(ae.add(e),z+=10*B,Re(10*B,a.x,a.y-12)),B>=2&&(le(d.comboPop(B),a.x,a.y+22,"cmb",90,Ye[(B-2)%Ye.length]),p("cmbN").textContent=d.combo(B),P(p("combo"),"pkb-on")),ue(12)}p("cbar").addEventListener("animationend",()=>{p("combo").classList.remove("pkb-on"),B=0});function it(e){e.forEach(t=>{let a=pe(L[t]);le(d.reachPop,a.x,a.y-34,"rch",150)}),E(()=>T.reach(),150)}function st(e,t){let a=e.length,o=[...new Set(e.flatMap(i=>F[i]))],s=Math.min(70,300/o.length);o.forEach((i,l)=>E(()=>{Ae(i,0);let v=pe(L[i]);Q(v.x,v.y,14,{speed:5,g:.15,life:30,size:.7,star:.8}),T.note(l+3)},l*s)),E(()=>{p("bT").textContent=a>=3?d.bannerTriple:a===2?d.bannerDouble:d.bannerSingle,p("bS").textContent=a>1?d.bannerMulti(a):d.bannerNth(w.length),P(p("banner"),"pkb-show"),c||(P(p("flash"),"pkb-go"),P(x,"pkb-punch"));let i=pe(S);Q(i.x,i.y,a>1?180:110,{speed:a>1?16:13,star:.3}),T.bingo(a),ue(a>1?[40,60,40,60,90]:[40,60,40]),t&&E(()=>Re(t,i.x,i.y+105,"big"),350)},o.length*s+60)}function pt(e){let t=me?0:1e3;me=!0,z+=t,L.forEach((o,s)=>Ae(s,((s>>2)+(s&3))*60)),T.perfect(),c||P(p("flash"),"pkb-go"),p("sScore").textContent="0",p("sCombo").textContent="\xD70",p("sBingo").textContent="0",E(()=>{P(N,"pkb-show"),p("close").focus({preventScroll:!0}),E(()=>{c||P(x,"pkb-shake"),T.boom(),Q(0,G,90,{angle:-Math.PI/3,spread:.8,speed:22,g:.32,star:.3}),Q(H,G,90,{angle:-Math.PI*2/3,spread:.8,speed:22,g:.32,star:.3}),et(3500),ue([60,80,60,80,200]),t&&le(d.perfectBonus(t),H/2,G*.16,"big"),he(p("sScore"),0,z,1300,o=>o.toLocaleString(),!0),he(p("sCombo"),0,X,700,o=>"\xD7"+o),he(p("sBingo"),0,w.length,700,String),ge()},720),[1300,1650,2e3,2350,2700].forEach(o=>E(()=>nt(H*(.15+Math.random()*.7),G*(.12+Math.random()*.3)),o)),E(()=>tt(3e3),1500)},520);let a={score:z,maxCombo:X};e.push(()=>n.onPerfect?.(a))}function Ie(){A++,y.forEach(e=>clearTimeout(e)),y.clear(),cancelAnimationFrame(ce),ne=z,p("sc").textContent=z.toLocaleString()}function lt(){D=[],cancelAnimationFrame(K),K=0,f?.clearRect(0,0,I.width,I.height),x.querySelectorAll(".pkb-float, .pkb-ring").forEach(e=>e.remove()),p("banner").classList.remove("pkb-show"),p("flash").classList.remove("pkb-go"),p("combo").classList.remove("pkb-on"),N.classList.remove("pkb-show")}function xe(e,t){let a=[],o=h,s=o.filter(Boolean).length;w=F.flatMap((u,O)=>u.every(we=>o[we])?[O]:[]);let i=w.filter(u=>!ie.has(u));[...ie].some(u=>!w.includes(u))&&(Ie(),s<16&&N.classList.remove("pkb-show"));let l=new Set(w.flatMap(u=>F[u])),v=new Set;for(let u of F){let O=u.filter(we=>!o[we]);O.length===1&&v.add(O[0])}L.forEach((u,O)=>{u.classList.toggle("pkb-on",o[O]),u.classList.toggle("pkb-line",l.has(O)),u.classList.toggle("pkb-reach",v.has(O))}),x.classList.toggle("pkb-all",s===16),Be.classList.toggle("pkb-gold",s===16),Be.textContent=s===16?d.perfectTag:d.tag,p("cnt").textContent=`${s}/16`,p("bng").textContent=String(w.length);let q=p("bp");w.length>Me&&(q.classList.remove("pkb-hot"),q.offsetWidth),q.classList.toggle("pkb-hot",w.length>0),Me=w.length,je(i),e!==null&&rt(e,o[e]);let j=i.filter(u=>!J.has(u));j.forEach(u=>J.add(u));let Y=100*j.length*j.length;if(z+=Y,t)Y&&ge();else if(s===16&&!se)pt(a);else if(i.length){st(i,Y);let u={newLines:i,totalLines:w.length,score:z};a.push(()=>n.onBingo?.(u))}else if(e!==null&&o[e]){let u=[...v].filter(O=>!de.has(O));u.length&&it(u)}ie=new Set(w),de=v,se=s===16;let te=[...v].map(u=>k[u].label);return p("msg").textContent=s===16?d.statusDone:te.length?d.statusReach(te):w.length?d.statusLines(w.length,16-s):d.statusStart(16-s),a}let Ne=e=>{for(let t of e){if(b)return;t()}},De=()=>{$&&Ze($,JSON.stringify(h))};function He(e,t,a){h=e,re.forEach((s,i)=>s.checked=h[i]);let o=xe(t,a);return De(),o}function ve(e){Ie(),lt(),h=e,re.forEach((t,a)=>t.checked=h[a]),ae.clear(),J.clear(),h.forEach((t,a)=>t&&ae.add(a)),F.forEach((t,a)=>t.every(o=>h[o])&&J.add(a)),ie=new Set(J),de=new Set,se=h.every(Boolean),me=se,z=ne=ae.size*10+J.size*100,B=0,X=0,p("sc").textContent=z.toLocaleString(),xe(null,!0),De()}function Z(e,t,a={}){if(m){re.forEach((s,i)=>s.checked=h[i]),n.onChange?.(e.slice());return}let o=[];a.reset?ve(e):o=He(e,t,!!a.quiet),n.onChange?.(h.slice()),Ne(o)}if(C.addEventListener("change",e=>{let t=re.indexOf(e.target);if(t<0)return;let a=h.slice();a[t]=!a[t],Z(a,t)}),p("reset").addEventListener("click",()=>Z(_(void 0),null,{reset:!0})),p("close").addEventListener("click",()=>N.classList.remove("pkb-show")),N.addEventListener("click",e=>{e.target===N&&N.classList.remove("pkb-show")}),R){let e=!1,t=()=>{h.every(Boolean)?Z(_(void 0),null,{reset:!0}):N.classList.remove("pkb-show")},a=async o=>{if(!e){e=!0;try{t();let s=A;for(let i of o){if(await M(i.delay),b||s!==A)return;let l=h.slice();l[i.i]=!0,Z(l,i.i,{quiet:i.quiet})}}finally{e=!1}}};p("dB").addEventListener("click",()=>{let o=()=>F.map(i=>i.filter(l=>!h[l])).filter(i=>i.length).sort((i,l)=>i.length-l.length)[0]??[],s=h.every(Boolean)?[...F[0]]:o();a(s.map(i=>({i,delay:320})))}),p("dP").addEventListener("click",()=>{let o=h.every(Boolean)?L.map((s,i)=>i):L.map((s,i)=>i).filter(s=>!h[s]);a(o.map((s,i)=>i<o.length-1?{i:s,delay:170,quiet:!0}:{i:s,delay:450}))}),p("dR").addEventListener("click",()=>{e||Z(Je(),null,{reset:!0})})}let ee=null;if($)try{let e=JSON.parse(Qe($)??"null");Array.isArray(e)&&(ee=_(e))}catch{}!ee&&n.defaultChecked&&(ee=_(n.defaultChecked)),!ee&&R&&(ee=Je()),Pe(),ve(ee??_(void 0));let ye=typeof ResizeObserver=="function"?new ResizeObserver(()=>{Pe(),je()}):null;return ye?.observe(x),ye?.observe(S),{setChecked(e,t={}){if(b)return;let a=_(e),o=a.flatMap((s,i)=>s!==h[i]?[i]:[]);if(o.length){if(!t.animate||o.length!==1){ve(a);return}Ne(He(a,o[0],!1))}},reset(){b||Z(_(void 0),null,{reset:!0})},refresh(){b||xe(null,!0)},getState(){return{checked:h.slice(),lines:w.slice(),score:z,maxCombo:X,complete:h.every(Boolean)}},destroy(){b||(b=!0,y.forEach(e=>clearTimeout(e)),y.clear(),cancelAnimationFrame(K),cancelAnimationFrame(ce),ye?.disconnect(),T.close(),r.innerHTML="")}}}return kt(yt);})();
126
+ <div class="pkb-perfect" data-r="perfect"><div class="pkb-card" role="dialog" aria-label="${x(n.perfectTitle)}">
127
+ <div class="pkb-medal">${x(n.perfectStamp)}</div><h3 class="pkb-ptitle">${x(n.perfectTitle)}</h3><p class="pkb-pbody" data-r="pbody">${x(gt(n,t.items.length))}</p>
128
+ <div class="pkb-stats"><div><small>${x(n.statScore)}</small><b data-r="sScore">0</b></div><div><small>${x(n.statCombo)}</small><b data-r="sCombo">\xD70</b></div><div><small>${x(n.statLines)}</small><b data-r="sBingo">0</b></div></div>
129
+ <button type="button" class="pkb-close" data-r="close">${x(n.close)}</button></div></div>
130
+ <canvas class="pkb-fx"></canvas></div>${k}</div>`}var gt=(t,n)=>typeof t.perfectBody=="function"?t.perfectBody(n):t.perfectBody;function Dt(t,n={}){let s=ot(n),{items:c,lines:b,cellLines:L}=s,k=s.size,l=c.length,d=e=>Array.from({length:l},(a,r)=>!!e?.[r]),g=[...L[0],...L[2*k].slice(1,-1)],M=new Set(s.itemCell.flatMap((e,a)=>g.includes(e)?[a]:[])),v=()=>Array.from({length:l},(e,a)=>M.has(a)),$=e=>Math.floor(e/k)+e%k,F=Math.min(1,4/k),u={...qe,...n.messages};n.title!=null&&(u.title=n.title),n.tag!=null&&(u.tag=n.tag),n.subtitle!=null&&(u.subtitle=n.subtitle);let I=!!n.controlled,C=lt(n),H=!!n.demo,z=typeof matchMedia=="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches,S=!1,J=new Set,R=(e,a)=>{let r=window.setTimeout(()=>{J.delete(r),S||e()},a);J.add(r)},ht=e=>new Promise(a=>window.setTimeout(a,e)),se=0;Nt(n.fonts!==!1),t.innerHTML=jt(s,u,H);let m=e=>{let a=t.querySelector(`[data-r="${e}"]`);if(!a)throw new Error(`[packing-bingo] internal: missing element "${e}"`);return a},G=t.querySelector(".pkb-board"),de=t.querySelector(".pkb-gw"),ye=t.querySelector(".pkb-grid"),Ne=t.querySelector(".pkb-lines"),pe=t.querySelector(".pkb-fx"),y=pe.getContext("2d"),Z=Array.from(ye.children),Q=s.itemCell.map(e=>Z[e]),xt=s.center>=0?Z[s.center]:null,me=Q.map(e=>e.querySelector("input")),je=m("kick"),we=m("snd"),U=m("perfect"),w=d(void 0),B=[],fe=new Set,Ee=new Set,ue=!1,De=0,O=0,le=0,T=0,ee=0,He=0,Le=!1,ce=new Set,te=new Set,Ge=ut(ft),X=Ge!=null?Ge==="1":n.sound===!1,A=pt(()=>X),Ue=()=>{we.textContent=X?u.soundOff:u.soundOn,we.setAttribute("aria-pressed",String(!X))};we.addEventListener("click",()=>{X=!X,kt(ft,X?"1":"0"),Ue(),X||A.pop(4)}),Ue();let _=[],Y=0,be=1,K=0,W=0,_e=()=>{let e=G.getBoundingClientRect();be=Math.min(2,window.devicePixelRatio||1),K=e.width,W=e.height,pe.width=Math.round(K*be),pe.height=Math.round(W*be)},Se=(e,a,r,o,p,i,f,E)=>({x:e,y:a,vx:r,vy:o,g:p,life:f,shape:E,w:(5+Math.random()*6)*i,h:(3+Math.random()*5)*i,r:Math.random()*6,vr:(Math.random()-.5)*.35,c:dt[Math.random()*dt.length|0]}),Be=()=>{!Y&&y&&(Y=requestAnimationFrame(Ke))};function ne(e,a,r,o={}){if(!z){for(let p=0;p<r;p++){let i=(o.angle??-Math.PI/2)+(Math.random()-.5)*(o.spread??Math.PI*2),f=(o.speed??10)*(.35+Math.random()*.85),E=Math.random()<(o.star??.15)?"star":Math.random()<.3?"round":"rect";_.push(Se(e,a,Math.cos(i)*f,Math.sin(i)*f,o.g??.28,o.size??1,(o.life??110)+Math.random()*40,E))}Be()}}function vt(e){if(z)return;let a=performance.now()+e,r=()=>{for(let o=0;o<4;o++)_.push(Se(Math.random()*K,-12,(Math.random()-.5)*2,2+Math.random()*3,.045,1,420,Math.random()<.2?"star":"rect"));Be(),performance.now()<a&&R(r,45)};r()}function yt(e){if(z)return;let a=performance.now()+e,r=()=>{let o=Se(Math.random()*K,-30,(Math.random()-.5)*1.5,1.5+Math.random()*2,.05,1,500,"emoji");o.e=c[Math.random()*c.length|0].emoji,o.w=22+Math.random()*12,o.vr=(Math.random()-.5)*.06,_.push(o),Be(),performance.now()<a&&R(r,110)};r()}function wt(e,a){ne(e,a,80,{speed:7.5,g:.06,life:85,star:.4}),A.boom()}function Et(e,a){e.beginPath();for(let r=0;r<10;r++){let o=r*Math.PI/5-Math.PI/2,p=r%2?a*.45:a;e.lineTo(Math.cos(o)*p,Math.sin(o)*p)}e.closePath(),e.fill()}function Ke(){if(Y=0,!(S||!y)){y.setTransform(be,0,0,be,0,0),y.clearRect(0,0,K,W),_=_.filter(e=>e.life>0&&e.y<W+40);for(let e of _)e.vx*=.985,e.vy=e.vy*.985+e.g,e.x+=e.vx,e.y+=e.vy,e.r+=e.vr,e.life--,y.save(),y.globalAlpha=Math.min(1,e.life/25),y.translate(e.x,e.y),y.rotate(e.r),y.fillStyle=e.c,e.shape==="round"?(y.beginPath(),y.arc(0,0,e.h/1.6,0,7),y.fill()):e.shape==="star"?Et(y,e.w*.8):e.shape==="emoji"?(y.font=`${e.w}px "Apple Color Emoji","Segoe UI Emoji","Noto Color Emoji",sans-serif`,y.textAlign="center",y.textBaseline="middle",y.fillText(e.e??"",0,0)):(y.scale(1,Math.cos(e.r*2.3)),y.fillRect(-e.w/2,-e.h/2,e.w,e.h)),y.restore();_.length&&(Y=requestAnimationFrame(Ke))}}let ke=e=>{let a=G.getBoundingClientRect(),r=e.getBoundingClientRect();return{x:r.left-a.left+r.width/2,y:r.top-a.top+r.height/2}},P=(e,a)=>{e.classList.remove(a),e.offsetWidth,e.classList.add(a)},We=(e,a)=>{z||(e.classList.remove("pkb-squash"),e.style.setProperty("--pkb-d",a+"ms"),P(e,"pkb-hop"))};ye.addEventListener("animationend",e=>{let a=e.target;a.classList.contains("pkb-tile")&&(e.animationName==="pkb-hop"||e.animationName==="pkb-squash")&&a.classList.remove(e.animationName)});let Lt=e=>{let a=document.createElement("span");a.className="pkb-ring",e.appendChild(a),a.addEventListener("animationend",()=>a.remove())},Me=e=>{let a=navigator.userActivation;if(!(a&&!a.hasBeenActive))try{navigator.vibrate?.(e)}catch{}},ge=(e,a,r,o,p=0,i)=>{let f=document.createElement("div");f.className="pkb-float pkb-"+o,f.textContent=e,f.style.left=a+"px",f.style.top=r+"px",p&&(f.style.animationDelay=p+"ms"),i&&(f.style.color=i),G.appendChild(f),f.addEventListener("animationend",()=>f.remove())},Ve=(e,a,r)=>Math.max(0,Math.min(1,(e-a)/r)),Xe=e=>1-Math.pow(1-e,3),he=0;function $e(){cancelAnimationFrame(he);let e=le,a=O,r=performance.now(),o=p=>{if(S)return;let i=Ve(p,r,450);le=Math.round(e+(a-e)*Xe(i)),m("sc").textContent=le.toLocaleString(),i<1&&(he=requestAnimationFrame(o))};o(r),z||P(m("sp"),"pkb-bump")}let Ye=(e,a,r,o="pt")=>{ge(`+${e}`,a,r,o),$e()};function Ce(e,a,r,o,p,i=!1){let f=performance.now(),E=se,j=0,D=q=>{if(S||E!==se)return;let oe=Ve(q,f,o);e.textContent=p(Math.round(a+(r-a)*Xe(oe))),i&&oe<1&&q-j>55&&(A.tick(),j=q),oe<1?requestAnimationFrame(D):z||P(e,"pkb-bump")};D(f)}let Je=e=>({x:e.offsetLeft+e.offsetWidth/2,y:e.offsetTop+e.offsetHeight/2});function Ze(e=[]){Ne.setAttribute("viewBox",`0 0 ${de.clientWidth} ${de.clientHeight}`),Ne.innerHTML=B.map(a=>{let r=Je(Z[L[a][0]]),o=Je(Z[L[a][k-1]]),p=o.x-r.x,i=o.y-r.y,f=Math.hypot(p,i)||1,E=26*F,j=p/f*E,D=i/f*E,q=`x1="${r.x-j}" y1="${r.y-D}" x2="${o.x+j}" y2="${o.y+D}" pathLength="1"`;return`<g${e.includes(a)?' class="pkb-draw"':""}><line class="pkb-u" ${q}/><line class="pkb-o" ${q}/></g>`}).join("")}function St(e,a){let r=ke(Q[e]);if(!a){T=0,m("combo").classList.remove("pkb-on"),A.off();return}let o=performance.now();T=o-He<qt?T+1:1,He=o,ee=Math.max(ee,T),A.pop(T-1),z||(P(Q[e],"pkb-squash"),Lt(Q[e])),ne(r.x,r.y,18,{speed:6,g:.2,life:30,size:.6,star:.5}),ce.has(e)||(ce.add(e),O+=10*T,Ye(10*T,r.x,r.y-12)),T>=2&&(ge(u.comboPop(T),r.x,r.y+22,"cmb",90,mt[(T-2)%mt.length]),m("cmbN").textContent=u.combo(T),P(m("combo"),"pkb-on")),Me(12)}m("cbar").addEventListener("animationend",()=>{m("combo").classList.remove("pkb-on"),T=0});function Bt(e){e.forEach(a=>{let r=ke(Q[a]);ge(u.reachPop,r.x,r.y-34,"rch",150)}),R(()=>A.reach(),150)}function Mt(e,a){let r=e.length,o=[...new Set(e.flatMap(i=>L[i]))].map(i=>Z[i]),p=Math.min(70,300/o.length);o.forEach((i,f)=>R(()=>{We(i,0);let E=ke(i);ne(E.x,E.y,14,{speed:5,g:.15,life:30,size:.7,star:.8}),A.note(f+3)},f*p)),R(()=>{m("bT").textContent=r>=3?u.bannerTriple:r===2?u.bannerDouble:u.bannerSingle,m("bS").textContent=r>1?u.bannerMulti(r):u.bannerNth(B.length),P(m("banner"),"pkb-show"),z||(P(m("flash"),"pkb-go"),P(G,"pkb-punch"));let i=ke(de);ne(i.x,i.y,r>1?180:110,{speed:r>1?16:13,star:.3}),A.bingo(r),Me(r>1?[40,60,40,60,90]:[40,60,40]),a&&R(()=>Ye(a,i.x,i.y+105,"big"),350)},o.length*p+60)}function $t(e){let a=Le?0:1e3;Le=!0,O+=a,Z.forEach((o,p)=>We(o,$(p)*180/Math.max(1,k-1))),A.perfect(),z||P(m("flash"),"pkb-go"),m("pbody").textContent=gt(u,l),m("sScore").textContent="0",m("sCombo").textContent="\xD70",m("sBingo").textContent="0",R(()=>{P(U,"pkb-show"),m("close").focus({preventScroll:!0}),R(()=>{z||P(G,"pkb-shake"),A.boom(),ne(0,W,90,{angle:-Math.PI/3,spread:.8,speed:22,g:.32,star:.3}),ne(K,W,90,{angle:-Math.PI*2/3,spread:.8,speed:22,g:.32,star:.3}),vt(3500),Me([60,80,60,80,200]),a&&ge(u.perfectBonus(a),K/2,W*.16,"big"),Ce(m("sScore"),0,O,1300,o=>o.toLocaleString(),!0),Ce(m("sCombo"),0,ee,700,o=>"\xD7"+o),Ce(m("sBingo"),0,B.length,700,String),$e()},720),[1300,1650,2e3,2350,2700].forEach(o=>R(()=>wt(K*(.15+Math.random()*.7),W*(.12+Math.random()*.3)),o)),R(()=>yt(3e3),1500)},520);let r={score:O,maxCombo:ee};e.push(()=>n.onPerfect?.(r))}function Qe(){se++,J.forEach(e=>clearTimeout(e)),J.clear(),cancelAnimationFrame(he),le=O,m("sc").textContent=O.toLocaleString()}function Ct(){_=[],cancelAnimationFrame(Y),Y=0,y?.clearRect(0,0,pe.width,pe.height),G.querySelectorAll(".pkb-float, .pkb-ring").forEach(e=>e.remove()),m("banner").classList.remove("pkb-show"),m("flash").classList.remove("pkb-go"),m("combo").classList.remove("pkb-on"),U.classList.remove("pkb-show")}function ze(e,a){let r=[],o=w,p=o.filter(Boolean).length;B=b.flatMap((h,N)=>h.every(Ae=>o[Ae])?[N]:[]);let i=B.filter(h=>!fe.has(h));[...fe].some(h=>!B.includes(h))&&(Qe(),p<l&&U.classList.remove("pkb-show"));let f=new Set(B.flatMap(h=>L[h])),E=new Set;for(let h of b){let N=h.filter(Ae=>!o[Ae]);N.length===1&&E.add(N[0])}Q.forEach((h,N)=>{h.classList.toggle("pkb-on",o[N]),h.classList.toggle("pkb-line",f.has(s.itemCell[N])),h.classList.toggle("pkb-reach",E.has(N))}),xt?.classList.toggle("pkb-line",f.has(s.center)),G.classList.toggle("pkb-all",p===l),je.classList.toggle("pkb-gold",p===l),je.textContent=p===l?u.perfectTag:u.tag,m("cnt").textContent=`${p}/${l}`,m("bng").textContent=String(B.length);let j=m("bp");B.length>De&&(j.classList.remove("pkb-hot"),j.offsetWidth),j.classList.toggle("pkb-hot",B.length>0),De=B.length,Ze(i),e!==null&&St(e,o[e]);let D=i.filter(h=>!te.has(h));D.forEach(h=>te.add(h));let q=100*D.length*D.length;if(O+=q,a)q&&$e();else if(p===l&&!ue)$t(r);else if(i.length){Mt(i,q);let h={newLines:i,totalLines:B.length,score:O};r.push(()=>n.onBingo?.(h))}else if(e!==null&&o[e]){let h=[...E].filter(N=>!Ee.has(N));h.length&&Bt(h)}fe=new Set(B),Ee=E,ue=p===l;let oe=[...E].map(h=>c[h].label);return m("msg").textContent=p===l?u.statusDone:oe.length?u.statusReach(oe):B.length?u.statusLines(B.length,l-p):u.statusStart(l-p),r}let et=e=>{for(let a of e){if(S)return;a()}},tt=()=>{C&&kt(C,JSON.stringify(w))};function nt(e,a,r){w=e,me.forEach((p,i)=>p.checked=w[i]);let o=ze(a,r);return tt(),o}function Te(e){Qe(),Ct(),w=e,me.forEach((a,r)=>a.checked=w[r]),ce.clear(),te.clear(),w.forEach((a,r)=>a&&ce.add(r)),b.forEach((a,r)=>a.every(o=>w[o])&&te.add(r)),fe=new Set(te),Ee=new Set,ue=w.every(Boolean),Le=ue,O=le=ce.size*10+te.size*100,T=0,ee=0,m("sc").textContent=O.toLocaleString(),ze(null,!0),tt()}function ae(e,a,r={}){if(I){me.forEach((p,i)=>p.checked=w[i]),n.onChange?.(e.slice());return}let o=[];r.reset?Te(e):o=nt(e,a,!!r.quiet),n.onChange?.(w.slice()),et(o)}if(ye.addEventListener("change",e=>{let a=me.indexOf(e.target);if(a<0)return;let r=w.slice();r[a]=!r[a],ae(r,a)}),m("reset").addEventListener("click",()=>ae(d(void 0),null,{reset:!0})),m("close").addEventListener("click",()=>U.classList.remove("pkb-show")),U.addEventListener("click",e=>{e.target===U&&U.classList.remove("pkb-show")}),H){let e=!1,a=()=>{w.every(Boolean)?ae(d(void 0),null,{reset:!0}):U.classList.remove("pkb-show")},r=async o=>{if(!e){e=!0;try{a();let p=se;for(let i of o){if(await ht(i.delay),S||p!==se)return;let f=w.slice();f[i.i]=!0,ae(f,i.i,{quiet:i.quiet})}}finally{e=!1}}};m("dB").addEventListener("click",()=>{let o=()=>b.map(i=>i.filter(f=>!w[f])).filter(i=>i.length).sort((i,f)=>i.length-f.length)[0]??[],p=w.every(Boolean)?[...b[0]]:o();r(p.map(i=>({i,delay:320})))}),m("dP").addEventListener("click",()=>{let o=c.map((i,f)=>f),p=w.every(Boolean)?o:o.filter(i=>!w[i]);r(p.map((i,f)=>f<p.length-1?{i,delay:170,quiet:!0}:{i,delay:450}))}),m("dR").addEventListener("click",()=>{e||ae(v(),null,{reset:!0})})}let re=null;if(C)try{let e=JSON.parse(ut(C)??"null");Array.isArray(e)&&(re=d(e))}catch{}!re&&n.defaultChecked&&(re=d(n.defaultChecked)),!re&&H&&(re=v()),_e(),Te(re??d(void 0));let Oe=typeof ResizeObserver=="function"?new ResizeObserver(()=>{_e(),Ze()}):null;return Oe?.observe(G),Oe?.observe(de),{setChecked(e,a={}){if(S)return;let r=d(e),o=r.flatMap((p,i)=>p!==w[i]?[i]:[]);if(o.length){if(!a.animate||o.length!==1){Te(r);return}et(nt(r,o[0],!1))}},reset(){S||ae(d(void 0),null,{reset:!0})},refresh(){S||ze(null,!0)},getState(){return{checked:w.slice(),lines:B.slice(),score:O,maxCombo:ee,complete:w.every(Boolean),size:k,free:s.free}},destroy(){S||(S=!0,J.forEach(e=>clearTimeout(e)),J.clear(),cancelAnimationFrame(Y),cancelAnimationFrame(he),Oe?.disconnect(),A.close(),t.innerHTML="")}}}return Ft(Ht);})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "packing-bingo",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "A school-trip packing checklist that plays like bingo, as a React component (or plain JS): combos, fanfares and fireworks.",
5
5
  "license": "MIT",
6
6
  "author": "Jin-hiroo",
@@ -8,7 +8,7 @@
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/Jin-hiroo/packing-bingo.git"
10
10
  },
11
- "homepage": "https://github.com/Jin-hiroo/packing-bingo#readme",
11
+ "homepage": "https://jin-hiroo.github.io/packing-bingo/",
12
12
  "bugs": "https://github.com/Jin-hiroo/packing-bingo/issues",
13
13
  "keywords": [
14
14
  "react",