Compare commits

..

2 commits

2 changed files with 27 additions and 7 deletions

View file

@ -201,7 +201,7 @@ const cardStyle = computed(() => {
'transparent'
return {
transform: `translate(${deltaX.value}px, ${deltaY.value}px) scale(0.35)`,
transform: `translate(${deltaX.value}px, ${deltaY.value - 80}px) scale(0.55)`,
borderRadius: '50%',
background: aura,
transition: 'border-radius 150ms ease, background 150ms ease',
@ -230,6 +230,7 @@ const cardStyle = computed(() => {
display: flex;
justify-content: center;
align-items: flex-start;
overflow: visible; /* ball must escape the collapsed stack bounds */
}
.card-stack.bucket-mode .card-shadow {
@ -269,6 +270,10 @@ const cardStyle = computed(() => {
}
.card-wrapper.is-held {
cursor: grabbing;
/* Override bucket-mode clip and opacity so the held ball renders cleanly */
clip-path: none !important;
opacity: 1 !important;
pointer-events: auto !important;
}
/* Dismissal animations dismiss class is only applied during the motion.rich await window,

View file

@ -1,7 +1,7 @@
<template>
<div class="label-view">
<!-- Header bar -->
<header class="lv-header">
<header class="lv-header" :class="{ 'is-held': isHeld }">
<span class="queue-count">
<span v-if="loading" class="queue-status">Loading</span>
<template v-else-if="store.totalRemaining > 0">
@ -54,7 +54,7 @@
></div>
</Transition>
<div class="card-stack-wrapper">
<div class="card-stack-wrapper" :class="{ 'is-held': isHeld }">
<EmailCardStack
:item="store.current"
:is-bucket-mode="isHeld"
@ -314,7 +314,8 @@ onUnmounted(() => {
padding: 1rem;
max-width: 640px;
margin: 0 auto;
min-height: 100dvh;
height: 100dvh; /* hard cap — prevents grid from drifting below fold */
overflow: hidden;
}
.queue-status {
@ -328,6 +329,11 @@ onUnmounted(() => {
justify-content: space-between;
gap: 0.75rem;
flex-wrap: wrap;
transition: opacity 200ms ease;
}
.lv-header.is-held {
opacity: 0.2;
pointer-events: none;
}
.queue-count {
@ -418,24 +424,33 @@ onUnmounted(() => {
.card-stack-wrapper {
flex: 1;
/* Give bottom breathing room so grid doesn't overlap content */
min-height: 0; /* allow flex child to shrink — default auto prevents this */
overflow-y: auto;
padding-bottom: 0.5rem;
transition: opacity 200ms ease;
}
/* When held: escape the overflow clip so the ball floats freely,
and rise above the footer (z-index 10) so the ball is visible. */
.card-stack-wrapper.is-held {
overflow: visible;
position: relative;
z-index: 20;
}
/* Bucket grid stays pinned to the bottom of the viewport while the email card
can be scrolled freely. "hired" (10th button) may clip on very small screens
that is intentional per design. */
.bucket-grid-footer {
position: sticky;
bottom: 0;
background: var(--color-bg, var(--color-surface, #f0f4fc));
padding: 0.5rem 0 0.75rem;
z-index: 10;
transition: transform 250ms cubic-bezier(0.34, 1.56, 0.64, 1),
opacity 200ms ease,
background 200ms ease;
}
.bucket-grid-footer.grid-active {
transform: translateY(-8px);
opacity: 0.45; /* semi-transparent so ball aura is visible through it */
}
/* ── Toss edge zones ── */