> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kombify.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Richte deine Passwortmanager-Apps ein

> Erstelle dein Tresor-Konto, speichere ein erstes Passwort und verbinde die Bitwarden-Apps auf Handy, Browser und Computer mit deinem eigenen Tresor.

export const ClientSetupGuide = ({id, labels, locale = 'en', direction = 'ltr', meta = [], requirements = [], requirementsHelp, appsTitle = labels.appsTitle, vendor, apps = [], appsNote, stepsTitle = labels.stepsTitle, steps = [], help = [], helpTitle = labels.helpTitle, next = [], nextTitle = labels.nextTitle, attribution, sources}) => {
  const Anchor = 'a', Article = 'article', Details = 'details', Dialog = 'dialog', Figcaption = 'figcaption', Figure = 'figure', Footer = 'footer', Img = 'img', Summary = 'summary';
  const number = new Intl.NumberFormat(locale);
  const stepNumber = new Intl.NumberFormat(locale, {
    minimumIntegerDigits: 2
  });
  const message = (key, values = {}) => labels[key].replace(/\{(\w+)\}/g, (_, name) => String(values[name]));
  const count = steps.length;
  const last = count - 1;
  const storageKey = `kombify-client-guide:${id}:v1`;
  const rootRef = useRef(null);
  const zoomRef = useRef(null);
  const toastTimer = useRef(null);
  const focusTab = useRef(false);
  const [current, setCurrent] = useState(0);
  const [completed, setCompleted] = useState(() => steps.map(() => false));
  const [verified, setVerified] = useState(() => steps.map(step => (step.verify || []).map(() => false)));
  const [failed, setFailed] = useState({});
  const [zoom, setZoom] = useState(null);
  const [toast, setToast] = useState('');
  const isExternal = href => (/^https?:\/\//).test(href || '');
  const icon = name => {
    const paths = {
      apple: <path d="M16.7 1.8c0 2.1-1.7 4.4-3.7 4.2-.4-2.1 1.8-4.3 3.7-4.2ZM20.4 17.3c-.5 1.2-.8 1.7-1.5 2.7-1 1.5-2.4 3.3-4.2 3.3-1.6 0-2-1-4.1-.9-2.1 0-2.5 1-4.2.9-1.8-.1-3.1-1.7-4.1-3.2C-.5 15.9-.7 10.4 1 7.6c1.2-2 3.1-3.1 4.9-3.1 1.9 0 3.1 1 4.7 1 1.5 0 2.5-1 4.7-1 1.6 0 3.3.9 4.5 2.3-4 2.2-3.3 8 0 10.5Z" fill="currentColor" stroke="none" transform="translate(2 0) scale(.87)" />,
      android: <><path d="M5 12a7 7 0 0 1 14 0v6H5Zm2-6L5 3m12 3 2-3M2 12v5m20-5v5M8 18v4m8-4v4" /><path d="M8.5 9h.01M15.5 9h.01" /></>,
      browser: <><rect height="16" rx="2" width="20" x="2" y="4" /><path d="M2 9h20M6 6.5h.01M9 6.5h.01" /></>,
      desktop: <><rect height="14" rx="2" width="20" x="2" y="3" /><path d="M8 22h8M12 17v5" /></>,
      web: <><circle cx="12" cy="12" r="9" /><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18" /></>,
      server: <><rect height="7" rx="2" width="18" x="3" y="3" /><rect height="7" rx="2" width="18" x="3" y="14" /><path d="M7 6.5h.01M7 17.5h.01M16 6.5h2M16 17.5h2" /></>,
      phone: <><rect height="20" rx="3" width="12" x="6" y="2" /><path d="M10 5h4M11 19h2" /></>,
      steps: <><rect height="7" rx="1.5" width="7" x="3" y="3" /><rect height="7" rx="1.5" width="7" x="14" y="3" /><rect height="7" rx="1.5" width="7" x="3" y="14" /><rect height="7" rx="1.5" width="7" x="14" y="14" /></>,
      book: <path d="M12 5v15M3 4c4-1 6 0 9 1 3-1 5-2 9-1v15c-4-1-6 0-9 1-3-1-5-2-9-1Z" />,
      clock: <><circle cx="12" cy="12" r="9" /><path d="M12 7v5l3 2" /></>,
      print: <><path d="M6 8V3h12v5M6 17H3V8h18v9h-3M6 14h12v7H6Z" /><path d="M17 11h.01" /></>,
      check: <path d="m5 12 4 4L19 6" />,
      arrow: <path d="M5 12h14M13 6l6 6-6 6" />,
      back: <path d="m15 5-7 7 7 7" />,
      external: <><path d="M14 4h6v6m0-6L10 14" /><path d="M10 4H5a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-5" /></>,
      info: <><circle cx="12" cy="12" r="9" /><path d="M12 11v5M12 7h.01" /></>,
      ok: <><circle cx="12" cy="12" r="9" /><path d="m8 12 3 3 5-6" /></>,
      camera: <><path d="M3 7h4l2-3h6l2 3h4v13H3Z" /><circle cx="12" cy="13" r="4" /></>,
      zoom: <><circle cx="10.5" cy="10.5" r="6.5" /><path d="m16 16 5 5M7 10.5h7M10.5 7v7" /></>,
      shield: <><path d="M12 3 3 7v6c0 5 9 9 9 9s9-4 9-9V7Z" /><path d="m8 12 3 3 5-6" /></>,
      close: <path d="m6 6 12 12M6 18 18 6" />
    };
    return <svg aria-hidden="true" className="ico" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.7" viewBox="0 0 24 24">{paths[name] || paths.info}</svg>;
  };
  const safeHref = href => (/^(https:\/\/|\/|#)/).test(href || '') ? href : '#';
  const link = (href, children, className, key) => isExternal(href) ? <Anchor className={className || ''} href={safeHref(href)} key={key} rel="noopener noreferrer" target="_blank">{children} {icon('external')}<span className="sr-only">{labels.opensInNewTab}</span></Anchor> : <Anchor className={className || ''} href={safeHref(href)} key={key} onClick={(href || '').startsWith('#') ? () => {
    zoomRef.current?.close();
    reveal(href.slice(1));
  } : undefined}>{children}</Anchor>;
  const rich = text => {
    if (!text || !text.split) return text;
    return text.split(/(\[\[[^\]]+\]\]|\*\*[^*]+\*\*|\[[^\]]+\]\([^)\s]+\))/g).map((part, i) => {
      if ((/^\[\[[^\]]+\]\]$/).test(part)) return <span className="key" key={i}>{part.slice(2, -2)}</span>;
      if ((/^\*\*[^*]+\*\*$/).test(part)) return <strong key={i}>{part.slice(2, -2)}</strong>;
      const match = (/^\[([^\]]+)\]\(([^)\s]+)\)$/).exec(part);
      if (match) return link(match[2], match[1], undefined, i);
      return part;
    });
  };
  useEffect(() => {
    try {
      const saved = JSON.parse(localStorage.getItem(storageKey) || 'null');
      if (Array.isArray(saved?.completed) && saved.completed.length === count) setCompleted(saved.completed.map(Boolean));
      if (Array.isArray(saved?.verified) && saved.verified.length === count) setVerified(saved.verified.map((list, i) => (steps[i].verify || []).map((_, j) => Boolean(list?.[j]))));
    } catch (_) {}
    const root = rootRef.current;
    const timer = setTimeout(() => {
      if (!root) return;
      const broken = {};
      root.querySelectorAll('.screen-image > img').forEach(image => {
        if (image.complete && !image.naturalWidth) broken[image.getAttribute('src')] = true;
      });
      if (Object.keys(broken).length) setFailed(old => ({
        ...old,
        ...broken
      }));
    }, 7000);
    const openAll = () => root?.querySelectorAll('details').forEach(node => {
      node.open = true;
    });
    window.addEventListener('beforeprint', openAll);
    return () => {
      clearTimeout(timer);
      clearTimeout(toastTimer.current);
      window.removeEventListener('beforeprint', openAll);
    };
  }, []);
  useEffect(() => {
    if (!focusTab.current) return;
    focusTab.current = false;
    rootRef.current?.querySelector(`[id="${id}-tab-${current}"]`)?.focus();
  }, [current]);
  const persist = (nextCompleted, nextVerified) => {
    try {
      localStorage.setItem(storageKey, JSON.stringify({
        completed: nextCompleted,
        verified: nextVerified
      }));
    } catch (_) {}
  };
  const say = text => {
    setToast('');
    setTimeout(() => setToast(text), 60);
    clearTimeout(toastTimer.current);
    toastTimer.current = setTimeout(() => setToast(''), 3800);
  };
  const select = (index, focus) => {
    const target = Math.max(0, Math.min(last, index));
    setCurrent(target);
    focusTab.current = Boolean(focus);
  };
  const onNext = () => {
    const checks = verified[current] || [];
    if (checks.length && !checks.every(Boolean)) {
      say(labels.verifyRequired);
      rootRef.current?.querySelector(`[id="${id}-verify-${current}-${checks.indexOf(false)}"]`)?.focus();
      return;
    }
    const nextCompleted = completed.map((done, i) => i === current ? true : done);
    setCompleted(nextCompleted);
    persist(nextCompleted, verified);
    if (current < last) select(current + 1, true); else {
      const done = nextCompleted.filter(Boolean).length;
      say(done === count ? labels.allDone : message('remainingSteps', {
        done: number.format(done),
        count: number.format(count)
      }));
      rootRef.current?.querySelector(`[id="${id}-more"], [id="${id}-help"]`)?.scrollIntoView({
        block: 'start'
      });
    }
  };
  const onVerify = (stepIndex, checkIndex, value) => {
    const nextVerified = verified.map((list, i) => i === stepIndex ? list.map((v, j) => j === checkIndex ? value : v) : list);
    const nextCompleted = completed.map((done, i) => i === stepIndex && !value ? false : done);
    setVerified(nextVerified);
    setCompleted(nextCompleted);
    persist(nextCompleted, nextVerified);
  };
  const onReset = () => {
    const nextCompleted = steps.map(() => false);
    const nextVerified = steps.map(step => (step.verify || []).map(() => false));
    setCompleted(nextCompleted);
    setVerified(nextVerified);
    persist(nextCompleted, nextVerified);
    select(0);
    say(labels.progressReset);
  };
  const onTabKey = event => {
    const moves = {
      ArrowRight: c => (c + 1) % count,
      ArrowLeft: c => (c - 1 + count) % count,
      Home: () => 0,
      End: () => last
    };
    const move = moves[event.key];
    if (!move) return;
    event.preventDefault();
    focusTab.current = true;
    setCurrent(move);
  };
  const openZoom = shot => {
    setZoom(shot);
    const dialog = zoomRef.current;
    if (dialog && !dialog.open) dialog.showModal();
  };
  const closeOnBackdrop = event => {
    const dialog = event.currentTarget;
    if (event.target !== dialog) return;
    const rect = dialog.getBoundingClientRect();
    if (event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom) dialog.close();
  };
  const reveal = targetId => {
    const node = rootRef.current?.querySelector(`[id="${targetId}"]`);
    const details = node && (node.tagName === 'DETAILS' ? node : node.querySelector('details'));
    if (details) details.open = true;
  };
  const renderShot = (shot, stepIndex) => {
    const unavailable = failed[shot.src];
    const label = shot.vendor ? labels.vendorScreenshotTag : labels.kombifyScreenshotTag;
    return <>
        <span className="screenshot-tag">{icon('camera')} {label}</span>
        <Figure className={`screen-figure${shot.frame === 'phone' ? ' phone' : ''}${unavailable ? ' image-unavailable' : ''}`}>
          <div className="screen-image">
            <Img alt={shot.alt} className={shot.srcDark ? 'only-light has-dark' : undefined} decoding="async" height={shot.height} loading={stepIndex === 0 ? 'eager' : 'lazy'} onError={() => setFailed(old => ({
      ...old,
      [shot.src]: true
    }))} referrerPolicy="no-referrer" src={shot.src} width={shot.width} />
            {shot.srcDark ? <Img alt={shot.alt} className="only-dark" decoding="async" height={shot.height} loading="lazy" onError={() => setFailed(old => ({
      ...old,
      [shot.src]: true
    }))} src={shot.srcDark} width={shot.width} /> : null}
            {(shot.vendor ? [] : shot.annotations || []).map((mark, i) => <span aria-hidden="true" className="annotation" data-n={mark.n ?? undefined} key={i} style={{
      top: `${mark.top}%`,
      left: `${mark.left}%`,
      width: `${mark.width}%`,
      height: `${mark.height}%`
    }} />)}
            <Anchor className="image-fallback" href={shot.vendor ? shot.creditHref || shot.src : shot.src} rel="noopener noreferrer" target="_blank">{icon('external')} {shot.vendor ? labels.openVendorPage : labels.openScreenshot}<span>{shot.vendor ? labels.vendorImageUnavailable : labels.imageUnavailable}</span></Anchor>
            <button aria-label={message('enlargeScreenshot', {
      description: shot.alt
    })} className="zoom-button" onClick={() => openZoom(shot)} type="button">{icon('zoom')}</button>
          </div>
          <Figcaption>
            {shot.caption}{shot.credit ? <> · {shot.creditHref ? link(shot.creditHref, shot.credit) : shot.credit}</> : null}
            {shot.version || shot.captured ? <span className="meta">{[shot.version, shot.captured ? message('captured', {
      date: shot.captured
    }) : null].filter(Boolean).join(' · ')}</span> : null}
          </Figcaption>
        </Figure>
      </>;
  };
  const renderLinkVisual = visual => <>
      <span className="screenshot-tag">{icon('external')} {visual.tag || labels.vendorGuideTag}</span>
      <div className="link-visual">
        {visual.title ? <strong>{visual.title}</strong> : null}
        {visual.text ? <p>{rich(visual.text)}</p> : null}
        {(visual.links || []).map((item, i) => <Anchor className="vendor-link" href={item.href} key={i} rel="noopener noreferrer" target="_blank">
            {icon(item.icon || 'book')}<span>{item.label}{item.detail ? <small>{item.detail}</small> : null}</span>{icon('external')}<span className="sr-only">{labels.opensInNewTab}</span>
          </Anchor>)}
      </div>
    </>;
  return <div className="kombify-client-guide not-prose" id={id} dir={direction} lang={locale} ref={rootRef} style={{
    '--kcg-steps': count
  }}>
      <div className="guide-content">
        <div className="page-top">
          <div className="intro-meta">{meta.map((item, i) => <span key={i}>{icon(item.icon)} {item.text}</span>)}</div>
          <div className="page-tools"><button aria-label={labels.printGuide} className="tool-button" onClick={() => window.print()} type="button">{icon('print')}</button></div>
        </div>
        {requirements.length ? <div className="ready-strip">
            <strong>{labels.requirementsTitle}</strong>
            {requirements.map((item, i) => <span key={i}>{icon('check')} {rich(item)}</span>)}
            {requirementsHelp ? <Anchor href={`#${requirementsHelp.target}`} onClick={() => reveal(requirementsHelp.target)}>{requirementsHelp.label} {icon('arrow')}</Anchor> : null}
          </div> : null}

        {apps.length ? <section aria-labelledby={`${id}-apps-title`} className="downloads" id={`${id}-apps`}>
            <div className="section-top">
              <h2 id={`${id}-apps-title`}>{appsTitle}</h2>
              {vendor ? link(vendor.href, vendor.label, 'small-link') : null}
            </div>
            <div className="downloads-grid">
              {apps.map((app, i) => <Anchor className="download-card" href={app.href} key={i} rel="noopener noreferrer" target="_blank">
                  <span className="platform-icon">{icon(app.platform)}</span>
                  <span className="download-text">
                    <strong>{app.label}</strong>
                    <small>{app.detail}</small>
                    <span className="store-name">{app.store} {icon('external')}</span>
                    <span className={`badge ${app.official ? 'official' : 'unofficial'}`}>{app.official ? message('officialApp', {
    vendor: app.vendor
  }) : message('thirdPartyApp', {
    vendor: app.vendor
  })}</span>
                  </span>
                  <span className="sr-only">{labels.opensInNewTab}</span>
                </Anchor>)}
            </div>
            {appsNote ? <p className="download-hint">{rich(appsNote)}</p> : null}
          </section> : null}

        <section aria-labelledby={`${id}-guide-title`} className="guide-section" id={`${id}-guide`}>
          <div className="guide-heading"><h2 id={`${id}-guide-title`}>{stepsTitle}</h2></div>
          <div className="wizard">
            <div aria-label={labels.setupSteps} className="step-tabs" onKeyDown={onTabKey} role="tablist">
              {steps.map((step, i) => <button aria-controls={`${id}-panel-${i}`} aria-selected={i === current} className={`step-tab${completed[i] ? ' done' : ''}`} id={`${id}-tab-${i}`} key={i} onClick={() => select(i)} role="tab" tabIndex={i === current ? 0 : -1} type="button">
                  <span className="step-dot">{completed[i] ? '✓' : number.format(i + 1)}</span><span>{step.tab}</span>
                </button>)}
            </div>
            {steps.map((step, i) => <Article aria-labelledby={`${id}-tab-${i}`} className={`guide-panel${i === current ? ' active' : ''}`} id={`${id}-panel-${i}`} key={i} role="tabpanel">
                <div className="panel-copy">
                  <div className="step-kicker">{message('stepPosition', {
    current: stepNumber.format(i + 1),
    count: stepNumber.format(count)
  })}</div>
                  <h3>{step.title}</h3>
                  {step.intro ? <p className="step-intro">{rich(step.intro)}</p> : null}
                  {step.clicks?.length ? <ol className="click-list">{step.clicks.map((click, j) => <li key={j}><span className="click-num">{number.format(j + 1)}</span><span>{rich(click)}</span></li>)}</ol> : null}
                  {step.verify?.length ? <div className="verify-list">
                      {step.verify.map((item, j) => <label key={j}><input checked={Boolean(verified[i]?.[j])} id={`${id}-verify-${i}-${j}`} onChange={event => onVerify(i, j, event.target.checked)} type="checkbox" /><span>{rich(item)}</span></label>)}
                    </div> : null}
                  {step.note ? <div className="micro-note">{icon('info')}<span>{rich(step.note)}</span></div> : null}
                  {(step.faq ? [].concat(step.faq) : []).map((faq, j) => <Details key={j}><Summary>{faq.q}</Summary><p>{rich(faq.a)}</p></Details>)}
                  {step.check ? <div className="step-check">{icon('ok')} {rich(step.check)}</div> : null}
                </div>
                <div className="panel-visual">
                  {step.screenshot ? renderShot(step.screenshot, i) : step.visual ? renderLinkVisual(step.visual) : null}
                </div>
              </Article>)}
            <div className="wizard-bottom">
              <div className="progress-note">
                <span>{message('progress', {
    done: number.format(completed.filter(Boolean).length),
    count: number.format(count)
  })}</span>
                <div aria-hidden="true" className="progress-meter">{steps.map((step, i) => <span className={completed[i] ? 'done' : undefined} key={i} />)}</div>
              </div>
              <button className="prev" disabled={current === 0} onClick={() => select(current - 1, true)} type="button">{icon('back')} {labels.back}</button>
              <button className="next" onClick={onNext} type="button"><span>{current === last ? labels.finish : labels.next}</span>{icon('arrow')}</button>
            </div>
          </div>
          {sources ? <p className="provenance-inline">{sources.summary} <Anchor href={`#${id}-sources`} onClick={() => reveal(`${id}-sources-detail`)}>{labels.imageSources}</Anchor></p> : null}
        </section>

        {next.length ? <section aria-labelledby={`${id}-more-title`} className="more-section" id={`${id}-more`}>
            <div className="section-top"><h2 id={`${id}-more-title`}>{nextTitle}</h2></div>
            <div className="more-grid">
              {next.map((item, i) => link(item.href, <>
                  <span className="more-icon">{icon(item.icon || 'arrow')}</span>
                  <span><strong>{item.title}</strong><small>{item.text}</small></span>
                </>, 'more-card', i))}
            </div>
          </section> : null}

        {help.length ? <section aria-labelledby={`${id}-help-title`} className="faq-section" id={`${id}-help`}>
            <h2 id={`${id}-help-title`}>{helpTitle}</h2>
            {help.map((item, i) => <Details className="faq" id={item.id} key={i}><Summary>{item.q}</Summary><div className="answer">{rich(item.a)}</div></Details>)}
          </section> : null}

        <Footer className="footline">
          <div className="attribution">{attribution ? rich(attribution) : null}</div>
          <button className="reset" onClick={onReset} type="button">{labels.resetProgress}</button>
        </Footer>

        {sources ? <section className="source-section" id={`${id}-sources`}>
            <Details id={`${id}-sources-detail`}>
              <Summary>{labels.sourcesTitle}</Summary>
              <div className="source-content">
                {(sources.paragraphs || []).map((text, i) => <p key={i}>{rich(text)}</p>)}
                <div className="source-links">{(sources.links || []).map((item, i) => link(item.href, item.label, undefined, i))}</div>
              </div>
            </Details>
            <div className="dim">{labels.ownershipNotice}</div>
          </section> : null}
      </div>

      <Dialog aria-labelledby={`${id}-zoom-title`} className="zoom-dialog" onClick={closeOnBackdrop} ref={zoomRef}>
        <div className="dialog-header">
          <h2 id={`${id}-zoom-title`}>{zoom?.vendor ? labels.vendorScreenshot : labels.screenshot}</h2>
          <button aria-label={labels.closeImage} className="dialog-close" onClick={() => zoomRef.current?.close()} type="button">{icon('close')}</button>
        </div>
        <div className="zoom-content">
          {zoom ? <Img alt={zoom.alt} src={zoom.src} /> : null}
          {zoom?.creditHref ? link(zoom.creditHref, zoom.vendor ? labels.openOriginal : labels.aboutScreenshot) : null}
        </div>
      </Dialog>
      <div aria-live="polite" className="sr-only" role="status">{toast}</div>
      <div aria-hidden="true" className={`toast${toast ? ' show' : ''}`}>{toast}</div>
    </div>;
};

