2026-02-21 09:53:31 -05:00
< script setup lang = "ts" >
2026-03-21 16:45:37 -05:00
import { onMounted , onUnmounted , ref , computed , watch } from 'vue'
2026-02-21 09:53:31 -05:00
import { useI18n } from 'vue-i18n'
import { useTaxiStore } from '@/stores/taxi'
import { analyticsService } from '@/services/analyticsService'
2026-02-26 22:17:56 -05:00
import type { Taxi } from '@/types'
2026-02-21 09:53:31 -05:00
import FavoriteButton from '@/components/FavoriteButton.vue'
2026-03-21 16:06:21 -05:00
import AppImage from '@/components/AppImage.vue'
2026-03-03 13:21:09 -05:00
import AuthGuard from '@/components/common/AuthGuard.vue'
2026-03-04 11:17:16 -05:00
import LoadingBranded from '@/components/common/LoadingBranded.vue'
2026-02-21 09:53:31 -05:00
const { t } = useI18n ( )
const taxiStore = useTaxiStore ( )
const selectedZone = ref ( 'all' )
const selectedShift = ref ( 'all' )
const onlyEnglish = ref ( false )
const corregimientos = [ 'all' , 'Boquete' , 'David - Boquete' , 'Boquete - David' , 'Aeropuerto - Boquete' ]
const shifts = [ 'all' , 'dia' , 'tarde' , 'noche' ]
2026-03-21 16:45:37 -05:00
// Infinite Scroll
const displayLimit = ref ( 12 )
const observerTarget = ref < HTMLElement | null > ( null )
let observer : IntersectionObserver | null = null
2026-03-03 15:04:16 -05:00
function fetchData ( ) {
taxiStore . loadTaxis ( )
}
function handleRefocus ( ) {
2026-03-03 20:51:17 -05:00
// Recarga silenciosa: no congela la UI si ya hay datos
taxiStore . silentReload ( )
2026-03-03 15:04:16 -05:00
}
2026-02-21 09:53:31 -05:00
onMounted ( async ( ) => {
2026-02-27 10:57:42 -05:00
analyticsService . logEvent ( { event _name : 'screen_view' , screen _name : 'TaxisLocales' } )
2026-03-03 15:04:16 -05:00
window . addEventListener ( 'app-refocus' , handleRefocus )
2026-03-21 16:45:37 -05:00
// Infinite Scroll Observer
observer = new IntersectionObserver ( ( entries ) => {
if ( entries [ 0 ] ? . isIntersecting ) {
displayLimit . value += 12
}
} , { rootMargin : '400px' } )
if ( observerTarget . value && observer ) {
observer . observe ( observerTarget . value )
}
2026-02-27 10:57:42 -05:00
if ( taxiStore . taxis . length === 0 ) {
2026-03-03 15:04:16 -05:00
await fetchData ( )
2026-02-27 10:57:42 -05:00
}
2026-02-21 09:53:31 -05:00
} )
2026-03-03 15:04:16 -05:00
onUnmounted ( ( ) => {
window . removeEventListener ( 'app-refocus' , handleRefocus )
2026-03-21 16:45:37 -05:00
if ( observer ) {
observer . disconnect ( )
}
} )
watch ( [ selectedZone , selectedShift , onlyEnglish ] , ( ) => {
displayLimit . value = 12
2026-03-03 15:04:16 -05:00
} )
2026-02-21 09:53:31 -05:00
const filteredTaxis = computed ( ( ) => {
return taxiStore . taxis . filter ( taxi => {
const matchesZone = selectedZone . value === 'all' || taxi . corregimiento === selectedZone . value
2026-03-03 10:40:04 -05:00
// Ahora comprueba si el turno seleccionado está en el array de turnos del taxi
const matchesShift = selectedShift . value === 'all' || ( taxi . shifts && taxi . shifts . includes ( selectedShift . value ) )
2026-02-21 09:53:31 -05:00
const matchesEnglish = ! onlyEnglish . value || taxi . english _speaking
return matchesZone && matchesShift && matchesEnglish
} )
} )
2026-03-21 16:45:37 -05:00
const visibleTaxis = computed ( ( ) => {
return filteredTaxis . value . slice ( 0 , displayLimit . value )
} )
2026-03-03 10:40:04 -05:00
const isOnline = ( taxi : Taxi ) => {
if ( ! taxi . shifts ) return false
return taxi . shifts . includes ( 'dia' ) || taxi . shifts . includes ( 'tarde' )
}
const getShiftsDisplay = ( taxi : Taxi ) => {
if ( ! taxi . shifts || taxi . shifts . length === 0 ) return ''
return taxi . shifts . map ( s => getShiftLabel ( s ) ) . join ( ' · ' )
}
2026-02-21 09:53:31 -05:00
const handleCall = ( taxi : Taxi ) => {
analyticsService . logEvent ( {
event _name : 'taxi_click' ,
2026-03-04 20:36:31 -05:00
entity _type : 'taxi' ,
entity _id : taxi . id ,
entity _name : taxi . owner _name ,
2026-02-21 09:53:31 -05:00
properties : {
action : 'call' ,
taxi _id : taxi . id ,
plate : taxi . license _plate
}
} )
window . location . href = ` tel: ${ taxi . phone _number } `
}
function getShiftLabel ( shift : string ) {
if ( shift === 'dia' ) return t ( 'taxi.dayShift' )
if ( shift === 'tarde' ) return t ( 'taxi.afternoonShift' )
if ( shift === 'noche' ) return t ( 'taxi.nightShift' )
return shift
}
< / script >
< template >
2026-02-27 10:57:42 -05:00
< div class = "taxis-locales" >
< div class = "filters-container" >
2026-03-03 10:08:57 -05:00
< div class = "filter-card glass-effect" >
2026-02-21 09:53:31 -05:00
< div class = "selectors-side" >
2026-03-03 10:08:57 -05:00
< div class = "select-group-premium" >
< div class = "group-content" >
< label > { { t ( 'taxi.allZones' ) } } < / label >
< select v-model = "selectedZone" >
< option value = "all" > { { t ( 'taxi.allZones' ) } } < / option >
< option v-for = "zone in corregimientos.filter(z => z !== 'all')" :key="zone" :value="zone" > {{ zone }} < / option >
< / select >
< / div >
2026-02-21 09:53:31 -05:00
< / div >
2026-03-03 10:08:57 -05:00
< div class = "select-group-premium" >
< div class = "group-content" >
< label > { { t ( 'taxi.shift' ) } } < / label >
< select v-model = "selectedShift" >
< option value = "all" > { { t ( 'taxi.shift' ) } } < / option >
< option v-for = "s in shifts.filter(x => x !== 'all')" :key="s" :value="s" > {{ getShiftLabel ( s ) }} < / option >
< / select >
< / div >
2026-02-21 09:53:31 -05:00
< / div >
< / div >
< div class = "lang-toggle-side" >
2026-03-03 10:08:57 -05:00
< div class = "lang-pill" : class = "{ 'lang-pill--active': onlyEnglish }" @click ="onlyEnglish = !onlyEnglish" >
2026-03-31 18:29:55 -05:00
< span class = "material-icons notranslate" translate = "no" > { { onlyEnglish ? 'check_circle' : 'language' } } < / span >
2026-03-03 10:08:57 -05:00
< span > English < / span >
< / div >
2026-02-21 09:53:31 -05:00
< / div >
< / div >
< / div >
< div v-if = "taxiStore.isLoading" class="state-container" >
2026-03-04 11:17:16 -05:00
< LoadingBranded : message = "t('taxi.loadingTaxis') || 'Cargando taxis...'" icon = "local_taxi" / >
2026-02-21 09:53:31 -05:00
< / div >
< div v-else-if = "taxiStore.error" class="state-container" >
2026-03-31 18:29:55 -05:00
< span class = "material-icons notranslate" translate = "no" > error _outline < / span >
2026-02-21 09:53:31 -05:00
< p > { { taxiStore . error } } < / p >
2026-02-24 13:02:19 -05:00
< button class = "retry-btn" @click ="taxiStore.loadTaxis()" >
2026-03-31 18:29:55 -05:00
< span class = "material-icons notranslate" translate = "no" > refresh < / span >
2026-03-01 12:15:08 -05:00
{ { t ( 'common.retry' ) || 'Reintentar' } }
2026-02-24 13:02:19 -05:00
< / button >
2026-02-21 09:53:31 -05:00
< / div >
2026-03-03 13:21:09 -05:00
< AuthGuard
: title = "t('discover.auth.title')"
: message = "t('shuttle.auth.message')"
>
< div class = "taxis-grid" >
2026-03-21 16:45:37 -05:00
< div v-for = "taxi in visibleTaxis" :key="taxi.id" v-memo="[taxi.id]" class="taxi-card-new glass-effect" >
2026-02-21 09:53:31 -05:00
< div class = "card-top" >
2026-03-03 10:08:57 -05:00
< div class = "driver-avatar-wrap" >
< div class = "driver-avatar" >
2026-03-21 16:06:21 -05:00
< AppImage
: src = "taxi.image_url"
type = "taxi"
2026-03-03 10:08:57 -05:00
alt = "Driver"
2026-03-21 16:06:21 -05:00
/ >
2026-03-03 10:08:57 -05:00
< / div >
2026-03-03 10:40:04 -05:00
< div class = "driver-status" : class = "{ 'status-online': isOnline(taxi) }" > < / div >
2026-02-21 09:53:31 -05:00
< / div >
< div class = "driver-info" >
2026-03-03 10:40:04 -05:00
< div class = "flex items-center gap-2 mb-0.5" >
< h3 class = "driver-name" > { { taxi . owner _name } } < / h3 >
2026-03-31 18:29:55 -05:00
< span v-if = "taxi.is_accessible" class="material-icons text-blue-500 text-sm notranslate" title="Accesible para personas con discapacidad" translate="no" > accessible < / span >
2026-03-03 10:40:04 -05:00
< / div >
2026-03-03 10:08:57 -05:00
< div class = "driver-meta" >
< div class = "rating-stars" >
2026-03-31 18:29:55 -05:00
< span class = "material-icons star-filled notranslate" translate = "no" > star < / span >
2026-03-03 10:08:57 -05:00
< span class = "rating-value" > { { ( taxi . rating || 5 ) . toFixed ( 1 ) } } < / span >
< / div >
< span class = "meta-dot" > · < / span >
2026-03-03 10:40:04 -05:00
< span class = "shift-badge" > { { getShiftsDisplay ( taxi ) } } < / span >
2026-02-21 09:53:31 -05:00
< / div >
< / div >
< div class = "fav-icon-wrapper" >
< FavoriteButton
item - type = "taxi"
: item - id = "taxi.id"
: item - name = "taxi.owner_name"
: item - image = "taxi.image_url || undefined"
/ >
< / div >
< / div >
2026-03-03 10:08:57 -05:00
< div class = "card-details" >
< div class = "detail-item" v-if = "taxi.corregimiento" >
2026-03-31 18:29:55 -05:00
< span class = "material-icons detail-icon notranslate" translate = "no" > location _on < / span >
2026-03-03 10:08:57 -05:00
< span class = "detail-text" > { { taxi . corregimiento } } < / span >
< / div >
2026-03-03 10:40:04 -05:00
< div class = "detail-item" v-if = "taxi.vehicle_type" >
2026-03-31 18:29:55 -05:00
< span class = "material-icons detail-icon notranslate" translate = "no" > local _taxi < / span >
2026-03-03 10:40:04 -05:00
< span class = "detail-text" > { { taxi . vehicle _type } } < / span >
< / div >
2026-03-03 10:08:57 -05:00
< div class = "detail-item" v-if = "taxi.english_speaking" >
2026-03-31 18:29:55 -05:00
< span class = "material-icons detail-icon notranslate" translate = "no" > g _translate < / span >
2026-03-03 10:08:57 -05:00
< span class = "detail-text" > { { t ( 'taxi.englishLabel' ) } } < / span >
2026-02-21 09:53:31 -05:00
< / div >
< / div >
2026-03-03 10:08:57 -05:00
< div class = "card-actions" >
< a :href = "`tel:${taxi.phone_number}`" class = "call-btn-premium" @click ="handleCall(taxi)" >
2026-03-31 18:29:55 -05:00
< span class = "material-icons notranslate" translate = "no" > phone _in _talk < / span >
2026-03-03 10:08:57 -05:00
< div class = "btn-content" >
< span class = "btn-label" > { { t ( 'taxi.callNow' ) } } < / span >
< span class = "btn-subtext" > { { taxi . phone _number } } < / span >
< / div >
< / a >
2026-02-21 09:53:31 -05:00
< / div >
< / div >
2026-03-21 16:45:37 -05:00
<!-- Infinite Scroll Trigger -- >
< div ref = "observerTarget" class = "h-10 w-full mt-4" > < / div >
2026-02-21 09:53:31 -05:00
< div v-if = "filteredTaxis.length === 0" class="empty-state" >
2026-03-31 18:29:55 -05:00
< span class = "material-icons notranslate" translate = "no" > no _accounts < / span >
2026-02-21 09:53:31 -05:00
< p > { { t ( 'taxi.noTaxisAvailable' ) } } < / p >
< / div >
2026-03-03 13:21:09 -05:00
< / div >
< / AuthGuard >
2026-02-27 10:57:42 -05:00
2026-02-21 09:53:31 -05:00
< / div >
< / template >
< style scoped >
2026-03-03 10:14:13 -05:00
/* FILTROS PREMIUM */
2026-03-03 10:08:57 -05:00
. filters - container {
padding : 0 1 rem 1.5 rem ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. filter - card {
2026-03-22 10:38:53 -05:00
border - radius : 1 rem ;
padding : 0.75 rem 1 rem ;
2026-02-21 09:53:31 -05:00
display : flex ;
2026-03-03 10:08:57 -05:00
flex - direction : column ;
2026-03-22 10:38:53 -05:00
gap : 0.75 rem ;
2026-02-21 09:53:31 -05:00
border : 1 px solid var ( -- border - color ) ;
2026-03-22 10:38:53 -05:00
box - shadow : 0 4 px 15 px rgba ( 0 , 0 , 0 , 0.05 ) ;
2026-03-03 10:08:57 -05:00
background : var ( -- card - bg ) ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
@ media ( min - width : 640 px ) {
. filter - card {
flex - direction : row ;
align - items : center ;
justify - content : space - between ;
}
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. selectors - side {
flex : 1 ;
display : grid ;
2026-03-22 10:38:53 -05:00
grid - template - columns : 1 fr 1 fr ;
gap : 0.5 rem ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. select - group - premium {
2026-02-24 13:02:19 -05:00
display : flex ;
align - items : center ;
2026-03-22 10:38:53 -05:00
gap : 0.5 rem ;
2026-03-03 10:08:57 -05:00
background : var ( -- bg - primary ) ;
border : 1 px solid var ( -- border - color ) ;
2026-03-22 10:38:53 -05:00
border - radius : 0.75 rem ;
padding : 0.5 rem 0.75 rem ;
2026-03-03 10:08:57 -05:00
transition : all 0.3 s ease ;
2026-02-24 10:46:17 -05:00
}
2026-03-03 10:08:57 -05:00
. select - group - premium : focus - within {
border - color : var ( -- active - color ) ;
box - shadow : 0 0 0 3 px rgba ( 254 , 231 , 21 , 0.1 ) ;
2026-02-24 10:46:17 -05:00
}
2026-03-03 10:08:57 -05:00
. group - content {
flex : 1 ;
2026-02-24 10:46:17 -05:00
display : flex ;
flex - direction : column ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. group - content label {
font - size : 0.65 rem ;
font - weight : 800 ;
text - transform : uppercase ;
letter - spacing : 0.05 em ;
color : var ( -- text - secondary ) ;
line - height : 1 ;
margin - bottom : 0.25 rem ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. group - content select {
background : transparent ;
border : none ;
color : var ( -- text - primary ) ;
font - weight : 700 ;
font - size : 0.9375 rem ;
outline : none ;
cursor : pointer ;
padding : 0 ;
width : 100 % ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. lang - pill {
display : inline - flex ;
2026-02-21 09:53:31 -05:00
align - items : center ;
2026-03-22 10:38:53 -05:00
gap : 0.25 rem ;
padding : 0.5 rem 1 rem ;
2026-03-03 10:08:57 -05:00
background : var ( -- bg - primary ) ;
border : 1 px solid var ( -- border - color ) ;
2026-03-22 10:38:53 -05:00
border - radius : 0.75 rem ;
2026-03-03 10:08:57 -05:00
font - weight : 700 ;
font - size : 0.875 rem ;
color : var ( -- text - secondary ) ;
cursor : pointer ;
transition : all 0.3 s ease ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. lang - pill -- active {
background : rgba ( 254 , 231 , 21 , 0.1 ) ;
border - color : var ( -- active - color ) ;
color : var ( -- active - color ) ;
2026-02-24 10:46:17 -05:00
}
2026-03-03 10:14:13 -05:00
/* GRID Y TARJETAS PREMIUM */
2026-03-03 10:08:57 -05:00
. taxis - grid {
display : grid ;
grid - template - columns : repeat ( auto - fill , minmax ( 320 px , 1 fr ) ) ;
gap : 1.5 rem ;
padding : 1.5 rem 1 rem ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. taxi - card - new {
border - radius : 1.5 rem ;
padding : 1.25 rem ;
border : 1 px solid var ( -- border - color ) ;
transition : all 0.4 s cubic - bezier ( 0.175 , 0.885 , 0.32 , 1.275 ) ;
2026-02-21 09:53:31 -05:00
display : flex ;
2026-03-03 10:08:57 -05:00
flex - direction : column ;
gap : 1.25 rem ;
background : var ( -- card - bg ) ;
2026-02-24 10:46:17 -05:00
}
2026-03-03 10:08:57 -05:00
. taxi - card - new : hover {
transform : translateY ( - 8 px ) ;
border - color : var ( -- active - color ) ;
box - shadow : 0 20 px 40 px rgba ( 0 , 0 , 0 , 0.2 ) ;
2026-02-24 10:46:17 -05:00
}
2026-03-03 10:08:57 -05:00
. card - top {
2026-02-21 09:53:31 -05:00
display : flex ;
align - items : center ;
2026-03-03 10:08:57 -05:00
gap : 1 rem ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. driver - avatar - wrap {
position : relative ;
2026-02-24 10:46:17 -05:00
flex - shrink : 0 ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. driver - avatar {
width : 56 px ;
height : 56 px ;
border - radius : 1 rem ;
overflow : hidden ;
background : var ( -- bg - secondary ) ;
border : 2 px solid var ( -- border - color ) ;
2026-02-24 10:46:17 -05:00
}
2026-03-03 10:08:57 -05:00
. driver - avatar img {
width : 100 % ;
height : 100 % ;
object - fit : cover ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. driver - status {
position : absolute ;
bottom : - 2 px ;
right : - 2 px ;
width : 14 px ;
height : 14 px ;
border - radius : 50 % ;
background : # 94 a3b8 ;
border : 3 px solid var ( -- card - bg ) ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. status - online {
background : # 22 c55e ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. driver - info {
flex : 1 ;
2026-02-24 10:46:17 -05:00
}
2026-03-03 10:08:57 -05:00
. driver - name {
margin : 0 0 0.25 rem ;
font - size : 1.125 rem ;
font - weight : 800 ;
color : var ( -- text - primary ) ;
line - height : 1.2 ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. driver - meta {
2026-02-21 09:53:31 -05:00
display : flex ;
2026-03-03 10:08:57 -05:00
align - items : center ;
gap : 0.5 rem ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. rating - stars {
2026-02-21 09:53:31 -05:00
display : flex ;
align - items : center ;
2026-03-03 10:08:57 -05:00
gap : 0.25 rem ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. star - filled {
color : var ( -- active - color ) ;
font - size : 1 rem ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. rating - value {
font - size : 0.875 rem ;
font - weight : 800 ;
color : var ( -- text - primary ) ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. meta - dot {
color : var ( -- text - secondary ) ;
opacity : 0.5 ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. shift - badge {
font - size : 0.75 rem ;
font - weight : 700 ;
color : var ( -- text - secondary ) ;
text - transform : capitalize ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. card - details {
2026-02-21 09:53:31 -05:00
display : flex ;
2026-03-03 10:08:57 -05:00
flex - wrap : wrap ;
gap : 0.75 rem ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. detail - item {
2026-02-24 10:46:17 -05:00
display : flex ;
align - items : center ;
2026-03-03 10:08:57 -05:00
gap : 0.375 rem ;
background : var ( -- bg - secondary ) ;
padding : 0.375 rem 0.75 rem ;
border - radius : 0.75 rem ;
font - size : 0.75 rem ;
font - weight : 700 ;
color : var ( -- text - secondary ) ;
2026-02-24 10:46:17 -05:00
}
2026-03-03 10:08:57 -05:00
. detail - icon {
2026-02-24 10:46:17 -05:00
font - size : 1 rem ;
2026-03-03 10:08:57 -05:00
color : var ( -- active - color ) ;
2026-02-24 10:46:17 -05:00
}
2026-03-03 10:08:57 -05:00
. card - actions {
margin - top : auto ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. call - btn - premium {
2026-02-21 09:53:31 -05:00
display : flex ;
align - items : center ;
2026-03-03 10:08:57 -05:00
gap : 1 rem ;
width : 100 % ;
padding : 0.75 rem 1.25 rem ;
background : var ( -- active - color ) ;
color : # 101820 ;
border - radius : 1.125 rem ;
2026-02-21 09:53:31 -05:00
text - decoration : none ;
2026-03-03 10:08:57 -05:00
transition : all 0.3 s ease ;
box - shadow : 0 4 px 15 px rgba ( 254 , 231 , 21 , 0.2 ) ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. call - btn - premium : hover {
transform : scale ( 1.02 ) ;
box - shadow : 0 6 px 20 px rgba ( 254 , 231 , 21 , 0.35 ) ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. call - btn - premium : active {
transform : scale ( 0.98 ) ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. call - btn - premium . material - icons {
font - size : 1.5 rem ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. btn - content {
display : flex ;
flex - direction : column ;
align - items : flex - start ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. btn - label {
font - size : 0.9375 rem ;
font - weight : 900 ;
line - height : 1 ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. btn - subtext {
font - size : 0.75 rem ;
font - weight : 700 ;
opacity : 0.7 ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. empty - state {
2026-03-03 10:14:13 -05:00
grid - column - start : 1 ;
grid - column - end : - 1 ;
2026-03-03 10:08:57 -05:00
text - align : center ;
padding : 4 rem 2 rem ;
color : var ( -- text - secondary ) ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. empty - state . material - icons {
font - size : 4 rem ;
margin - bottom : 1 rem ;
opacity : 0.5 ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. empty - state p {
font - size : 1.125 rem ;
font - weight : 600 ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. state - container {
display : flex ;
flex - direction : column ;
align - items : center ;
justify - content : center ;
padding : 4 rem 2 rem ;
gap : 1 rem ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. spin {
animation : spin 1 s infinite linear ;
font - size : 3 rem ;
color : var ( -- active - color ) ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
@ keyframes spin {
from { transform : rotate ( 0 deg ) ; }
to { transform : rotate ( 360 deg ) ; }
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. retry - btn {
display : inline - flex ;
align - items : center ;
gap : 0.5 rem ;
padding : 0.75 rem 1.5 rem ;
background : var ( -- active - color ) ;
color : # 101820 ;
border : none ;
border - radius : 99 px ;
font - weight : 800 ;
cursor : pointer ;
transition : all 0.3 s ease ;
2026-02-21 09:53:31 -05:00
}
2026-03-03 10:08:57 -05:00
. retry - btn : hover {
transform : scale ( 1.05 ) ;
2026-02-21 09:53:31 -05:00
}
@ media ( max - width : 600 px ) {
2026-03-03 10:08:57 -05:00
. taxis - grid {
2026-02-21 09:53:31 -05:00
grid - template - columns : 1 fr ;
}
}
2026-02-27 10:57:42 -05:00
< / style >