@bytebrand/fe-ui-core-autobahn 1.0.114 → 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 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: '10px 18px', display: 'flex', flexDirection: 'column', gap: 0, flex: 1 }}>
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: 6 }} />
297
+ <SeoLine car={car} style={{ marginTop: 0 }} />
298
298
  {adminAction && (
299
299
  <div style={{ marginTop: 8 }}>
300
300
  <Button
@@ -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 { DocCheckIcon, EvalBar } from '../vdp/FinanceCalculator';
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: 8, borderTop: '1px solid var(--md-outline-variant)', paddingTop: 8 }}
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={{ flex: 2 }}
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
- <DocCheckIcon size={16} />
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
- icon="phone"
803
- style={{ flex: 'none', width: 44, padding: 0 }}
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
- icon="sliders-horizontal"
812
- style={{ flex: 1.5 }}
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>
@@ -86,7 +86,7 @@
86
86
  "priceRatingAria": "Preisbewertung: {{rating}}",
87
87
  "detailsShow": "Details anzeigen",
88
88
  "paymentLabel": "Zahlung",
89
- "paymentValue": "Zahlung per Überweisung",
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",
@@ -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.114",
3
+ "version": "1.0.115",
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: var(--md-r-full);
3402
- border: 0;
3403
- background: rgba(255, 255, 255, 0.92);
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: 22px;
3430
+ left: 10px;
3416
3431
  }
3417
3432
  .md3 .car-arrow--r {
3418
- right: 22px;
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
- grid-template-columns: 1fr 1fr;
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 {
@@ -6297,14 +6328,29 @@ line-height: 31px;
6297
6328
  /* Visible icon glyphs 24-28px (spec range) — the shared .icon-btn/.mbtn rules force 20px/18px
6298
6329
  everywhere else in the app, which is fine there but read visibly smaller than the Figma
6299
6330
  mobile header reference. */
6300
- .md3 header .icon-btn {
6301
- width: 48px;
6302
- height: 48px;
6303
- }
6304
6331
  .md3 header .icon-btn .lucide {
6305
6332
  width: 24px;
6306
6333
  height: 24px;
6307
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
+ }
6308
6354
  .md3 header .topbar-account-btn .lucide {
6309
6355
  width: 24px;
6310
6356
  height: 24px;
@@ -6319,6 +6365,13 @@ line-height: 31px;
6319
6365
  .md3 .topbar-logo {
6320
6366
  width: 122px;
6321
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;
6322
6375
  }
6323
6376
  /* Gap between action icons 2-6px (spec: "Abstand Aktionen") — separate from the wider gap the
6324
6377
  hamburger/logo/nav still use (that's the outer .container's own gap, untouched here). */
@@ -6640,6 +6693,13 @@ line-height: 31px;
6640
6693
  .md3 .cards-2 {
6641
6694
  grid-template-columns: 1fr;
6642
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
+ }
6643
6703
  /* listing card stacks: image (4:3) → info → price */
6644
6704
  .md3 .listcard {
6645
6705
  grid-template-columns: 1fr;
@@ -6738,7 +6798,7 @@ line-height: 31px;
6738
6798
  z-index: -1;
6739
6799
  }
6740
6800
  .md3 .field-grid-2 {
6741
- grid-template-columns: 1fr;
6801
+ grid-template-columns: minmax(0, 1fr);
6742
6802
  gap: 10px;
6743
6803
  }
6744
6804
  .md3 .hero-search {
@@ -7261,8 +7321,10 @@ line-height: 31px;
7261
7321
  z-index: 3;
7262
7322
  }
7263
7323
 
7264
- /* VDP main wrapper: phone gets a tighter top gap (10px) and narrower side gutters
7265
- (14px) than the 14/24px desktop default set inline. */
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. */
7266
7328
  @media (max-width: 600px) {
7267
7329
  .md3 .vdp-main {
7268
7330
  padding: 0 10px 48px !important;
@@ -7445,6 +7507,28 @@ color: #005CFF;
7445
7507
  line-height: 17px;
7446
7508
  color: #1D2A38;
7447
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
+ }
7448
7532
  .md3 .fin-toggle-addservices > div {
7449
7533
  gap: 13px !important;
7450
7534
  }
@@ -7485,6 +7569,12 @@ color: #005CFF;
7485
7569
  top: auto;
7486
7570
  bottom: auto;
7487
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
+ }
7488
7578
  .md3 .fin-modal .show-mobile .fin-toggle-tooltip {
7489
7579
  border-radius: 11px;
7490
7580
  }
@@ -7535,9 +7625,6 @@ color: #005CFF;
7535
7625
  letter-spacing: 0.4px;
7536
7626
  color: var(--md-on-surface-variant);
7537
7627
  }
7538
- .md3 .fin-calc-card .fin-toggle-addservices.fin-toggle-addservices--cash .md-title-sm .lucide {
7539
- display: none;
7540
- }
7541
7628
  .md3 .fin-calc-card .fin-toggle-addservices.fin-toggle-addservices--cash .num,
7542
7629
  .md3 .fin-calc-card .fin-toggle-addservices.fin-toggle-addservices--cash > div > span:last-child {
7543
7630
  font-family: var(--md-font-display) !important;
@@ -8765,6 +8852,23 @@ color: #005CFF;
8765
8852
  grid-template-areas: "rate evalcol" "cond cond";
8766
8853
  align-items: start;
8767
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
+ }
8768
8872
  .md3 .fin-eval-col {
8769
8873
  display: flex;
8770
8874
  flex-direction: column;
@@ -8799,6 +8903,11 @@ color: #005CFF;
8799
8903
  font-weight: 400;
8800
8904
  font-size: 13px;
8801
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;
8802
8911
  color: #111820;
8803
8912
  margin: 0px 0px;
8804
8913
  margin-bottom: 12px;
@@ -10583,7 +10692,7 @@ color: #005CFF;
10583
10692
  right: 11px !important;
10584
10693
  }
10585
10694
  .md3 .cc-card .cc-badges {
10586
- top: 15px !important;
10695
+ top: 18px !important;
10587
10696
  }
10588
10697
 
10589
10698
  /* hero price — Figma's rate figure (Finanzierung/Leasing) is much larger than the shared
@@ -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
- <Icon name="chevron-left" size={20} />
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
- <Icon name="chevron-right" size={20} />
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"