export const clientSetupLabelsDe = {
  appsTitle: 'Lade zuerst die App herunter.',
  stepsTitle: 'Verbinde dich Schritt für Schritt.',
  helpTitle: 'Du kommst nicht weiter?',
  nextTitle: 'Wie es weitergeht.',
  opensInNewTab: ' (öffnet in einem neuen Tab)',
  verifyRequired: 'Hake jeden Punkt ab, nachdem du ihn selbst geprüft hast.',
  allDone: 'Alle Schritte sind in diesem Browser als erledigt markiert.',
  remainingSteps: '{done} von {count} Schritten sind als erledigt markiert. Öffne die anderen Tabs, um sie abzuschließen.',
  progressReset: 'Dein Fortschritt in diesem Browser wurde zurückgesetzt.',
  vendorScreenshotTag: 'HERSTELLER-SCREENSHOT',
  kombifyScreenshotTag: 'KOMBIFY-SCREENSHOT',
  openVendorPage: 'Herstellerseite öffnen',
  openScreenshot: 'Screenshot öffnen',
  vendorImageUnavailable: 'Zum Laden ist eine Internetverbindung nötig.',
  imageUnavailable: 'Das Bild konnte nicht geladen werden.',
  enlargeScreenshot: 'Screenshot vergrößern: {description}',
  captured: 'aufgenommen am {date}',
  vendorGuideTag: 'HERSTELLER-ANLEITUNG',
  printGuide: 'Anleitung drucken',
  requirementsTitle: 'Was du brauchst',
  officialApp: 'Offiziell · {vendor}',
  thirdPartyApp: 'Drittanbieter · {vendor}',
  setupSteps: 'Einrichtungsschritte',
  stepPosition: 'SCHRITT {current} / {count}',
  progress: '{done} von {count} Schritten erledigt',
  back: 'Zurück',
  finish: 'Fertig',
  next: 'Erledigt · weiter',
  imageSources: 'Bildquellen und Datum',
  resetProgress: 'Fortschritt zurücksetzen',
  sourcesTitle: 'Bildquellen, geprüfte Links und Datum',
  ownershipNotice: 'Anleitung von kombify · Produktnamen, Screenshots von Hersteller-Apps und Marken gehören ihren jeweiligen Inhabern.',
  vendorScreenshot: 'Hersteller-Screenshot',
  screenshot: 'Screenshot',
  closeImage: 'Bild schließen',
  openOriginal: 'Original beim Hersteller öffnen',
  aboutScreenshot: 'Zu diesem Screenshot'
};

