@@ -21,7 +21,9 @@ const Toast = ({
2121 links,
2222} ) => {
2323 const visualSettings = useVisualSettings ( ) ;
24- const isTerracotta = visualSettings ?. fezcodexTheme === 'terracotta' ;
24+ const theme = visualSettings ?. fezcodexTheme ;
25+ const isTerracotta = theme === 'terracotta' ;
26+ const isLuxe = theme === 'luxe' ;
2527
2628 useEffect ( ( ) => {
2729 const timer = setTimeout ( ( ) => {
@@ -200,7 +202,160 @@ const Toast = ({
200202 }
201203
202204 /* ============================================================
203- * DEFAULT TOAST (brutalist / luxe / retained legacy styling)
205+ * LUXE TOAST — refined cream card with bronze rule + serif title
206+ * ============================================================ */
207+ if ( isLuxe ) {
208+ const luxeAccent = ( ( ) => {
209+ switch ( type ) {
210+ case 'error' :
211+ return '#7A2020' ;
212+ case 'gold' :
213+ return '#B88532' ;
214+ case 'techno' :
215+ return '#355E3B' ;
216+ default :
217+ return '#8D4004' ;
218+ }
219+ } ) ( ) ;
220+
221+ const luxeIcon = ( ( ) => {
222+ if ( icon ) return icon ;
223+ const common = { weight : 'duotone' , style : { color : luxeAccent } } ;
224+ switch ( type ) {
225+ case 'error' :
226+ return < WarningCircleIcon { ...common } /> ;
227+ case 'gold' :
228+ return < TrophyIcon { ...common } /> ;
229+ case 'techno' :
230+ return < TerminalIcon { ...common } /> ;
231+ default :
232+ return < CheckCircleIcon { ...common } /> ;
233+ }
234+ } ) ( ) ;
235+
236+ const luxeKicker = ( ( ) => {
237+ switch ( type ) {
238+ case 'error' :
239+ return 'Alert' ;
240+ case 'gold' :
241+ return 'Accolade' ;
242+ case 'techno' :
243+ return 'System' ;
244+ default :
245+ return 'Notice' ;
246+ }
247+ } ) ( ) ;
248+
249+ return (
250+ < motion . div
251+ layout
252+ initial = { { y : - 20 , opacity : 0 } }
253+ animate = { { y : 0 , opacity : 1 } }
254+ exit = { { y : - 20 , opacity : 0 } }
255+ transition = { { type : 'spring' , stiffness : 260 , damping : 26 } }
256+ className = "relative w-80 md:w-[380px] bg-[#FAFAF8] border border-[#1A1A1A]/10 shadow-[0_24px_48px_-24px_rgba(26,26,26,0.28)] rounded-sm overflow-hidden mb-4 group"
257+ >
258+ { /* top hairline accent */ }
259+ < span
260+ aria-hidden = "true"
261+ className = "absolute top-0 left-0 right-0 h-[2px]"
262+ style = { { backgroundColor : luxeAccent , opacity : 0.55 } }
263+ />
264+ { /* bottom timer */ }
265+ < motion . div
266+ initial = { { width : '100%' } }
267+ animate = { { width : 0 } }
268+ transition = { { duration : duration / 1000 , ease : 'linear' } }
269+ className = "absolute bottom-0 left-0 h-[1px] z-20"
270+ style = { { backgroundColor : luxeAccent , opacity : 0.55 } }
271+ />
272+
273+ < div className = "px-6 py-5 flex gap-4 items-start" >
274+ < div
275+ className = "flex-shrink-0 mt-0.5 text-[22px] w-9 h-9 flex items-center justify-center rounded-full"
276+ style = { { backgroundColor : `${ luxeAccent } 12` } }
277+ >
278+ { luxeIcon }
279+ </ div >
280+
281+ < div className = "flex-grow min-w-0 space-y-1.5" >
282+ < div
283+ className = "font-outfit text-[9.5px] tracking-[0.24em] uppercase"
284+ style = { { color : luxeAccent } }
285+ >
286+ { luxeKicker }
287+ </ div >
288+ < h4 className = "font-playfairDisplay text-[19px] italic leading-tight text-[#1A1A1A]" >
289+ { title }
290+ </ h4 >
291+ < p className = "font-outfit text-[12.5px] leading-[1.55] text-[#1A1A1A]/70" >
292+ { message }
293+ </ p >
294+
295+ { links && links . length > 0 && (
296+ < div className = "flex flex-wrap gap-2 pt-2.5" >
297+ { links . map ( ( link , index ) => {
298+ const btnClass =
299+ 'font-outfit text-[10px] tracking-[0.18em] uppercase px-3 py-1.5 border border-[#1A1A1A]/15 text-[#1A1A1A] hover:bg-[#1A1A1A] hover:text-[#FAFAF8] hover:border-[#1A1A1A] transition-colors rounded-sm' ;
300+ if ( link . to )
301+ return (
302+ < Link
303+ key = { index }
304+ to = { link . to }
305+ className = { btnClass }
306+ onClick = { ( ) => removeToast ( id ) }
307+ >
308+ { link . label }
309+ </ Link >
310+ ) ;
311+ if ( link . href )
312+ return (
313+ < a
314+ key = { index }
315+ href = { link . href }
316+ target = "_blank"
317+ rel = "noopener noreferrer"
318+ className = { btnClass }
319+ onClick = { ( ) => removeToast ( id ) }
320+ >
321+ { link . label }
322+ </ a >
323+ ) ;
324+ if ( link . onClick )
325+ return (
326+ < button
327+ type = "button"
328+ key = { index }
329+ onClick = { ( ) => {
330+ link . onClick ( ) ;
331+ removeToast ( id ) ;
332+ } }
333+ className = { btnClass }
334+ >
335+ { link . label }
336+ </ button >
337+ ) ;
338+ return null ;
339+ } ) }
340+ </ div >
341+ ) }
342+ </ div >
343+
344+ < button
345+ type = "button"
346+ onClick = { ( ) => removeToast ( id ) }
347+ className = "flex-shrink-0 text-[#1A1A1A]/30 hover:text-[#1A1A1A] transition-colors p-1"
348+ aria-label = "Dismiss"
349+ >
350+ < XIcon size = { 14 } weight = "bold" />
351+ </ button >
352+ </ div >
353+ </ motion . div >
354+ ) ;
355+ }
356+
357+ /* ============================================================
358+ * DEFAULT TOAST — brutalist dark card (legacy)
204359 * ============================================================ */
205360
206361 const getIcon = ( ) => {
0 commit comments