@bytebrand/fe-ui-core-autobahn 1.0.114 → 1.0.116
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cards/CarCard.tsx +2 -2
- package/cards/cardParts.tsx +116 -9
- package/locales/de/autobahn.json +2 -1
- package/locales/en/autobahn.json +1 -0
- package/package.json +1 -1
- package/theme/md3.css +151 -23
- package/ui/CardCarousel.tsx +8 -4
- package/ui/Dropdown.tsx +201 -45
- package/ui/FormDropdown.tsx +7 -1
- package/vdp/FinanceCalculator.tsx +62 -13
- package/vdp/VdpModules.tsx +13 -2
- package/vdp/VdpViewer.tsx +141 -50
package/cards/CarCard.tsx
CHANGED
|
@@ -240,7 +240,7 @@ const CarCard: React.FunctionComponent<CarCardProps> = ({
|
|
|
240
240
|
<GalleryActivityPill viewsCount={car.viewsCount} favoritesCount={car.favoritesCount} />
|
|
241
241
|
</div>
|
|
242
242
|
</div>
|
|
243
|
-
<div style={{ padding: '
|
|
243
|
+
<div style={{ padding: '8px 18px', display: 'flex', flexDirection: 'column', gap: 0, flex: 1 }}>
|
|
244
244
|
<div>
|
|
245
245
|
<div className="md-title" style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
|
246
246
|
{car.make} {car.model}
|
|
@@ -294,7 +294,7 @@ const CarCard: React.FunctionComponent<CarCardProps> = ({
|
|
|
294
294
|
/>
|
|
295
295
|
{/* legacy VehicleSmallCard's "SeoText" footer line (full spec + equipment list) —
|
|
296
296
|
renders nothing when the caller hasn't populated car.seoText. */}
|
|
297
|
-
<SeoLine car={car} style={{ marginTop:
|
|
297
|
+
<SeoLine car={car} style={{ marginTop: 0 }} />
|
|
298
298
|
{adminAction && (
|
|
299
299
|
<div style={{ marginTop: 8 }}>
|
|
300
300
|
<Button
|
package/cards/cardParts.tsx
CHANGED
|
@@ -19,7 +19,7 @@ import { TranslationFunction } from '../types';
|
|
|
19
19
|
import { defaultConfig } from '@bytebrand/fe-financing';
|
|
20
20
|
|
|
21
21
|
import { Icon, Button } from '../ui';
|
|
22
|
-
import {
|
|
22
|
+
import { EvalBar } from '../vdp/FinanceCalculator';
|
|
23
23
|
import { CO2_CLASSES, CO2_COLORS, TIER_KEYS, TIER_COLORS } from '../constants';
|
|
24
24
|
import { AutobahnCar } from './types';
|
|
25
25
|
// pure, non-React — shared with the Meta AIA marketing-image renderer (a plain Node service).
|
|
@@ -784,37 +784,144 @@ export interface CardCtaRowProps {
|
|
|
784
784
|
export const CardCtaRow: React.FunctionComponent<CardCtaRowProps> = ({ car, mode, onRequestOffer, onCall, onOpenRateAdjust, t }) => (
|
|
785
785
|
<div
|
|
786
786
|
className="card-cta-row show-mobile"
|
|
787
|
-
style={{ display: 'flex', gap:
|
|
787
|
+
style={{ display: 'flex', gap: 6, borderTop: '1px solid var(--md-outline-variant)', paddingTop: 8 }}
|
|
788
788
|
>
|
|
789
789
|
<Button
|
|
790
790
|
variant="filled"
|
|
791
|
-
style={{
|
|
791
|
+
style={{
|
|
792
|
+
// Figma width (157px) as a STARTING size, not a hard fixed one — flex-grow:1 so this
|
|
793
|
+
// button (and "Adjust rate" below) still fill extra row width on wider cards instead of
|
|
794
|
+
// leaving dead space next to the fixed 40px phone button; flex-shrink:1 lets it narrow
|
|
795
|
+
// gracefully (text ellipsizes via the existing .card-cta-row .mbtn overflow rule) rather
|
|
796
|
+
// than overflow on very narrow cards.
|
|
797
|
+
flex: '1 1 157px',
|
|
798
|
+
height: 40,
|
|
799
|
+
background: '#005cff',
|
|
800
|
+
borderRadius: 16,
|
|
801
|
+
padding: '0 8px',
|
|
802
|
+
fontFamily: 'Arial',
|
|
803
|
+
fontStyle: 'normal',
|
|
804
|
+
fontWeight: 700,
|
|
805
|
+
fontSize: 13,
|
|
806
|
+
lineHeight: '15px',
|
|
807
|
+
color: '#ffffff',
|
|
808
|
+
}}
|
|
792
809
|
onClick={(e) => {
|
|
793
810
|
e.stopPropagation();
|
|
794
811
|
onRequestOffer();
|
|
795
812
|
}}
|
|
796
813
|
>
|
|
797
|
-
|
|
814
|
+
{/* exact design icon (single self-contained SVG) — replaces the composed lucide
|
|
815
|
+
file-text + check-circle badge (DocCheckIcon), which is still used as-is on VDP's own
|
|
816
|
+
"Angebot anfragen" buttons; this swap is scoped to the search-card CTA only.
|
|
817
|
+
flex:none for the same shrink reason as the "Adjust rate" icon above. */}
|
|
818
|
+
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg" style={{ flex: 'none' }}>
|
|
819
|
+
<path
|
|
820
|
+
d="M6.90625 3.65625H15.275L19.9062 8.2875V20.7188C19.9062 21.6162 19.1787 22.3438 18.2812 22.3438H6.90625C6.00879 22.3438 5.28125 21.6162 5.28125 20.7188V5.28125C5.28125 4.38379 6.00879 3.65625 6.90625 3.65625Z"
|
|
821
|
+
stroke="white"
|
|
822
|
+
strokeLinecap="round"
|
|
823
|
+
strokeLinejoin="round"
|
|
824
|
+
/>
|
|
825
|
+
<path d="M15.0312 3.85938V8.53125H19.7031" stroke="white" strokeLinecap="round" strokeLinejoin="round" />
|
|
826
|
+
<path d="M8.9375 11.375H14.625" stroke="white" strokeLinecap="round" />
|
|
827
|
+
<path d="M8.9375 14.625H13.4062" stroke="white" strokeLinecap="round" />
|
|
828
|
+
<path d="M8.9375 17.875H12.5938" stroke="white" strokeLinecap="round" />
|
|
829
|
+
<path
|
|
830
|
+
d="M18.4844 23.1562C20.8402 23.1562 22.75 21.2465 22.75 18.8906C22.75 16.5348 20.8402 14.625 18.4844 14.625C16.1285 14.625 14.2188 16.5348 14.2188 18.8906C14.2188 21.2465 16.1285 23.1562 18.4844 23.1562Z"
|
|
831
|
+
fill="#005CFF"
|
|
832
|
+
stroke="white"
|
|
833
|
+
/>
|
|
834
|
+
<path d="M17.0625 18.3219L18.5656 19.825L23.7656 14.625" stroke="white" strokeLinecap="round" strokeLinejoin="round" />
|
|
835
|
+
<path d="M21.6533 17.875L23.2783 16.25" stroke="#005CFF" strokeLinecap="round" strokeLinejoin="round" />
|
|
836
|
+
<path d="M20.1904 17.0625L21.8154 15.4375" stroke="#005CFF" strokeLinecap="round" strokeLinejoin="round" />
|
|
837
|
+
</svg>
|
|
798
838
|
{t('autobahn:finance.secureOffer')}
|
|
799
839
|
</Button>
|
|
800
840
|
<Button
|
|
801
841
|
variant="outlined"
|
|
802
|
-
|
|
803
|
-
|
|
842
|
+
style={{
|
|
843
|
+
flex: '0 0 auto',
|
|
844
|
+
width: 40,
|
|
845
|
+
height: 40,
|
|
846
|
+
background: '#ffffff',
|
|
847
|
+
border: '1.6px solid #005cff',
|
|
848
|
+
borderRadius: 16,
|
|
849
|
+
padding: 0,
|
|
850
|
+
}}
|
|
804
851
|
onClick={(e) => {
|
|
805
852
|
e.stopPropagation();
|
|
806
853
|
onCall();
|
|
807
854
|
}}
|
|
808
|
-
|
|
855
|
+
>
|
|
856
|
+
{/* exact design icon (not lucide's "phone") — no class="lucide", so the
|
|
857
|
+
.card-cta-row .mbtn .lucide 15px override doesn't touch it; the rect-clip from the
|
|
858
|
+
source SVG was a full-viewBox no-op (already inside 0-20/0-20) and dropped, since a
|
|
859
|
+
static clipPath id would collide across the many CarCard instances on one search page. */}
|
|
860
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
861
|
+
<path
|
|
862
|
+
d="M18.3332 14.1004V16.6004C18.3341 16.8325 18.2866 17.0622 18.1936 17.2749C18.1006 17.4875 17.9643 17.6784 17.7933 17.8353C17.6222 17.9922 17.4203 18.1116 17.2005 18.186C16.9806 18.2603 16.7477 18.288 16.5165 18.2671C13.9523 17.9881 11.4892 17.1119 9.32486 15.7087C7.31139 14.4293 5.60431 12.7222 4.32486 10.7087C2.91679 8.5346 2.04037 6.0595 1.76653 3.48374C1.7457 3.2533 1.77309 3.02104 1.84695 2.80176C1.9208 2.58248 2.03951 2.38098 2.1955 2.21009C2.3515 2.0392 2.54137 1.90266 2.75302 1.80917C2.96468 1.71569 3.19348 1.66729 3.42486 1.66707H5.92486C6.32928 1.66309 6.72136 1.80631 7.028 2.07002C7.33464 2.33373 7.53493 2.69995 7.59153 3.10041C7.69153 3.85041 7.86653 4.57541 8.11653 5.26707C8.22865 5.56534 8.25291 5.8895 8.18645 6.20114C8.11999 6.51278 7.96558 6.79883 7.74153 7.02541L6.74153 8.03374C7.95617 10.2329 9.76739 12.0441 11.9665 13.2587L12.9749 12.2587C13.2014 12.0347 13.4875 11.8803 13.7991 11.8138C14.1108 11.7474 14.4349 11.7716 14.7332 11.8837C15.4249 12.1337 16.1499 12.3087 16.8999 12.4087C17.3047 12.4658 17.6744 12.6697 17.9386 12.9817C18.2029 13.2936 18.3433 13.6917 18.3332 14.1004Z"
|
|
863
|
+
stroke="#005cff"
|
|
864
|
+
strokeWidth={1.66667}
|
|
865
|
+
strokeLinecap="round"
|
|
866
|
+
strokeLinejoin="round"
|
|
867
|
+
/>
|
|
868
|
+
</svg>
|
|
869
|
+
</Button>
|
|
809
870
|
<Button
|
|
810
871
|
variant="outlined"
|
|
811
|
-
|
|
812
|
-
|
|
872
|
+
style={{
|
|
873
|
+
// same "starting size that can still grow/shrink" reasoning as "Request offer" above.
|
|
874
|
+
flex: '1 1 125px',
|
|
875
|
+
height: 40,
|
|
876
|
+
background: '#ffffff',
|
|
877
|
+
border: '1.6px solid #5b6b7f',
|
|
878
|
+
borderRadius: 16,
|
|
879
|
+
padding: '0 6px',
|
|
880
|
+
fontFamily: 'Arial',
|
|
881
|
+
fontStyle: 'normal',
|
|
882
|
+
fontWeight: 700,
|
|
883
|
+
fontSize: 13,
|
|
884
|
+
lineHeight: '15px',
|
|
885
|
+
color: '#5b6b7f',
|
|
886
|
+
}}
|
|
813
887
|
onClick={(e) => {
|
|
814
888
|
e.stopPropagation();
|
|
815
889
|
onOpenRateAdjust(mode);
|
|
816
890
|
}}
|
|
817
891
|
>
|
|
892
|
+
{/* exact design icon (not lucide's "sliders-horizontal") — colors are baked into the SVG
|
|
893
|
+
itself (matches the button's #5b6b7f border/text), not currentColor. flex:none is
|
|
894
|
+
load-bearing: this button is a flex row (icon + the "Adjust rate" label) inside a fixed
|
|
895
|
+
125px width, and without it the icon was a shrinkable flex item — flexbox squeezed its
|
|
896
|
+
WIDTH down to fit the text (rendering ~12.94x18, squashed) while its literal height
|
|
897
|
+
attribute stayed 18. Lucide icons here dodge this via the unrelated .card-cta-row .mbtn
|
|
898
|
+
.lucide CSS rule (flex: none), which doesn't match a plain <svg> with no lucide class. */}
|
|
899
|
+
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" style={{ flex: 'none' }}>
|
|
900
|
+
<path d="M3 5.25H15" stroke="#5B6B7F" strokeWidth={1.91667} strokeLinecap="round" strokeLinejoin="round" />
|
|
901
|
+
<path
|
|
902
|
+
d="M6 6.75C6.82843 6.75 7.5 6.07843 7.5 5.25C7.5 4.42157 6.82843 3.75 6 3.75C5.17157 3.75 4.5 4.42157 4.5 5.25C4.5 6.07843 5.17157 6.75 6 6.75Z"
|
|
903
|
+
fill="#FFFEFE"
|
|
904
|
+
stroke="#5B6B7F"
|
|
905
|
+
strokeLinecap="round"
|
|
906
|
+
strokeLinejoin="round"
|
|
907
|
+
/>
|
|
908
|
+
<path d="M3 9H15" stroke="#5B6B7F" strokeWidth={1.91667} strokeLinecap="round" strokeLinejoin="round" />
|
|
909
|
+
<path
|
|
910
|
+
d="M12.4565 10.5C13.285 10.5 13.9565 9.82843 13.9565 9C13.9565 8.17157 13.285 7.5 12.4565 7.5C11.6281 7.5 10.9565 8.17157 10.9565 9C10.9565 9.82843 11.6281 10.5 12.4565 10.5Z"
|
|
911
|
+
fill="white"
|
|
912
|
+
stroke="#5B6B7F"
|
|
913
|
+
strokeLinecap="round"
|
|
914
|
+
strokeLinejoin="round"
|
|
915
|
+
/>
|
|
916
|
+
<path d="M3 12.75H15" stroke="#5B6B7F" strokeWidth={1.91667} strokeLinecap="round" strokeLinejoin="round" />
|
|
917
|
+
<path
|
|
918
|
+
d="M9.81543 14.25C10.6439 14.25 11.3154 13.5784 11.3154 12.75C11.3154 11.9216 10.6439 11.25 9.81543 11.25C8.987 11.25 8.31543 11.9216 8.31543 12.75C8.31543 13.5784 8.987 14.25 9.81543 14.25Z"
|
|
919
|
+
fill="white"
|
|
920
|
+
stroke="#5B6B7F"
|
|
921
|
+
strokeLinecap="round"
|
|
922
|
+
strokeLinejoin="round"
|
|
923
|
+
/>
|
|
924
|
+
</svg>
|
|
818
925
|
{t('autobahn:finance.adjustRate')}
|
|
819
926
|
</Button>
|
|
820
927
|
</div>
|
package/locales/de/autobahn.json
CHANGED
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"priceRatingAria": "Preisbewertung: {{rating}}",
|
|
87
87
|
"detailsShow": "Details anzeigen",
|
|
88
88
|
"paymentLabel": "Zahlung",
|
|
89
|
-
"paymentValue": "
|
|
89
|
+
"paymentValue": "Überweisung",
|
|
90
90
|
"warrantyLabel": "Garantie",
|
|
91
91
|
"warrantyValue": "1 Jahr inklusive",
|
|
92
92
|
"deliveryLabel": "Lieferung",
|
|
@@ -105,6 +105,7 @@
|
|
|
105
105
|
"callCta": "Anrufen",
|
|
106
106
|
"finalInstallmentToggle": "Mit Schlussrate",
|
|
107
107
|
"addServicesToggle": "Rundum-Sorglos-Paket",
|
|
108
|
+
"moreInfoAria": "Weitere Informationen zu {{label}}",
|
|
108
109
|
"addServicesPerMonth": "+{{value}} € / Monat",
|
|
109
110
|
"addServicesOnce": "+{{value}} €",
|
|
110
111
|
"addServicesIncluded": "inklusive",
|
package/locales/en/autobahn.json
CHANGED
|
@@ -105,6 +105,7 @@
|
|
|
105
105
|
"callCta": "Call",
|
|
106
106
|
"finalInstallmentToggle": "With final installment",
|
|
107
107
|
"addServicesToggle": "All-round care package",
|
|
108
|
+
"moreInfoAria": "More information about {{label}}",
|
|
108
109
|
"addServicesPerMonth": "+€{{value}} / month",
|
|
109
110
|
"addServicesOnce": "+€{{value}}",
|
|
110
111
|
"addServicesIncluded": "included",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bytebrand/fe-ui-core-autobahn",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.116",
|
|
4
4
|
"description": "auto.de md3 (Autobahn) design system — UI primitives, cards, chrome, VDP modules, theme CSS and locales. Ships raw TypeScript source (like fe-ui-core before it); each consumer's bundler compiles it.",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"license": "UNLICENSED",
|
package/theme/md3.css
CHANGED
|
@@ -3398,11 +3398,17 @@ line-height: 31px;
|
|
|
3398
3398
|
transform: translateY(-50%);
|
|
3399
3399
|
width: 32px;
|
|
3400
3400
|
height: 32px;
|
|
3401
|
-
border-radius:
|
|
3402
|
-
border:
|
|
3403
|
-
|
|
3401
|
+
border-radius: 50%;
|
|
3402
|
+
border: 1px solid #E8EDF3;
|
|
3403
|
+
/* same "glass" translucency (0.5 alpha + light border + blur) as the sibling overlays on this
|
|
3404
|
+
card — .cc-photo-pill (image count) and .cc-activity-pill (views) — so the arrows read as
|
|
3405
|
+
part of the same overlay family instead of a heavier, opaque control. Dropped the old
|
|
3406
|
+
box-shadow: var(--md-e1) for the same reason — neither sibling pill carries one, and a drop
|
|
3407
|
+
shadow under a low-alpha glass circle looked muddy. The blur is what keeps the dark #08162A
|
|
3408
|
+
chevron legible against busy vehicle photos underneath (contrast doesn't depend on the photo). */
|
|
3409
|
+
background: rgba(255, 255, 255, 0.5);
|
|
3410
|
+
backdrop-filter: blur(2px);
|
|
3404
3411
|
color: var(--md-on-surface);
|
|
3405
|
-
box-shadow: var(--md-e1);
|
|
3406
3412
|
display: flex;
|
|
3407
3413
|
align-items: center;
|
|
3408
3414
|
justify-content: center;
|
|
@@ -3411,11 +3417,20 @@ line-height: 31px;
|
|
|
3411
3417
|
transition: opacity var(--dur-1);
|
|
3412
3418
|
z-index: 2;
|
|
3413
3419
|
}
|
|
3420
|
+
/* Touch target: the visible circle stays 32px (matches the design), but that's below the ~44px
|
|
3421
|
+
minimum recommended for a reliable touch target (WCAG 2.5.5 / Apple HIG). This invisible
|
|
3422
|
+
pseudo-element pads the actual hit area out to 44px (32 + 6 + 6) without changing how the
|
|
3423
|
+
button looks — clicks/taps anywhere in the padded zone still hit the real <button>. */
|
|
3424
|
+
.md3 .car-arrow::before {
|
|
3425
|
+
content: '';
|
|
3426
|
+
position: absolute;
|
|
3427
|
+
inset: -6px;
|
|
3428
|
+
}
|
|
3414
3429
|
.md3 .car-arrow--l {
|
|
3415
|
-
left:
|
|
3430
|
+
left: 10px;
|
|
3416
3431
|
}
|
|
3417
3432
|
.md3 .car-arrow--r {
|
|
3418
|
-
right:
|
|
3433
|
+
right: 10px;
|
|
3419
3434
|
}
|
|
3420
3435
|
.md3 .cardcar:hover .car-arrow {
|
|
3421
3436
|
opacity: 1;
|
|
@@ -3435,6 +3450,14 @@ line-height: 31px;
|
|
|
3435
3450
|
border: 1px solid #D4DDE7;
|
|
3436
3451
|
box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.08);
|
|
3437
3452
|
}
|
|
3453
|
+
/* pin the VDP gallery's own edge offset — the base .car-arrow--l/--r rule above was moved to
|
|
3454
|
+
10px for the SRP card carousels; the VDP viewer keeps its original, larger offset. */
|
|
3455
|
+
.md3 .vdp-gallerybox .car-arrow--l {
|
|
3456
|
+
left: 22px;
|
|
3457
|
+
}
|
|
3458
|
+
.md3 .vdp-gallerybox .car-arrow--r {
|
|
3459
|
+
right: 22px;
|
|
3460
|
+
}
|
|
3438
3461
|
|
|
3439
3462
|
/* ==========================================================================
|
|
3440
3463
|
RESPONSIVE LAYOUT LAYER
|
|
@@ -3458,7 +3481,15 @@ line-height: 31px;
|
|
|
3458
3481
|
}
|
|
3459
3482
|
.md3 .field-grid-2 {
|
|
3460
3483
|
display: grid;
|
|
3461
|
-
|
|
3484
|
+
/* minmax(0,1fr), not plain 1fr: a bare 1fr track's implicit minimum is auto (= its content's
|
|
3485
|
+
min-content), and a searchable Dropdown's open/editing state swaps the trigger <button> for
|
|
3486
|
+
a <div><input></div> — inputs carry their own browser-default intrinsic min-content width
|
|
3487
|
+
that flex's min-width:0 on the input doesn't fully suppress once a CSS Grid track (not just
|
|
3488
|
+
the inner flex row) is the one asking "how small can you get". That let the Make/Model
|
|
3489
|
+
column widen the moment it opened, shoving into its sibling column instead of staying put.
|
|
3490
|
+
Same fix/diagnosis as .fin-price-grid above (see its own comment) — minmax(0,1fr) overrides
|
|
3491
|
+
the track's floor directly, so it can't happen regardless of what's inside. */
|
|
3492
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
|
3462
3493
|
gap: 12px;
|
|
3463
3494
|
}
|
|
3464
3495
|
.md3 .cards-3 {
|
|
@@ -5305,6 +5336,11 @@ line-height: 31px;
|
|
|
5305
5336
|
.md3 .card-cta-row .mbtn { font-size: 12.5px; padding: 0 10px; gap: 5px; min-width: 0; }
|
|
5306
5337
|
.md3 .card-cta-row .mbtn span, .md3 .card-cta-row .mbtn { overflow: hidden; text-overflow: ellipsis; }
|
|
5307
5338
|
.md3 .card-cta-row .mbtn .lucide { width: 15px; height: 15px; flex: none; }
|
|
5339
|
+
/* the phone/"Rate anpassen" outlined buttons set their own explicit `border` (1.6px solid) inline —
|
|
5340
|
+
.mbtn--outlined's inset box-shadow (the DEFAULT way that class draws its border everywhere else)
|
|
5341
|
+
stacks on top of it as a second, slightly offset ring ("double border"). Suppress just the
|
|
5342
|
+
shadow here; the real border keeps rendering from each button's own inline style. */
|
|
5343
|
+
.md3 .card-cta-row .mbtn--outlined { box-shadow: none; }
|
|
5308
5344
|
/* muted buyer activity (#5) */
|
|
5309
5345
|
.md3 .pp-activity {
|
|
5310
5346
|
display: flex;
|
|
@@ -6297,14 +6333,29 @@ line-height: 31px;
|
|
|
6297
6333
|
/* Visible icon glyphs 24-28px (spec range) — the shared .icon-btn/.mbtn rules force 20px/18px
|
|
6298
6334
|
everywhere else in the app, which is fine there but read visibly smaller than the Figma
|
|
6299
6335
|
mobile header reference. */
|
|
6300
|
-
.md3 header .icon-btn {
|
|
6301
|
-
width: 48px;
|
|
6302
|
-
height: 48px;
|
|
6303
|
-
}
|
|
6304
6336
|
.md3 header .icon-btn .lucide {
|
|
6305
6337
|
width: 24px;
|
|
6306
6338
|
height: 24px;
|
|
6307
6339
|
}
|
|
6340
|
+
/* Bug: "Header distribution" — Figma has the logo starting at x=49 and the search/phone/account
|
|
6341
|
+
icon group starting at x=246 (390px reference), but the logo was rendering ~25px too far
|
|
6342
|
+
right and the icon group ~15-17px too far left. Root cause: this rule used to ALSO force
|
|
6343
|
+
hamburger/search/phone's own icon-btn box to 48×48 (copied from .topbar-account-btn just
|
|
6344
|
+
below, whose 48×48 IS spec'd — WCAG/Header-System touch-target — but nothing here documented
|
|
6345
|
+
the same for these three). That extra 8px of box per icon (48 vs the base .icon-btn's 40px)
|
|
6346
|
+
pushed the logo right (hamburger wider) and pulled the action-icon group left (search/phone
|
|
6347
|
+
wider, eating into the row before the right-aligned account button). Dropped back to the
|
|
6348
|
+
base 40×40 box — glyph size above is unaffected, so nothing looks visually smaller — and
|
|
6349
|
+
restored the lost touch-target room with an invisible ::before hit-slop instead (inset:-4px
|
|
6350
|
+
= 48×48 effective tap zone, same technique as the SRP card-carousel arrows use). */
|
|
6351
|
+
.md3 header .icon-btn {
|
|
6352
|
+
position: relative;
|
|
6353
|
+
}
|
|
6354
|
+
.md3 header .icon-btn::before {
|
|
6355
|
+
content: '';
|
|
6356
|
+
position: absolute;
|
|
6357
|
+
inset: -4px;
|
|
6358
|
+
}
|
|
6308
6359
|
.md3 header .topbar-account-btn .lucide {
|
|
6309
6360
|
width: 24px;
|
|
6310
6361
|
height: 24px;
|
|
@@ -6319,6 +6370,13 @@ line-height: 31px;
|
|
|
6319
6370
|
.md3 .topbar-logo {
|
|
6320
6371
|
width: 122px;
|
|
6321
6372
|
height: auto;
|
|
6373
|
+
/* pulls the logo from x≈68 (12px padding + the hamburger's 40px box + the .topbar-container
|
|
6374
|
+
row's own 16px gap, set inline and shared with other pairs in that row — not touched here,
|
|
6375
|
+
see the icon-btn comment above for why) to Figma's x=49. A negative margin on THIS one item
|
|
6376
|
+
is deliberate: shrinking the shared row gap instead would have also pulled the search/
|
|
6377
|
+
phone/account cluster on the right closer together, which is already correct after the
|
|
6378
|
+
icon-btn fix above and must stay untouched. */
|
|
6379
|
+
margin-left: -19px;
|
|
6322
6380
|
}
|
|
6323
6381
|
/* Gap between action icons 2-6px (spec: "Abstand Aktionen") — separate from the wider gap the
|
|
6324
6382
|
hamburger/logo/nav still use (that's the outer .container's own gap, untouched here). */
|
|
@@ -6640,6 +6698,13 @@ line-height: 31px;
|
|
|
6640
6698
|
.md3 .cards-2 {
|
|
6641
6699
|
grid-template-columns: 1fr;
|
|
6642
6700
|
}
|
|
6701
|
+
/* fe-landing (/angebot) TopResults + Alternatives grids — shared side gutter,
|
|
6702
|
+
same 12px pattern as .md3 .container elsewhere. .cards-3 is untouched (not
|
|
6703
|
+
used with this gutter treatment; only .cards-2 callers asked for it). */
|
|
6704
|
+
.md3 .cards-2 {
|
|
6705
|
+
padding-left: 12px !important;
|
|
6706
|
+
padding-right: 12px !important;
|
|
6707
|
+
}
|
|
6643
6708
|
/* listing card stacks: image (4:3) → info → price */
|
|
6644
6709
|
.md3 .listcard {
|
|
6645
6710
|
grid-template-columns: 1fr;
|
|
@@ -6707,16 +6772,30 @@ line-height: 31px;
|
|
|
6707
6772
|
}
|
|
6708
6773
|
.md3 .srp-bar {
|
|
6709
6774
|
position: sticky;
|
|
6710
|
-
/*
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
6775
|
+
/* default: docked directly under the always-visible header (its 64px height). Same 0.25s
|
|
6776
|
+
duration as .topbar's own transform transition (below) — the header slides in/out over
|
|
6777
|
+
0.25s, so this bar's top must animate in step with it, not jump instantly, or a gap (bar
|
|
6778
|
+
already at 64px, header still sliding in) or an overlap (bar already at 0, header still
|
|
6779
|
+
sliding out) flashes for that quarter-second. */
|
|
6780
|
+
top: 64px;
|
|
6781
|
+
transition: top 0.25s;
|
|
6714
6782
|
z-index: 20;
|
|
6715
6783
|
background: #fff;
|
|
6716
6784
|
padding: 8px 0;
|
|
6717
6785
|
margin: 0 0 8px;
|
|
6718
6786
|
box-shadow: 0 6px 8px -8px rgba(0, 0, 0, 0.3);
|
|
6719
6787
|
}
|
|
6788
|
+
/* once the header slides away on scroll-down (autoHideOnScroll, TopBar.tsx adds
|
|
6789
|
+
.topbar--hidden), this bar takes its place at the very top instead of leaving a 64px gap.
|
|
6790
|
+
The header's box stays in the layout flow even while hidden (transform doesn't affect
|
|
6791
|
+
`position: sticky`'s slot — see the .topbar--hidden rule above), so without this override
|
|
6792
|
+
the bar's own sticky top would also need to jump — and it must jump BACK to 64px the moment
|
|
6793
|
+
scroll-up brings the header back (topbar--hidden removed), or the reappearing header
|
|
6794
|
+
(z-index 50) sticks at the same top:0 slot and paints over/hides this bar (z-index 20)
|
|
6795
|
+
underneath it instead of sitting above it. */
|
|
6796
|
+
.md3:has(.topbar--hidden) .srp-bar {
|
|
6797
|
+
top: 0px;
|
|
6798
|
+
}
|
|
6720
6799
|
/* full-bleed white to the true viewport edges, WITHOUT moving .srp-bar's own text — it stays
|
|
6721
6800
|
inside .srp-main's own side padding, this pseudo-element just paints white past it on both
|
|
6722
6801
|
sides so no gap of page background shows while the bar is sticky. NOT a box-shadow spread
|
|
@@ -6738,7 +6817,7 @@ line-height: 31px;
|
|
|
6738
6817
|
z-index: -1;
|
|
6739
6818
|
}
|
|
6740
6819
|
.md3 .field-grid-2 {
|
|
6741
|
-
grid-template-columns: 1fr;
|
|
6820
|
+
grid-template-columns: minmax(0, 1fr);
|
|
6742
6821
|
gap: 10px;
|
|
6743
6822
|
}
|
|
6744
6823
|
.md3 .hero-search {
|
|
@@ -7261,11 +7340,13 @@ line-height: 31px;
|
|
|
7261
7340
|
z-index: 3;
|
|
7262
7341
|
}
|
|
7263
7342
|
|
|
7264
|
-
/* VDP main wrapper: phone gets a tighter top gap (
|
|
7265
|
-
(
|
|
7343
|
+
/* VDP main wrapper: phone gets a tighter top gap (0, was 15px) and narrower side gutters
|
|
7344
|
+
(10px, matches production) than the 15/24px desktop default set inline — title, highlight
|
|
7345
|
+
chips and the pricing card all inherit this from their shared .vdp-main ancestor, so there's
|
|
7346
|
+
no separate per-element rule to keep in sync with this one. */
|
|
7266
7347
|
@media (max-width: 600px) {
|
|
7267
7348
|
.md3 .vdp-main {
|
|
7268
|
-
padding: 0
|
|
7349
|
+
padding: 0 14px 48px !important;
|
|
7269
7350
|
}
|
|
7270
7351
|
.md3 .vdp-push-badges {
|
|
7271
7352
|
gap: 6px;
|
|
@@ -7445,6 +7526,28 @@ color: #005CFF;
|
|
|
7445
7526
|
line-height: 17px;
|
|
7446
7527
|
color: #1D2A38;
|
|
7447
7528
|
}
|
|
7529
|
+
/* all three tabs (Finanzierung/Leasing/Kaufen), desktop + mobile — ToggleRow is the one shared
|
|
7530
|
+
render for all of them. Info icon sits raised near the top of the label, like a small
|
|
7531
|
+
superscript badge, instead of centered against the text. */
|
|
7532
|
+
.md3 .fin-toggle-addservices .md-title-sm .lucide {
|
|
7533
|
+
position: relative;
|
|
7534
|
+
top: -7px;
|
|
7535
|
+
left: -2px;
|
|
7536
|
+
}
|
|
7537
|
+
/* tooltip-trigger touch target (all 3 tabs, incl. --cash — an a11y correctness fix, not a
|
|
7538
|
+
per-tab visual choice like the icon nudge above). Trigger is now the 15x15 icon alone (the
|
|
7539
|
+
label text beside it is inert), so BOTH axes need padding out to 48px, not just the vertical
|
|
7540
|
+
one. ::after is positioned off layout flow (doesn't grow the row or push the label/price/
|
|
7541
|
+
switch siblings over) but still real estate for hit-testing — clicks/taps anywhere in its box
|
|
7542
|
+
count as hitting the trigger span itself. (15 + 17 + 17 = 49, clears the 48px minimum.) */
|
|
7543
|
+
.md3 .fin-toggle-info-trigger {
|
|
7544
|
+
position: relative;
|
|
7545
|
+
}
|
|
7546
|
+
.md3 .fin-toggle-info-trigger::after {
|
|
7547
|
+
content: '';
|
|
7548
|
+
position: absolute;
|
|
7549
|
+
inset: -17px;
|
|
7550
|
+
}
|
|
7448
7551
|
.md3 .fin-toggle-addservices > div {
|
|
7449
7552
|
gap: 13px !important;
|
|
7450
7553
|
}
|
|
@@ -7485,6 +7588,12 @@ color: #005CFF;
|
|
|
7485
7588
|
top: auto;
|
|
7486
7589
|
bottom: auto;
|
|
7487
7590
|
}
|
|
7591
|
+
/* Kaufen tab, desktop sidebar card (.fin-calc-card, NOT the .fin-modal sheet above) — the row
|
|
7592
|
+
sits lower in this card than the financing/leasing rows do, so the base "flush above" bottom:
|
|
7593
|
+
100% opens noticeably higher than the trigger; drops it closer instead. */
|
|
7594
|
+
.md3 .fin-calc-card .fin-toggle-addservices.fin-toggle-addservices--cash .fin-toggle-tooltip {
|
|
7595
|
+
bottom: -10%;
|
|
7596
|
+
}
|
|
7488
7597
|
.md3 .fin-modal .show-mobile .fin-toggle-tooltip {
|
|
7489
7598
|
border-radius: 11px;
|
|
7490
7599
|
}
|
|
@@ -7535,9 +7644,6 @@ color: #005CFF;
|
|
|
7535
7644
|
letter-spacing: 0.4px;
|
|
7536
7645
|
color: var(--md-on-surface-variant);
|
|
7537
7646
|
}
|
|
7538
|
-
.md3 .fin-calc-card .fin-toggle-addservices.fin-toggle-addservices--cash .md-title-sm .lucide {
|
|
7539
|
-
display: none;
|
|
7540
|
-
}
|
|
7541
7647
|
.md3 .fin-calc-card .fin-toggle-addservices.fin-toggle-addservices--cash .num,
|
|
7542
7648
|
.md3 .fin-calc-card .fin-toggle-addservices.fin-toggle-addservices--cash > div > span:last-child {
|
|
7543
7649
|
font-family: var(--md-font-display) !important;
|
|
@@ -8765,6 +8871,23 @@ color: #005CFF;
|
|
|
8765
8871
|
grid-template-areas: "rate evalcol" "cond cond";
|
|
8766
8872
|
align-items: start;
|
|
8767
8873
|
}
|
|
8874
|
+
/* Bug: switching the Financing/Leasing/Buy tabs made the price row, rating pill and the two
|
|
8875
|
+
CTA buttons below jump up/down, because the row above them had a different rendered height
|
|
8876
|
+
per tab: (a) .fin-cond (the "0 € Anzahlung · 60 Monate · ..." terms line) renders NOTHING on
|
|
8877
|
+
Buy (isCash hides it), collapsing to 0 height instead of one text line, and (b)
|
|
8878
|
+
.fin-price-grid--cash below zeroes the row-gap that the other two tabs keep. The two rules
|
|
8879
|
+
below cancel each of those, so Financing/Leasing/Buy all reserve the same total height.
|
|
8880
|
+
(A first pass also force-reserved height on .fin-rate-main itself, to additionally cover the
|
|
8881
|
+
rare case of an extra struck list-price line on Buy when the car has a discount — isCash &&
|
|
8882
|
+
showStrike in FinanceCalculator.tsx. Dropped: since Financing/Leasing/undiscounted-Buy don't
|
|
8883
|
+
need that extra room, it left a visible empty gap under the price on every normal tab just to
|
|
8884
|
+
pre-cover one edge case. That specific combination can still shift by the strike line's own
|
|
8885
|
+
height; every other tab switch is now jump-free without the dead space.) */
|
|
8886
|
+
.md3 .fin-calc-card .fin-price-grid.fin-price-grid--cash {
|
|
8887
|
+
/* same 12px row-gap as Financing/Leasing (the base .fin-price-grid rule) — the 0px gap on
|
|
8888
|
+
.fin-price-grid--cash further up this file otherwise pulls the CTA row 12px closer on Buy. */
|
|
8889
|
+
gap: 12px 15px;
|
|
8890
|
+
}
|
|
8768
8891
|
.md3 .fin-eval-col {
|
|
8769
8892
|
display: flex;
|
|
8770
8893
|
flex-direction: column;
|
|
@@ -8799,6 +8922,11 @@ color: #005CFF;
|
|
|
8799
8922
|
font-weight: 400;
|
|
8800
8923
|
font-size: 13px;
|
|
8801
8924
|
line-height: 15px;
|
|
8925
|
+
/* matches the line-height above: on the Buy tab this div renders empty (its "0 € Anzahlung ·
|
|
8926
|
+
60 Monate · ..." text is Financing/Leasing-only), so without a floor it collapsed to 0
|
|
8927
|
+
height instead of the one text line the other two tabs occupy — part of the cross-tab
|
|
8928
|
+
layout-jump fix, see the .fin-rate-main comment above. */
|
|
8929
|
+
min-height: 15px;
|
|
8802
8930
|
color: #111820;
|
|
8803
8931
|
margin: 0px 0px;
|
|
8804
8932
|
margin-bottom: 12px;
|
|
@@ -10583,7 +10711,7 @@ color: #005CFF;
|
|
|
10583
10711
|
right: 11px !important;
|
|
10584
10712
|
}
|
|
10585
10713
|
.md3 .cc-card .cc-badges {
|
|
10586
|
-
top:
|
|
10714
|
+
top: 18px !important;
|
|
10587
10715
|
}
|
|
10588
10716
|
|
|
10589
10717
|
/* hero price — Figma's rate figure (Finanzierung/Leasing) is much larger than the shared
|
package/ui/CardCarousel.tsx
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef, useEffect } from 'react';
|
|
2
2
|
|
|
3
|
-
import Icon from './Icon';
|
|
4
|
-
|
|
5
3
|
export interface CardCarouselProps {
|
|
6
4
|
/** ready-to-use image URLs (already resolved by the caller — no asset/window lookup here). */
|
|
7
5
|
images: string[];
|
|
@@ -147,10 +145,16 @@ const CardCarousel: React.FunctionComponent<CardCarouselProps> = ({
|
|
|
147
145
|
{n > 1 && (
|
|
148
146
|
<>
|
|
149
147
|
<button className="car-arrow car-arrow--l" aria-label="zurück" onClick={(e) => go(-1, e)}>
|
|
150
|
-
|
|
148
|
+
{/* exact icon from the design (not the lucide chevron-left) — 20x20 viewBox, dark
|
|
149
|
+
#08162A stroke so it stays legible on the translucent glass background above. */}
|
|
150
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
151
|
+
<path d="M12.0835 5L7.0835 10L12.0835 15" stroke="#08162A" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
|
|
152
|
+
</svg>
|
|
151
153
|
</button>
|
|
152
154
|
<button className="car-arrow car-arrow--r" aria-label="weiter" onClick={(e) => go(1, e)}>
|
|
153
|
-
<
|
|
155
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
156
|
+
<path d="M7.9165 5L12.9165 10L7.9165 15" stroke="#08162A" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
|
|
157
|
+
</svg>
|
|
154
158
|
</button>
|
|
155
159
|
<div
|
|
156
160
|
className="cardcar-dots"
|