<ClientSetupGuide
  labels={clientSetupLabelsDe}
  locale="de"
  id="kcg-passwords"
  meta={[
{ icon: "phone", text: "Handy, Browser & Computer" },
{ icon: "steps", text: "6 kurze Schritte" },
{ icon: "book", text: "Keine Vorkenntnisse nötig" },
]}
  requirements={[
"Deine Tresor-Adresse, zum Beispiel https://vault.home.test",
"Eine Einladung für deine E-Mail-Adresse",
"Jedes Gerät ist von der Person, die kombify eingerichtet hat, für deinen Heimtresor vorbereitet",
"Ein Master-Passwort, das du dir merken kannst",
]}
  requirementsHelp={{ label: "Noch keine Einladung?", target: "kcg-passwords-no-invite" }}
  appsTitle="Lade zuerst die Bitwarden-App herunter."
  vendor={{ label: "Alle Downloads von Bitwarden", href: "https://bitwarden.com/download/" }}
  apps={[
{ platform: "apple", label: "iPhone & iPad", detail: "Bitwarden Password Manager", store: "Im App Store öffnen", href: "https://apps.apple.com/app/bitwarden-password-manager/id1137397744", vendor: "Bitwarden", official: true },
{ platform: "android", label: "Android", detail: "Bitwarden Password Manager", store: "In Google Play öffnen", href: "https://play.google.com/store/apps/details?id=com.x8bit.bitwarden", vendor: "Bitwarden", official: true },
{ platform: "browser", label: "Browser-Erweiterung", detail: "Chrome, Firefox, Edge, Safari und mehr", store: "Bitwarden-Downloadseite öffnen", href: "https://bitwarden.com/download/", vendor: "Bitwarden", official: true },
{ platform: "desktop", label: "Computer", detail: "Windows, macOS und Linux", store: "Bitwarden-Downloadseite öffnen", href: "https://bitwarden.com/download/", vendor: "Bitwarden", official: true },
]}
  appsNote="Browser-Stores: [Chrome](https://chromewebstore.google.com/detail/bitwarden-password-manager/nngceckbapebfimnlniiiahkandclblb) · [Firefox](https://addons.mozilla.org/firefox/addon/bitwarden-password-manager/) · [Edge](https://microsoftedge.microsoft.com/addons/detail/bitwarden-password-manager/jbkfoedolllekgbhcbcoahefnbanhhlh) · [Safari (Mac App Store)](https://apps.apple.com/app/bitwarden/id1352778147). Dein Tresor läuft auf Vaultwarden, das mit diesen offiziellen Bitwarden-Apps funktioniert. Eine eigene Vaultwarden-App brauchst du nicht."
  stepsTitle="Richte deinen Tresor Schritt für Schritt ein."
  steps={[
{
  tab: "Tresor öffnen",
  title: "Öffne deinen Tresor im Browser.",
  intro: "Fang am Computer an. Dein Tresor hat eine eigene Webadresse, wie eine Website, die nur dein Haushalt nutzt.",
  clicks: [
    "Gib deine Tresor-Adresse in die Adressleiste des Browsers ein, zum Beispiel **https://vault.home.test**, und drücke die Eingabetaste.",
    "Klicke unter dem Anmeldefeld auf [[Create account]].",
  ],
  note: "Die Adresse in dieser Anleitung ist ein Beispiel. Verwende die Adresse, die du von der Person bekommen hast, die kombify eingerichtet hat.",
  faq: { q: "Was ist eine Tresor-Adresse?", a: "Das ist die Webadresse des Passwort-Tresors deines Haushalts. Sie beginnt meist mit **https://vault.** und endet mit dem Namen deines Heimnetzwerks. Die Person, die kombify eingerichtet hat, nennt dir die genaue Adresse." },
  check: "Du siehst das Formular [[Create account]].",
  screenshot: { src: "/images/guides/passwords/vaultwarden/web-01-open-vault.webp", width: 1088, height: 830, alt: "Vaultwarden-Anmeldeseite mit markiertem Link Create account", caption: "Anmeldeseite des Tresors", credit: "kombify-Screenshot", creditHref: "#kcg-passwords-sources", version: "Vaultwarden 1.37.2 · Web-Tresor 2026.7.0", captured: "2026-09-24", annotations: [{ n: 2, top: 84.3, left: 38.3, width: 23.5, height: 7.2 }] },
},
{
  tab: "Konto erstellen",
  title: "Erstelle dein Konto.",
  intro: "Dein Tresor akzeptiert nur eingeladene E-Mail-Adressen. Verwende dieselbe Adresse, an die die Einladung ging.",
  clicks: [
    "Gib bei [[Email address]] deine eingeladene E-Mail-Adresse ein.",
    "Gib bei [[Name]] deinen Namen ein. Die Person, die den Tresor betreibt, und alle, mit denen du Passwörter teilst, können ihn sehen.",
    "Klicke auf [[Continue]].",
  ],
  faq: { q: "Ist das mein kombify-Konto?", a: "Nein. Dieses Konto gehört nur zu deinem Passwort-Tresor. Es hat eine eigene E-Mail-Adresse und ein eigenes Master-Passwort." },
  check: "Die Seite fordert dich jetzt auf, [[Set a strong password]].",
  screenshot: { src: "/images/guides/passwords/vaultwarden/web-02-create-account.webp", width: 1088, height: 718, alt: "Formular Create account mit der E-Mail-Adresse alex@example.com und dem Namen Alex Example", caption: "Konto erstellen", credit: "kombify-Screenshot", creditHref: "#kcg-passwords-sources", version: "Vaultwarden 1.37.2 · Web-Tresor 2026.7.0", captured: "2026-09-24", annotations: [{ n: 1, top: 37.6, left: 16.4, width: 65.1, height: 13.4 }, { n: 2, top: 61, left: 16.4, width: 65.1, height: 13.4 }, { n: 3, top: 76.3, left: 14, width: 72.1, height: 13.9 }] },
},
{
  tab: "Master-Passwort",
  title: "Wähle dein Master-Passwort.",
  intro: "Das Master-Passwort ist das einzige Passwort, das du dir noch merken musst. Es schaltet alle anderen frei.",
  clicks: [
    "Gib bei [[Master password]] ein langes Passwort ein. Ein kurzer Satz aus vier oder mehr Wörtern funktioniert gut.",
    "Gib dasselbe Passwort bei [[Confirm master password]] noch einmal ein.",
    "Klicke auf [[Create account]]. Wenn die Seite die Browser-Erweiterung vorschlägt, klicke auf [[Add it later]] und dann auf [[Skip to web app]]. Die Erweiterung verbindest du in Schritt 5.",
  ],
  note: "**Ein vergessenes Master-Passwort kann niemand wiederherstellen**, auch nicht die Person, die deinen Tresor betreibt. Schreib es auf und bewahre den Zettel an einem sicheren Ort außerhalb des Tresors auf.",
  faq: { q: "Was bedeutet die Stärkeanzeige?", a: "Sie schätzt, wie schwer dein Passwort zu erraten ist. Ziel ist **Strong**. Länger ist besser als kompliziert." },
  check: "Dein leerer Tresor öffnet sich mit dem Titel [[All vaults]].",
  screenshot: { src: "/images/guides/passwords/vaultwarden/web-03-master-password.webp", width: 1088, height: 1310, alt: "Seite Set a strong password mit zweimal eingegebenem Master-Passwort, bewertet mit Strong", caption: "Set a strong password", credit: "kombify-Screenshot", creditHref: "#kcg-passwords-sources", version: "Vaultwarden 1.37.2 · Web-Tresor 2026.7.0", captured: "2026-09-24", annotations: [{ n: 1, top: 25.5, left: 16.4, width: 60.7, height: 7.3 }, { n: 2, top: 52.2, left: 16.4, width: 60.7, height: 7.3 }, { n: 3, top: 87, left: 14, width: 72.1, height: 7.6 }] },
},
{
  tab: "Erstes Passwort",
  title: "Speichere dein erstes Passwort.",
  intro: "Speichere eine Anmeldung zum Testen. Sie zeigt dir später, dass deine Apps mit deinem Tresor verbunden sind.",
  clicks: [
    "Klicke oben rechts auf [[New]] und wähle [[Login]]. Wenn zuerst ein Willkommensfenster erscheint, klicke auf [[Skip]].",
    "Gib bei [[Item name]] einen Namen ein, den du wiedererkennst, zum Beispiel den Namen eines Shops.",
    "Gib deinen [[Username]] ein. Klicke neben [[Password]] auf die kreisförmigen Pfeile, um ein Passwort zu erzeugen, und dann auf [[Use this password]].",
    "Klicke auf [[Save]].",
  ],
  note: "Trag die Webadresse des Shops unter [[Website (URI)]] ein. Die Browser-Erweiterung schlägt diese Anmeldung dann auf dieser Website vor.",
  check: "Die Meldung [[Item added]] erscheint und deine Anmeldung steht in der Liste.",
  screenshot: { src: "/images/guides/passwords/vaultwarden/web-04-new-login.webp", width: 1472, height: 1664, alt: "Fenster New Login mit dem Eintragsnamen Example Shop, einem Benutzernamen und einem erzeugten Passwort", caption: "New Login", credit: "kombify-Screenshot", creditHref: "#kcg-passwords-sources", version: "Vaultwarden 1.37.2 · Web-Tresor 2026.7.0", captured: "2026-09-24", annotations: [{ n: 2, top: 12.1, left: 7.9, width: 82.6, height: 5.8 }, { n: 3, top: 41.8, left: 7.9, width: 79.3, height: 5.8 }, { n: 3, top: 52.3, left: 87.5, width: 5.7, height: 5 }, { n: 4, top: 92.1, left: 2.7, width: 10.4, height: 6 }] },
},
{
  tab: "Apps verbinden",
  title: "Verbinde die Bitwarden-Apps.",
  intro: "Jede Bitwarden-App verbindet sich zuerst mit den Servern von Bitwarden. Sag ihr einmalig, dass sie stattdessen deinen Tresor verwenden soll.",
  clicks: [
    "Installiere die Bitwarden-App aus der Liste oben und öffne sie.",
    "Öffne auf dem Anmeldebildschirm das Menü [[Logging in on]] und wähle [[Self-hosted]]. In der Computer-App heißt das Menü [[Accessing]].",
    "Gib bei [[Server URL]] deine Tresor-Adresse mit **https://** am Anfang ein und tippe auf [[Save]].",
    "Melde dich mit deiner E-Mail-Adresse und deinem Master-Passwort an.",
  ],
  note: "Wiederhole diese Schritte auf jedem Handy, in jedem Browser und auf jedem Computer, den du nutzt. Jeder braucht deine Tresor-Adresse einmal.",
  faq: { q: "Warum gibt es hier kein Bild der App?", a: "Die Nutzungsbedingungen von Bitwarden erlauben nicht, die Bilder weiterzuverwenden. Die eigene Anleitung von Bitwarden zeigt jeden Bildschirm, und die Bezeichnungen oben passen dazu." },
  check: "Die App zeigt die Anmeldung, die du in Schritt 4 gespeichert hast.",
  visual: {
    tag: "BITWARDEN-ANLEITUNG",
    title: "Bitwarden zeigt jeden Bildschirm",
    text: "Wähle in der Bitwarden-Anleitung dein Gerät aus. Suche den Abschnitt zu einem **selbst gehosteten** Server.",
    links: [
      { label: "Eine App mit dem eigenen Server verbinden", detail: "bitwarden.com · alle Geräte", href: "https://bitwarden.com/help/change-client-environment/", icon: "server" },
      { label: "Erste Schritte mit der Browser-Erweiterung", detail: "bitwarden.com", href: "https://bitwarden.com/help/getting-started-browserext/", icon: "browser" },
      { label: "Erste Schritte mit der Mobile-App", detail: "bitwarden.com", href: "https://bitwarden.com/help/getting-started-mobile/", icon: "phone" },
    ],
  },
},
{
  tab: "Prüfen",
  title: "Ist alles verbunden?",
  intro: "Prüfe es im Web-Tresor und in einer App. Hake nur ab, was du selbst geprüft hast.",
  verify: [
    "Ich kann meine Tresor-Adresse öffnen und mich anmelden.",
    "Die von mir gespeicherte Anmeldung erscheint in einer Bitwarden-App auf meinem Handy, in meinem Browser oder auf meinem Computer.",
    "Mein Master-Passwort ist aufgeschrieben und außerhalb des Tresors aufbewahrt.",
  ],
  note: "Diese Anleitung liest deinen Tresor nicht aus. Deine Haken bleiben in diesem Browser.",
  check: "Jetzt kannst du deine anderen Passwörter in den Tresor übertragen.",
  screenshot: { src: "/images/guides/passwords/vaultwarden/web-05-first-item.webp", width: 1430, height: 300, alt: "Liste All vaults mit der gespeicherten Anmeldung Example Shop", caption: "Deine erste Anmeldung im Tresor", credit: "kombify-Screenshot", creditHref: "#kcg-passwords-sources", version: "Vaultwarden 1.37.2 · Web-Tresor 2026.7.0", captured: "2026-09-24", annotations: [{ n: null, top: 37.2, left: 1, width: 98, height: 58.1 }] },
},
]}
  nextTitle="Wie es weitergeht."
  next={[
{ icon: "shield", title: "Zwei-Schritt-Anmeldung aktivieren", text: "Bitwarden erklärt, wie du einen zweiten Anmeldeschritt hinzufügst.", href: "https://bitwarden.com/help/setup-two-step-login/" },
{ icon: "server", title: "Den Tresor sichern", text: "Für die Person, die kombify betreibt: schütze die Tresordaten.", href: "/de/guides/stackkits/back-up-and-restore" },
]}
  help={[
{ id: "kcg-passwords-no-invite", q: "Ich habe noch keine Tresor-Adresse und keine Einladung.", a: "Frag die Person, die kombify in deinem Haushalt eingerichtet hat. Sie fügt den Dienst Passwörter hinzu und lädt deine E-Mail-Adresse ein. [So funktioniert Passwörter mit kombify](/de/guides/stackkits/use-cases/passwords) · [Owner-Setup](/de/stackkits/apps/vaultwarden)." },
{ q: "Create account meldet „Registration not allowed or user already exists“.", a: "Prüfe, ob du genau die eingeladene E-Mail-Adresse verwendest. Wenn du dein Konto schon erstellt hast, geh zurück und melde dich stattdessen an. Sonst bitte um eine neue Einladung." },
{ q: "Die Adresse lässt sich nicht öffnen, oder der Browser warnt vor der Verbindung.", a: "Probiere die Adresse zuerst auf einem Gerät in deinem Heimnetzwerk. Wenn dein Tresor nur zu Hause läuft, verbinde dich mit deinem Heim-WLAN oder mit der Heimverbindungs-App, die du bekommen hast. Jedes Gerät muss außerdem so eingerichtet sein, dass es deinem Heimserver vertraut; das erledigt die Person, die kombify eingerichtet hat. Wenn der Browser meldet, die Verbindung sei nicht privat, brich hier ab und frag sie. Klicke nicht über die Warnung hinweg. [Über Heimadressen](/de/guides/stackkits/use-cases/network)." },
{ q: "Ich habe mein Master-Passwort vergessen.", a: "Niemand kann es wiederherstellen. Dein Tresor ist damit verschlüsselt. Die Person, die deinen Tresor betreibt, kann dein Konto löschen, damit du neu anfangen kannst, aber die darin gespeicherten Passwörter gehen verloren. [Bitwarden zu Master-Passwörtern](https://bitwarden.com/help/master-password/)." },
{ q: "Mein Android-Handy hat kein Google Play.", a: "Bitwarden betreibt ein eigenes F-Droid-Repository. Die Adresse steht auf der [Bitwarden-Downloadseite](https://bitwarden.com/download/)." },
{ q: "Warum steht hier Vaultwarden und Bitwarden?", a: "Vaultwarden ist das Programm, das deinen Tresor betreibt. Es ist ein inoffizieller Server, der mit den offiziellen Bitwarden-Apps funktioniert. Vaultwarden steht in keiner Verbindung zu Bitwarden, Inc. Die Bilder zeigen Vaultwarden 1.37.2 auf Englisch; neuere Versionen und andere Sprachen können anders aussehen." },
]}
  attribution="**Vaultwarden betreibt deinen Tresor, und die Bitwarden-Apps öffnen ihn. kombify installiert ihn für dich.** kombify stellt keine der beiden Apps her. [Vaultwarden](https://github.com/dani-garcia/vaultwarden) (AGPL-3.0) · Web-Tresor: [Bitwarden-Web-Client für Vaultwarden](https://github.com/dani-garcia/bw_web_builds) (GPL-3.0) · [Bitwarden](https://bitwarden.com/)"
  sources={{
summary: "Screenshots von kombify aus einer lokalen Vaultwarden-Installation · erfundenes Konto · englische Menüs.",
paragraphs: [
  "**Screenshots · 24. September 2026.** kombify hat die Bilder des Web-Tresors aus einer lokalen Referenzinstallation aufgenommen: Vaultwarden 1.37.2, das Image, das der StackKits-Katalog für Passwörter ausliefert, mit dem mitgelieferten Web-Tresor 2026.7.0 (dem Bitwarden-Web-Client, GPL-3.0). Die Installation nutzte die Beispieladresse https://vault.home.test und das erfundene Konto alex@example.com. Es ist eine Referenzinstallation, kein StackKits-Rollout-Test. Diese Anleitung hat die violetten Markierungen ergänzt.",
  "Die Bildschirme der Bitwarden-Apps werden nicht gezeigt. Die [Bedingungen von Bitwarden](https://bitwarden.com/terms/) erlauben nicht, seine Inhalte weiterzuverwenden, deshalb verweist Schritt 5 auf die eigene Anleitung von Bitwarden.",
  "Store-Links und Hilfeseiten wurden am 24. September 2026 geprüft. Dein Fortschritt bleibt in diesem Browser. Die Anleitung verbindet keine Konten und fragt nach keinen Passwörtern.",
],
links: [
  { label: "Bitwarden: einzelne Apps verbinden", href: "https://bitwarden.com/help/change-client-environment/" },
  { label: "Bitwarden-Downloads", href: "https://bitwarden.com/download/" },
  { label: "Vaultwarden-Projekt", href: "https://github.com/dani-garcia/vaultwarden" },
],
}}
/>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.