studio-engine 0.51.0 → 0.52.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +108 -0
- data/app/assets/javascripts/studio/alpine.js +16 -0
- data/app/controllers/studio/profiles_controller.rb +53 -0
- data/app/views/layouts/studio/_head.html.erb +20 -1
- data/app/views/studio/profiles/_birthday_fields.html.erb +210 -12
- data/app/views/studio/profiles/_birthday_picker_script.html.erb +144 -0
- data/app/views/studio/profiles/_identity.html.erb +22 -1
- data/app/views/studio/profiles/_identity_body.html.erb +52 -23
- data/app/views/studio/profiles/_identity_styles.html.erb +76 -15
- data/app/views/studio/profiles/_newsletter_modals.html.erb +61 -0
- data/app/views/studio/profiles/_newsletter_section.html.erb +65 -0
- data/app/views/studio/profiles/edit.html.erb +26 -9
- data/app/views/studio/profiles/show.html.erb +35 -0
- data/lib/studio/engine.rb +1 -0
- data/lib/studio/newsletter.rb +70 -0
- data/lib/studio/profile_sections.rb +33 -6
- data/lib/studio/version.rb +1 -1
- data/lib/studio.rb +9 -0
- metadata +6 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4db67e2d7b38334f6a16bb80e80e2188a9ad0fc3d7a71dffcb8e6c4e8cce25a0
|
|
4
|
+
data.tar.gz: dca6e5cde6e66c1bc02cdd1c3e34e9919788ded47848451dc20de3e2933e2e81
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a44e46ce3ae371350306781e46bfdf58ad7cca95365e44298fe5bbab403079eb8839b210c206313f2ea11fc211d8c73606f5745bddd0db9f5e97779a1ac045d2
|
|
7
|
+
data.tar.gz: 67d82abcd2997f698640fa1b8753f9cc9627a871fce118472b21f0bc9ec6508adcfaa0e276dfd5b8f808c176b941cebbd131e0d99f119769ebb8b45d3e4a1b39
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,114 @@ The format is [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This pro
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- **The edit page's avatar is now the control; its corner badge is gone.**
|
|
10
|
+
Hovering the identity card fades a **Change photo** label over the picture, and
|
|
11
|
+
clicking anywhere on the picture opens the file picker and then the cropper. A
|
|
12
|
+
128px target replaces a 28px one, and a label replaces a glyph that had to be
|
|
13
|
+
interpreted. The reveal also fires on **focus**, because a keyboard never
|
|
14
|
+
hovers and this is the only route to changing a photo; on touch the label stays
|
|
15
|
+
visible over a thinner scrim, so the affordance exists without hiding the photo
|
|
16
|
+
it describes.
|
|
17
|
+
|
|
18
|
+
The label is the button's **accessible name**, so it is hidden by `opacity`
|
|
19
|
+
and never by `display`/`visibility` — either of those would drop it out of the
|
|
20
|
+
accessibility tree and leave the button silently unnamed at rest.
|
|
21
|
+
|
|
22
|
+
**The read page is unchanged**: its whole card is a link to `/profile/edit` and
|
|
23
|
+
its badge stays a decorative `<span>` (an `<a>` inside an `<a>` is invalid, and
|
|
24
|
+
browsers repair it by closing the outer link early).
|
|
25
|
+
|
|
26
|
+
- **Birthday is entered through a calendar rather than an open field.** The
|
|
27
|
+
popover carries month and year **selects** rather than only step arrows —
|
|
28
|
+
stepping from today to 1985 is about four hundred clicks, which is why
|
|
29
|
+
turf-monster's contest picker could not simply be reused. Future dates are
|
|
30
|
+
disabled per-day (the boundary month is half valid), today is still selectable,
|
|
31
|
+
and a set birthday can be cleared.
|
|
32
|
+
|
|
33
|
+
It is `position: fixed`, placed from the trigger's rect, for two reasons: an
|
|
34
|
+
absolutely-positioned popover is clipped the day a consumer's card carries
|
|
35
|
+
`position: relative` alongside `overflow-hidden`, and viewport coordinates only
|
|
36
|
+
stay meaningful under `fixed` once the page scrolls.
|
|
37
|
+
|
|
38
|
+
**Without JavaScript the native `<input type="date">` renders instead**, and
|
|
39
|
+
the two branches are `<template x-if>` rather than `x-show` — only one is ever
|
|
40
|
+
in the DOM, so the form can never submit two `profile[birthday]` fields.
|
|
41
|
+
|
|
42
|
+
The three integer columns are unchanged; the UI joins them for entry and
|
|
43
|
+
`ProfilesController#update` splits them again.
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
|
|
48
|
+
- **`/profile` gains the Newsletter row.** Lifted from turf-monster's `/account`
|
|
49
|
+
card, which has run this flow in production, and stripped of everything
|
|
50
|
+
turf-specific on the way: its 25-seed on-chain welcome bonus, its quest state,
|
|
51
|
+
its seeds level-up payload. What the engine takes is the part every app needs.
|
|
52
|
+
|
|
53
|
+
New routes: `POST /profile/newsletter` (`profile_newsletter_path`) joins,
|
|
54
|
+
`DELETE` on the same path leaves.
|
|
55
|
+
|
|
56
|
+
**TWO TIMESTAMPS, NOT A BOOLEAN.** `joined_email_list_at` and
|
|
57
|
+
`left_email_list_at`, matching turf, because the pair carries three states a
|
|
58
|
+
flag cannot: never asked (both nil), subscribed (joined after left, *including
|
|
59
|
+
a rejoin where both are set*), and unsubscribed. `Studio::Newsletter` holds the
|
|
60
|
+
rules — `subscribed?`, `ever_joined?`, `needs_email?` — pure and duck-typed
|
|
61
|
+
like `Studio::OauthIdentity`.
|
|
62
|
+
|
|
63
|
+
`ever_joined?` is deliberately a different question from `subscribed?`: leaving
|
|
64
|
+
stamps a date and never clears the join, so a consumer paying a once-ever
|
|
65
|
+
welcome bonus cannot have it re-earned by cycling.
|
|
66
|
+
|
|
67
|
+
**ASYMMETRIC ON PURPOSE.** Joining is one click; leaving asks for confirmation
|
|
68
|
+
in a modal. Joining is reversible from the same card, so a confirm step would
|
|
69
|
+
be friction protecting nothing — a mis-click on leave is silent until the next
|
|
70
|
+
send that never arrives. An account with **no address on file** (a wallet-only
|
|
71
|
+
sign-in) is asked for one in a modal rather than allowed to submit and fail;
|
|
72
|
+
the address is written but **not** marked verified, because typing an address
|
|
73
|
+
is not the same as holding it.
|
|
74
|
+
|
|
75
|
+
Gated on `requires:` like every other row, so a host without the columns gets
|
|
76
|
+
silence rather than a 500. The columns ship consumer-first under
|
|
77
|
+
*Roll Out Standard Profile Columns*.
|
|
78
|
+
|
|
79
|
+
### Fixed
|
|
80
|
+
|
|
81
|
+
- **A page-scoped modal host rendered outside an Alpine scope was inert, and
|
|
82
|
+
`/profile/edit` was in exactly that state.** `studio/modals/_scoped_host`
|
|
83
|
+
declares no `x-data` of its own, and Alpine 3 only initialises trees rooted at
|
|
84
|
+
one — so its outer `<template x-if>` never runs. The store registers, `open()`
|
|
85
|
+
pushes onto the stack, `current()` returns the right modal id, and **no dialog
|
|
86
|
+
reaches the document**. Every symptom points at the modal id or the store;
|
|
87
|
+
none of them is the cause.
|
|
88
|
+
|
|
89
|
+
`/profile/edit` mounts its crop-photo host after the `studioProfileForm` div
|
|
90
|
+
closes, with no scope above it, so the avatar cropper could not open. The
|
|
91
|
+
engine's other live call site (`studio/emails/index.html.erb`) happens to
|
|
92
|
+
render inside `x-data="emailRecipients(...)"`, which is the only reason this
|
|
93
|
+
pattern has worked anywhere.
|
|
94
|
+
|
|
95
|
+
Both pages now wrap the host in `<div x-data>`. Found by the newsletter row's
|
|
96
|
+
first browser spec — the view suite was green on the `@click` attribute
|
|
97
|
+
throughout.
|
|
98
|
+
|
|
99
|
+
### Changed
|
|
100
|
+
|
|
101
|
+
- **The read page mounts a modal host only when a row asks for one.** This is the
|
|
102
|
+
registry's `modals:` key finally doing the job it was documented for — until
|
|
103
|
+
the newsletter row, nothing on `/profile` opened a modal and mounting a host
|
|
104
|
+
would have been furniture for nobody.
|
|
105
|
+
|
|
106
|
+
`modals:` is now **a partial path rather than a boolean**. A host row that
|
|
107
|
+
declares modals keeps its partial in the host's own app, so any convention like
|
|
108
|
+
`"studio/profiles/#{key}_modals"` would resolve to a path that does not exist
|
|
109
|
+
there. It costs one string and works for everyone.
|
|
110
|
+
|
|
111
|
+
The host is **not** the cropper: `/profile` mounts `studio/modals/_scoped_host`
|
|
112
|
+
and never `studio/cropper_assets`, because the avatar is read-only on that page.
|
|
113
|
+
|
|
114
|
+
|
|
7
115
|
### Added
|
|
8
116
|
|
|
9
117
|
- **The link sidebar leads with a Profile link, shipped by the engine.** The
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*! Alpine.js 3.16.1 — VENDORED into studio-engine. Do not edit.
|
|
2
|
+
*
|
|
3
|
+
* Source: https://cdn.jsdelivr.net/npm/alpinejs@3.16.1/dist/cdn.min.js
|
|
4
|
+
*
|
|
5
|
+
* This replaced a FLOATING `3.x.x` CDN load in layouts/studio/_head.html.erb.
|
|
6
|
+
* A floating range meant two CI runs on one SHA could execute different builds,
|
|
7
|
+
* production depended on a third party, and an upgrade arrived with no diff.
|
|
8
|
+
*
|
|
9
|
+
* TO UPGRADE: re-download at a PINNED version, then update this header and the
|
|
10
|
+
* comment in layouts/studio/_head.html.erb. Both, so neither can drift.
|
|
11
|
+
*/
|
|
12
|
+
(()=>{var re=!1,ne=!1,G=[],ie=-1,oe=!1;function qe(t){In(t)}function Ke(){oe=!0}function We(){oe=!1,Je()}function In(t){G.includes(t)||G.push(t),Je()}function Ge(t){let e=G.indexOf(t);e!==-1&&e>ie&&G.splice(e,1)}function Je(){if(!ne&&!re){if(oe)return;re=!0,queueMicrotask(kn)}}function kn(){re=!1,ne=!0;for(let t=0;t<G.length;t++)G[t](),ie=t;G.length=0,ie=-1,ne=!1}var C,M,L,ae,se=!0;function Ye(t){se=!1,t(),se=!0}function Xe(t){C=t.reactive,L=t.release,M=e=>t.effect(e,{scheduler:r=>{se?qe(r):r()}}),ae=t.raw}function ce(t){M=t}function Ze(t){let e=()=>{};return[n=>{let i=M(n);return t._x_effects||(t._x_effects=new Set,t._x_runEffects=()=>{t._x_effects.forEach(o=>o())}),t._x_effects.add(i),e=()=>{i!==void 0&&(t._x_effects.delete(i),L(i))},i},()=>{e()}]}function vt(t,e){let r=!0,n,i,o=M(()=>{let s=t(),a=JSON.stringify(s);if(!r&&(typeof s=="object"||s!==n)){let c=typeof n=="object"?JSON.parse(i):n;queueMicrotask(()=>{e(s,c)})}n=s,i=a,r=!1});return()=>L(o)}async function Qe(t){Ke();try{await t(),await Promise.resolve()}finally{We()}}var tr=[],er=[],rr=[];function nr(t){rr.push(t)}function rt(t,e){typeof e=="function"?(t._x_cleanups||(t._x_cleanups=[]),t._x_cleanups.push(e)):(e=t,er.push(e))}function Ot(t){tr.push(t)}function Ct(t,e,r){t._x_attributeCleanups||(t._x_attributeCleanups={}),t._x_attributeCleanups[e]||(t._x_attributeCleanups[e]=[]),t._x_attributeCleanups[e].push(r)}function le(t,e){t._x_attributeCleanups&&Object.entries(t._x_attributeCleanups).forEach(([r,n])=>{(e===void 0||e.includes(r))&&(n.forEach(i=>i()),delete t._x_attributeCleanups[r])})}function ir(t){for(t._x_effects?.forEach(Ge);t._x_cleanups?.length;)t._x_cleanups.pop()()}var ue=new MutationObserver(me),fe=!1;function ft(){ue.observe(document,{subtree:!0,childList:!0,attributes:!0,attributeOldValue:!0}),fe=!0}function de(){jn(),ue.disconnect(),fe=!1}var ut=[];function jn(){let t=ue.takeRecords();ut.push(()=>t.length>0&&me(t));let e=ut.length;queueMicrotask(()=>{if(ut.length===e)for(;ut.length>0;)ut.shift()()})}function m(t){if(!fe)return t();de();let e=t();return ft(),e}var pe=!1,At=[];function or(){pe=!0}function sr(){pe=!1,me(At),At=[]}function me(t){if(pe){At=At.concat(t);return}let e=[],r=new Set,n=new Map,i=new Map;for(let o=0;o<t.length;o++)if(!t[o].target._x_ignoreMutationObserver&&(t[o].type==="childList"&&(t[o].removedNodes.forEach(s=>{s.nodeType===1&&s._x_marker&&r.add(s)}),t[o].addedNodes.forEach(s=>{if(s.nodeType===1){if(r.has(s)){r.delete(s);return}s._x_marker||e.push(s)}})),t[o].type==="attributes")){let s=t[o].target,a=t[o].attributeName,c=t[o].oldValue,l=()=>{n.has(s)||n.set(s,[]),n.get(s).push({name:a,value:s.getAttribute(a)})},u=()=>{i.has(s)||i.set(s,[]),i.get(s).push(a)};s.hasAttribute(a)&&c===null?l():s.hasAttribute(a)?(u(),l()):u()}i.forEach((o,s)=>{le(s,o)}),n.forEach((o,s)=>{tr.forEach(a=>a(s,o))});for(let o of r)e.some(s=>s.contains(o))||er.forEach(s=>s(o));for(let o of e)o.isConnected&&rr.forEach(s=>s(o));e=null,r=null,n=null,i=null}function Tt(t){return P(F(t))}function N(t,e,r){return t._x_dataStack=[e,...F(r||t)],()=>{t._x_dataStack=t._x_dataStack.filter(n=>n!==e)}}function F(t){return t._x_dataStack?t._x_dataStack:typeof ShadowRoot=="function"&&t instanceof ShadowRoot?F(t.host):t.parentNode?F(t.parentNode):[]}function P(t){return new Proxy({objects:t},$n)}function ar(t,e){return t===null||t===Object.prototype?null:Object.prototype.hasOwnProperty.call(t,e)?t:ar(Object.getPrototypeOf(t),e)}var $n={ownKeys({objects:t}){return Array.from(new Set(t.flatMap(e=>Object.keys(e))))},has({objects:t},e){return e==Symbol.unscopables?!1:t.some(r=>Object.prototype.hasOwnProperty.call(r,e)||Reflect.has(r,e))},get({objects:t},e,r){return e=="toJSON"?Ln:Reflect.get(t.find(n=>Reflect.has(n,e))||{},e,r)},set({objects:t},e,r,n){let i;for(let s of t)if(i=ar(s,e),i)break;i||(i=t[t.length-1]);let o=Object.getOwnPropertyDescriptor(i,e);return o?.set&&o?.get?o.set.call(n,r)||!0:Reflect.set(i,e,r)}};function Ln(){return Reflect.ownKeys(this).reduce((e,r)=>(e[r]=Reflect.get(this,r),e),{})}function nt(t,e=()=>{}){let r=i=>typeof i=="object"&&!Array.isArray(i)&&i!==null,n=(i,o="")=>{Object.entries(Object.getOwnPropertyDescriptors(i)).forEach(([s,{value:a,enumerable:c}])=>{if(c===!1||a===void 0||typeof a=="object"&&a!==null&&a.__v_skip)return;let l=o===""?s:`${o}.${s}`;typeof a=="object"&&a!==null&&a._x_interceptor?i[s]=a.initialize(t,l,s,e):r(a)&&a!==i&&!(a instanceof Element)&&n(a,l)})};return n(t)}function Rt(t,e=()=>{}){let r={initialValue:void 0,_x_interceptor:!0,initialize(n,i,o,s){return t(this.initialValue,()=>Fn(n,i),a=>he(n,i,a),i,o,s)}};return e(r),n=>{if(typeof n=="object"&&n!==null&&n._x_interceptor){let i=r.initialize.bind(r);r.initialize=(o,s,a,c)=>{let l=n.initialize(o,s,a,c);return r.initialValue=l,i(o,s,a,c)}}else r.initialValue=n;return r}}function Fn(t,e){return e.split(".").reduce((r,n)=>r[n],t)}function he(t,e,r){if(typeof e=="string"&&(e=e.split(".")),e.length===1)t[e[0]]=r;else{if(e.length===0)throw error;return t[e[0]]||(t[e[0]]={}),he(t[e[0]],e.slice(1),r)}}var cr={};function x(t,e){cr[t]=e}function V(t,e){let r=Bn(e);return Object.entries(cr).forEach(([n,i])=>{Object.defineProperty(t,`$${n}`,{get(){return i(e,r)},enumerable:!1})}),t}function Bn(t){let[e,r]=_e(t),n={interceptor:Rt,...e};return rt(t,r),n}function lr(t,e,r,...n){try{return r(...n)}catch(i){it(i,t,e)}}function it(...t){return ur(...t)}var ur=zn;function fr(t){ur=t}function zn(t,e,r=void 0){t=Object.assign(t??{message:"No error message given."},{el:e,expression:r}),console.warn(`Alpine Expression Error: ${t.message}
|
|
13
|
+
|
|
14
|
+
${r?'Expression: "'+r+`"
|
|
15
|
+
|
|
16
|
+
`:""}`,e),setTimeout(()=>{throw t},0)}var ot=!0;function Mt(t){let e=ot;ot=!1;let r=t();return ot=e,r}function T(t,e,r={}){let n;return _(t,e)(i=>n=i,r),n}function _(...t){return dr(...t)}var dr=()=>{};function pr(t){dr=t}var mr;function hr(t){mr=t}function _r(t,e){let r={};V(r,t);let n=[r,...F(t)],i=typeof e=="function"?Hn(n,e):Un(n,e,t);return lr.bind(null,t,e,i)}function Hn(t,e){return(r=()=>{},{scope:n={},params:i=[],context:o}={})=>{if(!ot){dt(r,e,P([n,...t]),i);return}let s=e.apply(P([n,...t]),i);dt(r,s)}}var ge={};function Vn(t,e){if(ge[t])return ge[t];let r=Object.getPrototypeOf(async function(){}).constructor,n=/^[\n\s]*if.*\(.*\)/.test(t.trim())||/^(let|const)\s/.test(t.trim())?`(async()=>{ ${t} })()`:t,o=(()=>{try{let s=new r(["__self","scope"],`with (scope) { __self.result = ${n} }; __self.finished = true; return __self.result;`);return Object.defineProperty(s,"name",{value:`[Alpine] ${t}`}),s}catch(s){return it(s,e,t),Promise.resolve()}})();return ge[t]=o,o}function Un(t,e,r){let n=Vn(e,r);return(i=()=>{},{scope:o={},params:s=[],context:a}={})=>{n.result=void 0,n.finished=!1;let c=P([o,...t]);if(typeof n=="function"){let l=n.call(a,n,c).catch(u=>it(u,r,e));n.finished?(dt(i,n.result,c,s,r),n.result=void 0):l.then(u=>{dt(i,u,c,s,r)}).catch(u=>it(u,r,e)).finally(()=>n.result=void 0)}}}function dt(t,e,r,n,i){if(ot&&typeof e=="function"){let o=e.apply(r,n);o instanceof Promise?o.then(s=>dt(t,s,r,n)).catch(s=>it(s,i,e)):t(o)}else typeof e=="object"&&e instanceof Promise?e.then(o=>t(o)):t(e)}function gr(...t){return mr(...t)}function xr(t,e,r={}){let n={};V(n,t);let i=[n,...F(t)],o=P([r.scope??{},...i]),s=r.params??[];if(e.includes("await")){let a=Object.getPrototypeOf(async function(){}).constructor,c=/^[\n\s]*if.*\(.*\)/.test(e.trim())||/^(let|const)\s/.test(e.trim())?`(async()=>{ ${e} })()`:e;return new a(["scope"],`with (scope) { let __result = ${c}; return __result }`).call(r.context,o)}else{let a=/^[\n\s]*if.*\(.*\)/.test(e.trim())||/^(let|const)\s/.test(e.trim())?`(()=>{ ${e} })()`:e,l=new Function(["scope"],`with (scope) { let __result = ${a}; return __result }`).call(r.context,o);return typeof l=="function"&&ot?l.apply(o,s):l}}var be="x-";function O(t=""){return be+t}function yr(t){be=t}var Nt={};function p(t,e){return Nt[t]=e,{before(r){if(!Nt[r]){console.warn(String.raw`Cannot find directive \`${r}\`. \`${t}\` will use the default order of execution`);return}let n=J.indexOf(r);J.splice(n>=0?n:J.indexOf("DEFAULT"),0,t)}}}function br(t){return Object.keys(Nt).includes(t)}function mt(t,e,r){if(e=Array.from(e),t._x_virtualDirectives){let o=Object.entries(t._x_virtualDirectives).map(([a,c])=>({name:a,value:c})),s=we(o);o=o.map(a=>s.find(c=>c.name===a.name)?{name:`x-bind:${a.name}`,value:`"${a.value}"`}:a),e=e.concat(o)}let n={};return e.map(Sr((o,s)=>n[o]=s)).filter(Ar).map(Kn(n,r)).sort(Wn).map(o=>qn(t,o))}function we(t){return Array.from(t).map(Sr()).filter(e=>!Ar(e))}var xe=!1,pt=new Map,wr=Symbol();function Er(t){xe=!0;let e=Symbol();wr=e,pt.set(e,[]);let r=()=>{for(;pt.get(e).length;)pt.get(e).shift()();pt.delete(e)},n=()=>{xe=!1,r()};t(r),n()}function _e(t){let e=[],r=a=>e.push(a),[n,i]=Ze(t);return e.push(i),[{Alpine:B,effect:n,cleanup:r,evaluateLater:_.bind(_,t),evaluate:T.bind(T,t)},()=>e.forEach(a=>a())]}function qn(t,e){let r=()=>{},n=Nt[e.type]||r,[i,o]=_e(t);Ct(t,e.original,o);let s=()=>{t._x_ignore||t._x_ignoreSelf||(n.inline&&n.inline(t,e,i),n=n.bind(n,t,e,i),xe?pt.get(wr).push(n):n())};return s.runCleanups=o,s}var Pt=(t,e)=>({name:r,value:n})=>(r.startsWith(t)&&(r=r.replace(t,e)),{name:r,value:n}),Dt=t=>t;function Sr(t=()=>{}){return({name:e,value:r})=>{let{name:n,value:i}=vr.reduce((o,s)=>s(o),{name:e,value:r});return n!==e&&t(n,e),{name:n,value:i}}}var vr=[];function st(t){vr.push(t)}function Ar({name:t}){return Or().test(t)}var Or=()=>new RegExp(`^${be}([^:^.]+)\\b`);function Kn(t,e){return({name:r,value:n})=>{r===n&&(n="");let i=r.match(Or()),o=r.match(/:([a-zA-Z0-9\-_:]+)/),s=r.match(/\.[^.\]]+(?=[^\]]*$)/g)||[],a=e||t[r]||r;return{type:i?i[1]:null,value:o?o[1]:null,modifiers:s.map(c=>c.replace(".","")),expression:n,original:a}}}var ye="DEFAULT",J=["ignore","ref","id","data","anchor","bind","init","for","model","modelable","transition","show","if",ye,"teleport"];function Wn(t,e){let r=J.indexOf(t.type)===-1?ye:t.type,n=J.indexOf(e.type)===-1?ye:e.type;return J.indexOf(r)-J.indexOf(n)}function Y(t,e,r={},n={}){return t.dispatchEvent(new CustomEvent(e,{detail:r,bubbles:!0,composed:!0,cancelable:!0,...n}))}function D(t,e){if(typeof ShadowRoot=="function"&&t instanceof ShadowRoot){Array.from(t.children).forEach(i=>D(i,e));return}let r=!1;if(e(t,()=>r=!0),r)return;let n=t.firstElementChild;for(;n;)D(n,e,!1),n=n.nextElementSibling}function E(t,...e){console.warn(`Alpine Warning: ${t}`,...e)}var Cr=!1;function Tr(){Cr&&E("Alpine has already been initialized on this page. Calling Alpine.start() more than once can cause problems."),Cr=!0,document.body||E("Unable to initialize. Trying to load Alpine before `<body>` is available. Did you forget to add `defer` in Alpine's `<script>` tag?"),Y(document,"alpine:init"),Y(document,"alpine:initializing"),ft(),nr(e=>S(e,D)),rt(e=>I(e)),Ot((e,r)=>{mt(e,r).forEach(n=>n())});let t=e=>!X(e.parentElement,!0);Array.from(document.querySelectorAll(Nr().join(","))).filter(t).forEach(e=>{S(e)}),Y(document,"alpine:initialized"),setTimeout(()=>{Jn()})}var Ee=[],Rr=[];function Mr(){return Ee.map(t=>t())}function Nr(){return Ee.concat(Rr).map(t=>t())}function It(t){Ee.push(t)}function kt(t){Rr.push(t)}function X(t,e=!1){return A(t,r=>{if((e?Nr():Mr()).some(i=>r.matches(i)))return!0})}function A(t,e){if(t){if(e(t))return t;if(t._x_teleportBack)return A(t._x_teleportBack,e);if(t.parentNode instanceof ShadowRoot)return A(t.parentNode.host,e);if(t.parentElement)return A(t.parentElement,e)}}function Pr(t){return Mr().some(e=>t.matches(e))}var Dr=[];function Ir(t){Dr.push(t)}var Gn=1;function S(t,e=D,r=()=>{}){A(t,n=>n._x_ignore)||Er(()=>{e(t,(n,i)=>{n._x_marker||(r(n,i),Dr.forEach(o=>o(n,i)),mt(n,n.attributes).forEach(o=>o()),n._x_ignore||(n._x_marker=Gn++),n._x_ignore&&i())})})}function I(t,e=D){e(t,r=>{ir(r),le(r),delete r._x_marker})}function Jn(){[["ui","dialog",["[x-dialog], [x-popover]"]],["anchor","anchor",["[x-anchor]"]],["sort","sort",["[x-sort]"]]].forEach(([e,r,n])=>{br(r)||n.some(i=>{if(document.querySelector(i))return E(`found "${i}", but missing ${e} plugin`),!0})})}var Se=[],ve=!1;function at(t=()=>{}){return queueMicrotask(()=>{ve||setTimeout(()=>{jt()})}),new Promise(e=>{Se.push(()=>{t(),e()})})}function jt(){for(ve=!1;Se.length;)Se.shift()()}function kr(){ve=!0}function ht(t,e){return Array.isArray(e)?jr(t,e.join(" ")):typeof e=="object"&&e!==null?Yn(t,e):typeof e=="function"?ht(t,e()):jr(t,e)}function Ae(t){return t.split(/\s/).filter(Boolean)}function jr(t,e){let r=i=>Ae(i).filter(o=>!t.classList.contains(o)).filter(Boolean),n=i=>(t.classList.add(...i),()=>{t.classList.remove(...i)});return e=e===!0?e="":e||"",n(r(e))}function Yn(t,e){let r=Object.entries(e).flatMap(([s,a])=>a?Ae(s):!1).filter(Boolean),n=Object.entries(e).flatMap(([s,a])=>a?!1:Ae(s)).filter(Boolean),i=[],o=[];return n.forEach(s=>{t.classList.contains(s)&&(t.classList.remove(s),o.push(s))}),r.forEach(s=>{t.classList.contains(s)||(t.classList.add(s),i.push(s))}),()=>{o.forEach(s=>t.classList.add(s)),i.forEach(s=>t.classList.remove(s))}}function Z(t,e){return typeof e=="object"&&e!==null?Xn(t,e):Zn(t,e)}function Xn(t,e){let r={};return Object.entries(e).forEach(([n,i])=>{r[n]=t.style[n],n.startsWith("--")||(n=Qn(n)),t.style.setProperty(n,i)}),setTimeout(()=>{t.style.length===0&&t.removeAttribute("style")}),()=>{Z(t,r)}}function Zn(t,e){let r=t.getAttribute("style",e);return t.setAttribute("style",e),()=>{t.setAttribute("style",r||"")}}function Qn(t){return t.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}function _t(t,e=()=>{}){let r=!1;return function(){r?e.apply(this,arguments):(r=!0,t.apply(this,arguments))}}p("transition",(t,{value:e,modifiers:r,expression:n},{evaluate:i})=>{typeof n=="function"&&(n=i(n)),n!==!1&&(!n||typeof n=="boolean"?ei(t,r,e):ti(t,n,e))});function ti(t,e,r){$r(t,ht,""),{enter:i=>{t._x_transition.enter.during=i},"enter-start":i=>{t._x_transition.enter.start=i},"enter-end":i=>{t._x_transition.enter.end=i},leave:i=>{t._x_transition.leave.during=i},"leave-start":i=>{t._x_transition.leave.start=i},"leave-end":i=>{t._x_transition.leave.end=i}}[r](e)}function ei(t,e,r){$r(t,Z);let n=!e.includes("in")&&!e.includes("out")&&!r,i=n||e.includes("in")||["enter"].includes(r),o=n||e.includes("out")||["leave"].includes(r);e.includes("in")&&!n&&(e=e.filter((w,et)=>et<e.indexOf("out"))),e.includes("out")&&!n&&(e=e.filter((w,et)=>et>e.indexOf("out")));let s=!e.includes("opacity")&&!e.includes("scale"),a=s||e.includes("opacity"),c=s||e.includes("scale"),l=a?0:1,u=c?gt(e,"scale",95)/100:1,d=gt(e,"delay",0)/1e3,b=gt(e,"origin","center"),g="opacity, transform",$=gt(e,"duration",150)/1e3,f=gt(e,"duration",75)/1e3,y="cubic-bezier(0.4, 0.0, 0.2, 1)";i&&(t._x_transition.enter.during={transformOrigin:b,transitionDelay:`${d}s`,transitionProperty:g,transitionDuration:`${$}s`,transitionTimingFunction:y},t._x_transition.enter.start={opacity:l,transform:`scale(${u})`},t._x_transition.enter.end={opacity:1,transform:"scale(1)"}),o&&(t._x_transition.leave.during={transformOrigin:b,transitionDelay:`${d}s`,transitionProperty:g,transitionDuration:`${f}s`,transitionTimingFunction:y},t._x_transition.leave.start={opacity:1,transform:"scale(1)"},t._x_transition.leave.end={opacity:l,transform:`scale(${u})`})}function $r(t,e,r={}){t._x_transition||(t._x_transition={enter:{during:r,start:r,end:r},leave:{during:r,start:r,end:r},in(n=()=>{},i=()=>{}){$t(t,e,{during:this.enter.during,start:this.enter.start,end:this.enter.end},n,i)},out(n=()=>{},i=()=>{}){$t(t,e,{during:this.leave.during,start:this.leave.start,end:this.leave.end},n,i)}})}window.Element.prototype._x_toggleAndCascadeWithTransitions=function(t,e,r,n){let i=document.visibilityState==="visible"?requestAnimationFrame:setTimeout,o=()=>i(r);if(e){t._x_transition&&(t._x_transition.enter||t._x_transition.leave)?t._x_transition.enter&&(Object.entries(t._x_transition.enter.during).length||Object.entries(t._x_transition.enter.start).length||Object.entries(t._x_transition.enter.end).length)?t._x_transition.in(r):o():t._x_transition?t._x_transition.in(r):o();return}t._x_hidePromise=t._x_transition?new Promise((s,a)=>{t._x_transition.out(()=>{},()=>s(n)),t._x_transitioning&&t._x_transitioning.beforeCancel(()=>a({isFromCancelledTransition:!0}))}):Promise.resolve(n),queueMicrotask(()=>{let s=Lr(t);s?(s._x_hideChildren||(s._x_hideChildren=[]),s._x_hideChildren.push(t)):i(()=>{let a=c=>{let l=Promise.all([c._x_hidePromise,...(c._x_hideChildren||[]).map(a)]).then(([u])=>u?.());return delete c._x_hidePromise,delete c._x_hideChildren,l};a(t).catch(c=>{if(!c.isFromCancelledTransition)throw c})})})};function Lr(t){let e=t.parentNode;if(e)return e._x_hidePromise?e:Lr(e)}function $t(t,e,{during:r,start:n,end:i}={},o=()=>{},s=()=>{}){if(t._x_transitioning&&t._x_transitioning.cancel(),Object.keys(r).length===0&&Object.keys(n).length===0&&Object.keys(i).length===0){o(),s();return}let a,c,l;ri(t,{start(){a=e(t,n)},during(){c=e(t,r)},before:o,end(){a(),l=e(t,i)},after:s,cleanup(){c(),l()}})}function ri(t,e){let r,n,i,o=_t(()=>{m(()=>{r=!0,n||e.before(),i||(e.end(),jt()),e.after(),t.isConnected&&e.cleanup(),delete t._x_transitioning})});t._x_transitioning={beforeCancels:[],beforeCancel(s){this.beforeCancels.push(s)},cancel:_t(function(){for(;this.beforeCancels.length;)this.beforeCancels.shift()();o()}),finish:o},m(()=>{e.start(),e.during()}),kr(),requestAnimationFrame(()=>{if(r)return;let s=Number(getComputedStyle(t).transitionDuration.replace(/,.*/,"").replace("s",""))*1e3,a=Number(getComputedStyle(t).transitionDelay.replace(/,.*/,"").replace("s",""))*1e3;s===0&&(s=Number(getComputedStyle(t).animationDuration.replace("s",""))*1e3),m(()=>{e.before()}),n=!0,requestAnimationFrame(()=>{r||(m(()=>{e.end()}),jt(),setTimeout(t._x_transitioning.finish,s+a),i=!0)})})}function gt(t,e,r){if(t.indexOf(e)===-1)return r;let n=t[t.indexOf(e)+1];if(!n||e==="scale"&&isNaN(n))return r;if(e==="duration"||e==="delay"){let i=n.match(/([0-9]+)ms/);if(i)return i[1]}return e==="origin"&&["top","right","left","center","bottom"].includes(t[t.indexOf(e)+2])?[n,t[t.indexOf(e)+2]].join(" "):n}var k=!1;function v(t,e=()=>{}){return(...r)=>k?e(...r):t(...r)}function Fr(t){return(...e)=>k&&t(...e)}var Br=[];function U(t){Br.push(t)}function zr(t,e){Br.forEach(r=>r(t,e)),k=!0,Vr(()=>{S(e,(r,n)=>{n(r,()=>{})})}),k=!1}var Lt=!1;function Hr(t,e){e._x_dataStack||(e._x_dataStack=t._x_dataStack),k=!0,Lt=!0,Vr(()=>{ni(e)}),k=!1,Lt=!1}function ni(t){let e=!1;S(t,(n,i)=>{D(n,(o,s)=>{if(e&&Pr(o))return s();e=!0,i(o,s)})})}function Vr(t){let e=M;ce((r,n)=>{let i=e(r);return L(i),()=>{}}),t(),ce(e)}function xt(t,e,r,n=[]){switch(t._x_bindings||(t._x_bindings=C({})),t._x_bindings[e]=r,e=n.includes("camel")?fi(e):e,e){case"value":ii(t,r);break;case"style":si(t,r);break;case"class":oi(t,r);break;case"selected":case"checked":ai(t,e,r);break;default:Oe(t,e,r);break}}function ii(t,e){if(Ft(t))t.attributes.value===void 0&&(t.value=e);else if(bt(t))Number.isInteger(e)?t.value=e:!Array.isArray(e)&&typeof e!="boolean"&&![null,void 0].includes(e)?t.value=String(e):Array.isArray(e)?t.checked=e.some(r=>di(r,t.value)):t.checked=!!e;else if(t.tagName==="SELECT")ui(t,e);else if(t.tagName==="OPTION")Oe(t,"value",e);else{if(t.value===e&&(typeof e!="object"||e===null))return;t.value=e===void 0?"":e}}function oi(t,e){t._x_undoAddedClasses&&t._x_undoAddedClasses(),t._x_undoAddedClasses=ht(t,e)}function si(t,e){t._x_undoAddedStyles&&t._x_undoAddedStyles(),t._x_undoAddedStyles=Z(t,e)}function ai(t,e,r){Oe(t,e,r),li(t,e,r)}function Oe(t,e,r){[null,void 0,!1].includes(r)&&mi(e)?t.removeAttribute(e):(Ur(e)&&(r=e),hi(r)&&(r=JSON.stringify(r)),ci(t,e,r))}function ci(t,e,r){t.getAttribute(e)!=r&&t.setAttribute(e,r)}function li(t,e,r){t[e]!==r&&(t[e]=r)}function ui(t,e){let r=[].concat(e).map(n=>n+"");Array.from(t.options).forEach(n=>{n.selected=r.includes(n.value)})}function fi(t){return t.toLowerCase().replace(/-(\w)/g,(e,r)=>r.toUpperCase())}function di(t,e){return t==e}function yt(t){return[1,"1","true","on","yes",!0].includes(t)?!0:[0,"0","false","off","no",!1].includes(t)?!1:t?Boolean(t):null}var pi=new Set(["allowfullscreen","async","autofocus","autoplay","checked","controls","default","defer","disabled","formnovalidate","inert","ismap","itemscope","loop","multiple","muted","nomodule","novalidate","open","playsinline","readonly","required","reversed","selected","shadowrootclonable","shadowrootdelegatesfocus","shadowrootserializable"]);function Ur(t){return pi.has(t)}function mi(t){return!["aria-pressed","aria-checked","aria-expanded","aria-selected"].includes(t)}function hi(t){return typeof t=="object"&&t!==null}function qr(t,e,r){return t._x_bindings&&t._x_bindings[e]!==void 0?t._x_bindings[e]:Wr(t,e,r)}function Kr(t,e,r,n=!0){if(t._x_bindings&&t._x_bindings[e]!==void 0)return t._x_bindings[e];if(t._x_inlineBindings&&t._x_inlineBindings[e]!==void 0){let i=t._x_inlineBindings[e];return i.extract=n,Mt(()=>T(t,i.expression))}return Wr(t,e,r)}function Wr(t,e,r){let n=t.getAttribute(e);return n===null?typeof r=="function"?r():r:n===""?!0:Ur(e)?!![e,"true"].includes(n):n}function bt(t){return t.type==="checkbox"||t.localName==="ui-checkbox"||t.localName==="ui-switch"}function Ft(t){return t.type==="radio"||t.localName==="ui-radio"}function Bt(t,e){let r;return function(){let n=this,i=arguments,o=function(){r=null,t.apply(n,i)};clearTimeout(r),r=setTimeout(o,e)}}function zt(t,e){let r;return function(){let n=this,i=arguments;r||(t.apply(n,i),r=!0,setTimeout(()=>r=!1,e))}}function Ht({get:t,set:e},{get:r,set:n}){let i=!0,o,s,a=M(()=>{let c=t(),l=r();if(i)n(Ce(c)),i=!1;else{let u=JSON.stringify(c),d=JSON.stringify(l);u!==o?n(Ce(c)):u!==d&&e(Ce(l))}o=JSON.stringify(t()),s=JSON.stringify(r())});return()=>{L(a)}}function Ce(t){return typeof t=="object"?JSON.parse(JSON.stringify(t)):t}function Gr(t){(Array.isArray(t)?t:[t]).forEach(r=>r(B))}var z={},Jr=!1;function Yr(t,e){if(Jr||(z=C(z),Jr=!0),e===void 0)return z[t];z[t]=e,typeof e=="object"&&e!==null&&e._x_interceptor?z[t]=e.initialize(z,t,t,()=>{}):nt(z[t]),typeof e=="object"&&e!==null&&e.hasOwnProperty("init")&&typeof e.init=="function"&&z[t].init()}function Xr(){return z}var Zr={};function Qr(t,e){let r=typeof e!="function"?()=>e:e;return t instanceof Element?Te(t,r()):(Zr[t]=r,()=>{})}function tn(t){return Object.entries(Zr).forEach(([e,r])=>{Object.defineProperty(t,e,{get(){return(...n)=>r(...n)}})}),t}function Te(t,e,r){let n=[];for(;n.length;)n.pop()();let i=Object.entries(e).map(([s,a])=>({name:s,value:a})),o=we(i);return i=i.map(s=>o.find(a=>a.name===s.name)?{name:`x-bind:${s.name}`,value:`"${s.value}"`}:s),mt(t,i,r).map(s=>{n.push(s.runCleanups),s()}),()=>{for(;n.length;)n.pop()()}}var en={};function rn(t,e){en[t]=e}function nn(t,e){return Object.entries(en).forEach(([r,n])=>{Object.defineProperty(t,r,{get(){return(...i)=>n.bind(e)(...i)},enumerable:!1})}),t}var _i={get reactive(){return C},get release(){return L},get effect(){return M},get raw(){return ae},get transaction(){return Qe},version:"3.16.1",flushAndStopDeferringMutations:sr,dontAutoEvaluateFunctions:Mt,disableEffectScheduling:Ye,startObservingMutations:ft,stopObservingMutations:de,setReactivityEngine:Xe,onAttributeRemoved:Ct,onAttributesAdded:Ot,closestDataStack:F,skipDuringClone:v,onlyDuringClone:Fr,addRootSelector:It,addInitSelector:kt,setErrorHandler:fr,interceptClone:U,addScopeToNode:N,deferMutations:or,mapAttributes:st,evaluateLater:_,interceptInit:Ir,initInterceptors:nt,injectMagics:V,setEvaluator:pr,setRawEvaluator:hr,mergeProxies:P,extractProp:Kr,findClosest:A,onElRemoved:rt,closestRoot:X,destroyTree:I,interceptor:Rt,transition:$t,setStyles:Z,mutateDom:m,directive:p,entangle:Ht,throttle:zt,debounce:Bt,evaluate:T,evaluateRaw:gr,initTree:S,nextTick:at,prefixed:O,prefix:yr,plugin:Gr,magic:x,store:Yr,start:Tr,clone:Hr,cloneNode:zr,bound:qr,$data:Tt,watch:vt,walk:D,data:rn,bind:Qr},B=_i;function Re(t,e){let r=Object.create(null),n=t.split(",");for(let i=0;i<n.length;i++)r[n[i]]=!0;return e?i=>!!r[i.toLowerCase()]:i=>!!r[i]}var gi="itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly";var Gs=Re(gi+",async,autofocus,autoplay,controls,default,defer,disabled,hidden,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected");var on=Object.freeze({}),Js=Object.freeze([]);var xi=Object.prototype.hasOwnProperty,wt=(t,e)=>xi.call(t,e),q=Array.isArray,ct=t=>sn(t)==="[object Map]";var yi=t=>typeof t=="string",Vt=t=>typeof t=="symbol",Et=t=>t!==null&&typeof t=="object";var bi=Object.prototype.toString,sn=t=>bi.call(t),Me=t=>sn(t).slice(8,-1);var Ut=t=>yi(t)&&t!=="NaN"&&t[0]!=="-"&&""+parseInt(t,10)===t;var qt=t=>{let e=Object.create(null);return r=>e[r]||(e[r]=t(r))},wi=/-(\w)/g,Ys=qt(t=>t.replace(wi,(e,r)=>r?r.toUpperCase():"")),Ei=/\B([A-Z])/g,Xs=qt(t=>t.replace(Ei,"-$1").toLowerCase()),Ne=qt(t=>t.charAt(0).toUpperCase()+t.slice(1)),Zs=qt(t=>t?`on${Ne(t)}`:""),Pe=(t,e)=>t!==e&&(t===t||e===e);var De=new WeakMap,St=[],j,Q=Symbol("iterate"),Ie=Symbol("Map key iterate");function Si(t){return t&&t._isEffect===!0}function dn(t,e=on){Si(t)&&(t=t.raw);let r=Ai(t,e);return e.lazy||r(),r}function pn(t){t.active&&(mn(t),t.options.onStop&&t.options.onStop(),t.active=!1)}var vi=0;function Ai(t,e){let r=function(){if(!r.active)return t();if(!St.includes(r)){mn(r);try{return Ci(),St.push(r),j=r,t()}finally{St.pop(),hn(),j=St[St.length-1]}}};return r.id=vi++,r.allowRecurse=!!e.allowRecurse,r._isEffect=!0,r.active=!0,r.raw=t,r.deps=[],r.options=e,r}function mn(t){let{deps:e}=t;if(e.length){for(let r=0;r<e.length;r++)e[r].delete(t);e.length=0}}var lt=!0,je=[];function Oi(){je.push(lt),lt=!1}function Ci(){je.push(lt),lt=!0}function hn(){let t=je.pop();lt=t===void 0?!0:t}function R(t,e,r){if(!lt||j===void 0)return;let n=De.get(t);n||De.set(t,n=new Map);let i=n.get(r);i||n.set(r,i=new Set),i.has(j)||(i.add(j),j.deps.push(i),j.options.onTrack&&j.options.onTrack({effect:j,target:t,type:e,key:r}))}function W(t,e,r,n,i,o){let s=De.get(t);if(!s)return;let a=new Set,c=u=>{u&&u.forEach(d=>{(d!==j||d.allowRecurse)&&a.add(d)})};if(e==="clear")s.forEach(c);else if(r==="length"&&q(t))s.forEach((u,d)=>{(d==="length"||d>=n)&&c(u)});else switch(r!==void 0&&c(s.get(r)),e){case"add":q(t)?Ut(r)&&c(s.get("length")):(c(s.get(Q)),ct(t)&&c(s.get(Ie)));break;case"delete":q(t)||(c(s.get(Q)),ct(t)&&c(s.get(Ie)));break;case"set":ct(t)&&c(s.get(Q));break}let l=u=>{u.options.onTrigger&&u.options.onTrigger({effect:u,target:t,key:r,type:e,newValue:n,oldValue:i,oldTarget:o}),u.options.scheduler?u.options.scheduler(u):u()};a.forEach(l)}var Ti=Re("__proto__,__v_isRef,__isVue"),_n=new Set(Object.getOwnPropertyNames(Symbol).map(t=>Symbol[t]).filter(Vt)),Ri=gn();var Mi=gn(!0);var an=Ni();function Ni(){let t={};return["includes","indexOf","lastIndexOf"].forEach(e=>{t[e]=function(...r){let n=h(this);for(let o=0,s=this.length;o<s;o++)R(n,"get",o+"");let i=n[e](...r);return i===-1||i===!1?n[e](...r.map(h)):i}}),["push","pop","shift","unshift","splice"].forEach(e=>{t[e]=function(...r){Oi();let n=h(this)[e].apply(this,r);return hn(),n}}),t}function gn(t=!1,e=!1){return function(n,i,o){if(i==="__v_isReactive")return!t;if(i==="__v_isReadonly")return t;if(i==="__v_raw"&&o===(t?e?Wi:wn:e?Ki:bn).get(n))return n;let s=q(n);if(!t&&s&&wt(an,i))return Reflect.get(an,i,o);let a=Reflect.get(n,i,o);return(Vt(i)?_n.has(i):Ti(i))||(t||R(n,"get",i),e)?a:ke(a)?!s||!Ut(i)?a.value:a:Et(a)?t?En(a):Zt(a):a}}var Pi=Di();function Di(t=!1){return function(r,n,i,o){let s=r[n];if(!t&&(i=h(i),s=h(s),!q(r)&&ke(s)&&!ke(i)))return s.value=i,!0;let a=q(r)&&Ut(n)?Number(n)<r.length:wt(r,n),c=Reflect.set(r,n,i,o);return r===h(o)&&(a?Pe(i,s)&&W(r,"set",n,i,s):W(r,"add",n,i)),c}}function Ii(t,e){let r=wt(t,e),n=t[e],i=Reflect.deleteProperty(t,e);return i&&r&&W(t,"delete",e,void 0,n),i}function ki(t,e){let r=Reflect.has(t,e);return(!Vt(e)||!_n.has(e))&&R(t,"has",e),r}function ji(t){return R(t,"iterate",q(t)?"length":Q),Reflect.ownKeys(t)}var $i={get:Ri,set:Pi,deleteProperty:Ii,has:ki,ownKeys:ji},Li={get:Mi,set(t,e){return console.warn(`Set operation on key "${String(e)}" failed: target is readonly.`,t),!0},deleteProperty(t,e){return console.warn(`Delete operation on key "${String(e)}" failed: target is readonly.`,t),!0}};var $e=t=>Et(t)?Zt(t):t,Le=t=>Et(t)?En(t):t,Fe=t=>t,Xt=t=>Reflect.getPrototypeOf(t);function Kt(t,e,r=!1,n=!1){t=t.__v_raw;let i=h(t),o=h(e);e!==o&&!r&&R(i,"get",e),!r&&R(i,"get",o);let{has:s}=Xt(i),a=n?Fe:r?Le:$e;if(s.call(i,e))return a(t.get(e));if(s.call(i,o))return a(t.get(o));t!==i&&t.get(e)}function Wt(t,e=!1){let r=this.__v_raw,n=h(r),i=h(t);return t!==i&&!e&&R(n,"has",t),!e&&R(n,"has",i),t===i?r.has(t):r.has(t)||r.has(i)}function Gt(t,e=!1){return t=t.__v_raw,!e&&R(h(t),"iterate",Q),Reflect.get(t,"size",t)}function cn(t){t=h(t);let e=h(this);return Xt(e).has.call(e,t)||(e.add(t),W(e,"add",t,t)),this}function ln(t,e){e=h(e);let r=h(this),{has:n,get:i}=Xt(r),o=n.call(r,t);o?yn(r,n,t):(t=h(t),o=n.call(r,t));let s=i.call(r,t);return r.set(t,e),o?Pe(e,s)&&W(r,"set",t,e,s):W(r,"add",t,e),this}function un(t){let e=h(this),{has:r,get:n}=Xt(e),i=r.call(e,t);i?yn(e,r,t):(t=h(t),i=r.call(e,t));let o=n?n.call(e,t):void 0,s=e.delete(t);return i&&W(e,"delete",t,void 0,o),s}function fn(){let t=h(this),e=t.size!==0,r=ct(t)?new Map(t):new Set(t),n=t.clear();return e&&W(t,"clear",void 0,void 0,r),n}function Jt(t,e){return function(n,i){let o=this,s=o.__v_raw,a=h(s),c=e?Fe:t?Le:$e;return!t&&R(a,"iterate",Q),s.forEach((l,u)=>n.call(i,c(l),c(u),o))}}function Yt(t,e,r){return function(...n){let i=this.__v_raw,o=h(i),s=ct(o),a=t==="entries"||t===Symbol.iterator&&s,c=t==="keys"&&s,l=i[t](...n),u=r?Fe:e?Le:$e;return!e&&R(o,"iterate",c?Ie:Q),{next(){let{value:d,done:b}=l.next();return b?{value:d,done:b}:{value:a?[u(d[0]),u(d[1])]:u(d),done:b}},[Symbol.iterator](){return this}}}}function K(t){return function(...e){{let r=e[0]?`on key "${e[0]}" `:"";console.warn(`${Ne(t)} operation ${r}failed: target is readonly.`,h(this))}return t==="delete"?!1:this}}function Fi(){let t={get(o){return Kt(this,o)},get size(){return Gt(this)},has:Wt,add:cn,set:ln,delete:un,clear:fn,forEach:Jt(!1,!1)},e={get(o){return Kt(this,o,!1,!0)},get size(){return Gt(this)},has:Wt,add:cn,set:ln,delete:un,clear:fn,forEach:Jt(!1,!0)},r={get(o){return Kt(this,o,!0)},get size(){return Gt(this,!0)},has(o){return Wt.call(this,o,!0)},add:K("add"),set:K("set"),delete:K("delete"),clear:K("clear"),forEach:Jt(!0,!1)},n={get(o){return Kt(this,o,!0,!0)},get size(){return Gt(this,!0)},has(o){return Wt.call(this,o,!0)},add:K("add"),set:K("set"),delete:K("delete"),clear:K("clear"),forEach:Jt(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach(o=>{t[o]=Yt(o,!1,!1),r[o]=Yt(o,!0,!1),e[o]=Yt(o,!1,!0),n[o]=Yt(o,!0,!0)}),[t,r,e,n]}var[Bi,zi,Hi,Vi]=Fi();function xn(t,e){let r=e?t?Vi:Hi:t?zi:Bi;return(n,i,o)=>i==="__v_isReactive"?!t:i==="__v_isReadonly"?t:i==="__v_raw"?n:Reflect.get(wt(r,i)&&i in n?r:n,i,o)}var Ui={get:xn(!1,!1)};var qi={get:xn(!0,!1)};function yn(t,e,r){let n=h(r);if(n!==r&&e.call(t,n)){let i=Me(t);console.warn(`Reactive ${i} contains both the raw and reactive versions of the same object${i==="Map"?" as keys":""}, which can lead to inconsistencies. Avoid differentiating between the raw and reactive versions of an object and only use the reactive version if possible.`)}}var bn=new WeakMap,Ki=new WeakMap,wn=new WeakMap,Wi=new WeakMap;function Gi(t){switch(t){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function Ji(t){return t.__v_skip||!Object.isExtensible(t)?0:Gi(Me(t))}function Zt(t){return t&&t.__v_isReadonly?t:Sn(t,!1,$i,Ui,bn)}function En(t){return Sn(t,!0,Li,qi,wn)}function Sn(t,e,r,n,i){if(!Et(t))return console.warn(`value cannot be made reactive: ${String(t)}`),t;if(t.__v_raw&&!(e&&t.__v_isReactive))return t;let o=i.get(t);if(o)return o;let s=Ji(t);if(s===0)return t;let a=new Proxy(t,s===2?n:r);return i.set(t,a),a}function h(t){return t&&h(t.__v_raw)||t}function ke(t){return Boolean(t&&t.__v_isRef===!0)}x("nextTick",()=>at);x("dispatch",t=>Y.bind(Y,t));x("watch",(t,{evaluateLater:e,cleanup:r})=>(n,i)=>{let o=e(n),a=vt(()=>{let c;return o(l=>c=l),c},i);r(a)});x("store",Xr);x("data",t=>Tt(t));x("root",t=>X(t));x("refs",t=>(t._x_refs_proxy||(t._x_refs_proxy=P(Yi(t))),t._x_refs_proxy));function Yi(t){let e=[];return A(t,r=>{r._x_refs&&e.push(r._x_refs)}),e}var Be={};function ze(t){return Be[t]||(Be[t]=0),++Be[t]}function vn(t,e){return A(t,r=>{if(r._x_ids&&r._x_ids[e])return!0})}function An(t,e){t._x_ids||(t._x_ids={}),t._x_ids[e]||(t._x_ids[e]=ze(e))}x("id",(t,{cleanup:e})=>(r,n=null)=>{let i=`${r}${n?`-${n}`:""}`;return Xi(t,i,e,()=>{let o=vn(t,r),s=o?o._x_ids[r]:ze(r);return n?`${r}-${s}-${n}`:`${r}-${s}`})});U((t,e)=>{t._x_id&&(e._x_id=t._x_id)});function Xi(t,e,r,n){if(t._x_id||(t._x_id={}),t._x_id[e])return t._x_id[e];let i=n();return t._x_id[e]=i,r(()=>{delete t._x_id[e]}),i}x("el",t=>t);On("Focus","focus","focus");On("Persist","persist","persist");function On(t,e,r){x(e,n=>E(`You can't use [$${e}] without first installing the "${t}" plugin here: https://alpinejs.dev/plugins/${r}`,n))}p("modelable",(t,{expression:e},{effect:r,evaluateLater:n,cleanup:i})=>{let o=n(e),s=()=>{let u;return o(d=>u=d),u},a=n(`${e} = __placeholder`),c=u=>a(()=>{},{scope:{__placeholder:u}}),l=s();c(l),queueMicrotask(()=>{if(!t._x_model)return;t._x_removeModelListeners.default();let u=t._x_model.get,d=t._x_model.setWithModifiers,b=Ht({get(){return u()},set(g){d(g)}},{get(){return s()},set(g){c(g)}});i(b)})});p("teleport",(t,{modifiers:e,expression:r},{cleanup:n})=>{t.tagName.toLowerCase()!=="template"&&E("x-teleport can only be used on a <template> tag",t);let i=Cn(r),o=t.content.cloneNode(!0).firstElementChild;t._x_teleport=o,o._x_teleportBack=t,t.setAttribute("data-teleport-template",!0),o.setAttribute("data-teleport-target",!0),t._x_forwardEvents&&t._x_forwardEvents.forEach(a=>{o.addEventListener(a,c=>{c.stopPropagation(),t.dispatchEvent(new c.constructor(c.type,c))})}),N(o,{},t);let s=(a,c,l)=>{l.includes("prepend")?c.parentNode.insertBefore(a,c):l.includes("append")?c.parentNode.insertBefore(a,c.nextSibling):c.appendChild(a)};m(()=>{v(()=>{s(o,i,e),S(o)})()}),t._x_teleportPutBack=()=>{let a=Cn(r);m(()=>{s(t._x_teleport,a,e)})},n(()=>m(()=>{o.remove(),I(o)}))});var Zi=document.createElement("div");function Cn(t){let e=v(()=>document.querySelector(t),()=>Zi)();return e||E(`Cannot find x-teleport element for selector: "${t}"`),e}var Tn=()=>{};Tn.inline=(t,{modifiers:e},{cleanup:r})=>{e.includes("self")?t._x_ignoreSelf=!0:t._x_ignore=!0,r(()=>{e.includes("self")?delete t._x_ignoreSelf:delete t._x_ignore})};p("ignore",Tn);p("effect",v((t,{expression:e},{effect:r})=>{r(_(t,e))}));function H(t,e,r,n){let i=t,o=c=>n(c),s={},a=(c,l)=>u=>l(c,u);return r.includes("dot")&&(e=Qi(e)),r.includes("camel")&&(e=to(e)),r.includes("capture")&&(s.capture=!0),r.includes("window")&&(i=window),r.includes("document")&&(i=document),r.includes("passive")&&(s.passive=r[r.indexOf("passive")+1]!=="false"),o=He(r,o),r.includes("prevent")&&(o=a(o,(c,l)=>{l.preventDefault(),c(l)})),r.includes("stop")&&(o=a(o,(c,l)=>{l.stopPropagation(),c(l)})),r.includes("once")&&(o=a(o,(c,l)=>{c(l),i.removeEventListener(e,o,s)})),(r.includes("away")||r.includes("outside"))&&(i=document,o=a(o,(c,l)=>{t.contains(l.target)||l.target.isConnected!==!1&&(t.offsetWidth<1&&t.offsetHeight<1||t._x_isShown!==!1&&c(l))})),r.includes("self")&&(o=a(o,(c,l)=>{l.target===t&&c(l)})),e==="submit"&&(o=a(o,(c,l)=>{l.target._x_pendingModelUpdates&&l.target._x_pendingModelUpdates.forEach(u=>u()),c(l)})),(ro(e)||Mn(e))&&(o=a(o,(c,l)=>{no(l,r)||c(l)})),i.addEventListener(e,o,s),()=>{i.removeEventListener(e,o,s)}}function He(t,e){if(t.includes("debounce")){let r=t[t.indexOf("debounce")+1]||"invalid-wait",n=Qt(r.split("ms")[0])?Number(r.split("ms")[0]):250;e=Bt(e,n)}if(t.includes("throttle")){let r=t[t.indexOf("throttle")+1]||"invalid-wait",n=Qt(r.split("ms")[0])?Number(r.split("ms")[0]):250;e=zt(e,n)}return e}function Qi(t){return t.replace(/-/g,".")}function to(t){return t.toLowerCase().replace(/-(\w)/g,(e,r)=>r.toUpperCase())}function Qt(t){return!Array.isArray(t)&&!isNaN(t)}function eo(t){return[" ","_"].includes(t)?t:t.replace(/([a-z])([A-Z])/g,"$1-$2").replace(/[_\s]/,"-").toLowerCase()}function ro(t){return["keydown","keyup"].includes(t)}function Mn(t){return["contextmenu","click","mouse"].some(e=>t.includes(e))}function no(t,e){let r=e.filter(o=>!["window","document","prevent","stop","once","capture","self","away","outside","passive","preserve-scroll","blur","change","lazy"].includes(o));if(r.includes("debounce")){let o=r.indexOf("debounce");r.splice(o,Qt((r[o+1]||"invalid-wait").split("ms")[0])?2:1)}if(r.includes("throttle")){let o=r.indexOf("throttle");r.splice(o,Qt((r[o+1]||"invalid-wait").split("ms")[0])?2:1)}if(r.length===0||r.length===1&&Rn(t.key).includes(r[0]))return!1;let i=["ctrl","shift","alt","meta","cmd","super"].filter(o=>r.includes(o));return r=r.filter(o=>!i.includes(o)),!(i.length>0&&i.filter(s=>((s==="cmd"||s==="super")&&(s="meta"),t[`${s}Key`])).length===i.length&&(Mn(t.type)||Rn(t.key).includes(r[0])))}function Rn(t){if(!t)return[];t=eo(t);let e={ctrl:"control",slash:"/",space:" ",spacebar:" ",cmd:"meta",esc:"escape",up:"arrow-up",down:"arrow-down",left:"arrow-left",right:"arrow-right",period:".",comma:",",equal:"=",minus:"-",underscore:"_"};return e[t]=t,Object.keys(e).map(r=>{if(e[r]===t)return r}).filter(r=>r)}p("model",(t,{modifiers:e,expression:r},{effect:n,cleanup:i})=>{let o=t;e.includes("parent")&&(o=A(t,f=>f!==t));let s=_(o,r),a;typeof r=="string"?a=_(o,`${r} = __placeholder`):typeof r=="function"&&typeof r()=="string"?a=_(o,`${r()} = __placeholder`):a=()=>{};let c=()=>{let f;return s(y=>f=y),Nn(f)?f.get():f},l=f=>{let y;s(w=>y=w),Nn(y)?y.set(f):a(()=>{},{scope:{__placeholder:f}})};typeof r=="string"&&t.type==="radio"&&m(()=>{t.hasAttribute("name")||t.setAttribute("name",r)});let u=e.includes("change")||e.includes("lazy"),d=e.includes("blur"),b=e.includes("enter"),g=u||d||b,$;if(k)$=()=>{};else if(g){let f=[],y=w=>l(te(t,e,w,c()));if(u&&f.push(H(t,"change",e,y)),d&&(f.push(H(t,"blur",e,y)),t.form)){let w=t.form,et=()=>y({target:t});w._x_pendingModelUpdates||(w._x_pendingModelUpdates=[]),w._x_pendingModelUpdates.push(et),i(()=>{w._x_pendingModelUpdates&&w._x_pendingModelUpdates.splice(w._x_pendingModelUpdates.indexOf(et),1)})}b&&f.push(H(t,"keydown",e,w=>{w.key==="Enter"&&y(w)})),$=()=>f.forEach(w=>w())}else{let f=t.tagName.toLowerCase()==="select"||["checkbox","radio"].includes(t.type)?"change":"input";$=H(t,f,e,y=>{l(te(t,e,y,c()))})}if(e.includes("fill")&&([void 0,null,""].includes(c())||bt(t)&&Array.isArray(c())||t.tagName.toLowerCase()==="select"&&t.multiple)&&l(te(t,e,{target:t},c())),t._x_removeModelListeners||(t._x_removeModelListeners={}),t._x_removeModelListeners.default=$,i(()=>t._x_removeModelListeners.default()),t.form){let f=H(t.form,"reset",[],y=>{at(()=>t._x_model&&t._x_model.set(te(t,e,{target:t},c())))});i(()=>f())}if(t._x_model={get(){return c()},set(f){l(f)},setWithModifiers:He(e,l)},t._x_forceModelUpdate=f=>{f===void 0&&typeof r=="string"&&r.match(/\./)&&(f=""),m(()=>{bt(t)?Array.isArray(f)?t.checked=f.some(y=>y==t.value):t.checked=!!f:Ft(t)?typeof f=="boolean"?t.checked=yt(t.value)===f:t.checked=t.value==f:xt(t,"value",f)})},t.tagName==="SELECT"){let f=new MutationObserver(()=>{t._x_forceModelUpdate(c())});f.observe(t,{childList:!0}),i(()=>f.disconnect())}n(()=>{let f=c();e.includes("unintrusive")&&document.activeElement.isSameNode(t)||t._x_forceModelUpdate(f)})});function te(t,e,r,n){return m(()=>{if(r instanceof CustomEvent&&r.detail!==void 0)return r.detail!==null&&r.detail!==void 0?r.detail:r.target.value;if(bt(t))if(Array.isArray(n)){let i=null;return e.includes("number")?i=Ve(r.target.value):e.includes("boolean")?i=yt(r.target.value):i=r.target.value,r.target.checked?n.includes(i)?n:n.concat([i]):n.filter(o=>!io(o,i))}else return r.target.checked;else{if(t.tagName.toLowerCase()==="select"&&t.multiple)return e.includes("number")?Array.from(r.target.selectedOptions).map(i=>{let o=i.value||i.text;return Ve(o)}):e.includes("boolean")?Array.from(r.target.selectedOptions).map(i=>{let o=i.value||i.text;return yt(o)}):Array.from(r.target.selectedOptions).map(i=>i.value||i.text);{let i;return Ft(t)?r.target.checked?i=r.target.value:i=n:i=r.target.value,e.includes("number")?Ve(i):e.includes("boolean")?yt(i):e.includes("trim")?i.trim():i}}})}function Ve(t){let e=t?parseFloat(t):null;return oo(e)?e:t}function io(t,e){return t==e}function oo(t){return!Array.isArray(t)&&!isNaN(t)}function Nn(t){return t!==null&&typeof t=="object"&&typeof t.get=="function"&&typeof t.set=="function"}p("cloak",t=>queueMicrotask(()=>m(()=>t.removeAttribute(O("cloak")))));kt(()=>`[${O("init")}]`);p("init",v((t,{expression:e},{evaluate:r})=>typeof e=="string"?!!e.trim()&&r(e,{},!1):r(e,{},!1)));p("text",(t,{expression:e},{effect:r,evaluateLater:n})=>{let i=n(e);r(()=>{i(o=>{m(()=>{t.textContent=o})})})});p("html",(t,{expression:e},{effect:r,evaluateLater:n})=>{let i=n(e);r(()=>{i(o=>{m(()=>{t.innerHTML=o??"",t._x_ignoreSelf=!0,S(t),delete t._x_ignoreSelf})})})});st(Pt(":",Dt(O("bind:"))));var Pn=(t,{value:e,modifiers:r,expression:n,original:i},{effect:o,cleanup:s})=>{if(!e){let c={};tn(c),_(t,n)(u=>{Te(t,u,i)},{scope:c});return}if(e==="key")return so(t,n);if(t._x_inlineBindings&&t._x_inlineBindings[e]&&t._x_inlineBindings[e].extract)return;let a=_(t,n);o(()=>a(c=>{c===void 0&&typeof n=="string"&&n.match(/\./)&&(c=""),m(()=>xt(t,e,c,r))})),s(()=>{t._x_undoAddedClasses&&t._x_undoAddedClasses(),t._x_undoAddedStyles&&t._x_undoAddedStyles()})};Pn.inline=(t,{value:e,modifiers:r,expression:n})=>{e&&(t._x_inlineBindings||(t._x_inlineBindings={}),t._x_inlineBindings[e]={expression:n,extract:!1})};p("bind",Pn);function so(t,e){t._x_keyExpression=e}It(()=>`[${O("data")}]`);var tt=Symbol();p("data",(t,{expression:e},{cleanup:r})=>{if(co(t))return;let n=t[tt];if(n?.expression===e)return;e=e===""?"{}":e;let i={};V(i,t);let o={};nn(o,i);let s=T(t,e,{scope:o});(s===void 0||s===!0)&&(s={}),V(s,t);let a;if(n?.reactiveData){a=n.reactiveData,ao(a,s);let l={expression:e};t[tt]=l,queueMicrotask(()=>{t[tt]===l&&delete t[tt]})}else a=C(s);nt(a,r);let c=N(t,a);a.init&&T(t,a.init),r(()=>{a.destroy&&T(t,a.destroy),c();let l={reactiveData:a};t[tt]=l,queueMicrotask(()=>{t[tt]===l&&delete t[tt]})})});function ao(t,e){Object.keys(e).forEach(r=>{let n=Object.getOwnPropertyDescriptor(e,r),i=Object.getOwnPropertyDescriptor(t,r);n.get||n.set||i?.get||i?.set?(i&&delete t[r],i||(t[r]=void 0),n.get||n.set?Object.defineProperty(t,r,n):t[r]=e[r]):t[r]=e[r]}),Object.keys(t).filter(r=>!Object.prototype.hasOwnProperty.call(e,r)).forEach(r=>delete t[r])}U((t,e)=>{t._x_dataStack&&(e._x_dataStack=t._x_dataStack,e.setAttribute("data-has-alpine-state",!0))});function co(t){return k?Lt?!0:t.hasAttribute("data-has-alpine-state"):!1}p("show",(t,{modifiers:e,expression:r},{effect:n})=>{let i=_(t,r);t._x_doHide||(t._x_doHide=()=>{m(()=>{t.style.setProperty("display","none",e.includes("important")?"important":void 0)})}),t._x_doShow||(t._x_doShow=()=>{m(()=>{t.style.length===1&&t.style.display==="none"?t.removeAttribute("style"):t.style.removeProperty("display")})});let o=()=>{t._x_doHide(),t._x_isShown=!1},s=()=>{t._x_doShow(),t._x_isShown=!0},a=()=>setTimeout(s),c=_t(d=>d?s():o(),d=>{typeof t._x_toggleAndCascadeWithTransitions=="function"?t._x_toggleAndCascadeWithTransitions(t,d,s,o):d?a():o()}),l,u=!0;n(()=>i(d=>{!u&&d===l||(e.includes("immediate")&&(d?a():o()),c(d),l=d,u=!1)}))});p("for",v((t,{expression:e},{effect:r,cleanup:n})=>{let i=fo(e),o=_(t,i.items),s=_(t,t._x_keyExpression||"index");t._x_lookup=new Map,r(()=>uo(t,i,o,s)),n(()=>{t._x_lookup.forEach(a=>m(()=>{I(a),a.remove()})),delete t._x_lookup,delete t._x_lastRenderedEl})}));function lo(t){return e=>{Object.entries(e).forEach(([r,n])=>{t[r]=n})}}function uo(t,e,r,n){r(i=>{mo(i)&&(i=Array.from({length:i},(l,u)=>u+1)),i==null&&(i=[]),i instanceof Set&&(i=Array.from(i)),i instanceof Map&&(i=Array.from(i));let o=t._x_lookup,s=new Map;t._x_lookup=s;let a=ho(i),c=Object.entries(i).map(([l,u])=>{a||(l=parseInt(l));let d=po(e,u,l,i),b;return n(g=>{typeof g=="object"&&E("x-for key cannot be an object, it must be a string or an integer",t),o.has(g)&&(s.set(g,o.get(g)),o.delete(g)),b=g},{scope:{index:l,...d}}),[b,d]});m(()=>{o.forEach(d=>{I(d),d.remove()});let l=new Set,u=t;c.forEach(([d,b])=>{if(s.has(d)){let f=s.get(d);f._x_refreshXForScope(b),u.nextElementSibling!==f&&(u.nextElementSibling&&f.replaceWith(u.nextElementSibling),u.after(f)),u=f,f._x_currentIfEl&&(f.nextElementSibling!==f._x_currentIfEl&&u.after(f._x_currentIfEl),u=f._x_currentIfEl);return}t.content.children.length>1&&E("x-for templates require a single root element, additional elements will be ignored.",t);let g=document.importNode(t.content,!0).firstElementChild,$=C(b);N(g,$,t),g._x_refreshXForScope=lo($),s.set(d,g),l.add(g),u.after(g),u=g}),l.forEach(d=>S(d)),u!==t?t._x_lastRenderedEl=u:delete t._x_lastRenderedEl})})}function fo(t){let e=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,r=/^\s*\(|\)\s*$/g,n=/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/,i=t.match(n);if(!i)return;let o={};o.items=i[2].trim();let s=i[1].replace(r,"").trim(),a=s.match(e);return a?(o.item=s.replace(e,"").trim(),o.index=a[1].trim(),a[2]&&(o.collection=a[2].trim())):o.item=s,o}function po(t,e,r,n){let i={};return/^\[.*\]$/.test(t.item)&&Array.isArray(e)?t.item.replace("[","").replace("]","").split(",").map(s=>s.trim()).forEach((s,a)=>{i[s]=e[a]}):/^\{.*\}$/.test(t.item)&&!Array.isArray(e)&&typeof e=="object"?t.item.replace("{","").replace("}","").split(",").map(s=>s.trim()).forEach(s=>{i[s]=e[s]}):i[t.item]=e,t.index&&(i[t.index]=r),t.collection&&(i[t.collection]=n),i}function mo(t){return typeof t!="object"&&!isNaN(t)}function ho(t){return typeof t=="object"&&!Array.isArray(t)}function Dn(){}Dn.inline=(t,{expression:e},{cleanup:r})=>{let n=X(t);n&&(n._x_refs||(n._x_refs={}),n._x_refs[e]=t,r(()=>delete n._x_refs[e]))};p("ref",Dn);p("if",v((t,{expression:e},{effect:r,cleanup:n})=>{t.tagName.toLowerCase()!=="template"&&E("x-if can only be used on a <template> tag",t);let i=_(t,e),o=()=>{if(t._x_currentIfEl)return t._x_currentIfEl;let a=t.content.cloneNode(!0).firstElementChild;return N(a,{},t),m(()=>{t.after(a),S(a)}),t._x_currentIfEl=a,t._x_lastRenderedEl=a,t._x_undoIf=()=>{m(()=>{I(a),a.remove()}),delete t._x_currentIfEl,delete t._x_lastRenderedEl},a},s=()=>{t._x_undoIf&&(t._x_undoIf(),delete t._x_undoIf)};r(()=>i(a=>{a?o():s()})),n(()=>t._x_undoIf&&t._x_undoIf())}));p("id",(t,{expression:e},{evaluate:r})=>{r(e).forEach(i=>An(t,i))});U((t,e)=>{t._x_ids&&(e._x_ids=t._x_ids)});st(Pt("@",Dt(O("on:"))));p("on",v((t,{value:e,modifiers:r,expression:n},{cleanup:i})=>{let o=n?_(t,n):()=>{};t.tagName.toLowerCase()==="template"&&(t._x_forwardEvents||(t._x_forwardEvents=[]),t._x_forwardEvents.includes(e)||t._x_forwardEvents.push(e));let s=H(t,e,r,a=>{o(()=>{},{scope:{$event:a},params:[a]})});i(()=>s())}));ee("Collapse","collapse","collapse");ee("Intersect","intersect","intersect");ee("Focus","trap","focus");ee("Mask","mask","mask");function ee(t,e,r){p(e,n=>E(`You can't use [x-${e}] without first installing the "${t}" plugin here: https://alpinejs.dev/plugins/${r}`,n))}B.setEvaluator(_r);B.setRawEvaluator(xr);B.setReactivityEngine({reactive:Zt,effect:dn,release:pn,raw:h});var Ue=B;window.Alpine=Ue;queueMicrotask(()=>{Ue.start()});})();
|
|
@@ -142,6 +142,59 @@ module Studio
|
|
|
142
142
|
end
|
|
143
143
|
end
|
|
144
144
|
|
|
145
|
+
# POST /profile/newsletter — join the mailing list.
|
|
146
|
+
#
|
|
147
|
+
# DIRECT, no confirmation. Joining is reversible in one click from the same
|
|
148
|
+
# card, so a confirm step would be friction protecting nothing. LEAVING is the
|
|
149
|
+
# one that asks, because a mis-click there is silent until the next send that
|
|
150
|
+
# never arrives.
|
|
151
|
+
#
|
|
152
|
+
# An account with no address on file supplies one here — a wallet-only sign-in
|
|
153
|
+
# has no email, and a newsletter needs somewhere to send. It is written as the
|
|
154
|
+
# account email but NOT marked verified: this proves the person can type an
|
|
155
|
+
# address, not that they hold it, and treating it as verified would turn a
|
|
156
|
+
# mailing-list form into an account-recovery path.
|
|
157
|
+
def subscribe_newsletter
|
|
158
|
+
return unsupported("newsletter") unless row_rendered?(:newsletter)
|
|
159
|
+
|
|
160
|
+
if Studio::Newsletter.needs_email?(current_user)
|
|
161
|
+
value = params.dig(:profile, :email).to_s.strip
|
|
162
|
+
unless value.match?(URI::MailTo::EMAIL_REGEXP)
|
|
163
|
+
return redirect_to profile_path, status: :see_other,
|
|
164
|
+
alert: "Enter an email address to subscribe."
|
|
165
|
+
end
|
|
166
|
+
current_user.email = value
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
rescue_and_log(target: current_user) do
|
|
170
|
+
# left_email_list_at is CLEARED rather than left in place. `subscribed?`
|
|
171
|
+
# compares the two dates, so a stale leave date in the future of the join
|
|
172
|
+
# would read as unsubscribed the moment the clock disagreed.
|
|
173
|
+
current_user.update!(joined_email_list_at: Time.current, left_email_list_at: nil)
|
|
174
|
+
redirect_to profile_path, notice: "You're on the list."
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# DELETE /profile/newsletter — leave it.
|
|
179
|
+
#
|
|
180
|
+
# STAMPS A DATE, never clears the join. "Have they ever joined" is a different
|
|
181
|
+
# question from "are they on the list", and a consumer that pays a once-ever
|
|
182
|
+
# welcome bonus (turf-monster does, on-chain) needs the first one to survive
|
|
183
|
+
# every leave and rejoin. Clearing joined_email_list_at here would let someone
|
|
184
|
+
# re-earn it by cycling.
|
|
185
|
+
def unsubscribe_newsletter
|
|
186
|
+
return unsupported("newsletter") unless row_rendered?(:newsletter)
|
|
187
|
+
|
|
188
|
+
unless Studio::Newsletter.subscribed?(current_user)
|
|
189
|
+
return redirect_to profile_path, alert: "You're not subscribed.", status: :see_other
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
rescue_and_log(target: current_user) do
|
|
193
|
+
current_user.update!(left_email_list_at: Time.current)
|
|
194
|
+
redirect_to profile_path, notice: "You've been unsubscribed."
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
145
198
|
private
|
|
146
199
|
|
|
147
200
|
# Would the page render this row for this viewer?
|
|
@@ -21,7 +21,26 @@
|
|
|
21
21
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
22
22
|
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
<%# Alpine is VENDORED into the engine (studio/alpine.js) and shipped through the
|
|
25
|
+
asset pipeline — no CDN, CSP-safe (same-origin :self), mirroring canvas_confetti
|
|
26
|
+
and sortable below. PINNED AT 3.16.1.
|
|
27
|
+
|
|
28
|
+
WHAT THIS REPLACED, and why it is worth the 47KB in the repo: the tag here was
|
|
29
|
+
|
|
30
|
+
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js">
|
|
31
|
+
|
|
32
|
+
— a FLOATING major range, fetched from a third party at page load, for the
|
|
33
|
+
library every chip, drawer, modal and board filter in the fleet depends on.
|
|
34
|
+
Three consequences, none of them visible in a diff: two CI runs on ONE SHA could
|
|
35
|
+
execute different Alpine builds; production interactivity depended on jsDelivr
|
|
36
|
+
being reachable and honest; and an upgrade arrived with no review, because
|
|
37
|
+
nothing changed in the repo when it did. Bumping is now a deliberate act —
|
|
38
|
+
replace the file, change the version in this comment, and the diff shows it.
|
|
39
|
+
|
|
40
|
+
Investigated as a suspect in the board-filter flake (three PRs reddened in one
|
|
41
|
+
day, 2026-08-15). This removes a real source of run-to-run variance; it does NOT
|
|
42
|
+
claim to be that flake's cause, and the remaining suspect there is untouched. %>
|
|
43
|
+
<%= javascript_include_tag "studio/alpine", defer: true, "data-turbo-track": "reload" %>
|
|
25
44
|
<%# canvas-confetti is VENDORED into the engine (studio/canvas_confetti.js) and
|
|
26
45
|
shipped through the asset pipeline — no CDN, CSP-safe (same-origin :self),
|
|
27
46
|
zero-per-app dependency. Defines the global `confetti`; studio_confetti.js
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<%# Birthday — ONE date
|
|
1
|
+
<%# Birthday — ONE date over THREE integer columns, entered through a calendar.
|
|
2
2
|
|
|
3
3
|
Locals: user (required).
|
|
4
4
|
|
|
@@ -9,23 +9,221 @@
|
|
|
9
9
|
(needs month and day, and no year at all). A single date column answers the
|
|
10
10
|
second one badly.
|
|
11
11
|
|
|
12
|
-
So the UI joins them and ProfilesController#update splits them again.
|
|
13
|
-
|
|
14
|
-
idea to the person entering it, and the browser already knows how to enter
|
|
15
|
-
one on every platform.
|
|
12
|
+
So the UI joins them and ProfilesController#update splits them again. The row
|
|
13
|
+
renders only when the host has all three columns, so nothing here re-checks.
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
TWO INPUTS, ONE NAME, AND ONLY EVER ONE IN THE DOM. `<template x-if>` is what
|
|
16
|
+
makes that true rather than a claim: the branch Alpine does not take is never
|
|
17
|
+
instantiated, so the form can never carry two `profile[birthday]` fields and
|
|
18
|
+
the server can never receive the wrong one. Toggling with x-show would leave
|
|
19
|
+
BOTH present and submit the hidden one's value too — the last duplicate wins
|
|
20
|
+
in Rack's params, which is precisely the bug this shape avoids.
|
|
21
|
+
|
|
22
|
+
no JS — the native `<input type="date">`. It is not a downgrade; it is the
|
|
23
|
+
control every platform already knows how to render, and the reason
|
|
24
|
+
a JS-less page can still set a birthday at all.
|
|
25
|
+
JS — the calendar below. `alpine` comes from the enclosing
|
|
26
|
+
studioProfileForm and is true only once that component has booted.
|
|
27
|
+
|
|
28
|
+
The operator asked for a calendar rather than an open field (2026-08-15).
|
|
19
29
|
%>
|
|
30
|
+
<label class="block text-sm text-secondary mb-2 font-medium" for="profile_birthday">Date of birth</label>
|
|
31
|
+
|
|
20
32
|
<%
|
|
21
33
|
y = user.birth_year
|
|
22
34
|
m = user.birth_month
|
|
23
35
|
d = user.birth_day
|
|
24
36
|
value = (y.present? && m.present? && d.present?) ? format("%04d-%02d-%02d", y, m, d) : nil
|
|
25
37
|
%>
|
|
26
|
-
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
38
|
+
|
|
39
|
+
<div x-data="studioBirthdayPicker('<%= value %>')">
|
|
40
|
+
<%# --- the JS-less path ------------------------------------------------- %>
|
|
41
|
+
<template x-if="!alpine">
|
|
42
|
+
<input type="date" name="profile[birthday]" id="profile_birthday"
|
|
43
|
+
value="<%= value %>" class="input-field"
|
|
44
|
+
autocomplete="bday" max="<%= Date.current.iso8601 %>">
|
|
45
|
+
</template>
|
|
46
|
+
|
|
47
|
+
<%# --- the calendar ------------------------------------------------------ %>
|
|
48
|
+
<template x-if="alpine">
|
|
49
|
+
<div>
|
|
50
|
+
<%# The value the form actually submits. The calendar writes here; nothing
|
|
51
|
+
types into it. %>
|
|
52
|
+
<input type="hidden" name="profile[birthday]" :value="value">
|
|
53
|
+
|
|
54
|
+
<button type="button" x-ref="trigger" @click="toggle()"
|
|
55
|
+
@keydown.escape="open = false"
|
|
56
|
+
:aria-expanded="open ? 'true' : 'false'"
|
|
57
|
+
aria-haspopup="dialog"
|
|
58
|
+
class="input-field w-full text-left flex items-center justify-between gap-2">
|
|
59
|
+
<span :class="displayValue ? 'text-heading' : 'text-muted'"
|
|
60
|
+
x-text="displayValue || 'Select your date of birth'"></span>
|
|
61
|
+
<svg class="w-4 h-4 text-muted flex-shrink-0" fill="none" stroke="currentColor"
|
|
62
|
+
stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true">
|
|
63
|
+
<path stroke-linecap="round" stroke-linejoin="round"
|
|
64
|
+
d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5"/>
|
|
65
|
+
</svg>
|
|
66
|
+
</button>
|
|
67
|
+
|
|
68
|
+
<div x-show="open" x-cloak
|
|
69
|
+
@click.outside="open = false"
|
|
70
|
+
@keydown.escape.window="open = false"
|
|
71
|
+
@scroll.window="place()" @resize.window="place()"
|
|
72
|
+
role="dialog" aria-label="Choose your date of birth"
|
|
73
|
+
class="studio-birthday-popover"
|
|
74
|
+
:style="'top:' + top + 'px; left:' + left + 'px; min-width:' + width + 'px;'">
|
|
75
|
+
|
|
76
|
+
<%# Month and year JUMP rather than step. Stepping from today to 1985 is
|
|
77
|
+
about four hundred clicks, which is the whole reason this is not the
|
|
78
|
+
contest picker. %>
|
|
79
|
+
<div class="studio-birthday-nav">
|
|
80
|
+
<select x-model.number="viewMonth" class="input-field studio-birthday-month"
|
|
81
|
+
aria-label="Month">
|
|
82
|
+
<template x-for="(name, i) in months" :key="name">
|
|
83
|
+
<option :value="i" x-text="name"></option>
|
|
84
|
+
</template>
|
|
85
|
+
</select>
|
|
86
|
+
<select x-model.number="viewYear" class="input-field studio-birthday-year"
|
|
87
|
+
aria-label="Year">
|
|
88
|
+
<template x-for="y in years" :key="y">
|
|
89
|
+
<option :value="y" x-text="y"></option>
|
|
90
|
+
</template>
|
|
91
|
+
</select>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<div class="studio-birthday-grid studio-birthday-weekdays">
|
|
95
|
+
<template x-for="(wd, i) in weekdays" :key="i">
|
|
96
|
+
<div x-text="wd"></div>
|
|
97
|
+
</template>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<div class="studio-birthday-grid">
|
|
101
|
+
<template x-for="(cell, i) in calDays()" :key="i">
|
|
102
|
+
<div>
|
|
103
|
+
<template x-if="cell">
|
|
104
|
+
<button type="button" @click="pick(cell)" :disabled="isFuture(cell)"
|
|
105
|
+
:class="isSelected(cell) && 'is-selected'"
|
|
106
|
+
class="studio-birthday-day"
|
|
107
|
+
x-text="cell"></button>
|
|
108
|
+
</template>
|
|
109
|
+
</div>
|
|
110
|
+
</template>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<%# A birthday already set is the only case where clearing is meaningful,
|
|
114
|
+
and without this the calendar is a one-way door — every day cell sets
|
|
115
|
+
a value and none of them unset one. %>
|
|
116
|
+
<div class="mt-3 flex justify-end" x-show="value">
|
|
117
|
+
<button type="button" @click="clear()"
|
|
118
|
+
class="text-xs text-secondary hover:text-heading transition">
|
|
119
|
+
Clear
|
|
120
|
+
</button>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
</template>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
31
127
|
<p class="text-muted text-xs mt-2">Stored as day, month and year — we use it for birthdays and age checks.</p>
|
|
128
|
+
|
|
129
|
+
<style>
|
|
130
|
+
/* EVERY RULE BELOW IS OWNED CSS, NOT TAILWIND UTILITIES, and that is not a
|
|
131
|
+
style preference — it is the bug the operator reported.
|
|
132
|
+
|
|
133
|
+
The engine ships a PREBUILT bundle to consumers. A Tailwind utility exists in
|
|
134
|
+
a consuming app only if that app's OWN views already emitted it, because its
|
|
135
|
+
build scans its own source, not the gem's. This calendar first shipped using
|
|
136
|
+
`grid grid-cols-7`, and `grid-cols-7` is rare enough that NO consumer had
|
|
137
|
+
ever emitted it: measured in mcritchie-studio's compiled bundle, zero
|
|
138
|
+
occurrences. With no grid, the seven weekday letters stacked into a single
|
|
139
|
+
vertical column and the popover grew to the height of the page.
|
|
140
|
+
`hover:bg-surface-alt` was missing for the same reason.
|
|
141
|
+
|
|
142
|
+
The same note is on studio/profiles/_identity_styles for the same reason.
|
|
143
|
+
|
|
144
|
+
AND THE BROWSER LANE COULD NOT SEE IT. e2e/tailwind_input.css carries
|
|
145
|
+
`@source "../app/views"`, so the lane compiles the engine's OWN views and
|
|
146
|
+
emits grid-cols-7 — every spec passed against a page no consumer renders.
|
|
147
|
+
That blindness is recorded in docs/E2E_LANE.md; the fix here is to stop
|
|
148
|
+
depending on the utility at all. */
|
|
149
|
+
.studio-birthday-nav {
|
|
150
|
+
display: flex;
|
|
151
|
+
align-items: center;
|
|
152
|
+
gap: 0.5rem;
|
|
153
|
+
margin-bottom: 0.75rem;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.studio-birthday-month { flex: 1 1 auto; }
|
|
157
|
+
|
|
158
|
+
.studio-birthday-month,
|
|
159
|
+
.studio-birthday-year {
|
|
160
|
+
font-size: 0.875rem;
|
|
161
|
+
padding-top: 0.25rem;
|
|
162
|
+
padding-bottom: 0.25rem;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/* THE ONE THAT BROKE. Seven columns, owned outright. */
|
|
166
|
+
.studio-birthday-grid {
|
|
167
|
+
display: grid;
|
|
168
|
+
grid-template-columns: repeat(7, minmax(0, 1fr));
|
|
169
|
+
text-align: center;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.studio-birthday-weekdays {
|
|
173
|
+
margin-bottom: 0.25rem;
|
|
174
|
+
font-size: 0.75rem;
|
|
175
|
+
font-weight: 500;
|
|
176
|
+
color: var(--color-text-muted, #9ca3af);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.studio-birthday-weekdays > div { padding: 0.25rem 0; }
|
|
180
|
+
|
|
181
|
+
.studio-birthday-day {
|
|
182
|
+
width: 2rem;
|
|
183
|
+
height: 2rem;
|
|
184
|
+
border-radius: 9999px;
|
|
185
|
+
font-size: 0.875rem;
|
|
186
|
+
color: var(--color-text-body, inherit);
|
|
187
|
+
transition: background-color 150ms ease, color 150ms ease;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.studio-birthday-day:hover:not(:disabled) {
|
|
191
|
+
background: var(--color-surface-alt, rgba(127, 127, 127, 0.15));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.studio-birthday-day:disabled {
|
|
195
|
+
opacity: 0.4;
|
|
196
|
+
cursor: not-allowed;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.studio-birthday-day.is-selected {
|
|
200
|
+
background: var(--color-primary);
|
|
201
|
+
color: #fff;
|
|
202
|
+
font-weight: 700;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* FIXED, not absolute, for TWO reasons — and the second is the one a spec can
|
|
206
|
+
actually catch.
|
|
207
|
+
|
|
208
|
+
1. Clipping. The edit page's rows sit inside `card p-0 overflow-hidden`. An
|
|
209
|
+
absolutely-positioned popover only escapes that clip while NO ancestor is
|
|
210
|
+
positioned; the day a consumer's card grows a `position: relative` it is
|
|
211
|
+
clipped out of sight, with perfectly correct markup.
|
|
212
|
+
2. Anchoring. place() writes VIEWPORT coordinates from the trigger's rect.
|
|
213
|
+
Fixed keeps them meaningful as the page scrolls; absolute reinterprets
|
|
214
|
+
them as document coordinates and the popover drifts by the scroll offset.
|
|
215
|
+
|
|
216
|
+
At scroll 0 the two are indistinguishable, which is why the spec that proves
|
|
217
|
+
this scrolls first. */
|
|
218
|
+
.studio-birthday-popover {
|
|
219
|
+
position: fixed;
|
|
220
|
+
z-index: 40;
|
|
221
|
+
background: var(--color-surface);
|
|
222
|
+
border: 1px solid var(--color-border-subtle);
|
|
223
|
+
border-radius: 0.75rem;
|
|
224
|
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.25);
|
|
225
|
+
padding: 0.75rem;
|
|
226
|
+
}
|
|
227
|
+
</style>
|
|
228
|
+
|
|
229
|
+
<%= render "studio/profiles/birthday_picker_script" %>
|