diff --git a/alfa-client/apps/demo/src/app/app.component.html b/alfa-client/apps/demo/src/app/app.component.html
index 81bc4dff284d5e739981af85b8d4e1cc0c4b3844..7dbdd36d8134a9a38fdd859b1371c5a0362820df 100644
--- a/alfa-client/apps/demo/src/app/app.component.html
+++ b/alfa-client/apps/demo/src/app/app.component.html
@@ -14,6 +14,16 @@
       <nav>NAV</nav>
     </div>
     <main class="flex-auto bg-background-50 p-6">
+      <div class="my-5">
+        <ods-instant-search
+          headerText="In der OZG-Cloud"
+          placeholder="zuständige Stelle suchen"
+          [control]="instantSearchFormControl"
+          [searchResults]="getInstantSearchResults()"
+          (searchResultSelected)="selectSearchResult($event)"
+          (searchQueryChanged)="onSearchQueryChanged($event)"
+        ></ods-instant-search>
+      </div>
       <div class="w-96">
         <ods-attachment-wrapper>
           <ods-attachment
@@ -21,6 +31,7 @@
             description="234 kB"
             fileType="pdf"
             isLoading="true"
+            loadingCaption="Mein_Bescheid.pdf wird heruntergeladen..."
           >
           </ods-attachment>
           <ods-attachment caption="Mein_Bescheid.xml" description="234 kB" fileType="xml">
@@ -94,7 +105,7 @@
             value="abgelehnt"
             variant="bescheid_abgelehnt"
           >
-            <ods-close-icon class="fill-abgelehnt" />
+            <ods-close-icon class="fill-abgelehnt" size="large" />
           </ods-radio-button-card>
         </div>
       </form>
@@ -209,14 +220,6 @@
             <p text class="text-center">Bescheiddokument<br />hochladen</p></ods-file-upload-button
           >
         </div>
-
-        <div class="mt-4">
-          <ods-file-upload-button class="w-72" [isLoading]="false" id="upload129">
-            <ods-bescheid-upload-icon />
-            <ods-spinner-icon spinner size="medium" />
-            <div text class="text-center">Anhang hochladen</div></ods-file-upload-button
-          >
-        </div>
         <div class="mt-4">
           <ods-file-upload-button class="w-72" [isLoading]="true" id="upload130">
             <ods-attachment-icon icon />
diff --git a/alfa-client/apps/demo/src/app/app.component.ts b/alfa-client/apps/demo/src/app/app.component.ts
index 5d64b15a623f2330d29201455ec298907bcd94fa..40addd4c8966f682e403357a673cb578348d5213 100644
--- a/alfa-client/apps/demo/src/app/app.component.ts
+++ b/alfa-client/apps/demo/src/app/app.component.ts
@@ -15,6 +15,7 @@ import {
   ErrorMessageComponent,
   FileIconComponent,
   FileUploadButtonComponent,
+  InstantSearchComponent,
   RadioButtonCardComponent,
   SaveIconComponent,
   SendIconComponent,
@@ -24,6 +25,11 @@ import {
   TextareaComponent,
 } from '@ods/system';
 
+import { EMPTY_STRING } from '@alfa-client/tech-shared';
+import {
+  InstantSearchQuery,
+  InstantSearchResult,
+} from 'libs/design-system/src/lib/instant-search/instant-search/instant-search.model';
 import { BescheidDialogExampleComponent } from './components/bescheid-dialog/bescheid-dialog.component';
 import { BescheidPaperComponent } from './components/bescheid-paper/bescheid-paper.component';
 import { BescheidStepperComponent } from './components/bescheid-stepper/bescheid-stepper.component';
@@ -46,6 +52,7 @@ import { CustomStepperComponent } from './components/cdk-demo/custom-stepper.com
     BescheidPaperComponent,
     RadioButtonCardComponent,
     ReactiveFormsModule,
+    InstantSearchComponent,
     SaveIconComponent,
     SendIconComponent,
     StampIconComponent,
@@ -64,14 +71,49 @@ import { CustomStepperComponent } from './components/cdk-demo/custom-stepper.com
   templateUrl: './app.component.html',
 })
 export class AppComponent {
-  title = 'demo';
-
   darkMode = signal<boolean>(JSON.parse(window.localStorage.getItem('darkMode') ?? 'false'));
 
   @HostBinding('class.dark') get mode() {
     return this.darkMode();
   }
 
+  title = 'demo';
+
+  instantSearchItems: InstantSearchResult<unknown>[] = [
+    {
+      title: 'Landeshauptstadt Kiel - Ordnungsamt, Gewerbe- und Schornsteinfegeraufsicht',
+      description: 'Fabrikstraße  8-10, 24103 Kiel',
+      data: { resource: 'dummy 1' },
+    },
+    {
+      title: 'Amt für Digitalisierung, Breitband und Vermessung Nürnberg Außenstelle Hersbruck',
+      description: 'Rathausmarkt 7, Hersbruck',
+      data: { resource: 'dummy 2' },
+    },
+    {
+      title: 'Amt für Digitalisierung, Breitband und Vermessung Stuttgart',
+      description: 'Rathausmarkt 7, Stuttgart',
+      data: { resource: 'dummy 3' },
+    },
+    {
+      title: 'Amt für Digitalisierung, Breitband und Vermessung Ulm',
+      description: 'Rathausmarkt 7, Ulm',
+      data: { resource: 'dummy 4' },
+    },
+  ];
+  instantSearchFormControl = new FormControl(EMPTY_STRING);
+
+  getInstantSearchResults() {
+    if (this.instantSearchFormControl.value.length < 2) return [];
+    return this.instantSearchItems.filter((item) =>
+      item.title.toLowerCase().includes(this.instantSearchFormControl.value.toLowerCase()),
+    );
+  }
+
+  selectSearchResult(result: InstantSearchResult<unknown>) {
+    console.log(result);
+  }
+
   exampleForm = new FormGroup({
     exampleName: new FormControl('bewilligt'),
   });
@@ -87,4 +129,8 @@ export class AppComponent {
       window.localStorage.setItem('darkMode', JSON.stringify(this.darkMode()));
     });
   }
+
+  public onSearchQueryChanged(searchQuery: InstantSearchQuery) {
+    console.info('Search query: %o', searchQuery);
+  }
 }
diff --git a/alfa-client/libs/bescheid/src/lib/beschieden-date-in-vorgang-container/beschieden-date-container/beschieden-date-container.component.html b/alfa-client/libs/bescheid/src/lib/beschieden-date-in-vorgang-container/beschieden-date-container/beschieden-date-container.component.html
index 704a6ddd28f903eee9a9fb887c8ac40d4d56683d..61ae1d119505cb9e60d173dce420dd872cfa784e 100644
--- a/alfa-client/libs/bescheid/src/lib/beschieden-date-in-vorgang-container/beschieden-date-container/beschieden-date-container.component.html
+++ b/alfa-client/libs/bescheid/src/lib/beschieden-date-in-vorgang-container/beschieden-date-container/beschieden-date-container.component.html
@@ -9,7 +9,6 @@
     <ods-close-icon
       *ngIf="!bescheid.bewilligt"
       data-test-id="abgelehnt-icon"
-      size="small"
       class="fill-abgelehnt"
     />
 
diff --git a/alfa-client/libs/design-system/src/index.ts b/alfa-client/libs/design-system/src/index.ts
index 5934b94acda30b1a9db2264244086f3d11bdcdbf..9a59b13cbc25c6174275daa3727bdd8388fb0dc4 100644
--- a/alfa-client/libs/design-system/src/index.ts
+++ b/alfa-client/libs/design-system/src/index.ts
@@ -22,4 +22,5 @@ export * from './lib/icons/save-icon/save-icon.component';
 export * from './lib/icons/send-icon/send-icon.component';
 export * from './lib/icons/spinner-icon/spinner-icon.component';
 export * from './lib/icons/stamp-icon/stamp-icon.component';
