@bytebrand/fe-ui-core-autobahn 1.0.113 → 1.0.115
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 +52 -5
- package/cards/CarRow.tsx +53 -4
- package/cards/cardParts.tsx +139 -13
- package/chrome/TopBar.tsx +8 -3
- package/locales/de/autobahn.json +8 -2
- package/locales/en/autobahn.json +7 -1
- package/package.json +1 -1
- package/theme/md3.css +243 -58
- package/ui/CardCarousel.tsx +20 -5
- package/ui/Dropdown.tsx +192 -45
- package/ui/FormDropdown.tsx +7 -1
- package/vdp/FinanceCalculator.tsx +62 -13
- package/vdp/VdpModules.tsx +4080 -4050
- package/vdp/VdpViewer.tsx +238 -62
package/theme/md3.css
CHANGED
|
@@ -453,6 +453,44 @@ line-height: 31px;
|
|
|
453
453
|
width: 14px;
|
|
454
454
|
height: 14px;
|
|
455
455
|
}
|
|
456
|
+
/* Figma spec for the rating chip in its two "Guter Preis" locations — the VDP header
|
|
457
|
+
(VdpHeaderSummary, .vdp-headrow) and the SRP list-card's price column (CarRow.tsx,
|
|
458
|
+
.listcard-price, both its mobile Finanzierung row and desktop Kaufen row share this one class).
|
|
459
|
+
Scoped to THESE locations only, not every .statchip site-wide (e.g. the price-history "drop"
|
|
460
|
+
chip a few sections down reuses tone="good" for a completely different purpose — a €-amount,
|
|
461
|
+
not a price rating — and keeps the theme-aware --md-good-container tokens untouched). min-width
|
|
462
|
+
(not a hard width) + white-space:nowrap: 108px is tight for icon+"Guter Preis"+⁴ on one line,
|
|
463
|
+
so this grows past it instead of wrapping/clipping rather than clamping to a width that doesn't fit. */
|
|
464
|
+
.md3 .vdp-headrow .statchip,
|
|
465
|
+
.md3 .listcard-price .statchip {
|
|
466
|
+
min-width: 108px;
|
|
467
|
+
height: 27px;
|
|
468
|
+
border-radius: 11px;
|
|
469
|
+
font-family: 'Arial';
|
|
470
|
+
font-weight: 700;
|
|
471
|
+
font-size: 12px;
|
|
472
|
+
line-height: 14px;
|
|
473
|
+
text-align: center;
|
|
474
|
+
white-space: nowrap;
|
|
475
|
+
justify-content: center;
|
|
476
|
+
}
|
|
477
|
+
.md3 .vdp-headrow .statchip sup,
|
|
478
|
+
.md3 .listcard-price .statchip sup {
|
|
479
|
+
position: relative;
|
|
480
|
+
top: -3px;
|
|
481
|
+
left: -4px;
|
|
482
|
+
font-size: 9px;
|
|
483
|
+
line-height: 9px;
|
|
484
|
+
}
|
|
485
|
+
/* 'good' tone here is specifically the "Guter Preis" rating (same canonical green as the
|
|
486
|
+
fin-eval-pill "good" tier elsewhere on this page) — literal color, not the --md-good-container
|
|
487
|
+
token, matching that other pill's own literal-color treatment. --warn (Fairer Preis) is
|
|
488
|
+
untouched, still tokenized. */
|
|
489
|
+
.md3 .vdp-headrow .statchip--good,
|
|
490
|
+
.md3 .listcard-price .statchip--good {
|
|
491
|
+
color: rgb(22, 138, 69);
|
|
492
|
+
background: color-mix(in srgb, rgb(22, 138, 69) 16%, transparent);
|
|
493
|
+
}
|
|
456
494
|
|
|
457
495
|
/* small image label (views, photo count) */
|
|
458
496
|
.md3 .imglabel {
|
|
@@ -3360,11 +3398,17 @@ line-height: 31px;
|
|
|
3360
3398
|
transform: translateY(-50%);
|
|
3361
3399
|
width: 32px;
|
|
3362
3400
|
height: 32px;
|
|
3363
|
-
border-radius:
|
|
3364
|
-
border:
|
|
3365
|
-
|
|
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);
|
|
3366
3411
|
color: var(--md-on-surface);
|
|
3367
|
-
box-shadow: var(--md-e1);
|
|
3368
3412
|
display: flex;
|
|
3369
3413
|
align-items: center;
|
|
3370
3414
|
justify-content: center;
|
|
@@ -3373,11 +3417,20 @@ line-height: 31px;
|
|
|
3373
3417
|
transition: opacity var(--dur-1);
|
|
3374
3418
|
z-index: 2;
|
|
3375
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
|
+
}
|
|
3376
3429
|
.md3 .car-arrow--l {
|
|
3377
|
-
left:
|
|
3430
|
+
left: 10px;
|
|
3378
3431
|
}
|
|
3379
3432
|
.md3 .car-arrow--r {
|
|
3380
|
-
right:
|
|
3433
|
+
right: 10px;
|
|
3381
3434
|
}
|
|
3382
3435
|
.md3 .cardcar:hover .car-arrow {
|
|
3383
3436
|
opacity: 1;
|
|
@@ -3397,6 +3450,14 @@ line-height: 31px;
|
|
|
3397
3450
|
border: 1px solid #D4DDE7;
|
|
3398
3451
|
box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.08);
|
|
3399
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
|
+
}
|
|
3400
3461
|
|
|
3401
3462
|
/* ==========================================================================
|
|
3402
3463
|
RESPONSIVE LAYOUT LAYER
|
|
@@ -3420,7 +3481,15 @@ line-height: 31px;
|
|
|
3420
3481
|
}
|
|
3421
3482
|
.md3 .field-grid-2 {
|
|
3422
3483
|
display: grid;
|
|
3423
|
-
|
|
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);
|
|
3424
3493
|
gap: 12px;
|
|
3425
3494
|
}
|
|
3426
3495
|
.md3 .cards-3 {
|
|
@@ -3747,7 +3816,7 @@ line-height: 31px;
|
|
|
3747
3816
|
min-width: 0;
|
|
3748
3817
|
}
|
|
3749
3818
|
/* "NEU" badge on car cards (legacy new-car label). */
|
|
3750
|
-
.md3 .neu-badge { display: inline-flex; align-items: center; height: 22px; padding: 0 8px; border-radius: var(--md-r-full); background: var(--md-primary); color: #fff; font-size: 10.5px; font-weight: 700; letter-spacing: .3px; white-space: nowrap; box-shadow: var(--md-e1); }
|
|
3819
|
+
.md3 .neu-badge { display: inline-flex; align-items: center; height: 22px; padding: 0 8px; border-radius: var(--md-r-full); background: var(--md-primary); color: #fff; font-size: 10.5px; font-weight: 700; line-height: 14px; letter-spacing: .3px; white-space: nowrap; box-shadow: var(--md-e1); }
|
|
3751
3820
|
/* "⚡ Angebot" badge — dark neutral pill above the gallery (card mockup), distinct from NEU. */
|
|
3752
3821
|
.md3 .offer-badge { display: inline-flex; align-items: center; gap: 4px; height: 24px; padding: 0 9px; border-radius: var(--md-r-full); background: var(--md-on-surface); color: #fff; font-size: 11px; font-weight: 600; white-space: nowrap; }
|
|
3753
3822
|
.md3 .offer-badge .lucide { width: 13px; height: 13px; }
|
|
@@ -5164,37 +5233,50 @@ line-height: 31px;
|
|
|
5164
5233
|
width: 112px;
|
|
5165
5234
|
flex: none;
|
|
5166
5235
|
}
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5236
|
+
/* Figma spec, now identical across all three "Guter Preis" pill locations (CarCard's own
|
|
5237
|
+
.cc-price, incl. the VDP "Ähnliche Fahrzeuge" rail; .fin-calc-card; .fin-modal) — one shared
|
|
5238
|
+
rule instead of three copies. `background`/`color` are deliberately NOT set here: they stay
|
|
5239
|
+
driven by the tier-color inline style each render site sets (see PriceEvalCol in
|
|
5240
|
+
cardParts.tsx / FinanceCalculator.tsx / VdpModules.tsx, all of which already resolve to the
|
|
5241
|
+
canonical rgb(22,138,69) for the 'good' tier) — a `!important` used to hardcode this pill's
|
|
5242
|
+
background to a fixed #dff3e5 here, silently overriding that inline value regardless of tier. */
|
|
5243
|
+
.md3 .cc-price .fin-eval-pill,
|
|
5244
|
+
.md3 .fin-calc-card .fin-eval-pill,
|
|
5245
|
+
.md3 .fin-modal .fin-eval-pill {
|
|
5246
|
+
font-family: 'Arial';
|
|
5170
5247
|
font-weight: 700;
|
|
5171
5248
|
font-size: 12px;
|
|
5172
5249
|
line-height: 14px;
|
|
5173
5250
|
text-align: center;
|
|
5174
5251
|
}
|
|
5175
|
-
.md3 .cc-price .fin-eval-pill--good
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
width:
|
|
5252
|
+
.md3 .cc-price .fin-eval-pill--good,
|
|
5253
|
+
.md3 .fin-calc-card .fin-eval-pill--good,
|
|
5254
|
+
.md3 .fin-modal .fin-eval-pill--good {
|
|
5255
|
+
width: 108px;
|
|
5179
5256
|
height: 27px;
|
|
5257
|
+
border-radius: 11px;
|
|
5180
5258
|
box-sizing: border-box;
|
|
5259
|
+
display: flex;
|
|
5260
|
+
align-items: center;
|
|
5181
5261
|
justify-content: center;
|
|
5182
5262
|
}
|
|
5183
5263
|
/* footnote 4 ("Top-Preis" claim) — .fin-eval-pill is a flex container, so vertical-align has
|
|
5184
5264
|
no effect on the sup (it's a flex item, not inline content); position:relative/top raises
|
|
5185
|
-
it instead, same technique as the hero price's own 1/2/3 footnote markers.
|
|
5186
|
-
|
|
5187
|
-
FinanceDetailsModal's embedded mobile rate sheet (.fin-modal). */
|
|
5265
|
+
it instead, same technique as the hero price's own 1/2/3 footnote markers. Same -3px lift now
|
|
5266
|
+
shared by all three locations above. */
|
|
5188
5267
|
.md3 .cc-price .fin-eval-pill sup,
|
|
5189
5268
|
.md3 .fin-calc-card .fin-eval-pill sup,
|
|
5190
5269
|
.md3 .fin-modal .fin-eval-pill sup {
|
|
5191
5270
|
position: relative;
|
|
5192
|
-
top:
|
|
5271
|
+
top: -3px;
|
|
5193
5272
|
left: -4px;
|
|
5194
5273
|
font-size: 9px;
|
|
5195
5274
|
line-height: 9px;
|
|
5196
5275
|
}
|
|
5197
5276
|
.md3 .cc-price .fin-eval-bar {
|
|
5277
|
+
/* matches the pill's own fixed 108px right above (both sit in the same 112px .fin-eval-col),
|
|
5278
|
+
so the two stay visually aligned instead of the bar stretching to the full column width. */
|
|
5279
|
+
width: 108px;
|
|
5198
5280
|
height: 7px;
|
|
5199
5281
|
}
|
|
5200
5282
|
.md3 .cc-price .fin-eval-seg:first-child {
|
|
@@ -5424,14 +5506,8 @@ line-height: 31px;
|
|
|
5424
5506
|
width: 112px;
|
|
5425
5507
|
justify-self: end;
|
|
5426
5508
|
}
|
|
5427
|
-
/*
|
|
5428
|
-
|
|
5429
|
-
.md3 .fin-calc-card .fin-eval-pill--good {
|
|
5430
|
-
width: 100%;
|
|
5431
|
-
display: flex;
|
|
5432
|
-
align-items: center;
|
|
5433
|
-
justify-content: center;
|
|
5434
|
-
}
|
|
5509
|
+
/* .fin-calc-card/.fin-modal's own "Guter Preis" pill text/box/sup sizing now lives in the one
|
|
5510
|
+
shared rule (with .cc-price) further up this file, near .cc-price's own .fin-eval-* rules. */
|
|
5435
5511
|
/* .fin-calc-card's own "Rate anpassen" panel is compact — the mobile-sheet/modal padding
|
|
5436
5512
|
(22/28px top, 20px bottom) is too roomy here. */
|
|
5437
5513
|
.md3 .fin-calc-card .fin-toggle-final,
|
|
@@ -6252,14 +6328,29 @@ line-height: 31px;
|
|
|
6252
6328
|
/* Visible icon glyphs 24-28px (spec range) — the shared .icon-btn/.mbtn rules force 20px/18px
|
|
6253
6329
|
everywhere else in the app, which is fine there but read visibly smaller than the Figma
|
|
6254
6330
|
mobile header reference. */
|
|
6255
|
-
.md3 header .icon-btn {
|
|
6256
|
-
width: 48px;
|
|
6257
|
-
height: 48px;
|
|
6258
|
-
}
|
|
6259
6331
|
.md3 header .icon-btn .lucide {
|
|
6260
6332
|
width: 24px;
|
|
6261
6333
|
height: 24px;
|
|
6262
6334
|
}
|
|
6335
|
+
/* Bug: "Header distribution" — Figma has the logo starting at x=49 and the search/phone/account
|
|
6336
|
+
icon group starting at x=246 (390px reference), but the logo was rendering ~25px too far
|
|
6337
|
+
right and the icon group ~15-17px too far left. Root cause: this rule used to ALSO force
|
|
6338
|
+
hamburger/search/phone's own icon-btn box to 48×48 (copied from .topbar-account-btn just
|
|
6339
|
+
below, whose 48×48 IS spec'd — WCAG/Header-System touch-target — but nothing here documented
|
|
6340
|
+
the same for these three). That extra 8px of box per icon (48 vs the base .icon-btn's 40px)
|
|
6341
|
+
pushed the logo right (hamburger wider) and pulled the action-icon group left (search/phone
|
|
6342
|
+
wider, eating into the row before the right-aligned account button). Dropped back to the
|
|
6343
|
+
base 40×40 box — glyph size above is unaffected, so nothing looks visually smaller — and
|
|
6344
|
+
restored the lost touch-target room with an invisible ::before hit-slop instead (inset:-4px
|
|
6345
|
+
= 48×48 effective tap zone, same technique as the SRP card-carousel arrows use). */
|
|
6346
|
+
.md3 header .icon-btn {
|
|
6347
|
+
position: relative;
|
|
6348
|
+
}
|
|
6349
|
+
.md3 header .icon-btn::before {
|
|
6350
|
+
content: '';
|
|
6351
|
+
position: absolute;
|
|
6352
|
+
inset: -4px;
|
|
6353
|
+
}
|
|
6263
6354
|
.md3 header .topbar-account-btn .lucide {
|
|
6264
6355
|
width: 24px;
|
|
6265
6356
|
height: 24px;
|
|
@@ -6274,6 +6365,13 @@ line-height: 31px;
|
|
|
6274
6365
|
.md3 .topbar-logo {
|
|
6275
6366
|
width: 122px;
|
|
6276
6367
|
height: auto;
|
|
6368
|
+
/* pulls the logo from x≈68 (12px padding + the hamburger's 40px box + the .topbar-container
|
|
6369
|
+
row's own 16px gap, set inline and shared with other pairs in that row — not touched here,
|
|
6370
|
+
see the icon-btn comment above for why) to Figma's x=49. A negative margin on THIS one item
|
|
6371
|
+
is deliberate: shrinking the shared row gap instead would have also pulled the search/
|
|
6372
|
+
phone/account cluster on the right closer together, which is already correct after the
|
|
6373
|
+
icon-btn fix above and must stay untouched. */
|
|
6374
|
+
margin-left: -19px;
|
|
6277
6375
|
}
|
|
6278
6376
|
/* Gap between action icons 2-6px (spec: "Abstand Aktionen") — separate from the wider gap the
|
|
6279
6377
|
hamburger/logo/nav still use (that's the outer .container's own gap, untouched here). */
|
|
@@ -6595,6 +6693,13 @@ line-height: 31px;
|
|
|
6595
6693
|
.md3 .cards-2 {
|
|
6596
6694
|
grid-template-columns: 1fr;
|
|
6597
6695
|
}
|
|
6696
|
+
/* fe-landing (/angebot) TopResults + Alternatives grids — shared side gutter,
|
|
6697
|
+
same 12px pattern as .md3 .container elsewhere. .cards-3 is untouched (not
|
|
6698
|
+
used with this gutter treatment; only .cards-2 callers asked for it). */
|
|
6699
|
+
.md3 .cards-2 {
|
|
6700
|
+
padding-left: 12px !important;
|
|
6701
|
+
padding-right: 12px !important;
|
|
6702
|
+
}
|
|
6598
6703
|
/* listing card stacks: image (4:3) → info → price */
|
|
6599
6704
|
.md3 .listcard {
|
|
6600
6705
|
grid-template-columns: 1fr;
|
|
@@ -6662,15 +6767,38 @@ line-height: 31px;
|
|
|
6662
6767
|
}
|
|
6663
6768
|
.md3 .srp-bar {
|
|
6664
6769
|
position: sticky;
|
|
6665
|
-
|
|
6770
|
+
/* was 64px (docked under the always-visible header) — now 0: once the header slides away
|
|
6771
|
+
(autoHideOnScroll, TopBar.tsx) this bar takes its place at the very top instead of leaving
|
|
6772
|
+
a gap, and sits flush under it again the moment the header slides back in. */
|
|
6773
|
+
top: 0px;
|
|
6666
6774
|
z-index: 20;
|
|
6667
|
-
background:
|
|
6775
|
+
background: #fff;
|
|
6668
6776
|
padding: 8px 0;
|
|
6669
6777
|
margin: 0 0 8px;
|
|
6670
6778
|
box-shadow: 0 6px 8px -8px rgba(0, 0, 0, 0.3);
|
|
6671
6779
|
}
|
|
6780
|
+
/* full-bleed white to the true viewport edges, WITHOUT moving .srp-bar's own text — it stays
|
|
6781
|
+
inside .srp-main's own side padding, this pseudo-element just paints white past it on both
|
|
6782
|
+
sides so no gap of page background shows while the bar is sticky. NOT a box-shadow spread
|
|
6783
|
+
(that bleeds in all 4 directions equally, including a huge slab below the bar covering the
|
|
6784
|
+
cards underneath it — that was tried and broke the page) — an absolutely-positioned layer
|
|
6785
|
+
confined to top:0/bottom:0 of .srp-bar's own box (position:sticky is a containing block for
|
|
6786
|
+
it, same as position:relative) stays exactly as tall as the bar, only wider. z-index:-1 is
|
|
6787
|
+
scoped to .srp-bar's own stacking context (it has z-index:20), so it paints behind the bar's
|
|
6788
|
+
text/buttons but still above the page content scrolling underneath. */
|
|
6789
|
+
.md3 .srp-bar::before {
|
|
6790
|
+
content: '';
|
|
6791
|
+
position: absolute;
|
|
6792
|
+
top: 0;
|
|
6793
|
+
bottom: 0;
|
|
6794
|
+
left: 50%;
|
|
6795
|
+
width: 100vw;
|
|
6796
|
+
transform: translateX(-50%);
|
|
6797
|
+
background: #fff;
|
|
6798
|
+
z-index: -1;
|
|
6799
|
+
}
|
|
6672
6800
|
.md3 .field-grid-2 {
|
|
6673
|
-
grid-template-columns: 1fr;
|
|
6801
|
+
grid-template-columns: minmax(0, 1fr);
|
|
6674
6802
|
gap: 10px;
|
|
6675
6803
|
}
|
|
6676
6804
|
.md3 .hero-search {
|
|
@@ -7193,8 +7321,10 @@ line-height: 31px;
|
|
|
7193
7321
|
z-index: 3;
|
|
7194
7322
|
}
|
|
7195
7323
|
|
|
7196
|
-
/* VDP main wrapper: phone gets a tighter top gap (
|
|
7197
|
-
(
|
|
7324
|
+
/* VDP main wrapper: phone gets a tighter top gap (0, was 15px) and narrower side gutters
|
|
7325
|
+
(10px, matches production) than the 15/24px desktop default set inline — title, highlight
|
|
7326
|
+
chips and the pricing card all inherit this from their shared .vdp-main ancestor, so there's
|
|
7327
|
+
no separate per-element rule to keep in sync with this one. */
|
|
7198
7328
|
@media (max-width: 600px) {
|
|
7199
7329
|
.md3 .vdp-main {
|
|
7200
7330
|
padding: 0 10px 48px !important;
|
|
@@ -7377,6 +7507,28 @@ color: #005CFF;
|
|
|
7377
7507
|
line-height: 17px;
|
|
7378
7508
|
color: #1D2A38;
|
|
7379
7509
|
}
|
|
7510
|
+
/* all three tabs (Finanzierung/Leasing/Kaufen), desktop + mobile — ToggleRow is the one shared
|
|
7511
|
+
render for all of them. Info icon sits raised near the top of the label, like a small
|
|
7512
|
+
superscript badge, instead of centered against the text. */
|
|
7513
|
+
.md3 .fin-toggle-addservices .md-title-sm .lucide {
|
|
7514
|
+
position: relative;
|
|
7515
|
+
top: -7px;
|
|
7516
|
+
left: -2px;
|
|
7517
|
+
}
|
|
7518
|
+
/* tooltip-trigger touch target (all 3 tabs, incl. --cash — an a11y correctness fix, not a
|
|
7519
|
+
per-tab visual choice like the icon nudge above). Trigger is now the 15x15 icon alone (the
|
|
7520
|
+
label text beside it is inert), so BOTH axes need padding out to 48px, not just the vertical
|
|
7521
|
+
one. ::after is positioned off layout flow (doesn't grow the row or push the label/price/
|
|
7522
|
+
switch siblings over) but still real estate for hit-testing — clicks/taps anywhere in its box
|
|
7523
|
+
count as hitting the trigger span itself. (15 + 17 + 17 = 49, clears the 48px minimum.) */
|
|
7524
|
+
.md3 .fin-toggle-info-trigger {
|
|
7525
|
+
position: relative;
|
|
7526
|
+
}
|
|
7527
|
+
.md3 .fin-toggle-info-trigger::after {
|
|
7528
|
+
content: '';
|
|
7529
|
+
position: absolute;
|
|
7530
|
+
inset: -17px;
|
|
7531
|
+
}
|
|
7380
7532
|
.md3 .fin-toggle-addservices > div {
|
|
7381
7533
|
gap: 13px !important;
|
|
7382
7534
|
}
|
|
@@ -7417,6 +7569,12 @@ color: #005CFF;
|
|
|
7417
7569
|
top: auto;
|
|
7418
7570
|
bottom: auto;
|
|
7419
7571
|
}
|
|
7572
|
+
/* Kaufen tab, desktop sidebar card (.fin-calc-card, NOT the .fin-modal sheet above) — the row
|
|
7573
|
+
sits lower in this card than the financing/leasing rows do, so the base "flush above" bottom:
|
|
7574
|
+
100% opens noticeably higher than the trigger; drops it closer instead. */
|
|
7575
|
+
.md3 .fin-calc-card .fin-toggle-addservices.fin-toggle-addservices--cash .fin-toggle-tooltip {
|
|
7576
|
+
bottom: -10%;
|
|
7577
|
+
}
|
|
7420
7578
|
.md3 .fin-modal .show-mobile .fin-toggle-tooltip {
|
|
7421
7579
|
border-radius: 11px;
|
|
7422
7580
|
}
|
|
@@ -7467,9 +7625,6 @@ color: #005CFF;
|
|
|
7467
7625
|
letter-spacing: 0.4px;
|
|
7468
7626
|
color: var(--md-on-surface-variant);
|
|
7469
7627
|
}
|
|
7470
|
-
.md3 .fin-calc-card .fin-toggle-addservices.fin-toggle-addservices--cash .md-title-sm .lucide {
|
|
7471
|
-
display: none;
|
|
7472
|
-
}
|
|
7473
7628
|
.md3 .fin-calc-card .fin-toggle-addservices.fin-toggle-addservices--cash .num,
|
|
7474
7629
|
.md3 .fin-calc-card .fin-toggle-addservices.fin-toggle-addservices--cash > div > span:last-child {
|
|
7475
7630
|
font-family: var(--md-font-display) !important;
|
|
@@ -8697,20 +8852,33 @@ color: #005CFF;
|
|
|
8697
8852
|
grid-template-areas: "rate evalcol" "cond cond";
|
|
8698
8853
|
align-items: start;
|
|
8699
8854
|
}
|
|
8855
|
+
/* Bug: switching the Financing/Leasing/Buy tabs made the price row, rating pill and the two
|
|
8856
|
+
CTA buttons below jump up/down, because the row above them had a different rendered height
|
|
8857
|
+
per tab: (a) .fin-cond (the "0 € Anzahlung · 60 Monate · ..." terms line) renders NOTHING on
|
|
8858
|
+
Buy (isCash hides it), collapsing to 0 height instead of one text line, and (b)
|
|
8859
|
+
.fin-price-grid--cash below zeroes the row-gap that the other two tabs keep. The two rules
|
|
8860
|
+
below cancel each of those, so Financing/Leasing/Buy all reserve the same total height.
|
|
8861
|
+
(A first pass also force-reserved height on .fin-rate-main itself, to additionally cover the
|
|
8862
|
+
rare case of an extra struck list-price line on Buy when the car has a discount — isCash &&
|
|
8863
|
+
showStrike in FinanceCalculator.tsx. Dropped: since Financing/Leasing/undiscounted-Buy don't
|
|
8864
|
+
need that extra room, it left a visible empty gap under the price on every normal tab just to
|
|
8865
|
+
pre-cover one edge case. That specific combination can still shift by the strike line's own
|
|
8866
|
+
height; every other tab switch is now jump-free without the dead space.) */
|
|
8867
|
+
.md3 .fin-calc-card .fin-price-grid.fin-price-grid--cash {
|
|
8868
|
+
/* same 12px row-gap as Financing/Leasing (the base .fin-price-grid rule) — the 0px gap on
|
|
8869
|
+
.fin-price-grid--cash further up this file otherwise pulls the CTA row 12px closer on Buy. */
|
|
8870
|
+
gap: 12px 15px;
|
|
8871
|
+
}
|
|
8700
8872
|
.md3 .fin-eval-col {
|
|
8701
8873
|
display: flex;
|
|
8702
8874
|
flex-direction: column;
|
|
8703
8875
|
gap: 16px;
|
|
8704
8876
|
grid-area: evalcol;
|
|
8705
8877
|
}
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
8710
|
-
height: 27px;
|
|
8711
|
-
box-sizing: border-box;
|
|
8712
|
-
justify-content: center;
|
|
8713
|
-
}
|
|
8878
|
+
/* box sizing for this pill (all three of its locations) lives in the shared, higher-specificity
|
|
8879
|
+
.cc-price/.fin-calc-card/.fin-modal rule near the top of this file — this generic, unscoped
|
|
8880
|
+
copy used to ALSO force `background: #dff3e5 !important`, silently overriding every tier's
|
|
8881
|
+
real inline color (the 'good' tier's canonical rgb(22,138,69) included) at this breakpoint. */
|
|
8714
8882
|
.md3 .fin-eval-bar {
|
|
8715
8883
|
height: 7px;
|
|
8716
8884
|
}
|
|
@@ -8735,6 +8903,11 @@ color: #005CFF;
|
|
|
8735
8903
|
font-weight: 400;
|
|
8736
8904
|
font-size: 13px;
|
|
8737
8905
|
line-height: 15px;
|
|
8906
|
+
/* matches the line-height above: on the Buy tab this div renders empty (its "0 € Anzahlung ·
|
|
8907
|
+
60 Monate · ..." text is Financing/Leasing-only), so without a floor it collapsed to 0
|
|
8908
|
+
height instead of the one text line the other two tabs occupy — part of the cross-tab
|
|
8909
|
+
layout-jump fix, see the .fin-rate-main comment above. */
|
|
8910
|
+
min-height: 15px;
|
|
8738
8911
|
color: #111820;
|
|
8739
8912
|
margin: 0px 0px;
|
|
8740
8913
|
margin-bottom: 12px;
|
|
@@ -10334,10 +10507,14 @@ color: #005CFF;
|
|
|
10334
10507
|
}
|
|
10335
10508
|
.md3 .vdp-photosheet {
|
|
10336
10509
|
position: absolute;
|
|
10337
|
-
left: 0
|
|
10338
|
-
|
|
10339
|
-
|
|
10340
|
-
|
|
10510
|
+
/* was `left/right/bottom: 0` + `height: 100vh` — over-constrained (top was the free value, so
|
|
10511
|
+
it was computed as containerHeight - 100vh) and, on the affected mobile browsers, 100vh can
|
|
10512
|
+
exceed the CURRENT visible height (e.g. address bar still shown), which solved to a NEGATIVE
|
|
10513
|
+
top: the sheet's top edge — its own header, with a close button — rendered above y=0 of this
|
|
10514
|
+
already-safely-sized fixed overlay (see VdpViewer.tsx's own top-of-file portal comment), i.e.
|
|
10515
|
+
behind the browser's UI. `inset: 0` instead just fills the (correctly-sized) positioned
|
|
10516
|
+
ancestor exactly, no viewport unit involved. */
|
|
10517
|
+
inset: 0;
|
|
10341
10518
|
z-index: 211;
|
|
10342
10519
|
display: flex;
|
|
10343
10520
|
flex-direction: column;
|
|
@@ -10356,7 +10533,9 @@ color: #005CFF;
|
|
|
10356
10533
|
align-items: center;
|
|
10357
10534
|
justify-content: center;
|
|
10358
10535
|
min-height: 88px;
|
|
10359
|
-
|
|
10536
|
+
/* safe-area-aware: with the `inset: 0` fix above this sits flush against the true top edge of
|
|
10537
|
+
the fullscreen overlay — same notch/status-bar territory as the main viewer's own header. */
|
|
10538
|
+
padding-top: max(10px, env(safe-area-inset-top));
|
|
10360
10539
|
touch-action: none;
|
|
10361
10540
|
}
|
|
10362
10541
|
.md3 .vdp-photosheet__handle {
|
|
@@ -10371,7 +10550,8 @@ color: #005CFF;
|
|
|
10371
10550
|
}
|
|
10372
10551
|
.md3 .vdp-photosheet__close {
|
|
10373
10552
|
position: absolute;
|
|
10374
|
-
|
|
10553
|
+
/* safe-area-aware: in the landscape layout the notch can rotate onto this side. */
|
|
10554
|
+
left: max(12px, env(safe-area-inset-left));
|
|
10375
10555
|
top: 50%;
|
|
10376
10556
|
transform: translateY(-50%);
|
|
10377
10557
|
}
|
|
@@ -10385,7 +10565,8 @@ color: #005CFF;
|
|
|
10385
10565
|
}
|
|
10386
10566
|
.md3 .vdp-photosheet__titles {
|
|
10387
10567
|
flex: none;
|
|
10388
|
-
|
|
10568
|
+
/* safe-area-aware left/right: landscape can rotate the notch onto either side. */
|
|
10569
|
+
padding: 0 max(16px, env(safe-area-inset-right)) 12px max(16px, env(safe-area-inset-left));
|
|
10389
10570
|
text-align: left;
|
|
10390
10571
|
}
|
|
10391
10572
|
.md3 .vdp-photosheet__title {
|
|
@@ -10408,7 +10589,9 @@ color: #005CFF;
|
|
|
10408
10589
|
flex: 1;
|
|
10409
10590
|
min-height: 0;
|
|
10410
10591
|
overflow-y: auto;
|
|
10411
|
-
|
|
10592
|
+
/* safe-area-aware left/right — otherwise the outer grid tiles can sit partly under a
|
|
10593
|
+
landscape-rotated notch, tappable in theory but visually cut off. */
|
|
10594
|
+
padding: 0 max(12px, env(safe-area-inset-right)) 12px max(12px, env(safe-area-inset-left));
|
|
10412
10595
|
}
|
|
10413
10596
|
.md3 .vdp-photosheet__grid {
|
|
10414
10597
|
display: grid;
|
|
@@ -10454,8 +10637,10 @@ color: #005CFF;
|
|
|
10454
10637
|
align-items: center;
|
|
10455
10638
|
justify-content: flex-start;
|
|
10456
10639
|
gap: 6px;
|
|
10457
|
-
height: 44px
|
|
10458
|
-
|
|
10640
|
+
/* was a fixed `height: 44px` — swapped for `min-height` so the safe-area bottom padding below
|
|
10641
|
+
(home indicator) grows the bar instead of pushing its text outside a clipped fixed box. */
|
|
10642
|
+
min-height: 44px;
|
|
10643
|
+
padding: 0 max(16px, env(safe-area-inset-right)) max(0px, env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
|
|
10459
10644
|
/* rgba(0,0,0,0.5) was invisible here — it darkens whatever's behind it, and the sheet's own
|
|
10460
10645
|
panel (rgb(6,11,18)) is already almost black, so a 50%-black overlay on top of near-black
|
|
10461
10646
|
reads as no change at all. #1c222c is lighter/bluer and already used elsewhere in this same
|
|
@@ -10507,7 +10692,7 @@ color: #005CFF;
|
|
|
10507
10692
|
right: 11px !important;
|
|
10508
10693
|
}
|
|
10509
10694
|
.md3 .cc-card .cc-badges {
|
|
10510
|
-
top:
|
|
10695
|
+
top: 18px !important;
|
|
10511
10696
|
}
|
|
10512
10697
|
|
|
10513
10698
|
/* 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[];
|
|
@@ -132,14 +130,31 @@ const CardCarousel: React.FunctionComponent<CardCarouselProps> = ({
|
|
|
132
130
|
))}
|
|
133
131
|
</div>
|
|
134
132
|
{/* arrows + dots only when there is actually something to switch to — with a single
|
|
135
|
-
image (e.g. SRP cards before their gallery is lazy-loaded) they are dead controls.
|
|
133
|
+
image (e.g. SRP cards before their gallery is lazy-loaded) they are dead controls.
|
|
134
|
+
States: single-image → n<=1 → hidden here (same "nothing to expand into" case as
|
|
135
|
+
GalleryCounter, cardParts.tsx). Loading → `images` starts as a 1-element array (the
|
|
136
|
+
card's main thumbnail) until the caller's lazy-load resolves, so this rule ALSO covers
|
|
137
|
+
"still loading" — arrows/dots simply aren't rendered yet, no skeleton, same discipline
|
|
138
|
+
as the other overlay controls. On touch devices this used to mean "hidden until the
|
|
139
|
+
user's first hover/touch on this exact card" (mouseenter/touchstart was the ONLY lazy-
|
|
140
|
+
load trigger) — CarCard's `eagerMedia` (see its own doc comment) starts that same load
|
|
141
|
+
on scroll-into-view instead, so this loading window is normally already closed by the
|
|
142
|
+
time the user reaches the card, without changing anything in this component. Desktop
|
|
143
|
+
hover-to-reveal (`.cardcar:hover .car-arrow`) vs. always-visible on touch is a CSS-only
|
|
144
|
+
concern — see `@media (hover: none)` in md3.css, not component state. */}
|
|
136
145
|
{n > 1 && (
|
|
137
146
|
<>
|
|
138
147
|
<button className="car-arrow car-arrow--l" aria-label="zurück" onClick={(e) => go(-1, e)}>
|
|
139
|
-
|
|
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>
|
|
140
153
|
</button>
|
|
141
154
|
<button className="car-arrow car-arrow--r" aria-label="weiter" onClick={(e) => go(1, e)}>
|
|
142
|
-
<
|
|
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>
|
|
143
158
|
</button>
|
|
144
159
|
<div
|
|
145
160
|
className="cardcar-dots"
|