+export * from './lib/instant-search/instant-search/instant-search.component';
 export * from './lib/testbtn/testbtn.component';
diff --git a/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.component.spec.ts b/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c0848c08f798f58fd91f850597ce0d15f267e065
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { AriaLiveRegionComponent } from './aria-live-region.component';
+
+describe('AriaLiveRegionComponent', () => {
+  let component: AriaLiveRegionComponent;
+  let fixture: ComponentFixture<AriaLiveRegionComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [AriaLiveRegionComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(AriaLiveRegionComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.component.ts b/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3cec9afff4c23502077704daea8b04f125158bdd
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.component.ts
@@ -0,0 +1,12 @@
+import { CommonModule } from '@angular/common';
+import { Component, Input } from '@angular/core';
+
+@Component({
+  selector: 'ods-aria-live-region',
+  standalone: true,
+  imports: [CommonModule],
+  template: `<span aria-live="polite" class="sr-only" role="status">{{ text }}</span>`,
+})
+export class AriaLiveRegionComponent {
+  @Input() text: string = '';
+}
diff --git a/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.stories.ts b/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7af950ebf415e5e2a634be01a2edaa32a9d78a01
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.stories.ts
@@ -0,0 +1,25 @@
+import { argsToTemplate, type Meta, type StoryObj } from '@storybook/angular';
+import { AriaLiveRegionComponent } from './aria-live-region.component';
+
+const meta: Meta<AriaLiveRegionComponent> = {
+  title: 'Aria live region',
+  component: AriaLiveRegionComponent,
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<AriaLiveRegionComponent>;
+
+export const Default: Story = {
+  args: {
+    text: '',
+  },
+  render: (args) => ({
+    props: args,
+    template: `
+      <h2>This component is suitable for screen reader. Fill text field to make screen reader read it aloud.</h2>
+      <ods-aria-live-region ${argsToTemplate(args)} />
+    `,
+  }),
+};
diff --git a/alfa-client/libs/design-system/src/lib/attachment-wrapper/attachment-wrapper.stories.ts b/alfa-client/libs/design-system/src/lib/attachment-wrapper/attachment-wrapper.stories.ts
index 485acda2600b59166e331fe38bffba7392c1e783..7d8f0fbec59aeb00afc99d2377c1902abd20c73d 100644
--- a/alfa-client/libs/design-system/src/lib/attachment-wrapper/attachment-wrapper.stories.ts
+++ b/alfa-client/libs/design-system/src/lib/attachment-wrapper/attachment-wrapper.stories.ts
@@ -1,7 +1,8 @@
-import { argsToTemplate, moduleMetadata, type Meta, type StoryObj } from '@storybook/angular';
+import { moduleMetadata, type Meta, type StoryObj } from '@storybook/angular';
 
 import { DownloadButtonComponent } from '../../../../design-component/src/lib/download-button/download-button.component';
 
+import { AttachmentHeaderComponent } from '../attachment-header/attachment-header.component';
 import { AttachmentComponent } from '../attachment/attachment.component';
 import { AttachmentWrapperComponent } from './attachment-wrapper.component';
 
@@ -17,7 +18,12 @@ const meta: Meta<AttachmentWrapperComponent> = {
   },
   decorators: [
     moduleMetadata({
-      imports: [AttachmentWrapperComponent, AttachmentComponent, DownloadButtonComponent],
+      imports: [
+        AttachmentWrapperComponent,
+        AttachmentComponent,
+        DownloadButtonComponent,
+        AttachmentHeaderComponent,
+      ],
     }),
   ],
   excludeStories: /.*Data$/,
@@ -28,18 +34,11 @@ export default meta;
 type Story = StoryObj<AttachmentWrapperComponent>;
 
 export const Default: Story = {
-  args: {
-    title: 'Anhänge',
-  },
-  argTypes: {
-    title: {
-      description: 'Title for group of files',
-    },
-  },
-  render: (args) => ({
-    props: args,
-    template: `<ods-attachment-wrapper ${argsToTemplate(args)}>
-        <ods-download-button action-buttons />
+  render: () => ({
+    template: `<ods-attachment-wrapper>
+        <ods-attachment-header title="Anhänge">
+          <ods-download-button action-buttons />
+        </ods-attachment-header>
         <ods-attachment caption="Attachment" description="200 kB" fileType="pdf"></ods-attachment>
         <ods-attachment caption="Second attachment" description="432 kB" fileType="doc"></ods-attachment>
     </ods-attachment-wrapper>`,
diff --git a/alfa-client/libs/design-system/src/lib/bescheid-status-text/bescheid-status-text.component.ts b/alfa-client/libs/design-system/src/lib/bescheid-status-text/bescheid-status-text.component.ts
index 9ed55dd799191cfb77c2462d25a357425f60c2ab..586fcb8a140c698f4e90a5d8b0b53f0e97556ac8 100644
--- a/alfa-client/libs/design-system/src/lib/bescheid-status-text/bescheid-status-text.component.ts
+++ b/alfa-client/libs/design-system/src/lib/bescheid-status-text/bescheid-status-text.component.ts
@@ -13,7 +13,7 @@ import { StampIconComponent } from '../icons/stamp-icon/stamp-icon.component';
       ><ods-stamp-icon size="medium" class="fill-bewilligt" />Bewilligt am {{ dateText }}</span
     >
     <span class="flex items-center gap-2" *ngIf="!bewilligt"
-      ><ods-close-icon size="medium" class="fill-abgelehnt" />Abgelehnt am
+      ><ods-close-icon class="fill-abgelehnt" />Abgelehnt am
       {{ dateText }}
     </span>
     <span
diff --git a/alfa-client/libs/design-system/src/lib/form/radio-button-card/radio-button-card.stories.ts b/alfa-client/libs/design-system/src/lib/form/radio-button-card/radio-button-card.stories.ts
index 96ec7406916b5f4773f6aa448ad12112c913ebfc..dd949aeef16caab452a0ee6c8aee76bb0624cd79 100644
--- a/alfa-client/libs/design-system/src/lib/form/radio-button-card/radio-button-card.stories.ts
+++ b/alfa-client/libs/design-system/src/lib/form/radio-button-card/radio-button-card.stories.ts
@@ -53,7 +53,7 @@ export const Default: Story = {
       value="abgelehnt"
       variant="bescheid_abgelehnt"
     >
-      <ods-close-icon class="fill-abgelehnt" />
+      <ods-close-icon class="fill-abgelehnt" size="large" />
     </ods-radio-button-card>
   </div>`,
   }),
diff --git a/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.ts b/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.ts
index e136a50bb991af6df9384d7ceca287879b3cdcc8..a374f53e940446a07e40774135bdb40d7578461d 100644
--- a/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.ts
+++ b/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.ts
@@ -1,12 +1,12 @@
-import { convertForDataTest, TechSharedModule } from '@alfa-client/tech-shared';
+import { convertForDataTest, EMPTY_STRING, TechSharedModule } from '@alfa-client/tech-shared';
 import { CommonModule } from '@angular/common';
-import { Component, ElementRef, Input, ViewChild } from '@angular/core';
+import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core';
 import { FormControl, ReactiveFormsModule } from '@angular/forms';
 import { cva, VariantProps } from 'class-variance-authority';
 import { ErrorMessageComponent } from '../error-message/error-message.component';
 
 const textInputVariants = cva(
-  'block w-full rounded-lg border bg-background-50 px-3 py-2 text-base leading-5 text-text focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2',
+  'w-full h-10 rounded-lg border bg-background-50 px-3 py-2 text-base leading-5 text-text focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2',
   {
     variants: {
       variant: {
@@ -28,23 +28,40 @@ type TextInputVariants = VariantProps<typeof textInputVariants>;
   standalone: true,
   imports: [CommonModule, ErrorMessageComponent, ReactiveFormsModule, TechSharedModule],
   template: `
-    <div>
+    <div class="relative">
       <label [for]="id" class="text-md mb-2 block font-medium text-text">
         {{ inputLabel }}<ng-container *ngIf="required"><i aria-hidden="true">*</i></ng-container>
       </label>
       <div class="mt-2">
+        <div
+          *ngIf="withPrefix"
+          class="pointer-events-none absolute bottom-2 left-2 flex size-6 items-center justify-center"
+        >
+          <ng-content select="[prefix]" />
+        </div>
         <input
           type="text"
           [id]="id"
           [formControl]="fieldControl"
-          [ngClass]="textInputVariants({ variant })"
+          [ngClass]="[
+            textInputVariants({ variant }),
+            withPrefix ? 'pl-10' : '',
+            withSuffix ? 'pr-10' : '',
+          ]"
           [placeholder]="placeholder"
           [autocomplete]="autocomplete"
           [attr.aria-required]="required"
           [attr.aria-invalid]="variant === 'error'"
           [attr.data-test-id]="(inputLabel | convertForDataTest) + '-text-input'"
+          (click)="clickEmitter.emit()"
           #inputElement
         />
+        <div
+          *ngIf="withSuffix"
+          class="absolute bottom-2 right-2 flex size-6 items-center justify-center"
+        >
+          <ng-content select="[suffix]" />
+        </div>
       </div>
       <ng-content select="[error]"></ng-content>
     </div>
@@ -60,8 +77,10 @@ export class TextInputComponent {
   @Input() placeholder: string = '';
   @Input() autocomplete: string = 'off';
   @Input() variant: TextInputVariants['variant'];
-  @Input() fieldControl: FormControl;
+  @Input() fieldControl: FormControl = new FormControl(EMPTY_STRING);
   @Input() required: boolean = false;
+  @Input() withPrefix: boolean = false;
+  @Input() withSuffix: boolean = false;
 
   @Input() set focus(value: boolean) {
     if (value && this.inputElement) {
@@ -69,6 +88,8 @@ export class TextInputComponent {
     }
   }
 
+  @Output() clickEmitter: EventEmitter<MouseEvent> = new EventEmitter<MouseEvent>();
+
   inputLabel: string;
   id: string;
   textInputVariants = textInputVariants;
diff --git a/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts b/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts
index 90a4fa85f7dcb0b5a55f6a926a0d08ab63e332a9..da75590e40ed4afedee224ff82f89a741c9d5bef 100644
--- a/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts
+++ b/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts
@@ -1,4 +1,4 @@
-import { TechSharedModule, convertForDataTest } from '@alfa-client/tech-shared';
+import { EMPTY_STRING, TechSharedModule, convertForDataTest } from '@alfa-client/tech-shared';
 import { CommonModule } from '@angular/common';
 import { Component, ElementRef, Input, ViewChild } from '@angular/core';
 import { FormControl, ReactiveFormsModule } from '@angular/forms';
@@ -59,7 +59,7 @@ export class TextareaComponent {
   @Input() rows: number = 3;
   @Input() autocomplete: string = 'off';
   @Input() variant: TextareaVariants['variant'];
-  @Input() fieldControl: FormControl;
+  @Input() fieldControl: FormControl = new FormControl(EMPTY_STRING);
   @Input() required: boolean = false;
 
   @Input() set focus(value: boolean) {
diff --git a/alfa-client/libs/design-system/src/lib/icons/close-icon/close-icon.component.ts b/alfa-client/libs/design-system/src/lib/icons/close-icon/close-icon.component.ts
index 5de688d73e98d67b1296d1519332fd7e3b7c9660..48fe0de3b897881d8bb669774572ea8f68a6895e 100644
--- a/alfa-client/libs/design-system/src/lib/icons/close-icon/close-icon.component.ts
+++ b/alfa-client/libs/design-system/src/lib/icons/close-icon/close-icon.component.ts
@@ -12,16 +12,16 @@ import { IconVariants, iconVariants } from '../iconVariants';
     xmlns="http://www.w3.org/2000/svg"
     [ngClass]="[twMerge(iconVariants({ size }), 'fill-black', class)]"
     aria-hidden="true"
-    viewBox="0 0 14 14"
+    viewBox="0 0 24 24"
     fill="inherit"
   >
     <path
-      d="M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z"
+      d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41Z"
     />
   </svg>`,
 })
 export class CloseIconComponent {
-  @Input() size: IconVariants['size'] = 'small';
+  @Input() size: IconVariants['size'] = 'medium';
   @Input() class: string = undefined;
 
   iconVariants = iconVariants;
diff --git a/alfa-client/libs/design-system/src/lib/icons/close-icon/close-icon.stories.ts b/alfa-client/libs/design-system/src/lib/icons/close-icon/close-icon.stories.ts
index b8a8eda0b8afab576ba5b7086d226aa2f0adcc96..9cd750050413bd481bcdc246810c8eeb24b53c8c 100644
--- a/alfa-client/libs/design-system/src/lib/icons/close-icon/close-icon.stories.ts
+++ b/alfa-client/libs/design-system/src/lib/icons/close-icon/close-icon.stories.ts
@@ -20,7 +20,7 @@ export const Default: Story = {
       options: ['small', 'medium', 'large', 'extra-large', 'full'],
       description: 'Size of icon. Property "full" means 100%',
       table: {
-        defaultValue: { summary: 'small' },
+        defaultValue: { summary: 'medium' },
       },
     },
   },
diff --git a/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.component.spec.ts b/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5981e81db28b29d1dfe651b306e3f3f938ec0bfb
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { SearchIconComponent } from './search-icon.component';
+
+describe('SearchIconComponent', () => {
+  let component: SearchIconComponent;
+  let fixture: ComponentFixture<SearchIconComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [SearchIconComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(SearchIconComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.component.ts b/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..641713c3842c42cadb4d4075051fc51141d5f2e3
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.component.ts
@@ -0,0 +1,28 @@
+import { NgClass } from '@angular/common';
+import { Component, Input } from '@angular/core';
+import { twMerge } from 'tailwind-merge';
+
+import { IconVariants, iconVariants } from '../iconVariants';
+
+@Component({
+  selector: 'ods-search-icon',
+  standalone: true,
+  imports: [NgClass],
+  template: `<svg
+    [ngClass]="twMerge(iconVariants({ size }), 'fill-primary', class)"
+    viewBox="0 0 24 24"
+    fill="none"
+    xmlns="http://www.w3.org/2000/svg"
+  >
+    <path
+      d="M15.5 14H14.71L14.43 13.73C15.41 12.59 16 11.11 16 9.5C16 5.91 13.09 3 9.5 3C5.91 3 3 5.91 3 9.5C3 13.09 5.91 16 9.5 16C11.11 16 12.59 15.41 13.73 14.43L14 14.71V15.5L19 20.49L20.49 19L15.5 14ZM9.5 14C7.01 14 5 11.99 5 9.5C5 7.01 7.01 5 9.5 5C11.99 5 14 7.01 14 9.5C14 11.99 11.99 14 9.5 14Z"
+    />
+  </svg>`,
+})
+export class SearchIconComponent {
+  @Input() size: IconVariants['size'] = 'medium';
+  @Input() class: string = '';
+
+  iconVariants = iconVariants;
+  twMerge = twMerge;
+}
diff --git a/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.stories.ts b/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1952260187ba8fc7f462803ad2e2674f6d071856
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.stories.ts
@@ -0,0 +1,27 @@
+import type { Meta, StoryObj } from '@storybook/angular';
+
+import { SearchIconComponent } from './search-icon.component';
+
+const meta: Meta<SearchIconComponent> = {
+  title: 'Icons/Search icon',
+  component: SearchIconComponent,
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<SearchIconComponent>;
+
+export const Default: Story = {
+  args: { size: 'large' },
+  argTypes: {
+    size: {
+      control: 'select',
+      options: ['small', 'medium', 'large', 'extra-large', 'full'],
+      description: 'Size of icon. Property "full" means 100%',
+      table: {
+        defaultValue: { summary: 'medium' },
+      },
+    },
+  },
+};
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.component.spec.ts b/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f900a81ba73a568c8be41ba225930acfc7d687a0
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.component.spec.ts
@@ -0,0 +1,609 @@
+import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
+import { EventEmitter } from '@angular/core';
+import {
+  ComponentFixture,
+  TestBed,
+  discardPeriodicTasks,
+  fakeAsync,
+  tick,
+} from '@angular/core/testing';
+import { Subscription } from 'rxjs';
+import { InstantSearchComponent } from './instant-search.component';
+import { InstantSearchQuery, InstantSearchResult } from './instant-search.model';
+
+describe('InstantSearchComponent', () => {
+  let component: InstantSearchComponent;
+  let fixture: ComponentFixture<InstantSearchComponent>;
+
+  const searchResults: InstantSearchResult<unknown>[] = [
+    { title: 'test', description: 'test' },
+    { title: 'caption', description: 'desc' },
+  ];
+  const searchBy: string = 'query';
+
+  let searchQueryChanged: Mock<EventEmitter<any>>;
+  let searchResultSelected: Mock<EventEmitter<any>>;
+
+  beforeEach(async () => {
+    searchQueryChanged = <any>mock(EventEmitter);
+    searchResultSelected = <any>mock(EventEmitter);
+
+    await TestBed.configureTestingModule({
+      imports: [InstantSearchComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(InstantSearchComponent);
+    component = fixture.componentInstance;
+    component.searchQueryChanged = useFromMock(searchQueryChanged);
+    component.searchResultSelected = useFromMock(searchResultSelected);
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('ngOnInit', () => {
+    it('should handle value changes', () => {
+      component.handleValueChanges = jest.fn();
+
+      component.ngOnInit();
+
+      expect(component.handleValueChanges).toHaveBeenCalled();
+    });
+  });
+
+  describe('handleValueChanges', () => {
+    beforeEach(() => {
+      component.showResults = jest.fn();
+    });
+
+    it('should subscribe to value changes', () => {
+      component.control.valueChanges.subscribe = jest.fn();
+
+      component.handleValueChanges();
+
+      expect(component.control.valueChanges.subscribe).toHaveBeenCalled();
+    });
+
+    it('should emit query', fakeAsync(() => {
+      component.handleValueChanges();
+
+      component.control.setValue(searchBy);
+
+      tick(InstantSearchComponent.DEBOUNCE_TIME_IN_MILLIS);
+      component.control.valueChanges.subscribe();
+
+      expect(searchQueryChanged.emit).toHaveBeenCalledWith({ searchBy } as InstantSearchQuery);
+    }));
+
+    it('should not emit query', fakeAsync(() => {
+      component.handleValueChanges();
+
+      const searchBy: string = 'q';
+      component.control.setValue(searchBy);
+
+      tick(InstantSearchComponent.DEBOUNCE_TIME_IN_MILLIS);
+      component.control.valueChanges.subscribe();
+
+      expect(searchQueryChanged.emit).not.toHaveBeenCalled();
+    }));
+
+    describe('result are already visible', () => {
+      beforeEach(() => {
+        component.areResultsVisible = true;
+      });
+
+      it('should not show results', fakeAsync(() => {
+        component.handleValueChanges();
+
+        component.control.setValue(searchBy);
+        tick(InstantSearchComponent.DEBOUNCE_TIME_IN_MILLIS);
+
+        component.control.valueChanges.subscribe();
+        expect(component.showResults).not.toHaveBeenCalled();
+
+        discardPeriodicTasks();
+      }));
+    });
+
+    describe('results are not visible', () => {
+      beforeEach(() => {
+        component.areResultsVisible = false;
+      });
+
+      it('should show results', fakeAsync(() => {
+        component.handleValueChanges();
+
+        component.control.setValue(searchBy);
+        tick(InstantSearchComponent.DEBOUNCE_TIME_IN_MILLIS);
+
+        component.control.valueChanges.subscribe();
+        expect(component.showResults).toHaveBeenCalled();
+
+        discardPeriodicTasks();
+      }));
+
+      it('should not show results if debounce time not reached', fakeAsync(() => {
+        component.handleValueChanges();
+
+        component.control.setValue(searchBy);
+        tick(InstantSearchComponent.DEBOUNCE_TIME_IN_MILLIS - 1);
+
+        component.control.valueChanges.subscribe();
+        expect(component.showResults).not.toHaveBeenCalled();
+
+        discardPeriodicTasks();
+      }));
+
+      it('should not show results if not enough characters entered', fakeAsync(() => {
+        component.handleValueChanges();
+
+        component.control.setValue('q');
+        tick(InstantSearchComponent.DEBOUNCE_TIME_IN_MILLIS);
+
+        component.control.valueChanges.subscribe();
+        expect(component.showResults).not.toHaveBeenCalled();
+
+        discardPeriodicTasks();
+      }));
+    });
+  });
+
+  describe('ngOnDestroy', () => {
+    it('should subscribe to value changes', () => {
+      component.formControlSubscription = new Subscription();
+      component.formControlSubscription.unsubscribe = jest.fn();
+
+      component.ngOnDestroy();
+
+      expect(component.formControlSubscription.unsubscribe).toHaveBeenCalled();
+    });
+  });
+
+  describe('set searchResults', () => {
+    describe('on different results', () => {
+      it('should call setSearchResults', () => {
+        component.setSearchResults = jest.fn();
+
+        component.searchResults = searchResults;
+
+        expect(component.setSearchResults).toHaveBeenCalled();
+      });
+    });
+
+    describe('on same results', () => {
+      it('should not call setSearchResults', () => {
+        component.setSearchResults = jest.fn();
+
+        component.searchResults = [];
+
+        expect(component.setSearchResults).not.toHaveBeenCalled();
+      });
+    });
+
+    describe('on null or undefined', () => {
+      it.each([null, undefined])(
+        'should not call setSearchResults for %s',
+        (searchResults: InstantSearchResult<unknown>[]) => {
+          component.setSearchResults = jest.fn();
+
+          component.searchResults = searchResults;
+
+          expect(component.setSearchResults).not.toHaveBeenCalled();
+        },
+      );
+    });
+  });
+
+  describe('setSearchResults', () => {
+    it('should set results', () => {
+      component.setSearchResults(searchResults);
+
+      expect(component.results).toEqual(searchResults);
+    });
+
+    it('should call buildAriaLiveText with search results length', () => {
+      component.buildAriaLiveText = jest.fn();
+
+      component.setSearchResults(searchResults);
+
+      expect(component.buildAriaLiveText).toHaveBeenCalledWith(searchResults.length);
+    });
+  });
+
+  describe('setFocusOnResultItem', () => {
+    beforeEach(() => {
+      component.resultsRef.get = jest.fn().mockReturnValue({ setFocus: jest.fn() });
+    });
+
+    it('should call get for resultsRef with index', () => {
+      component.setFocusOnResultItem(1);
+
+      expect(component.resultsRef.get).toHaveBeenCalledWith(1);
+    });
+
+    it('should call setFocus', () => {
+      component.setFocusOnResultItem(1);
+
+      expect(component.resultsRef.get(1).setFocus).toHaveBeenCalled();
+    });
+  });
+
+  describe('handleArrowNavigation', () => {
+    const event: KeyboardEvent = new KeyboardEvent('arrow');
+
+    beforeEach(() => {
+      component.getResultIndexForKey = jest.fn();
+      component.setFocusOnResultItem = jest.fn();
+    });
+
+    it('should call prevent default', () => {
+      event.preventDefault = jest.fn();
+
+      component.handleArrowNavigation(event);
+
+      expect(event.preventDefault).toHaveBeenCalled();
+    });
+
+    it('should call getResultIndexForKey', () => {
+      component.handleArrowNavigation(event);
+
+      expect(component.getResultIndexForKey).toHaveBeenCalledWith(event.key);
+    });
+
+    it('should call setFocusOnResultItem', () => {
+      component.getResultIndexForKey = jest.fn().mockReturnValue(0);
+
+      component.handleArrowNavigation(event);
+
+      expect(component.setFocusOnResultItem).toHaveBeenCalledWith(0);
+    });
+  });
+
+  describe('handleEscape', () => {
+    const event: KeyboardEvent = new KeyboardEvent('esc');
+
+    it('should call prevent default', () => {
+      event.preventDefault = jest.fn();
+
+      component.handleEscape(event);
+
+      expect(event.preventDefault).toHaveBeenCalled();
+    });
+
+    it('should call hideResults', () => {
+      component.hideResults = jest.fn();
+
+      component.handleEscape(event);
+
+      expect(component.hideResults).toHaveBeenCalled();
+    });
+  });
+
+  describe('getNextResultIndex', () => {
+    it('should return 0 if index is undefined', () => {
+      const result: number = component.getNextResultIndex(undefined, 2);
+
+      expect(result).toBe(0);
+    });
+
+    it('should return 0 if current index is last', () => {
+      const result: number = component.getNextResultIndex(1, 2);
+
+      expect(result).toBe(0);
+    });
+
+    it('should return next search result index', () => {
+      const result: number = component.getNextResultIndex(0, 2);
+
+      expect(result).toBe(1);
+    });
+  });
+
+  describe('getPreviousResultIndex', () => {
+    it('should return last index if current index is undefined', () => {
+      const result: number = component.getPreviousResultIndex(undefined, 2);
+
+      expect(result).toBe(1);
+    });
+
+    it('should return last index if current index is first', () => {
+      const result: number = component.getPreviousResultIndex(0, 2);
+
+      expect(result).toBe(1);
+    });
+
+    it('should return previous search result index', () => {
+      const result: number = component.getPreviousResultIndex(1, 2);
+
+      expect(result).toBe(0);
+    });
+  });
+
+  describe('getResultIndexForKey', () => {
+    it('should call getNextResultIndex if ArrowDown', () => {
+      component.getNextResultIndex = jest.fn();
+
+      component.getResultIndexForKey('ArrowDown');
+
+      expect(component.getNextResultIndex).toHaveBeenCalled();
+    });
+
+    it('should call getPreviousResultIndex if ArrowUp', () => {
+      component.getPreviousResultIndex = jest.fn();
+
+      component.getResultIndexForKey('ArrowUp');
+
+      expect(component.getPreviousResultIndex).toHaveBeenCalled();
+    });
+  });
+
+  describe('getLastItemIndex', () => {
+    it('should return 0', () => {
+      const result: number = component.getLastItemIndex(0);
+
+      expect(result).toBe(0);
+    });
+
+    it('should return decrement of array length', () => {
+      const result: number = component.getLastItemIndex(5);
+
+      expect(result).toBe(4);
+    });
+  });
+
+  describe('buildAriaLiveText', () => {
+    beforeEach(() => {
+      component.control.setValue('test');
+    });
+
+    it('should return text for one result', () => {
+      const result: string = component.buildAriaLiveText(1);
+
+      expect(result).toBe(
+        'Ein Suchergebnis für Eingabe test. Nutze Pfeiltaste nach unten, um das zu erreichen.',
+      );
+    });
+
+    it('should return text for many results', () => {
+      const result: string = component.buildAriaLiveText(4);
+
+      expect(result).toBe(
+        '4 Suchergebnisse für Eingabe test. Nutze Pfeiltaste nach unten, um diese zu erreichen.',
+      );
+    });
+
+    it('should return text for no results', () => {
+      const result: string = component.buildAriaLiveText(0);
+
+      expect(result).toBe('Keine Ergebnisse');
+    });
+  });
+
+  describe('showResults', () => {
+    it('should set isShowResults to true', () => {
+      component.showResults();
+
+      expect(component.areResultsVisible).toBe(true);
+    });
+  });
+
+  describe('hideResults', () => {
+    it('should set isShowResults to false', () => {
+      component.hideResults();
+
+      expect(component.areResultsVisible).toBe(false);
+    });
+  });
+
+  describe('onKeydownHandler', () => {
+    const keyboardEvent: KeyboardEvent = new KeyboardEvent('a');
+
+    beforeEach(() => {
+      component.isSearchResultsEmpty = jest.fn();
+      component.isArrowNavigationKey = jest.fn();
+      component.isEscapeKey = jest.fn();
+      component.handleArrowNavigation = jest.fn();
+      component.handleEscape = jest.fn();
+    });
+
+    it('should check for empty result', () => {
+      component.onKeydownHandler(keyboardEvent);
+
+      expect(component.isSearchResultsEmpty).toHaveBeenCalled();
+    });
+
+    describe('search result is empty', () => {
+      beforeEach(() => {
+        component.isSearchResultsEmpty = jest.fn().mockReturnValue(true);
+      });
+
+      it('should ignore key navigation', () => {
+        component.onKeydownHandler(keyboardEvent);
+
+        expect(component.isArrowNavigationKey).not.toHaveBeenCalled();
+      });
+
+      it('should ignore escape key handling', () => {
+        component.onKeydownHandler(keyboardEvent);
+
+        expect(component.isEscapeKey).not.toHaveBeenCalled();
+      });
+    });
+
+    describe('search result is not empty', () => {
+      beforeEach(() => {
+        component.isSearchResultsEmpty = jest.fn().mockReturnValue(false);
+      });
+
+      it('should check if arrow navigation', () => {
+        component.onKeydownHandler(keyboardEvent);
+
+        expect(component.isArrowNavigationKey).toHaveBeenCalled();
+      });
+
+      it('should handle arrow navigation', () => {
+        component.isArrowNavigationKey = jest.fn().mockReturnValue(true);
+
+        component.onKeydownHandler(keyboardEvent);
+
+        expect(component.handleArrowNavigation).toHaveBeenCalled();
+      });
+
+      it('should not handle arrow navigation', () => {
+        component.isArrowNavigationKey = jest.fn().mockReturnValue(false);
+
+        component.onKeydownHandler(keyboardEvent);
+
+        expect(component.handleArrowNavigation).not.toHaveBeenCalled();
+      });
+
+      describe('is not arrow navigation', () => {
+        beforeEach(() => {
+          component.isArrowNavigationKey = jest.fn().mockReturnValue(false);
+        });
+
+        it('should check for escape key', () => {
+          component.onKeydownHandler(keyboardEvent);
+
+          expect(component.isEscapeKey).toHaveBeenCalled();
+        });
+
+        it('should handle escape key', () => {
+          component.isEscapeKey = jest.fn().mockReturnValue(true);
+
+          component.onKeydownHandler(keyboardEvent);
+
+          expect(component.handleEscape).toHaveBeenCalled();
+        });
+
+        it('should not handle escape key', () => {
+          component.isEscapeKey = jest.fn().mockReturnValue(false);
+
+          component.onKeydownHandler(keyboardEvent);
+
+          expect(component.handleEscape).not.toHaveBeenCalled();
+        });
+      });
+    });
+  });
+
+  describe('isSearchResultsEmpty', () => {
+    it('should return true', () => {
+      component.results = [];
+
+      const result: boolean = component.isSearchResultsEmpty();
+
+      expect(result).toBe(true);
+    });
+
+    it('should return false', () => {
+      component.results = searchResults;
+
+      const result: boolean = component.isSearchResultsEmpty();
+
+      expect(result).toBe(false);
+    });
+  });
+
+  describe('isArrowNavigationKey', () => {
+    it.each(['ArrowUp', 'ArrowDown'])('should return true for key %s', (key: string) => {
+      const keyboardEvent: KeyboardEvent = { ...new KeyboardEvent('key'), key };
+
+      const result: boolean = component.isArrowNavigationKey(keyboardEvent);
+
+      expect(result).toBeTruthy();
+    });
+
+    it('should return false', () => {
+      const result: boolean = component.isArrowNavigationKey(new KeyboardEvent('not arrow'));
+
+      expect(result).toBe(false);
+    });
+  });
+
+  describe('isEscapeKey', () => {
+    it('should return true', () => {
+      const escapeKeyEvent = { ...new KeyboardEvent('esc'), key: 'Escape' };
+
+      const result: boolean = component.isEscapeKey(escapeKeyEvent);
+
+      expect(result).toBe(true);
+    });
+
+    it('should return false', () => {
+      const result: boolean = component.isEscapeKey(new KeyboardEvent('not escape'));
+
+      expect(result).toBe(false);
+    });
+  });
+
+  describe('isLastItemOrOutOfArray', () => {
+    it.each([3, 5])('should return true for %s', (index: number) => {
+      const result: boolean = component.isLastItemOrOutOfArray(index, 4);
+
+      expect(result).toBe(true);
+    });
+
+    it('should return false', () => {
+      const result: boolean = component.isLastItemOrOutOfArray(1, 3);
+
+      expect(result).toBe(false);
+    });
+  });
+
+  describe('isFirstItemOrOutOfArray', () => {
+    it.each([0, -1])('should return true for %s', (index: number) => {
+      const result: boolean = component.isFirstItemOrOutOfArray(index);
+
+      expect(result).toBe(true);
+    });
+
+    it('should return false', () => {
+      const result: boolean = component.isFirstItemOrOutOfArray(1);
+
+      expect(result).toBe(false);
+    });
+  });
+
+  describe('onItemClicked', () => {
+    beforeEach(() => {
+      component.hideResults = jest.fn();
+    });
+
+    it('should emit searchResultSelected', () => {
+      component.onItemClicked(searchResults[0], 0);
+
+      expect(searchResultSelected.emit).toHaveBeenCalledWith(searchResults[0]);
+    });
+
+    it('should hide results', () => {
+      component.onItemClicked(searchResults[0], 0);
+
+      expect(component.hideResults).toHaveBeenCalled();
+    });
+  });
+
+  describe('onClickHandler', () => {
+    const e: MouseEvent = { ...new MouseEvent('test') };
+
+    beforeEach(() => {
+      component.hideResults = jest.fn();
+    });
+
+    it('should call hideResults if instant search does not contain event target', () => {
+      component.onClickHandler(e);
+
+      expect(component.hideResults).toHaveBeenCalled();
+    });
+
+    it('should not call hideResults if instant search contains event target', () => {
+      component.ref.nativeElement.contains = jest.fn().mockReturnValue(true);
+
+      component.onClickHandler(e);
+
+      expect(component.hideResults).not.toHaveBeenCalled();
+    });
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.component.ts b/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c16d9fab5189ca71bb978839e0b602d114d35882
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.component.ts
@@ -0,0 +1,224 @@
+import { EMPTY_STRING, isNotNil } from '@alfa-client/tech-shared';
+import { CommonModule } from '@angular/common';
+import {
+  Component,
+  ElementRef,
+  EventEmitter,
+  HostListener,
+  Input,
+  OnDestroy,
+  OnInit,
+  Output,
+  QueryList,
+  ViewChildren,
+} from '@angular/core';
+import { FormControl } from '@angular/forms';
+import { isEqual, isUndefined } from 'lodash-es';
+import { Subscription, debounceTime, distinctUntilChanged, filter } from 'rxjs';
+import { AriaLiveRegionComponent } from '../../aria-live-region/aria-live-region.component';
+import { SearchFieldComponent } from '../search-field/search-field.component';
+import { SearchResultHeaderComponent } from '../search-result-header/search-result-header.component';
+import { SearchResultItemComponent } from '../search-result-item/search-result-item.component';
+import { SearchResultLayerComponent } from '../search-result-layer/search-result-layer.component';
+import { InstantSearchQuery, InstantSearchResult } from './instant-search.model';
+
+@Component({
+  selector: 'ods-instant-search',
+  standalone: true,
+  imports: [
+    CommonModule,
+    SearchFieldComponent,
+    SearchResultHeaderComponent,
+    SearchResultItemComponent,
+    SearchResultLayerComponent,
+    AriaLiveRegionComponent,
+  ],
+  template: ` <div class="relative">
+    <ods-search-field
+      [placeholder]="placeholder"
+      [label]="label"
+      [attr.aria-expanded]="results.length"
+      [control]="control"
+      aria-controls="results"
+      (inputClicked)="showResults()"
+      #searchField
+    />
+    <ods-aria-live-region [text]="ariaLiveText" />
+    <ods-search-result-layer
+      *ngIf="results.length && areResultsVisible"
+      class="absolute z-50 mt-3 w-full"
+      id="results"
+    >
+      <ods-search-result-header [text]="headerText" [count]="results.length" header />
+      <ods-search-result-item
+        *ngFor="let result of results; let i = index"
+        [title]="result.title"
+        [description]="result.description"
+        (itemClicked)="onItemClicked(result, i)"
+        #results
+      ></ods-search-result-item>
+    </ods-search-result-layer>
+  </div>`,
+})
+export class InstantSearchComponent implements OnInit, OnDestroy {
+  static readonly DEBOUNCE_TIME_IN_MILLIS: number = 300;
+
+  @Input() label: string = EMPTY_STRING;
+  @Input() placeholder: string = EMPTY_STRING;
+  @Input() headerText: string = EMPTY_STRING;
+  @Input() control: FormControl<string> = new FormControl(EMPTY_STRING);
+
+  @Input() set searchResults(searchResults: InstantSearchResult<unknown>[]) {
+    if (!isEqual(searchResults, this.results) && isNotNil(searchResults)) {
+      this.setSearchResults(searchResults);
+    }
+  }
+
+  @Output() searchResultSelected: EventEmitter<InstantSearchResult<unknown>> = new EventEmitter<
+    InstantSearchResult<unknown>
+  >();
+  @Output() searchQueryChanged: EventEmitter<InstantSearchQuery> =
+    new EventEmitter<InstantSearchQuery>();
+
+  readonly FIRST_ITEM_INDEX: number = 0;
+  readonly PREVIEW_SEARCH_STRING_MIN_LENGTH: number = 2;
+  results: InstantSearchResult<unknown>[] = [];
+  ariaLiveText: string = '';
+  areResultsVisible: boolean = true;
+  private focusedResult: number | undefined = undefined;
+  formControlSubscription: Subscription;
+
+  constructor(public ref: ElementRef) {}
+
+  @ViewChildren('results') resultsRef: QueryList<SearchResultItemComponent>;
+
+  ngOnInit(): void {
+    this.handleValueChanges();
+  }
+
+  handleValueChanges() {
+    this.formControlSubscription = this.control.valueChanges
+      .pipe(
+        debounceTime(InstantSearchComponent.DEBOUNCE_TIME_IN_MILLIS),
+        filter((value: string) => value.length >= this.PREVIEW_SEARCH_STRING_MIN_LENGTH),
+        distinctUntilChanged(),
+      )
+      .subscribe((searchBy: string) => {
+        this.searchQueryChanged.emit({ searchBy });
+        if (!this.areResultsVisible) {
+          this.showResults();
+        }
+      });
+  }
+
+  ngOnDestroy(): void {
+    if (isNotNil(this.formControlSubscription)) this.formControlSubscription.unsubscribe();
+  }
+
+  @HostListener('document:keydown', ['$event'])
+  onKeydownHandler(e: KeyboardEvent): void {
+    if (this.isSearchResultsEmpty()) return;
+    if (this.isArrowNavigationKey(e)) this.handleArrowNavigation(e);
+    if (this.isEscapeKey(e)) this.handleEscape(e);
+  }
+
+  @HostListener('document:click', ['$event'])
+  onClickHandler(e: MouseEvent): void {
+    if (!this.ref.nativeElement.contains(e.target)) {
+      this.hideResults();
+    }
+  }
+
+  handleArrowNavigation(e: KeyboardEvent): void {
+    e.preventDefault();
+    const newIndex = this.getResultIndexForKey(e.key);
+    this.focusedResult = newIndex;
+    this.setFocusOnResultItem(newIndex);
+  }
+
+  handleEscape(e: KeyboardEvent): void {
+    e.preventDefault();
+    this.hideResults();
+  }
+
+  setFocusOnResultItem(index: number): void {
+    this.resultsRef.get(index).setFocus();
+  }
+
+  setSearchResults(searchResults: InstantSearchResult<unknown>[]): void {
+    this.results = searchResults;
+    this.ariaLiveText = this.buildAriaLiveText(searchResults.length);
+  }
+
+  getNextResultIndex(index: number | undefined, resultLength: number): number {
+    if (isUndefined(index)) return this.FIRST_ITEM_INDEX;
+    if (this.isLastItemOrOutOfArray(index, resultLength)) return this.FIRST_ITEM_INDEX;
+    return index + 1;
+  }
+
+  getPreviousResultIndex(index: number | undefined, resultLength: number): number {
+    if (isUndefined(index)) return this.getLastItemIndex(resultLength);
+    if (this.isFirstItemOrOutOfArray(index)) return this.getLastItemIndex(resultLength);
+    return index - 1;
+  }
+
+  getLastItemIndex(arrayLength: number): number {
+    if (arrayLength < 1) return this.FIRST_ITEM_INDEX;
+    return arrayLength - 1;
+  }
+
+  getResultIndexForKey(key: string): number {
+    switch (key) {
+      case 'ArrowDown':
+        return this.getNextResultIndex(this.focusedResult, this.results.length);
+      case 'ArrowUp':
+        return this.getPreviousResultIndex(this.focusedResult, this.results.length);
+      default:
+        console.error('Key %s not allowed', key);
+    }
+  }
+
+  buildAriaLiveText(resultsLength: number): string {
+    if (resultsLength === 1)
+      return `Ein Suchergebnis für Eingabe ${this.control.value}. Nutze Pfeiltaste nach unten, um das zu erreichen.`;
+    if (resultsLength > 1)
+      return `${resultsLength} Suchergebnisse für Eingabe ${this.control.value}. Nutze Pfeiltaste nach unten, um diese zu erreichen.`;
+    return 'Keine Ergebnisse';
+  }
+
+  showResults(): void {
+    this.areResultsVisible = true;
+    this.focusedResult = undefined;
+  }
+
+  hideResults(): void {
+    this.areResultsVisible = false;
+    this.focusedResult = undefined;
+  }
+
+  isLastItemOrOutOfArray(index: number, arrayLength: number): boolean {
+    return index >= arrayLength - 1;
+  }
+
+  isFirstItemOrOutOfArray(index: number): boolean {
+    return index <= this.FIRST_ITEM_INDEX;
+  }
+
+  isSearchResultsEmpty(): boolean {
+    return this.results.length === 0;
+  }
+
+  isArrowNavigationKey(e: KeyboardEvent): boolean {
+    return e.key === 'ArrowDown' || e.key === 'ArrowUp';
+  }
+
+  isEscapeKey(e: KeyboardEvent): boolean {
+    return e.key === 'Escape';
+  }
+
+  onItemClicked(searchResult: InstantSearchResult<unknown>, index: number) {
+    this.searchResultSelected.emit(searchResult);
+    this.focusedResult = index;
+    this.hideResults();
+  }
+}
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.model.ts b/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5debae8ceb40be63d765fbb9a401cb47d601e5c5
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.model.ts
@@ -0,0 +1,9 @@
+export interface InstantSearchResult<T> {
+  title: string;
+  description: string;
+  data?: T;
+}
+
+export interface InstantSearchQuery {
+  searchBy: string;
+}
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.stories.ts b/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bfe67d23232b417e6cddd3b33f53245a793b161e
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.stories.ts
@@ -0,0 +1,40 @@
+import { type Meta, type StoryObj } from '@storybook/angular';
+import { InstantSearchComponent } from './instant-search.component';
+
+const meta: Meta<InstantSearchComponent> = {
+  title: 'Instant search/Instant search',
+  component: InstantSearchComponent,
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<InstantSearchComponent>;
+
+export const Default: Story = {
+  args: {
+    label: '',
+    placeholder: 'zuständige Stelle suchen',
+    headerText: 'In der OZG-Cloud',
+  },
+};
+
+export const SearchResults: Story = {
+  args: {
+    label: '',
+    placeholder: 'zuständige Stelle suchen',
+    headerText: 'In der OZG-Cloud',
+    searchResults: [
+      {
+        text: 'Landeshauptstadt Kiel - Ordnungsamt, Gewerbe- und Schornsteinfegeraufsicht',
+        subText: 'Fabrikstraße  8-10, 24103 Kiel',
+        onClick: () => undefined,
+      },
+      {
+        text: 'Amt für Digitalisierung, Breitband und Vermessung Nürnberg Außenstelle Hersbruck',
+        subText: 'Rathausmarkt 7, Hersbruck',
+        onClick: () => undefined,
+      },
+    ],
+  },
+};
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.component.spec.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f1f730f80e1b6cf82b90568b16df0ffd8b3a76bd
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.component.spec.ts
@@ -0,0 +1,47 @@
+import { EMPTY_STRING } from '@alfa-client/tech-shared';
+import { getElementFromFixtureByType, mock } from '@alfa-client/test-utils';
+import { EventEmitter } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormControl } from '@angular/forms';
+import { TextInputComponent } from '../../form/text-input/text-input.component';
+import { SearchFieldComponent } from './search-field.component';
+
+describe('SearchFieldComponent', () => {
+  let component: SearchFieldComponent;
+  let fixture: ComponentFixture<SearchFieldComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [SearchFieldComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(SearchFieldComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('inputClicked', () => {
+    it('should emit event', () => {
+      component.inputClicked = <any>mock(EventEmitter);
+      const input = getElementFromFixtureByType(fixture, TextInputComponent);
+
+      input.inputElement.nativeElement.click();
+
+      expect(component.inputClicked.emit).toHaveBeenCalled();
+    });
+  });
+
+  describe('clearValue', () => {
+    it('should set empty value', () => {
+      component.control = new FormControl('test');
+
+      component.clearInput();
+
+      expect(component.control.value).toBe(EMPTY_STRING);
+    });
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.component.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1f2e01bd046af2d15ce345fed69c9a9f43122cc6
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.component.ts
@@ -0,0 +1,38 @@
+import { CommonModule } from '@angular/common';
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { FormControl } from '@angular/forms';
+import { EMPTY_STRING } from '../../../../../tech-shared/src';
+import { TextInputComponent } from '../../form/text-input/text-input.component';
+import { CloseIconComponent } from '../../icons/close-icon/close-icon.component';
+import { SearchIconComponent } from '../../icons/search-icon/search-icon.component';
+
+@Component({
+  selector: 'ods-search-field',
+  standalone: true,
+  imports: [CommonModule, TextInputComponent, SearchIconComponent, CloseIconComponent],
+  template: `<ods-text-input
+    [label]="label"
+    [fieldControl]="control"
+    [placeholder]="placeholder"
+    [withPrefix]="true"
+    [withSuffix]="true"
+    (clickEmitter)="inputClicked.emit()"
+    role="combobox"
+  >
+    <ods-search-icon prefix aria-hidden="true" aria-label="Suchfeld" />
+    <button suffix *ngIf="control.value" (click)="clearInput()" aria-label="Eingabe löschen">
+      <ods-close-icon class="fill-primary hover:fill-primary-hover" />
+    </button>
+  </ods-text-input>`,
+})
+export class SearchFieldComponent {
+  @Input() label: string = EMPTY_STRING;
+  @Input() placeholder: string = EMPTY_STRING;
+  @Input() control = new FormControl(EMPTY_STRING);
+
+  @Output() inputClicked: EventEmitter<MouseEvent> = new EventEmitter<MouseEvent>();
+
+  clearInput() {
+    this.control.setValue(EMPTY_STRING);
+  }
+}
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.stories.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fec43fa8f65cd51c47e4639fd002a34e33c8b119
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.stories.ts
@@ -0,0 +1,19 @@
+import { type Meta, type StoryObj } from '@storybook/angular';
+import { SearchFieldComponent } from './search-field.component';
+
+const meta: Meta<SearchFieldComponent> = {
+  title: 'Instant search/Search field',
+  component: SearchFieldComponent,
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<SearchFieldComponent>;
+
+export const Default: Story = {
+  args: {
+    label: '',
+    placeholder: 'search something...',
+  },
+};
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-result-header/search-result-header.component.spec.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-result-header/search-result-header.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7c00b9a408879b4ce0c96c2a374edce5df6739c2
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-result-header/search-result-header.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { SearchResultHeaderComponent } from './search-result-header.component';
+
+describe('SearchResultHeaderComponent', () => {
+  let component: SearchResultHeaderComponent;
+  let fixture: ComponentFixture<SearchResultHeaderComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [SearchResultHeaderComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(SearchResultHeaderComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-result-header/search-result-header.component.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-result-header/search-result-header.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4ba8d7894dbddd157532a1418f175e28fa25c3b0
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-result-header/search-result-header.component.ts
@@ -0,0 +1,17 @@
+import { CommonModule } from '@angular/common';
+import { Component, Input } from '@angular/core';
+
+@Component({
+  selector: 'ods-search-result-header',
+  standalone: true,
+  imports: [CommonModule],
+  template: `
+    <h3 class="mx-6 my-3 w-fit border-b-2 border-primary py-1 text-sm font-semibold text-text">
+      {{ text }} ({{ count }})
+    </h3>
+  `,
+})
+export class SearchResultHeaderComponent {
+  @Input({ required: true }) text!: string;
+  @Input() count: number = 0;
+}
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-result-item/search-result-item.component.spec.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-result-item/search-result-item.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..089692b213692a024ccf7d6dc07071bd9c25d812
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-result-item/search-result-item.component.spec.ts
@@ -0,0 +1,46 @@
+import { getElementFromFixture, mock } from '@alfa-client/test-utils';
+import { EventEmitter } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
+import { SearchResultItemComponent } from './search-result-item.component';
+
+describe('SearchResultItemComponent', () => {
+  let component: SearchResultItemComponent;
+  let fixture: ComponentFixture<SearchResultItemComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [SearchResultItemComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(SearchResultItemComponent);
+    component = fixture.componentInstance;
+    component.title = 'Test';
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('itemClicked', () => {
+    it('should emit event', () => {
+      component.itemClicked = <any>mock(EventEmitter);
+      const button = getElementFromFixture(fixture, getDataTestIdOf('item-button'));
+
+      button.click();
+
+      expect(component.itemClicked.emit).toHaveBeenCalled();
+    });
+  });
+
+  describe('setFocus', () => {
+    it('should focus native element', () => {
+      component.buttonRef.nativeElement.focus = jest.fn();
+
+      component.setFocus();
+
+      expect(component.buttonRef.nativeElement.focus).toHaveBeenCalled();
+    });
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-result-item/search-result-item.component.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-result-item/search-result-item.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e02da6ddc31ea1fda0572f40be876b6a1969012b
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-result-item/search-result-item.component.ts
@@ -0,0 +1,38 @@
+import { CommonModule } from '@angular/common';
+import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core';
+
+@Component({
+  selector: 'ods-search-result-item',
+  standalone: true,
+  imports: [CommonModule],
+  template: `<button
+    *ngIf="title"
+    [ngClass]="[
+      'flex w-full justify-between border-2 border-transparent px-6 py-3',
+      'hover:border-focus focus:border-focus focus:outline-none',
+    ]"
+    role="listitem"
+    tabindex="-1"
+    (click)="itemClicked.emit()"
+    data-test-id="item-button"
+    #button
+  >
+    <div class="flex flex-col items-start justify-between text-text">
+      <p class="text-base font-medium">{{ title }}</p>
+      <p class="text-sm">{{ description }}</p>
+    </div>
+    <ng-content select="[action-button]" />
+  </button>`,
+})
+export class SearchResultItemComponent {
+  @Input({ required: true }) title!: string;
+  @Input() description: string = '';
+
+  @Output() public itemClicked: EventEmitter<MouseEvent> = new EventEmitter<MouseEvent>();
+
+  @ViewChild('button') buttonRef: ElementRef;
+
+  public setFocus() {
+    this.buttonRef.nativeElement.focus();
+  }
+}
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.component.spec.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d2c91333316ff8253ec828a228ce83b84514113c
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { SearchResultLayerComponent } from './search-result-layer.component';
+
+describe('SearchResultLayerComponent', () => {
+  let component: SearchResultLayerComponent;
+  let fixture: ComponentFixture<SearchResultLayerComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [SearchResultLayerComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(SearchResultLayerComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.component.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..971e06b585e2292b36be429b6972ba91090ccaa0
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.component.ts
@@ -0,0 +1,15 @@
+import { CommonModule } from '@angular/common';
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'ods-search-result-layer',
+  standalone: true,
+  imports: [CommonModule],
+  template: `<div class="rounded-lg border border-primary-600/50 bg-background-50 shadow-lg">
+    <ng-content select="[header]" />
+    <ul role="list">
+      <ng-content />
+    </ul>
+  </div>`,
+})
+export class SearchResultLayerComponent {}
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.stories.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..02aa94c67050ca8ec652784afb653f56d596454b
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.stories.ts
@@ -0,0 +1,30 @@
+import { moduleMetadata, type Meta, type StoryObj } from '@storybook/angular';
+import { SearchResultHeaderComponent } from '../search-result-header/search-result-header.component';
+import { SearchResultItemComponent } from '../search-result-item/search-result-item.component';
+import { SearchResultLayerComponent } from './search-result-layer.component';
+
+const meta: Meta<SearchResultLayerComponent> = {
+  title: 'Instant search/Search result layer',
+  component: SearchResultLayerComponent,
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+  decorators: [
+    moduleMetadata({
+      imports: [SearchResultItemComponent, SearchResultHeaderComponent],
+    }),
+  ],
+};
+
+export default meta;
+type Story = StoryObj<SearchResultLayerComponent>;
+
+export const Default: Story = {
+  args: {},
+  render: () => ({
+    template: `<ods-search-result-layer>
+      <ods-search-result-header text="In der OZG-Cloud" [count]="2" header />
+      <ods-search-result-item text="Amt Rantznau - Ordnungsamt" subText="Rathausmarkt 7, Kronshagen" />
+      <ods-search-result-item text="Amt Burg-St. Michaelisdonn - Der Amtsvorsteher" subText="Holzmarkt 7, 25712 Rantznau" />
+    </ods-search-result-layer>`,
+  }),
+};
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-antrag-bescheiden/vorgang-detail-bescheiden-antrag-bescheiden.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-antrag-bescheiden/vorgang-detail-bescheiden-antrag-bescheiden.component.html
index ad1704f9c19a82c2a3fe30cb866eb98730f4ff69..22c3e14619ff5c4636838a058b8e614684b64a83 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-antrag-bescheiden/vorgang-detail-bescheiden-antrag-bescheiden.component.html
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-antrag-bescheiden/vorgang-detail-bescheiden-antrag-bescheiden.component.html
@@ -14,7 +14,7 @@
       value="false"
       data-test-id="button-abgelehnt"
       variant="bescheid_abgelehnt"
-      ><ods-close-icon size="medium" class="fill-abgelehnt"></ods-close-icon>
+      ><ods-close-icon size="large" class="fill-abgelehnt"></ods-close-icon>
     </ods-radio-button-card>
   </div>
   <div class="flex w-full">