<?php
/**
 * Admin page: Wystaw fakturę ręcznie do KSeF — nowy card-based layout.
 *
 * @package KSEF\WordPress\Admin
 */

declare(strict_types=1);

namespace KSEF\WordPress\Admin;

// phpcs:disable WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders, WordPress.DB.SlowDBQuery, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.Security.NonceVerification -- Wlasne tabele gksef_*: wartosci przez $wpdb->prepare()/esc_like(), nazwy tabel z $wpdb->prefix, paginacja rzutowana (int); nonce weryfikowany w handlerze (check_ajax_referer/check_admin_referer).

use KSEF\WordPress\V2\Bootstrap as V2_Bootstrap;
use KSEF\WordPress\V2\Invoice_Numbering;

class Manual_Invoice_Page {

	public static function register_ajax(): void {
		add_action( 'wp_ajax_ksef_send_manual_invoice', [ self::class, 'ajax_send' ] );
		add_action( 'wp_ajax_ksef_save_manual_draft', [ self::class, 'ajax_save_draft' ] );
		add_action( 'wp_ajax_ksef_send_draft_invoice', [ self::class, 'ajax_send_draft' ] );
		add_action( 'wp_ajax_ksef_delete_draft', [ self::class, 'ajax_delete_draft' ] );
		add_action( 'wp_ajax_ksef_copy_invoice', [ self::class, 'ajax_copy_invoice' ] );
	}

	public const OPT_EXPENSE_CATEGORIES = 'gksef_expense_categories';

	/** Domyślne kategorie wydatków (gdy użytkownik nie ustawił własnych). */
	public static function default_expense_categories(): array {
		return [
			'Towary handlowe', 'Materiały', 'Usługi obce', 'Media (prąd/gaz/woda)',
			'Czynsz / najem', 'Paliwo', 'Transport / logistyka', 'Marketing / reklama',
			'Sprzęt / wyposażenie', 'Oprogramowanie / IT', 'Telekomunikacja',
			'Opłaty bankowe', 'Podatki / ZUS', 'Reprezentacja', 'Szkolenia', 'Inne',
		];
	}

	/**
	 * Lista kategorii wydatków — z ustawień (opcja, jedna na linię) lub domyślne.
	 *
	 * @return string[]
	 */
	public static function expense_categories(): array {
		$raw = (string) get_option( self::OPT_EXPENSE_CATEGORIES, '' );
		if ( '' === trim( $raw ) ) {
			return self::default_expense_categories();
		}
		$lines = array_values( array_filter( array_map( 'trim', preg_split( '/\r\n|\r|\n/', $raw ) ?: [] ), static fn( $l ) => '' !== $l ) );
		return $lines ?: self::default_expense_categories();
	}

	public function render_page(): void {
		if ( ! current_user_can( 'ksef_create_invoice' ) ) {
			wp_die( esc_html__( 'Brak uprawnień.', 'prostafaktura-ksef' ) );
		}
		global $wpdb;

		$action = isset( $_GET['action'] ) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : 'new';
		$mode_label = ( 'view' === $action )    ? 'Podgląd'
			: ( ( 'edit' === $action )    ? 'Edycja draftu'
			: ( ( 'correct' === $action ) ? 'Faktura korygująca'
			: 'Nowa faktura' ) );

		// Typ faktury (zakup/sprzedaż) — wpływa na okruszki i pigułkę statusu.
		$top_type = ( ( sanitize_text_field( wp_unslash( $_GET['type'] ?? '' ) ) ) === 'incoming' ) ? 'incoming' : 'outgoing';
		// Status pills near title (Szkic / status faktury).
		$hero_pills = '';
		$existing_for_pill = null;
		if ( in_array( $action, [ 'view', 'edit', 'correct' ], true ) && ! empty( $_GET['id'] ) ) {
			$pill_table = ( 'incoming' === $top_type ) ? 'gksef_incoming_invoices' : 'gksef_outgoing_invoices';
			$status_col = ( 'incoming' === $top_type ) ? "'received' AS status" : 'status';
			$existing_for_pill = $wpdb->get_row( // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- nazwy tabel z $wpdb->prefix, wartosci przez $wpdb->prepare().
				$wpdb->prepare( "SELECT {$status_col}, invoice_number FROM {$wpdb->prefix}{$pill_table} WHERE id = %d", (int) $_GET['id'] ),
				ARRAY_A
			);
		}
		$pill_st = (string) ( $existing_for_pill['status'] ?? 'draft' );
		$pill_label = 'Szkic';
		$pill_class = 'draft';
		if ( 'received' === $pill_st ) { $pill_label = 'Otrzymana'; $pill_class = 'paid'; }
		elseif ( in_array( $pill_st, [ 'sent', 'sent_from_draft' ], true ) ) { $pill_label = 'Wysłana'; $pill_class = 'sent'; }
		elseif ( 'confirmed' === $pill_st ) { $pill_label = 'Wystawiona'; $pill_class = 'paid'; }
		elseif ( 'issued' === $pill_st ) { $pill_label = 'Niewysłana'; $pill_class = 'draft'; }
		elseif ( 'failed' === $pill_st ) { $pill_label = 'Błąd wysyłki'; $pill_class = 'draft'; }
		elseif ( 'rejected' === $pill_st ) { $pill_label = 'Odrzucona'; $pill_class = 'draft'; }
		$hero_pills .= '<span class="status-pill ' . esc_attr( $pill_class ) . '">' . esc_html( $pill_label ) . '</span>';
		// (wersja darmowa: brak limitów/quota — wystawianie bez ograniczeń)
		// Eyebrow with invoice number (FV/Y/m/n).
		$inv_no_preview = (string) ( $existing_for_pill['invoice_number'] ?? Invoice_Numbering::preview() );

		// Tylko draft otwieramy od razu w edycji; issued/failed/rejected pokazujemy w podglądzie
		// (box ze statusem/błędem + przyciski „Wyślij do KSeF" / „Edytuj i wyślij").
		if ( 'view' === $action && 'incoming' !== $top_type && $existing_for_pill && 'draft' === (string) ( $existing_for_pill['status'] ?? '' ) ) {
			$action         = 'edit';
			$_GET['action'] = 'edit';
			$mode_label     = 'Edycja draftu';
		}

		// Tytuł/podtytuł zależne od trybu i typu — NIE „Wystaw fakturę" przy podglądzie.
		if ( 'view' === $action ) {
			$shell_title = ( 'incoming' === $top_type ) ? 'Faktura | zakupu' : 'Faktura | sprzedaży';
			$shell_sub   = ( 'incoming' === $top_type )
				? 'Podgląd otrzymanej faktury zakupu — pełne dane z KSeF (tylko do odczytu).'
				: 'Podgląd wystawionej faktury sprzedaży — pełne dane (tylko do odczytu).';
		} elseif ( 'edit' === $action ) {
			$shell_title = 'Edycja | faktury';
			$shell_sub   = 'Edycja szkicu faktury. Pola wymagane oznaczone gwiazdką.';
		} elseif ( 'correct' === $action ) {
			$shell_title = 'Faktura | korygująca';
			$shell_sub   = 'Wystaw korektę do faktury. Pola wymagane oznaczone gwiazdką.';
		} else {
			$shell_title = 'Wystaw | fakturę';
			$shell_sub   = 'Wystaw fakturę ręcznie i wyślij do Krajowego Systemu e-Faktur. Pola wymagane oznaczone gwiazdką. Faktura zapisuje się automatycznie jako szkic co 10 sekund.';
		}
		Modern_Shell::open( 'wystaw-fakture', [
			'crumbs'      => [ 'Faktury', ( 'incoming' === $top_type ? 'Zakupu' : 'Sprzedaży' ), $mode_label ],
			'ksef_id'     => $inv_no_preview,
			'title'       => $shell_title,
			'subtitle'    => $shell_sub,
			'title_pills' => $hero_pills,
		] );

		try {
			$this->render_page_inner();
		} finally {
			Modern_Shell::close();
		}
	}

	/**
	 * Pełnostronicowy podgląd faktury (tryb view) — kompletny widok tylko-do-odczytu.
	 * Pokazuje WYŁĄCZNIE pola obecne na fakturze (re-używa Plugin::render_invoice_full_readonly,
	 * tego samego co podgląd modalny), więc żadnych pustych kart formularza. Zachowuje
	 * aktywne zarządzanie statusem płatności i kategorią wydatku (zapis AJAX od razu).
	 *
	 * @param array  $prefill      payload z Fa3_Parser
	 * @param array  $existing_inv wiersz faktury z DB
	 * @param string $inv_type     'incoming' | 'outgoing'
	 * @param int    $inv_id       id faktury
	 * @param string $raw_xml      surowy XML FA(3) (dla drzewa pól źródłowych)
	 */
	private function render_readonly_invoice_view( array $prefill, array $existing_inv, string $inv_type, int $inv_id, string $raw_xml ): void {
		$nonce      = wp_create_nonce( 'ksef-nonce' );
		$ajax       = admin_url( 'admin-ajax.php' );
		$pay_status = (string) ( $existing_inv['payment_status'] ?? 'unpaid' );
		$xml_pay_status = (string) ( $prefill['payment']['payment_status'] ?? '' );
		if ( 'unpaid' === $pay_status && in_array( $xml_pay_status, [ 'paid', 'partial' ], true ) ) {
			$pay_status = $xml_pay_status;
		}
		$cur_cat  = (string) ( $existing_inv['category'] ?? '' );
		$has_data = ! empty( $prefill ) && ( ! empty( $prefill['seller'] ) || ! empty( $prefill['items'] ) );

		$h     = static fn ( $v ) => esc_html( (string) $v );
		$money = static fn ( $v ) => number_format( (float) $v, 2, ',', ' ' );
		$cur   = (string) ( $prefill['currency'] ?? $existing_inv['currency'] ?? 'PLN' );
		$num   = (string) ( $prefill['invoice_number'] ?? $existing_inv['invoice_number'] ?? ( '#' . $inv_id ) );
		$sys   = $prefill['system_info'] ?? [];
		$pdf_url = add_query_arg( [ 'action' => 'ksef_invoice_pdf', 'invoice_id' => $inv_id, 'type' => $inv_type, '_ajax_nonce' => $nonce ], $ajax );
		$pdf_preview_url = add_query_arg( [ 'preview' => '1' ], $pdf_url );

		// Adres do jednej linii
		$fmt_addr = static function ( array $a ) use ( $h ) {
			$l1 = trim( (string) ( $a['street'] ?? '' ) );
			$l2 = trim( ( (string) ( $a['postal_code'] ?? '' ) ) . ' ' . ( (string) ( $a['city'] ?? '' ) ) );
			$parts = array_filter( [ $l1, $l2 ] );
			$out = $parts ? implode( ', ', array_map( $h, $parts ) ) : '—';
			if ( ! empty( $a['country'] ) && 'PL' !== $a['country'] ) {
				$out .= ' · ' . $h( $a['country'] );
			}
			return $out;
		};
		$party_card = static function ( string $title, string $icon, array $p, bool $show_jstgv ) use ( $h, $fmt_addr ) {
			$a = $p['address'] ?? [];
			$id_line = '';
			if ( ! empty( $p['nip'] ) )         $id_line = 'NIP: ' . $h( $p['nip'] );
			elseif ( ! empty( $p['vat_ue'] ) )  $id_line = 'VAT-UE: ' . $h( ( $p['country_ue'] ?? '' ) . ' ' . $p['vat_ue'] );
			elseif ( ! empty( $p['nr_id'] ) )   $id_line = 'ID: ' . $h( $p['nr_id'] );
			elseif ( ! empty( $p['brak_id'] ) ) $id_line = 'Osoba prywatna';
			$out  = '<div class="ksv-card"><div class="ksv-card-h">' . $icon . ' <span>' . $h( $title ) . '</span></div>';
			$out .= '<div class="ksv-party-name">' . $h( $p['name'] ?? '—' ) . '</div>';
			if ( '' !== $id_line ) $out .= '<div class="ksv-party-id">' . $id_line . '</div>';
			$out .= '<div class="ksv-party-addr">📍 ' . $fmt_addr( (array) $a ) . '</div>';
			if ( $show_jstgv && ( '' !== (string) ( $p['jst'] ?? '' ) || '' !== (string) ( $p['gv'] ?? '' ) ) ) {
				$out .= '<div class="ksv-party-extra">';
				if ( '' !== (string) ( $p['jst'] ?? '' ) ) $out .= 'JST: ' . $h( $p['jst'] ) . '  ';
				if ( '' !== (string) ( $p['gv'] ?? '' ) )  $out .= 'GV: ' . $h( $p['gv'] );
				$out .= '</div>';
			}
			return $out . '</div>';
		};

		$ic_build  = '<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M9 8h1M9 12h1M9 16h1M14 8h1M14 12h1M14 16h1"/></svg>';
		$ic_person = '<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="8" r="4"/><path d="M4 21a8 8 0 0 1 16 0"/></svg>';

		$items = $prefill['items'] ?? [];
		$vs    = $prefill['vat_summary'] ?? [];
		$total_gross = (float) ( $prefill['total_gross'] ?? $existing_inv['gross_amount'] ?? 0 );
		$total_net   = (float) ( $prefill['total_net'] ?? $existing_inv['net_amount'] ?? 0 );
		$total_vat   = (float) ( $prefill['total_vat'] ?? $existing_inv['vat_amount'] ?? 0 );

		// Adnotacje (Tak/Nie)
		$adn = $prefill['adnotacje'] ?? [];
		$mk  = $prefill['markers'] ?? [];
		$ann = [
			[ 'P_16 (metoda kasowa)',            ( ( $adn['P_16'] ?? '2' ) === '1' ) ],
			[ 'P_17 (samofakturowanie)',         ( ( $adn['P_17'] ?? '2' ) === '1' ) ],
			[ 'P_18 (odwrotne obciążenie)',      ( ( $adn['P_18'] ?? '2' ) === '1' ) ],
			[ 'P_18A (split payment)',           ( ( $adn['P_18A'] ?? '2' ) === '1' ) ],
			[ 'Zwolnienie z VAT (P_19)',         ( ( ( $adn['P_19'] ?? '' ) === '1' ) || ( ( $adn['Zwolnienie']['P_19'] ?? '' ) === '1' ) || ! empty( $mk['P_19'] ) ) ],
			[ 'Nowe środki transportu (P_22)',   ( ( ( $adn['P_22'] ?? '' ) === '1' ) || ( ( $adn['NoweSrodkiTransportu']['P_22'] ?? '' ) === '1' ) || ! empty( $mk['P_22'] ) ) ],
			[ 'P_23 (WDT/usługi)',               ( ( $adn['P_23'] ?? '2' ) === '1' ) ],
			[ 'Procedura marży (PMarży)',        ( ! empty( $mk['PMarzy'] ) || ! empty( $adn['P_PMarzy'] ) ) ],
				[ 'Faktura do paragonu (FP)',        ( ! empty( $mk['FP'] ) ) ],
				[ 'Powiązania między stronami (TP)', ( ! empty( $mk['TP'] ) ) ],
				[ 'Faktura za okres',                ( ! empty( $mk['fa_za_okres'] ) ) ],
				[ 'Procedura OSS VAT',               ( ! empty( $mk['OSS'] ) ) ],
		];

		// Dodatkowy opis (DodatkowyOpis key/value, value bywa JSON)
		$knotes = $prefill['ksef_custom_notes'] ?? [];
		$label_map = [ 'partner_id' => 'Partner ID', 'internal_ref' => 'Internal ref', 'partner' => 'Partner', 'reference' => 'Referencja' ];

		$created = '';
		if ( ! empty( $sys['data_wytworzenia'] ) ) {
			$ts = strtotime( (string) $sys['data_wytworzenia'] );
			$created = $ts ? gmdate( 'd.m.Y', $ts ) : (string) $sys['data_wytworzenia'];
		}
		$form_bits = array_filter( [
			( $sys['kod_systemowy'] ?? '' ) ?: ( $sys['kod_formularza'] ?? '' ),
			! empty( $sys['wersja_schemy'] ) ? ( 'v' . $sys['wersja_schemy'] ) : '',
			! empty( $sys['wariant'] ) ? ( 'wariant ' . $sys['wariant'] ) : '',
		] );
		$rodzaj = (string) ( $prefill['rodzaj_faktury'] ?? 'VAT' );
		$list_url = admin_url( 'admin.php?page=' . ( 'incoming' === $inv_type ? 'ksef-incoming-invoices' : 'ksef-outgoing-invoices' ) );
		// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped -- szablon read-only: dane przez $h()=esc_html(), $money()=number_format(), $party_card() pre-escaped.
		?>
		<div class="ksv-wrap">
			<div class="ksv-head">
				<div class="ksv-title">
					<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="1.7"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg>
					<h2>Faktura <?php echo $h( $num ); ?></h2>
					<span class="ksv-badge"><?php echo $h( $rodzaj ); ?></span>
				</div>
			</div>

			<div class="ksv-tabs" role="tablist">
				<button type="button" class="ksv-tab is-active" data-tab="szczegoly"><?php esc_html_e( 'Szczegóły', 'prostafaktura-ksef' ); ?></button>
				<button type="button" class="ksv-tab" data-tab="pdf">PDF</button>
				<button type="button" class="ksv-tab" data-tab="xml">XML</button>
			</div>

			<!-- ZAKŁADKA: SZCZEGÓŁY -->
			<div class="ksv-panel is-active" id="ksv-tab-szczegoly">
				<?php if ( ! $has_data ) : ?>
					<div class="ksv-alert"><?php esc_html_e( 'Nie udało się pobrać pełnej treści faktury z KSeF (np. chwilowy problem z połączeniem). Odśwież stronę za chwilę.', 'prostafaktura-ksef' ); ?></div>
				<?php endif; ?>

				<div class="ksv-meta">
					<?php if ( ! empty( $existing_inv['ksef_reference_number'] ) ) : ?><span># KSeF: <code><?php echo $h( $existing_inv['ksef_reference_number'] ); ?></code></span><?php endif; ?>
					<?php if ( ! empty( $sys['system_info'] ) ) : ?><span>System: <?php echo $h( $sys['system_info'] ); ?></span><?php endif; ?>
					<?php if ( '' !== $created ) : ?><span>Utworzono: <?php echo $h( $created ); ?></span><?php endif; ?>
					<?php if ( $form_bits ) : ?><span class="ksv-form"><?php echo $h( implode( ' | ', $form_bits ) ); ?></span><?php endif; ?>
				</div>

				<div class="ksv-parties">
					<?php
					echo $party_card( __( 'Sprzedawca (Podmiot1)', 'prostafaktura-ksef' ), $ic_build, (array) ( $prefill['seller'] ?? [] ), false ); // phpcs:ignore
					echo $party_card( __( 'Nabywca (Podmiot2)', 'prostafaktura-ksef' ), $ic_person, (array) ( $prefill['buyer'] ?? [] ), true ); // phpcs:ignore
					?>
				</div>

				<div class="ksv-dates">
					<div><span><?php esc_html_e( 'Data wystawienia', 'prostafaktura-ksef' ); ?></span><strong><?php echo $h( $prefill['issue_date'] ?? '—' ); ?></strong></div>
					<div><span><?php esc_html_e( 'Data sprzedaży', 'prostafaktura-ksef' ); ?></span><strong><?php echo $h( $prefill['sale_date'] ?? '—' ); ?></strong></div>
					<div><span><?php esc_html_e( 'Waluta', 'prostafaktura-ksef' ); ?></span><strong><?php echo $h( $cur ); ?></strong></div>
				</div>

				<?php if ( ! empty( $items ) ) : ?>
				<h3 class="ksv-sec"><?php esc_html_e( 'Pozycje faktury', 'prostafaktura-ksef' ); ?></h3>
				<div class="ksv-table-wrap">
				<table class="ksv-table">
					<thead><tr>
						<th>Lp.</th><th><?php esc_html_e( 'Nazwa towaru / usługi', 'prostafaktura-ksef' ); ?></th><th>Jedn.</th>
						<th class="r"><?php esc_html_e( 'Ilość', 'prostafaktura-ksef' ); ?></th><th class="r"><?php esc_html_e( 'Cena netto', 'prostafaktura-ksef' ); ?></th>
						<th class="r"><?php esc_html_e( 'Wartość netto', 'prostafaktura-ksef' ); ?></th><th>VAT</th><th class="r"><?php esc_html_e( 'Wartość brutto', 'prostafaktura-ksef' ); ?></th>
					</tr></thead>
					<tbody>
					<?php foreach ( $items as $i => $it ) :
						$rate = $it['vat_rate'] ?? 23;
						$rate_str = is_numeric( $rate ) ? ( (int) round( (float) $rate ) ) . '%' : strtoupper( (string) $rate );
					?>
						<tr>
							<td><?php echo $h( $it['lp'] ?? ( $i + 1 ) ); ?></td>
							<td><?php echo $h( $it['description'] ?? '' ); ?></td>
							<td><?php echo $h( $it['unit'] ?? 'szt.' ); ?></td>
							<td class="r"><?php echo $h( number_format( (float) ( $it['quantity'] ?? 0 ), 2, ',', ' ' ) ); ?></td>
							<td class="r"><?php echo $h( $money( $it['unit_price_net'] ?? 0 ) ); ?> zł</td>
							<td class="r"><strong><?php echo $h( $money( $it['line_net'] ?? 0 ) ); ?> zł</strong></td>
							<td><?php echo $h( $rate_str ); ?></td>
							<td class="r"><strong><?php echo $h( $money( $it['line_gross'] ?? 0 ) ); ?> zł</strong></td>
						</tr>
					<?php endforeach; ?>
					</tbody>
				</table>
				</div>
				<?php endif; ?>

				<?php if ( ! empty( $vs ) ) : ?>
				<h3 class="ksv-sec"><?php esc_html_e( 'Podsumowanie VAT', 'prostafaktura-ksef' ); ?></h3>
				<table class="ksv-vat">
					<thead><tr><th><?php esc_html_e( 'Stawka', 'prostafaktura-ksef' ); ?></th><th class="r">Netto</th><th class="r">VAT</th><th class="r">Brutto</th></tr></thead>
					<tbody>
					<?php foreach ( $vs as $v ) :
						$rl = is_numeric( $v['rate'] ?? '' ) ? ( (int) round( (float) $v['rate'] ) ) . '%' : strtoupper( (string) ( $v['rate'] ?? '' ) );
						$br = (float) ( $v['base_net'] ?? 0 ) + (float) ( $v['vat_amount'] ?? 0 );
					?>
						<tr><td><?php echo $h( $rl ); ?></td><td class="r"><?php echo $h( $money( $v['base_net'] ?? 0 ) ); ?> zł</td><td class="r"><?php echo $h( $money( $v['vat_amount'] ?? 0 ) ); ?> zł</td><td class="r"><?php echo $h( $money( $br ) ); ?> zł</td></tr>
					<?php endforeach; ?>
						<tr class="tot"><td>RAZEM</td><td class="r"><?php echo $h( $money( $total_net ) ); ?> zł</td><td class="r"><?php echo $h( $money( $total_vat ) ); ?> zł</td><td class="r"><?php echo $h( $money( $total_gross ) ); ?> zł</td></tr>
					</tbody>
				</table>
				<?php endif; ?>

				<div class="ksv-due"><span><?php esc_html_e( 'Do zapłaty', 'prostafaktura-ksef' ); ?></span><strong><?php echo $h( $money( $total_gross ) ); ?> <?php echo $h( $cur ); ?></strong></div>

				<h3 class="ksv-sec"><?php esc_html_e( 'Adnotacje', 'prostafaktura-ksef' ); ?></h3>
				<div class="ksv-ann">
					<?php foreach ( $ann as $row ) : ?>
						<div class="ksv-ann-row"><span><?php echo $h( $row[0] ); ?></span><?php echo $row[1] ? '<b class="yes">Tak</b>' : '<b class="no">Nie</b>'; ?></div>
					<?php endforeach; ?>
				</div>

				<?php if ( ! empty( $knotes ) ) : ?>
				<h3 class="ksv-sec"><?php esc_html_e( 'Dodatkowy opis', 'prostafaktura-ksef' ); ?></h3>
				<?php foreach ( $knotes as $kn ) : ?>
					<div class="ksv-note">
						<?php if ( '' !== (string) ( $kn['key'] ?? '' ) ) : ?><div class="ksv-note-row"><span>Klucz</span><b><?php echo $h( $kn['key'] ); ?></b></div><?php endif; ?>
						<?php
						$val = (string) ( $kn['value'] ?? '' );
						$dec = json_decode( $val, true );
						if ( is_array( $dec ) ) {
							foreach ( $dec as $k => $v ) {
								$lbl = $label_map[ (string) $k ] ?? ucfirst( str_replace( '_', ' ', (string) $k ) );
								echo '<div class="ksv-note-row"><span>' . $h( $lbl ) . '</span><b>' . $h( is_scalar( $v ) ? $v : wp_json_encode( $v ) ) . '</b></div>';
							}
						} elseif ( '' !== $val ) {
							echo '<div class="ksv-note-row"><span>Wartość</span><b>' . $h( $val ) . '</b></div>';
						}
						?>
					</div>
				<?php endforeach; ?>
				<?php endif; ?>

				<!-- Rozliczenie (edytowalne) -->
				<h3 class="ksv-sec"><?php esc_html_e( 'Rozliczenie', 'prostafaktura-ksef' ); ?></h3>
				<div id="ksef-paystatus-field" data-invoice-id="<?php echo (int) $inv_id; ?>" data-inv-type="<?php echo esc_attr( $inv_type ); ?>" data-current="<?php echo esc_attr( $pay_status ); ?>">
					<label class="ksv-lbl"><?php esc_html_e( 'Status płatności', 'prostafaktura-ksef' ); ?></label>
					<div class="ksv-seg">
						<?php foreach ( [ 'unpaid' => __( 'Niezapłacona', 'prostafaktura-ksef' ), 'paid' => __( 'Zapłacona w całości', 'prostafaktura-ksef' ), 'partial' => __( 'Częściowo', 'prostafaktura-ksef' ) ] as $val => $lbl ) : ?>
							<label class="ksv-seg-item"><input type="radio" name="ro_payment_status" value="<?php echo esc_attr( $val ); ?>" <?php checked( $pay_status, $val ); ?>> <?php echo esc_html( $lbl ); ?></label>
						<?php endforeach; ?>
					</div>
					<span id="ksef-paystatus-saved" class="ksv-hint"></span>
				</div>
				<?php
				$ksef_pays = $inv_id > 0 ? \KSEF\WordPress\Payments_Repository::list_for_invoice( $inv_id ) : [];
				if ( ! empty( $ksef_pays ) ) : $pay_sum = 0.0; ?>
					<div class="ksv-paylist" style="margin-top:14px;">
						<label class="ksv-lbl"><?php esc_html_e( 'Zarejestrowane wpłaty', 'prostafaktura-ksef' ); ?></label>
						<table style="width:100%;border-collapse:collapse;font-size:13px;margin-top:6px;">
							<thead><tr style="border-bottom:1px solid #e2e2e7;">
								<th style="text-align:left;padding:6px 8px;color:#6b7280;font-weight:500;"><?php esc_html_e( 'Data', 'prostafaktura-ksef' ); ?></th>
								<th style="text-align:left;padding:6px 8px;color:#6b7280;font-weight:500;"><?php esc_html_e( 'Forma', 'prostafaktura-ksef' ); ?></th>
								<th style="text-align:right;padding:6px 8px;color:#6b7280;font-weight:500;"><?php esc_html_e( 'Kwota', 'prostafaktura-ksef' ); ?></th>
							</tr></thead>
							<tbody>
							<?php foreach ( $ksef_pays as $ksef_pay ) : $pay_sum += (float) ( $ksef_pay['amount'] ?? 0 ); ?>
								<tr style="border-bottom:1px solid #f1f1f4;">
									<td style="padding:6px 8px;"><?php echo esc_html( (string) ( $ksef_pay['payment_date'] ?? '' ) ); ?></td>
									<td style="padding:6px 8px;"><?php echo esc_html( (string) ( $ksef_pay['payment_method'] ?? '' ) ); ?></td>
									<td style="text-align:right;padding:6px 8px;"><?php echo esc_html( number_format( (float) ( $ksef_pay['amount'] ?? 0 ), 2, ',', ' ' ) ); ?></td>
								</tr>
							<?php endforeach; ?>
							</tbody>
							<tfoot><tr>
								<td colspan="2" style="text-align:right;padding:6px 8px;font-weight:600;"><?php esc_html_e( 'Razem wpłacono:', 'prostafaktura-ksef' ); ?></td>
								<td style="text-align:right;padding:6px 8px;font-weight:600;"><?php echo esc_html( number_format( $pay_sum, 2, ',', ' ' ) ); ?></td>
							</tr></tfoot>
						</table>
					</div>
				<?php endif; ?>
				<?php if ( 'incoming' === $inv_type ) : $cats = self::expense_categories(); ?>
				<div id="ksef-zakup-kat-field" data-invoice-id="<?php echo (int) $inv_id; ?>" style="margin-top:14px;">
					<label class="ksv-lbl" for="ro-zakup-kategoria"><?php esc_html_e( 'Kategoria wydatku', 'prostafaktura-ksef' ); ?></label>
					<select id="ro-zakup-kategoria" class="ksv-select">
						<option value=""><?php esc_html_e( '— wybierz —', 'prostafaktura-ksef' ); ?></option>
						<?php foreach ( $cats as $opt ) : ?><option value="<?php echo esc_attr( $opt ); ?>" <?php selected( $cur_cat, $opt ); ?>><?php echo esc_html( $opt ); ?></option><?php endforeach; ?>
						<?php if ( '' !== $cur_cat && ! in_array( $cur_cat, $cats, true ) ) : ?><option value="<?php echo esc_attr( $cur_cat ); ?>" selected><?php echo esc_html( $cur_cat ); ?></option><?php endif; ?>
					</select>
					<span id="zakup-cat-saved" class="ksv-hint"></span>
					<p class="ksv-sub"><a href="<?php echo esc_url( admin_url( 'admin.php?page=ksef-settings' ) ); ?>"><?php esc_html_e( 'Edytuj listę kategorii w Ustawieniach', 'prostafaktura-ksef' ); ?></a></p>
				</div>
				<?php endif; ?>
			</div>

			<!-- ZAKŁADKA: PDF -->
			<div class="ksv-panel" id="ksv-tab-pdf">
				<iframe id="ksv-pdf-frame" data-src="<?php echo esc_url( $pdf_preview_url ); ?>" style="width:100%;height:90vh;min-height:900px;border:0;border-radius:8px;background:#525659;"></iframe>
			</div>

			<!-- ZAKŁADKA: XML -->
			<div class="ksv-panel" id="ksv-tab-xml">
				<?php if ( '' !== $raw_xml ) :
					// Sformatuj (wcięcia) — KSeF często zwraca XML w jednej linii.
					$pretty = $raw_xml;
					$dxml = new \DOMDocument( '1.0', 'UTF-8' );
					$dxml->preserveWhiteSpace = false;
					$dxml->formatOutput = true;
					if ( @$dxml->loadXML( $raw_xml ) ) {
						$pretty = $dxml->saveXML();
					}
				?>
					<pre class="ksv-xml"><?php echo $h( $pretty ); ?></pre>
				<?php else : ?>
					<div class="ksv-alert"><?php esc_html_e( 'Brak pełnego XML dla tej faktury.', 'prostafaktura-ksef' ); ?></div>
				<?php endif; ?>
			</div>

			<!-- STOPKA: akcje -->
			<div class="ksv-foot">
				<a class="ksv-btn ksv-btn-light" href="<?php echo esc_url( $pdf_url ); ?>" target="_blank">📄 <?php esc_html_e( 'Pobierz PDF', 'prostafaktura-ksef' ); ?></a>
				<button type="button" class="ksv-btn ksv-btn-light" id="ksv-dl-xml" <?php echo '' === $raw_xml ? 'disabled' : ''; ?>>⬇ <?php esc_html_e( 'Pobierz XML', 'prostafaktura-ksef' ); ?></button>
				<?php if ( 'outgoing' === $inv_type && ! empty( $existing_inv['ksef_reference_number'] ) ) :
					$upo_dl = add_query_arg( [ 'action' => 'ksef_download_upo', 'invoice_id' => $inv_id, '_ajax_nonce' => $nonce ], $ajax );
				?>
					<a class="ksv-btn ksv-btn-light" href="<?php echo esc_url( $upo_dl ); ?>" target="_blank">🧾 <?php esc_html_e( 'Pobierz UPO', 'prostafaktura-ksef' ); ?></a>
				<?php endif; ?>
				<?php
					// Niewysłana do KSeF (draft/issued/failed/rejected) — można wysłać lub edytować i wysłać.
					$is_sendable_outgoing = ( 'outgoing' === $inv_type && empty( $existing_inv['ksef_reference_number'] )
						&& in_array( (string) ( $existing_inv['status'] ?? '' ), [ 'draft', 'issued', 'failed', 'rejected' ], true ) );
					if ( $is_sendable_outgoing ) :
						$edit_url = admin_url( 'admin.php?page=ksef-manual-invoice&action=edit&id=' . (int) $inv_id . '&type=outgoing' );
						$send_lbl = in_array( (string) ( $existing_inv['status'] ?? '' ), [ 'failed', 'rejected' ], true ) ? __( 'Ponów wysyłkę', 'prostafaktura-ksef' ) : __( 'Wyślij do KSeF', 'prostafaktura-ksef' );
					?>
						<a class="ksv-btn ksv-btn-light" href="<?php echo esc_url( $edit_url ); ?>">✎ <?php esc_html_e( 'Edytuj i wyślij', 'prostafaktura-ksef' ); ?></a>
						<button type="button" class="ksv-btn ksv-btn-primary" id="ksv-send-draft" data-draft-id="<?php echo (int) $inv_id; ?>">📤 <?php echo esc_html( $send_lbl ); ?></button>
					<?php endif; ?>
					<a class="ksv-btn ksv-btn-light" href="<?php echo esc_url( $list_url ); ?>"><?php esc_html_e( 'Wróć do listy', 'prostafaktura-ksef' ); ?></a>
			</div>
		</div>

		<?php ob_start(); ?>
		.ksv-wrap{max-width:1480px;margin:0 auto;background:#fff;border:1px solid #e7eaee;border-radius:16px;padding:22px 26px;font-family:-apple-system,"Segoe UI",Roboto,sans-serif;color:#1a1d21;}
		/* PDF na pełną szerokość karty (wybij poza wewnętrzny padding) */
		.ksv-panel#ksv-tab-pdf{margin:0 -26px;}
		#ksv-pdf-frame{display:block;}
		.ksv-head{display:flex;justify-content:space-between;align-items:center;}
		.ksv-title{display:flex;align-items:center;gap:10px;color:#374151;}
		.ksv-title h2{font-size:21px;font-weight:800;margin:0;color:#111827;}
		.ksv-badge{background:#eef2ff;color:#4f46e5;font-size:11px;font-weight:700;padding:3px 10px;border-radius:999px;border:1px solid #e0e7ff;}
		.ksv-tabs{display:flex;gap:6px;background:#f3f4f6;border-radius:12px;padding:5px;margin:18px 0 18px;}
		.ksv-tab{flex:1;border:0;background:transparent;border-radius:9px;padding:9px 14px;font-size:14px;font-weight:600;color:#6b7280;cursor:pointer;}
		.ksv-tab.is-active{background:#fff;color:#111827;box-shadow:0 1px 3px rgba(0,0,0,.08);}
		.ksv-panel{display:none;}
		.ksv-panel.is-active{display:block;}
		.ksv-meta{display:flex;flex-wrap:wrap;gap:6px 18px;color:#6b7280;font-size:12.5px;margin-bottom:18px;align-items:center;}
		.ksv-meta code{background:#f3f4f6;padding:1px 6px;border-radius:4px;font-size:11.5px;color:#374151;}
		.ksv-meta .ksv-form{margin-left:auto;color:#9ca3af;}
		.ksv-parties{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-bottom:18px;}
		.ksv-card{border:1px solid #e7eaee;border-radius:12px;padding:16px 18px;}
		.ksv-card-h{display:flex;align-items:center;gap:8px;color:#6b7280;font-size:14px;font-weight:600;margin-bottom:10px;}
		.ksv-party-name{font-size:16px;font-weight:700;color:#111827;margin-bottom:3px;}
		.ksv-party-id{color:#6b7280;font-size:13px;margin-bottom:8px;}
		.ksv-party-addr{color:#374151;font-size:13px;line-height:1.5;}
		.ksv-party-extra{color:#6b7280;font-size:12.5px;margin-top:8px;}
		.ksv-dates{display:grid;grid-template-columns:1fr 1fr 1fr;gap:14px;border-top:1px solid #f0f1f3;border-bottom:1px solid #f0f1f3;padding:14px 0;margin-bottom:18px;}
		.ksv-dates span{display:block;color:#6b7280;font-size:12px;margin-bottom:3px;}
		.ksv-dates strong{font-size:15px;color:#111827;}
		.ksv-sec{font-size:15px;font-weight:700;color:#111827;margin:18px 0 10px;}
		.ksv-table-wrap{overflow-x:auto;}
		.ksv-table{width:100%;border-collapse:collapse;font-size:13px;}
		.ksv-table th{text-align:left;color:#6b7280;font-size:11.5px;font-weight:600;text-transform:uppercase;padding:8px 10px;border-bottom:1px solid #e7eaee;}
		.ksv-table td{padding:12px 10px;border-bottom:1px solid #f0f1f3;vertical-align:top;}
		.ksv-table .r,.ksv-vat .r{text-align:right;}
		.ksv-vat{width:100%;max-width:560px;margin-left:auto;border-collapse:collapse;font-size:13px;}
		.ksv-vat th{color:#6b7280;font-size:11.5px;text-transform:uppercase;padding:8px 10px;border-bottom:1px solid #e7eaee;text-align:left;}
		.ksv-vat td{padding:9px 10px;border-bottom:1px solid #f0f1f3;}
		.ksv-vat tr.tot td{font-weight:800;border-top:2px solid #e5e7eb;background:#fafbfc;}
		.ksv-due{display:flex;justify-content:flex-end;align-items:center;gap:14px;margin:14px 0;}
		.ksv-due span{color:#6b7280;font-weight:600;}
		.ksv-due strong{background:#fff2eb;color:#d9531e;font-size:18px;font-weight:800;padding:8px 18px;border-radius:10px;border:1px solid #ffd7be;}
		.ksv-ann{display:grid;grid-template-columns:1fr 1fr;gap:8px 28px;}
		.ksv-ann-row{display:flex;justify-content:space-between;align-items:center;color:#4f46e5;font-size:13px;border-bottom:1px solid #f3f4f6;padding:5px 0;}
		.ksv-ann-row b.yes{color:#16a34a;}
		.ksv-ann-row b.no{color:#9ca3af;font-weight:600;}
		.ksv-note{border:1px solid #e7eaee;border-radius:10px;padding:12px 16px;margin-bottom:8px;}
		.ksv-note-row{display:grid;grid-template-columns:120px 1fr;gap:10px;font-size:13px;padding:3px 0;}
		.ksv-note-row span{color:#6b7280;}
		.ksv-lbl{display:block;font-size:12px;color:#6b7280;margin-bottom:6px;}
		.ksv-seg{display:inline-flex;gap:6px;flex-wrap:wrap;}
		.ksv-seg-item{display:inline-flex;align-items:center;gap:6px;border:1px solid #e7eaee;border-radius:8px;padding:8px 14px;font-size:13px;cursor:pointer;}
		.ksv-select{min-width:240px;padding:8px 10px;border:1px solid #e7eaee;border-radius:8px;font-size:13px;}
		.ksv-hint{margin-left:10px;font-size:12px;}
		.ksv-sub{font-size:11.5px;margin:6px 0 0;}
		.ksv-alert{background:#fef2f2;border:1px solid #fecaca;color:#b91c1c;border-radius:10px;padding:12px 14px;font-size:13px;margin-bottom:14px;}
		.ksv-xml{background:#0f172a;color:#e2e8f0;padding:16px;border-radius:10px;overflow:auto;max-height:70vh;font-size:12px;line-height:1.5;white-space:pre-wrap;word-break:break-word;tab-size:2;font-family:"SF Mono",Menlo,Consolas,monospace;}
		.ksv-foot{display:flex;gap:10px;justify-content:flex-end;align-items:center;border-top:1px solid #f0f1f3;margin-top:22px;padding-top:18px;}
		.ksv-btn{display:inline-flex;align-items:center;gap:6px;border-radius:10px;padding:10px 18px;font-size:14px;font-weight:600;cursor:pointer;text-decoration:none;border:1px solid transparent;}
		.ksv-btn-light{background:#fff;border-color:#d1d5db;color:#374151;}
		.ksv-btn-light:hover{background:#f9fafb;}
		.ksv-btn-primary{background:#d9531e;color:#fff;}
		.ksv-btn-primary:hover{opacity:.92;color:#fff;}
		.ksv-btn[disabled]{opacity:.5;cursor:not-allowed;}
		@media(max-width:780px){.ksv-parties,.ksv-dates,.ksv-ann{grid-template-columns:1fr;}}
		<?php Modern_Shell::inline_style( 'ksef-manual-invoice-a', ob_get_clean() ); ob_start(); ?>
		(function(){
			const AJAX = <?php echo wp_json_encode( $ajax ); ?>;
			const NONCE = <?php echo wp_json_encode( $nonce ); ?>;
			const RAWXML = <?php echo wp_json_encode( $raw_xml ); ?>;
			const NUM = <?php echo wp_json_encode( $num ); ?>;
			function flash(el, ok){ if(!el) return; el.textContent = ok ? '✓ zapisano' : '✗ błąd'; el.style.color = ok ? '#16a34a' : '#dc2626'; setTimeout(()=>{ el.textContent=''; }, 2500); }
				// Wyślij szkic do KSeF (z widoku podglądu)
				const sendBtn = document.getElementById('ksv-send-draft');
				if (sendBtn) sendBtn.addEventListener('click', async function(){
					const id = sendBtn.getAttribute('data-draft-id');
					if (!id) return;
					if (!confirm('Wysłać tę fakturę do KSeF? Po wysłaniu nie można jej już edytować.')) return;
					const orig = sendBtn.innerHTML;
					sendBtn.disabled = true; sendBtn.innerHTML = 'Wysyłanie…';
					try {
						const fd = new FormData();
						fd.append('action','ksef_send_draft_invoice');
						fd.append('nonce',NONCE);
						fd.append('draft_id',id);
						const resp = await fetch(AJAX,{method:'POST',body:fd,credentials:'same-origin'});
						const j = await resp.json();
						if (j && j.success) {
							sendBtn.innerHTML = '✓ Wysłano';
							setTimeout(()=>location.reload(), 600);
						} else {
							alert('Nie udało się wysłać do KSeF:\n' + ((j && j.data && j.data.message) || 'nieznany błąd'));
							sendBtn.disabled = false; sendBtn.innerHTML = orig;
						}
					} catch(e){
						alert('Błąd połączenia przy wysyłce do KSeF.');
						sendBtn.disabled = false; sendBtn.innerHTML = orig;
					}
				});
			// Tabs
			document.querySelectorAll('.ksv-tab').forEach(tab => {
				tab.addEventListener('click', () => {
					document.querySelectorAll('.ksv-tab').forEach(t => t.classList.remove('is-active'));
					document.querySelectorAll('.ksv-panel').forEach(p => p.classList.remove('is-active'));
					tab.classList.add('is-active');
					const panel = document.getElementById('ksv-tab-' + tab.dataset.tab);
					if (panel) panel.classList.add('is-active');
					if (tab.dataset.tab === 'pdf') {
						const f = document.getElementById('ksv-pdf-frame');
						// #view=FitH → natywna przeglądarka PDF dopasowuje stronę do SZEROKOŚCI
						// ramki (zamiast „cała strona", przez co wyglądała mała).
						if (f && !f.src) f.src = f.dataset.src + '#view=FitH&toolbar=1';
					}
				});
			});
			// Pobierz XML (client-side)
			const dl = document.getElementById('ksv-dl-xml');
			if (dl) dl.addEventListener('click', () => {
				if (!RAWXML) return;
				const blob = new Blob([RAWXML], { type: 'application/xml' });
				const a = document.createElement('a');
				a.href = URL.createObjectURL(blob);
				a.download = 'faktura-' + String(NUM).replace(/[^A-Za-z0-9_-]/g,'_') + '.xml';
				document.body.appendChild(a); a.click(); a.remove();
				setTimeout(()=>URL.revokeObjectURL(a.href), 1000);
			});
			// Status płatności
			const psf = document.getElementById('ksef-paystatus-field');
			if (psf) {
				const id = psf.getAttribute('data-invoice-id');
				const type = psf.getAttribute('data-inv-type') || 'outgoing';
				psf.querySelectorAll('input[name="ro_payment_status"]').forEach(r => {
					r.addEventListener('change', async function(){
						try {
							const fd = new FormData();
							fd.append('action','ksef_set_payment_status'); fd.append('_ajax_nonce',NONCE);
							fd.append('invoice_id',id); fd.append('type',type); fd.append('status',r.value);
							const resp = await fetch(AJAX,{method:'POST',body:fd,credentials:'same-origin'});
							const j = await resp.json(); flash(document.getElementById('ksef-paystatus-saved'), j.success);
						} catch(e){ flash(document.getElementById('ksef-paystatus-saved'), false); }
					});
				});
			}
			// Kategoria wydatku (zakup)
			const kf = document.getElementById('ksef-zakup-kat-field');
			const cat = document.getElementById('ro-zakup-kategoria');
			if (kf && cat) {
				const cid = kf.getAttribute('data-invoice-id');
				cat.addEventListener('change', async function(){
					try {
						const fd = new FormData();
						fd.append('action','ksef_set_incoming_category'); fd.append('_ajax_nonce',NONCE);
						fd.append('invoice_id',cid); fd.append('category',cat.value);
						const r = await fetch(AJAX,{method:'POST',body:fd,credentials:'same-origin'});
						const j = await r.json(); flash(document.getElementById('zakup-cat-saved'), j.success);
					} catch(e){ flash(document.getElementById('zakup-cat-saved'), false); }
				});
			}
		})();
		<?php Modern_Shell::inline_script( 'ksef-manual-invoice-a', ob_get_clean() ); ?>
		<?php
		// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
	}

	private function render_page_inner(): void {
		global $wpdb;
		$creds = $wpdb->get_results(
			"SELECT id, nip, name, ksef_environment FROM {$wpdb->prefix}gksef_credentials ORDER BY id ASC",
			ARRAY_A
		);
		$default_cred_id = (int) get_option( 'ksef_default_credential_id', 0 );
		$nonce = wp_create_nonce( 'ksef-nonce' );
		$ajax  = admin_url( 'admin-ajax.php' );

		// Tryb: new (default) / edit / view / correct
		$action     = isset( $_GET['action'] ) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : 'new';
		$inv_id     = intval( wp_unslash( $_GET['id'] ?? 0 ) );
		$is_view    = ( 'view' === $action );
		$is_edit    = ( 'edit' === $action );
		$is_correct = ( 'correct' === $action );

		// Wersja darmowa: wystawianie bez limitów (brak quota).
		$quota_exceeded = false;
		// Typ faktury do podglądu: 'incoming' (zakup) albo 'outgoing' (sprzedaż, default).
		$inv_type = ( ( sanitize_text_field( wp_unslash( $_GET['type'] ?? '' ) ) ) === 'incoming' ) ? 'incoming' : 'outgoing';
		$prefill = [];
		$existing_inv = null;
		$view_raw_xml = '';
		if ( ( $is_view || $is_edit || $is_correct ) && $inv_id > 0 ) {
			require_once KSEF_WORDPRESS_PATH . 'includes/v2/class-fa3-parser.php';

			if ( 'incoming' === $inv_type ) {
				// FAKTURA ZAKUPU — tylko podgląd. Dane budujemy z pełnego XML FA(3)
				// (dociągamy leniwie z KSeF gdy go jeszcze nie mamy), tak jak w podglądzie listy.
				$is_edit = false; $is_correct = false; $is_view = true;
				$existing_inv = $wpdb->get_row(
					$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gksef_incoming_invoices WHERE id = %d", $inv_id ),
					ARRAY_A
				);
				if ( $existing_inv ) {
					$raw = (string) \KSEF\WordPress\Crypto::decrypt_from_storage( $existing_inv['raw_xml'] ?? '' );
					$has_xml = '' !== $raw && strpos( ltrim( $raw ), '<' ) === 0;
					if ( $has_xml ) {
						$prefill = \KSEF\WordPress\V2\Fa3_Parser::parse( $raw ) ?: [];
						$view_raw_xml = $raw;
						// BEZ swapu — w podglądzie pokazujemy oba podmioty jawnie i poprawnie:
						// Sprzedawca (prefill.seller = dostawca) i Nabywca (prefill.buyer = my).
					}
				}
			} else {
				// FAKTURA SPRZEDAŻY — preferuj pełen XML (faktury pobrane z KSeF),
				// payload_json uzupełnia braki (faktury wystawione we wtyczce).
				$existing_inv = $wpdb->get_row(
					$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gksef_outgoing_invoices WHERE id = %d", $inv_id ),
					ARRAY_A
				);
				if ( $existing_inv ) {
					// Lazy-fetch pełnego XML FA(3): faktury pobrane z KSeF (source=ksef_pulled)
					// mają na starcie tylko metadane (payload_json camelCase, generated_xml puste).
					// Pełne dane (strony z adresami, pozycje, stawki, oznaczenia) dociągamy z KSeF
					// przy pierwszym otwarciu podglądu — identycznie jak w gałęzi zakupu powyżej.
					$xml     = (string) \KSEF\WordPress\Crypto::decrypt_from_storage( $existing_inv['generated_xml'] ?? '' );
					$has_xml = '' !== $xml && strpos( ltrim( $xml ), '<' ) === 0;
					$payload = ! empty( $existing_inv['payload_json'] )
						? ( json_decode( (string) \KSEF\WordPress\Crypto::decrypt_from_storage( $existing_inv['payload_json'] ), true ) ?: [] )
						: [];
					if ( '' !== $xml && strpos( ltrim( $xml ), '<' ) === 0 ) {
						$view_raw_xml = $xml;
						// Faktura lokalna ma payload_json w formacie formularza → NIE mieszamy z parserem
						// (inny kształt), żeby ujednolicony podgląd-formularz renderował się 1:1 jak edycja.
						$parsed = ( ! empty( $payload ) && ( ( $existing_inv['source'] ?? 'local' ) !== 'ksef_pulled' ) ) ? null : \KSEF\WordPress\V2\Fa3_Parser::parse( $xml );
						if ( is_array( $parsed ) && ! empty( $parsed ) ) {
							$payload = array_merge( $payload, $parsed ); // parsed XML ma priorytet (pełne dane)
						}
					}
					$prefill = $payload;
				}
				// Edycja DOZWOLONA dla draftów oraz faktur niewysłanych do KSeF (issued/failed/rejected) —
				// „Edytuj i wyślij": popraw dane i wyślij ponownie. Faktury w KSeF (sent/confirmed) — tylko korekta.
				if ( $is_edit && $existing_inv && ! in_array( (string) ( $existing_inv['status'] ?? '' ), [ 'draft', 'issued', 'failed', 'rejected' ], true ) ) {
					$is_edit = false;
					$is_view = true;
				}
			}
		}
		// PODGLĄD (view): renderuj kompletny widok tylko-do-odczytu (pokazuje WYŁĄCZNIE
		// pola obecne na fakturze — bez pustych kart formularza wystawiania) + aktywne
		// zarządzanie statusem płatności i kategorią wydatku. Pomija formularz edycji.
		if ( $is_view && $existing_inv ) {
			// Ujednolicony podgląd: faktury sprzedaży wystawione lokalnie renderują TEN SAM
			// formularz w trybie read-only (jak edycja). Zakup oraz faktury pobrane z KSeF
			// (tylko XML) pozostają na kompaktowym, odpornym widoku.
			$unified_form_view = ( 'incoming' !== $inv_type ) && ! empty( $existing_inv['payload_json'] )
				&& ( ( $existing_inv['source'] ?? 'local' ) !== 'ksef_pulled' );
			if ( ! $unified_form_view ) {
				$this->render_readonly_invoice_view( $prefill, $existing_inv, $inv_type, $inv_id, $view_raw_xml );
				return;
			}
		}

		// Dane korekty — do hidden fields + JS
		$correction_meta = [];
		if ( $is_correct && $existing_inv ) {
			$correction_meta = [
				'original_id'           => (int) $existing_inv['id'],
				'original_number'       => (string) ( $existing_inv['invoice_number'] ?? '' ),
				'original_date'         => (string) ( $prefill['issue_date'] ?? gmdate( 'Y-m-d', strtotime( (string) $existing_inv['created_at'] ) ) ),
				'original_ksef_number'  => (string) ( $existing_inv['ksef_reference_number'] ?? '' ),
			];
		}
		$page_title = $is_view ? __( 'Podgląd faktury', 'prostafaktura-ksef' )
			: ( $is_edit ? __( 'Edycja faktury', 'prostafaktura-ksef' )
				: ( $is_correct ? __( 'Faktura korygująca', 'prostafaktura-ksef' )
					: __( 'Wystaw fakturę', 'prostafaktura-ksef' ) ) );
		$page_subtitle = $is_view ? __( 'Faktura', 'prostafaktura-ksef' )
			: ( $is_edit ? __( 'Edycja draftu', 'prostafaktura-ksef' )
				: ( $is_correct ? __( 'Korekta', 'prostafaktura-ksef' ) : __( 'Nowa faktura', 'prostafaktura-ksef' ) ) );
		$dom_mode = $is_view ? 'view' : ( $is_edit ? 'edit' : ( $is_correct ? 'correct' : 'new' ) );
		?>
		<div class="ksef-app ksef-app-invoice-editor <?php echo $is_view ? 'ksef-app-readonly' : ''; ?>"
			data-mode="<?php echo esc_attr( $dom_mode ); ?>"
			data-existing-id="<?php echo esc_attr( (string) $inv_id ); ?>"
			data-credential-id="<?php echo esc_attr( (string) ( $existing_inv['credential_id'] ?? '' ) ); ?>"
			data-correction="<?php echo esc_attr( wp_json_encode( $correction_meta ) ); ?>"
			data-prefill="<?php echo esc_attr( wp_json_encode( $prefill ) ); ?>">
			<?php /* wersja darmowa: brak limitu faktur (quota) */ ?>
			<?php if ( empty( $creds ) ) : ?>
				<div class="notice notice-error" style="margin:14px 0;"><p>
					<?php
					printf(
						/* translators: %s: link */
						esc_html__( 'Brak skonfigurowanych kredencjałów KSeF. %s.', 'prostafaktura-ksef' ),
						'<a href="' . esc_url( admin_url( 'admin.php?page=ksef-credentials&action=add' ) ) . '">' . esc_html__( 'Dodaj pierwszy', 'prostafaktura-ksef' ) . '</a>'
					);
					?>
				</p></div>
				<?php return; ?>
			<?php endif; ?>

			<div class="ksef-app-layout">
			<form id="ksef-manual-invoice-form" class="ksef-app-main" autocomplete="off">
				<?php wp_nonce_field( 'ksef_send_manual_invoice', 'ksef_nonce' ); ?>
				<input type="hidden" id="ksef_nonce_pub" value="<?php echo esc_attr( $nonce ); ?>">

				<input type="hidden" name="buyer_type" id="buyer_type" value="b2c">
				<input type="hidden" name="contractor_id" id="contractor_id" value="">
				<input type="hidden" name="correct_of_id" id="correct_of_id" value="<?php echo $is_correct ? (int) $inv_id : ''; ?>">
				<input type="hidden" name="existing_id" id="ksef-existing-id" value="<?php echo ( $is_edit && $inv_id > 0 ) ? (int) $inv_id : ''; ?>">

				<?php
				// Faktura niewysłana do KSeF (issued/failed/rejected): pokaż status + ewentualny błąd
				// ostatniej wysyłki (z gksef_outgoing_invoices.offline_reason lub meta zamówienia WC).
				$ksef_inv_status = (string) ( $existing_inv['status'] ?? '' );
				if ( $existing_inv && 'incoming' !== $inv_type && in_array( $ksef_inv_status, [ 'issued', 'failed', 'rejected' ], true ) ) :
					$ksef_send_err = (string) ( $existing_inv['offline_reason'] ?? '' );
					if ( '' === trim( $ksef_send_err ) && ! empty( $existing_inv['wc_order_id'] ) && function_exists( 'wc_get_order' ) ) {
						$o_err = wc_get_order( (int) $existing_inv['wc_order_id'] );
						if ( $o_err ) { $ksef_send_err = (string) $o_err->get_meta( '_ksef_invoice_error' ); }
					}
					$ksef_send_err = trim( $ksef_send_err );
					$is_err_box = ( '' !== $ksef_send_err ) || in_array( $ksef_inv_status, [ 'failed', 'rejected' ], true );
					// Czytelny komunikat zamiast surowego błędu (np. „cURL error 28" → „Brak połączenia z KSeF").
					$ksef_friendly = ( '' !== $ksef_send_err && class_exists( '\\KSEF\\WordPress\\V2\\Ksef_Client' ) )
						? \KSEF\WordPress\V2\Ksef_Client::friendly_error( '', $ksef_send_err )
						: [ 'title' => '', 'hint' => '' ];
				$ksef_friendly_title = (string) ( $ksef_friendly['title'] ?? '' );
				$ksef_friendly_hint  = (string) ( $ksef_friendly['hint'] ?? '' );
				$box_title  = ( '' !== $ksef_friendly_title && $ksef_friendly_title !== $ksef_send_err ) ? $ksef_friendly_title
					: ( ( 'rejected' === $ksef_inv_status ) ? __( 'Faktura odrzucona przez KSeF', 'prostafaktura-ksef' )
					: ( ( 'failed' === $ksef_inv_status ) ? __( 'Wysyłka do KSeF nie powiodła się', 'prostafaktura-ksef' )
					: __( 'Wystawiona lokalnie — jeszcze nie wysłana do KSeF', 'prostafaktura-ksef' ) ) );
				?>
					<div class="ksef-card" style="border-left:4px solid <?php echo $is_err_box ? '#dc2626' : '#9ca3af'; ?>;background:<?php echo $is_err_box ? '#fef2f2' : '#f8fafc'; ?>;">
						<strong style="color:<?php echo $is_err_box ? '#991b1b' : '#374151'; ?>;font-size:14px;"><?php echo $is_err_box ? '⚠ ' : 'ℹ '; ?><?php echo esc_html( $box_title ); ?></strong>
						<?php if ( '' !== $ksef_friendly_hint ) : ?>
							<div style="margin-top:7px;color:<?php echo $is_err_box ? '#7f1d1d' : '#374151'; ?>;font-size:13px;"><?php echo esc_html( $ksef_friendly_hint ); ?></div>
						<?php endif; ?>
						<?php if ( '' !== $ksef_send_err ) : ?>
							<div style="margin-top:7px;color:#9ca3af;font-size:11.5px;white-space:pre-wrap;word-break:break-word;"><?php esc_html_e( 'Szczegóły techniczne:', 'prostafaktura-ksef' ); ?> <?php echo esc_html( $ksef_send_err ); ?></div>
						<?php endif; ?>
						<div style="margin-top:7px;color:#6b7280;font-size:12.5px;"><?php esc_html_e( 'Wyślij fakturę ponownie („Wyślij do KSeF") albo popraw dane („Edytuj i wyślij") — przyciski na dole.', 'prostafaktura-ksef' ); ?></div>
					</div>
				<?php endif; ?>

				<?php
				// Faktura W KSeF — status na GÓRZE (pod nagłówkiem): zaakceptowana (UPO/PDF) lub wysłana (czeka na MF).
				if ( $existing_inv && 'incoming' !== $inv_type && $is_view ) :
					$ks_ref2   = (string) ( $existing_inv['ksef_reference_number'] ?? '' );
					$dl_nonce2 = wp_create_nonce( 'ksef-nonce' );
					$pdf_link2 = add_query_arg( [ 'action' => 'ksef_invoice_pdf', 'invoice_id' => (int) $inv_id, '_ajax_nonce' => $dl_nonce2 ], admin_url( 'admin-ajax.php' ) );
					if ( '' !== $ks_ref2 ) :
						$upo_link2 = add_query_arg( [ 'action' => 'ksef_download_upo', 'invoice_id' => (int) $inv_id, 'format' => 'pdf', '_ajax_nonce' => $dl_nonce2 ], admin_url( 'admin-ajax.php' ) );
				?>
					<div style="margin:0 0 16px;padding:14px 18px;border:1px solid #BBF7D0;background:#F0FDF4;border-radius:12px;border-left:5px solid #16a34a;">
						<div style="font-size:15px;font-weight:700;color:#166534;margin-bottom:6px;">✓ <?php esc_html_e( 'Faktura zaakceptowana przez KSeF', 'prostafaktura-ksef' ); ?></div>
						<div style="font-size:13px;color:#374151;"><?php esc_html_e( 'Numer KSeF', 'prostafaktura-ksef' ); ?>: <code style="background:#fff;padding:2px 6px;border-radius:4px;border:1px solid #d1fae5;"><?php echo esc_html( $ks_ref2 ); ?></code>
							&nbsp;·&nbsp; <a href="<?php echo esc_url( $upo_link2 ); ?>" target="_blank">🧾 <?php esc_html_e( 'Pokaż UPO', 'prostafaktura-ksef' ); ?></a>
							&nbsp;·&nbsp; <a href="<?php echo esc_url( $pdf_link2 ); ?>" target="_blank">📄 <?php esc_html_e( 'Pobierz Fakturę w PDF', 'prostafaktura-ksef' ); ?></a>
						</div>
					</div>
				<?php elseif ( in_array( $ksef_inv_status, [ 'sent', 'sent_from_draft' ], true ) ) : ?>
					<div style="margin:0 0 16px;padding:14px 18px;border:1px solid #FDE68A;background:#FFFBEB;border-radius:12px;border-left:5px solid #F59E0B;">
						<div style="font-size:15px;font-weight:700;color:#92400E;margin-bottom:4px;">⏳ <?php esc_html_e( 'Faktura wysłana — czeka na potwierdzenie MF', 'prostafaktura-ksef' ); ?></div>
						<div style="font-size:13px;color:#6b7280;"><?php esc_html_e( 'Numer KSeF i UPO pojawią się po potwierdzeniu.', 'prostafaktura-ksef' ); ?>
							&nbsp;·&nbsp; <a href="<?php echo esc_url( $pdf_link2 ); ?>" target="_blank">📄 <?php esc_html_e( 'Pobierz Fakturę w PDF', 'prostafaktura-ksef' ); ?></a>
						</div>
					</div>
				<?php endif; endif; ?>

				<?php if ( $is_correct && $existing_inv ) : ?>
					<!-- Karta: Korekta -->
					<div class="ksef-card" style="border-left:4px solid #d9531e;">
						<div class="ksef-card-h">
							<span class="s-ic amber"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 20h9M16.5 3.5a2.121 2.121 0 1 1 3 3L7 19l-4 1 1-4z"/></svg></span>
							<div class="t">
								<h2><?php esc_html_e( 'Faktura korygująca', 'prostafaktura-ksef' ); ?></h2>
								<small><?php esc_html_e( 'Przyczyna i zmiana pozycji', 'prostafaktura-ksef' ); ?></small>
							</div>
						</div>
						<p class="ksef-hint" style="margin-top:-8px;">
							<?php printf(
								/* translators: 1: nr faktury, 2: numer KSeF */
								esc_html__( 'Korygujesz fakturę %1$s%2$s. Skoryguj poniżej pozycje/kwoty i podaj przyczynę.', 'prostafaktura-ksef' ),
								'<strong>' . esc_html( (string) $existing_inv['invoice_number'] ) . '</strong>',
								$existing_inv['ksef_reference_number'] ? ' (KSeF: ' . esc_html( (string) $existing_inv['ksef_reference_number'] ) . ')' : ''
							); ?>
						</p>
						<div class="ksef-field">
							<label for="correction_reason"><?php esc_html_e( 'Przyczyna korekty', 'prostafaktura-ksef' ); ?> <span class="req">*</span></label>
							<input type="text" id="correction_reason" name="correction_reason" required
								placeholder="<?php esc_attr_e( 'np. błędna ilość, zmiana ceny, rabat potransakcyjny', 'prostafaktura-ksef' ); ?>">
						</div>
					</div>
				<?php endif; ?>

				<!-- ROW 1: dwie karty obok siebie -->
				<div class="ksef-grid-2">
					<!-- Karta: Dane podstawowe -->
					<div class="ksef-card">
						<div class="ksef-card-h">
							<span class="s-ic brand"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 9.5 12 3l9 6.5V20a1 1 0 0 1-1 1h-5v-7h-6v7H4a1 1 0 0 1-1-1z"/></svg></span>
							<div class="t">
								<h2><?php esc_html_e( 'Dane podstawowe', 'prostafaktura-ksef' ); ?></h2>
								<small><?php esc_html_e( 'Sprzedawca, nabywca, numeracja', 'prostafaktura-ksef' ); ?></small>
							</div>
						</div>

						<!-- PODGLĄD: jawne, poprawnie podpisane strony faktury (Sprzedawca + Nabywca) -->
						<div class="ksef-view-only ksef-view-parties">
							<div class="ksef-vp">
								<div class="ksef-vp-label"><?php esc_html_e( 'Sprzedawca (wystawca)', 'prostafaktura-ksef' ); ?></div>
								<div class="ksef-vp-name" id="vp-seller-name">—</div>
								<div class="ksef-vp-meta" id="vp-seller-meta"></div>
							</div>
							<div class="ksef-vp">
								<div class="ksef-vp-label"><?php esc_html_e( 'Nabywca', 'prostafaktura-ksef' ); ?></div>
								<div class="ksef-vp-name" id="vp-buyer-name">—</div>
								<div class="ksef-vp-meta" id="vp-buyer-meta"></div>
							</div>
						</div>

						<?php if ( $is_view && 'incoming' === $inv_type && $existing_inv ) :
							$cur_cat = (string) ( $existing_inv['category'] ?? '' );
							$cats    = self::expense_categories();
						?>
						<!-- PODGLĄD ZAKUPU: kategoria wydatku (pod danymi stron), zapis od razu -->
						<div class="ksef-field ksef-keep-interactive" id="ksef-zakup-kat-field" data-invoice-id="<?php echo (int) $inv_id; ?>">
							<label for="zakup-kategoria"><?php esc_html_e( 'Kategoria wydatku', 'prostafaktura-ksef' ); ?></label>
							<select id="zakup-kategoria">
								<option value=""><?php esc_html_e( '— wybierz —', 'prostafaktura-ksef' ); ?></option>
								<?php foreach ( $cats as $opt ) : ?>
									<option value="<?php echo esc_attr( $opt ); ?>" <?php selected( $cur_cat, $opt ); ?>><?php echo esc_html( $opt ); ?></option>
								<?php endforeach; ?>
								<?php if ( '' !== $cur_cat && ! in_array( $cur_cat, $cats, true ) ) : ?>
									<option value="<?php echo esc_attr( $cur_cat ); ?>" selected><?php echo esc_html( $cur_cat ); ?></option>
								<?php endif; ?>
							</select>
							<span id="zakup-cat-saved" class="ksef-saved-hint"></span>
							<p class="ksef-hint"><a href="<?php echo esc_url( admin_url( 'admin.php?page=ksef-settings' ) ); ?>"><?php esc_html_e( 'Edytuj listę kategorii w Ustawieniach', 'prostafaktura-ksef' ); ?></a></p>
						</div>
						<?php endif; ?>

						<div class="ksef-field ksef-hide-in-view">
							<label for="credential_id"><?php esc_html_e( 'Sprzedawca', 'prostafaktura-ksef' ); ?> <span class="req">*</span></label>
							<?php if ( 1 === count( $creds ) ) :
								// Jedno konto KSeF → podstaw automatycznie (nie ma czego wybierać).
								// Wybór wielu kont (chooser) pojawia się dopiero przy >1 koncie (wersja Pro).
								$only_cred = reset( $creds ); ?>
								<input type="hidden" id="credential_id" name="credential_id" value="<?php echo (int) $only_cred['id']; ?>">
								<div class="ksef-seller-fixed" style="padding:9px 12px; border:1px solid var(--line,#e2e2e7); border-radius:8px; background:var(--surface-2,#f8f8fa); font-size:13.5px;">
									NIP <?php echo esc_html( $only_cred['nip'] ); ?> <?php echo $only_cred['name'] ? '(' . esc_html( $only_cred['name'] ) . ')' : ''; ?> · <?php echo esc_html( strtoupper( (string) $only_cred['ksef_environment'] ) ); ?>
								</div>
							<?php else : ?>
								<select id="credential_id" name="credential_id" required>
									<option value=""><?php esc_html_e( 'Wybierz konto KSeF', 'prostafaktura-ksef' ); ?></option>
									<?php foreach ( $creds as $c ) : ?>
										<option value="<?php echo (int) $c['id']; ?>" <?php selected( $default_cred_id, (int) $c['id'] ); ?>>
											NIP <?php echo esc_html( $c['nip'] ); ?> <?php echo $c['name'] ? '(' . esc_html( $c['name'] ) . ')' : ''; ?> · <?php echo esc_html( strtoupper( $c['ksef_environment'] ) ); ?>
										</option>
									<?php endforeach; ?>
								</select>
							<?php endif; ?>
						</div>

						<div class="ksef-field ksef-hide-in-view">
							<div style="display:flex; justify-content:space-between; align-items:center;">
								<label><?php esc_html_e( 'Nabywca', 'prostafaktura-ksef' ); ?> <span class="req">*</span></label>
								<small class="ksef-issue-only" style="font-size:11px; color:var(--ink-4);"><?php esc_html_e( 'B2C/B2B — autodetekcja NIP', 'prostafaktura-ksef' ); ?></small>
							</div>
							<div class="ksef-contractor-picker">
								<input type="text" id="contractor_search" placeholder="<?php esc_attr_e( 'Wyszukaj kontrahenta…', 'prostafaktura-ksef' ); ?>" autocomplete="off">
								<button type="button" class="ksef-btn ksef-btn-brand-soft" id="contractor-new-btn">+ <?php esc_html_e( 'Nowy', 'prostafaktura-ksef' ); ?></button>
								<div id="contractor-suggestions" class="ksef-suggestions"></div>
							</div>
							<div id="contractor-summary" class="ksef-contractor-summary"></div>
						</div>

						<?php
						$sale_schemes      = \KSEF\WordPress\V2\Invoice_Numbering::get_schemes( 'sale' );
						$default_scheme_id = '';
						foreach ( $sale_schemes as $ss ) {
							if ( ! empty( $ss['is_default'] ) ) { $default_scheme_id = (string) $ss['id']; break; }
						}
						?>
						<div class="ksef-field">
							<div style="display:flex;justify-content:space-between;align-items:center;">
								<label for="invoice_number"><?php esc_html_e( 'Numer faktury', 'prostafaktura-ksef' ); ?> <span class="req">*</span></label>
								<label class="ksef-toggle-mini ksef-issue-only">
									<input type="checkbox" name="custom_number" id="custom_number"> <?php esc_html_e( 'Własny numer', 'prostafaktura-ksef' ); ?>
								</label>
							</div>
							<div class="ksef-issue-only" id="numbering-scheme-wrap" style="margin-bottom:6px;">
								<select id="numbering_scheme_id" name="numbering_scheme_id">
									<?php foreach ( $sale_schemes as $ss ) : ?>
										<option value="<?php echo esc_attr( (string) $ss['id'] ); ?>"
											data-template="<?php echo esc_attr( (string) $ss['template'] ); ?>"
											data-prefix="<?php echo esc_attr( (string) ( $ss['prefix'] ?? '' ) ); ?>"
											data-padding="<?php echo esc_attr( (string) ( $ss['padding'] ?? 4 ) ); ?>"
											<?php selected( $default_scheme_id, (string) $ss['id'] ); ?>>
											<?php echo esc_html( (string) $ss['name'] ); ?> — <?php echo esc_html( (string) $ss['template'] ); ?><?php echo ! empty( $ss['is_default'] ) ? ' · ' . esc_html__( 'domyślna', 'prostafaktura-ksef' ) : ''; ?>
										</option>
									<?php endforeach; ?>
								</select>
							</div>
							<input id="invoice_number" name="invoice_number" type="text" placeholder="<?php echo esc_attr( Invoice_Numbering::preview( $default_scheme_id ?: null ) ); ?>" readonly>
							<input type="hidden" name="auto_number" id="auto_number" value="1">
							<p class="ksef-hint ksef-issue-only"><?php esc_html_e( 'Numer zostanie nadany automatycznie wg wybranego schematu.', 'prostafaktura-ksef' ); ?> · <a href="<?php echo esc_url( admin_url( 'admin.php?page=ksef-settings' ) ); ?>"><?php esc_html_e( 'Zarządzaj numeracją', 'prostafaktura-ksef' ); ?></a></p>
						</div>
					</div>

					<!-- Karta: Daty i płatność -->
					<div class="ksef-card">
						<div class="ksef-card-h">
							<span class="s-ic emerald"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="4" width="18" height="18" rx="2"/><path d="M16 2v4M8 2v4M3 10h18"/></svg></span>
							<div class="t">
								<h2><?php esc_html_e( 'Daty i płatność', 'prostafaktura-ksef' ); ?></h2>
								<small><?php esc_html_e( 'Wystawienie, sprzedaż, termin, status', 'prostafaktura-ksef' ); ?></small>
							</div>
						</div>

						<div class="ksef-grid-2-inner">
							<div class="ksef-field">
								<label for="issue_date"><?php esc_html_e( 'Data wystawienia', 'prostafaktura-ksef' ); ?> <span class="req">*</span></label>
								<input id="issue_date" name="issue_date" type="date" max="<?php echo esc_attr( gmdate( 'Y-m-d' ) ); ?>" value="<?php echo esc_attr( gmdate( 'Y-m-d' ) ); ?>" required>
							</div>
							<div class="ksef-field">
								<label for="sale_date"><?php esc_html_e( 'Data sprzedaży', 'prostafaktura-ksef' ); ?> <span class="req">*</span></label>
								<input id="sale_date" name="sale_date" type="date" max="<?php echo esc_attr( gmdate( 'Y-m-d' ) ); ?>" value="<?php echo esc_attr( gmdate( 'Y-m-d' ) ); ?>" required>
							</div>
							<div class="ksef-field">
								<div style="display:flex; justify-content:space-between; align-items:center;">
									<label for="payment_due"><?php esc_html_e( 'Termin płatności', 'prostafaktura-ksef' ); ?> <span class="req">*</span></label>
									<small style="font-size:11px; color:var(--ink-4);">+14 dni</small>
								</div>
								<input id="payment_due" name="payment_due" type="date" value="<?php echo esc_attr( gmdate( 'Y-m-d', strtotime( '+14 days' ) ) ); ?>">
							</div>
							<div class="ksef-field">
								<label for="payment_form"><?php esc_html_e( 'Metoda płatności', 'prostafaktura-ksef' ); ?> <span class="req">*</span></label>
								<select id="payment_form" name="payment_form">
									<option value="6" selected>Przelew</option>
									<option value="1">Gotówka</option>
									<option value="2">Karta</option>
									<option value="7">Płatność mobilna (BLIK)</option>
									<option value="3">Bon</option>
									<option value="4">Czek</option>
									<option value="5">Kredyt</option>
								</select>
							</div>
						</div>

						<div class="ksef-field<?php echo $is_view ? ' ksef-keep-interactive' : ''; ?>" id="ksef-paystatus-field"
							data-invoice-id="<?php echo (int) $inv_id; ?>"
							data-inv-type="<?php echo esc_attr( $inv_type ); ?>"
							data-current="<?php echo esc_attr( (string) ( $existing_inv['payment_status'] ?? 'unpaid' ) ); ?>">
							<label><?php esc_html_e( 'Status płatności', 'prostafaktura-ksef' ); ?></label>
							<div class="ksef-segmented">
								<input type="radio" name="initial_payment_status" id="ps_unpaid" value="unpaid" checked><label for="ps_unpaid"><?php esc_html_e( 'Niezapłacona', 'prostafaktura-ksef' ); ?></label>
								<input type="radio" name="initial_payment_status" id="ps_paid" value="paid"><label for="ps_paid"><?php esc_html_e( 'Zapłacona w całości', 'prostafaktura-ksef' ); ?></label>
								<input type="radio" name="initial_payment_status" id="ps_partial" value="partial"><label for="ps_partial"><?php esc_html_e( 'Częściowo', 'prostafaktura-ksef' ); ?></label>
							</div>
							<span id="ksef-paystatus-saved" class="ksef-saved-hint"></span>

							<?php
							// Podgląd istniejącej faktury → lista zarejestrowanych wpłat (read-only).
							if ( $is_view && $inv_id > 0 ) :
								$view_pays = \KSEF\WordPress\Payments_Repository::list_for_invoice( $inv_id );
								if ( ! empty( $view_pays ) ) : $view_pay_sum = 0.0; ?>
									<div style="margin-top:12px;">
										<label style="font-size:12px;color:var(--ink-3);display:block;margin-bottom:6px;"><?php esc_html_e( 'Zarejestrowane wpłaty', 'prostafaktura-ksef' ); ?></label>
										<table style="width:100%;border-collapse:collapse;font-size:13px;max-width:460px;">
											<thead><tr style="border-bottom:1px solid var(--line,#e2e2e7);">
												<th style="text-align:left;padding:5px 8px;color:var(--ink-4);font-weight:500;"><?php esc_html_e( 'Data', 'prostafaktura-ksef' ); ?></th>
												<th style="text-align:left;padding:5px 8px;color:var(--ink-4);font-weight:500;"><?php esc_html_e( 'Forma', 'prostafaktura-ksef' ); ?></th>
												<th style="text-align:right;padding:5px 8px;color:var(--ink-4);font-weight:500;"><?php esc_html_e( 'Kwota', 'prostafaktura-ksef' ); ?></th>
											</tr></thead>
											<tbody>
											<?php foreach ( $view_pays as $vp ) : $view_pay_sum += (float) ( $vp['amount'] ?? 0 ); ?>
												<tr style="border-bottom:1px solid var(--line-2,#f1f1f4);">
													<td style="padding:5px 8px;"><?php echo esc_html( (string) ( $vp['payment_date'] ?? '' ) ); ?></td>
													<td style="padding:5px 8px;"><?php echo esc_html( (string) ( $vp['payment_method'] ?? '' ) ); ?></td>
													<td style="text-align:right;padding:5px 8px;"><?php echo esc_html( number_format( (float) ( $vp['amount'] ?? 0 ), 2, ',', ' ' ) ); ?></td>
												</tr>
											<?php endforeach; ?>
											</tbody>
											<tfoot><tr>
												<td colspan="2" style="text-align:right;padding:5px 8px;font-weight:600;"><?php esc_html_e( 'Razem wpłacono:', 'prostafaktura-ksef' ); ?></td>
												<td style="text-align:right;padding:5px 8px;font-weight:600;"><?php echo esc_html( number_format( $view_pay_sum, 2, ',', ' ' ) ); ?></td>
											</tr></tfoot>
										</table>
									</div>
								<?php endif; ?>
							<?php endif; ?>

							<!-- Szczegóły płatności (tylko przy wystawianiu) -->
							<div class="ksef-issue-only" id="pay-detail" style="margin-top:12px;display:none;">
								<div id="pay-paid" style="display:none;">
									<label for="paid_method" style="font-size:12px;color:var(--ink-3);display:block;margin-bottom:4px;"><?php esc_html_e( 'Jak zapłacono?', 'prostafaktura-ksef' ); ?></label>
									<select name="paid_method" id="paid_method" style="width:100%;max-width:280px;">
										<option value="przelew"><?php esc_html_e( 'Przelew', 'prostafaktura-ksef' ); ?></option>
										<option value="gotowka"><?php esc_html_e( 'Gotówka', 'prostafaktura-ksef' ); ?></option>
										<option value="kompensata"><?php esc_html_e( 'Kompensata', 'prostafaktura-ksef' ); ?></option>
										<option value="online"><?php esc_html_e( 'Online', 'prostafaktura-ksef' ); ?></option>
										<option value="inne"><?php esc_html_e( 'Inne', 'prostafaktura-ksef' ); ?></option>
									</select>
								</div>
								<div id="pay-partial" style="display:none;">
									<label style="font-size:12px;color:var(--ink-3);display:block;margin-bottom:6px;"><?php esc_html_e( 'Wpłaty częściowe — kwota, data, forma', 'prostafaktura-ksef' ); ?></label>
									<div id="partial-rows"></div>
									<button type="button" class="ksef-btn ksef-btn-secondary" id="add-partial" style="margin-top:6px;">+ <?php esc_html_e( 'Dodaj wpłatę', 'prostafaktura-ksef' ); ?></button>
								</div>
							</div>
						</div>
					</div>
				</div>

				<!-- Karta: Pozycje faktury -->
				<div class="ksef-card">
					<div class="ksef-card-h">
						<span class="s-ic sky"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4zM3 6h18M16 10a4 4 0 0 1-8 0"/></svg></span>
						<div class="t">
							<h2><?php esc_html_e( 'Pozycje faktury', 'prostafaktura-ksef' ); ?></h2>
							<small><?php esc_html_e( 'Produkty, stawki VAT, rabaty', 'prostafaktura-ksef' ); ?></small>
						</div>
						<div class="ksef-card-actions">
							<div class="ksef-segmented ksef-segmented-sm">
								<input type="radio" name="price_mode" id="pm_net" value="net" checked><label for="pm_net"><?php esc_html_e( 'Cena netto', 'prostafaktura-ksef' ); ?></label>
								<input type="radio" name="price_mode" id="pm_gross" value="gross"><label for="pm_gross"><?php esc_html_e( 'Cena brutto', 'prostafaktura-ksef' ); ?></label>
							</div>
							<button type="button" class="ksef-btn ksef-btn-brand-soft" id="wc-products-btn">
								<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/></svg>
								<?php esc_html_e( 'Z produktów Woo', 'prostafaktura-ksef' ); ?>
							</button>
						</div>
					</div>

					<div id="ksef-items-table-wrap">
					<table class="ksef-items-table" id="ksef-items-table">
						<thead>
							<tr>
								<th style="width:38px;">Lp.</th>
								<th><?php esc_html_e( 'Produkt', 'prostafaktura-ksef' ); ?></th>
								<th style="width:90px;">PKWiU/CN</th>
								<th style="width:70px;">Jedn.</th>
								<th style="width:70px;">Ilość</th>
								<th style="width:90px;"><?php esc_html_e( 'Cena netto', 'prostafaktura-ksef' ); ?></th>
								<th style="width:70px;">Rabat %</th>
								<th style="width:80px;">Stawka</th>
								<th style="width:80px;">Wart. netto</th>
								<th style="width:80px;">Wart. brutto</th>
								<th style="width:80px;">GTU</th>
								<th style="width:32px;"></th>
							</tr>
						</thead>
						<tbody id="ksef-items-body"></tbody>
					</table>
					</div>
					<p style="margin-top:8px;"><button type="button" class="button-link" id="ksef-add-item" style="color:#d9531e;font-weight:600;">+ <?php esc_html_e( 'Nowy wiersz', 'prostafaktura-ksef' ); ?></button></p>

					<div class="ksef-items-summary">
						<table>
							<thead><tr><th>Stawka</th><th>Netto</th><th>VAT</th><th>Brutto</th></tr></thead>
							<tbody id="ksef-vat-summary"></tbody>
							<tfoot><tr><th>Razem (<span id="curr-display">PLN</span>)</th><th id="ksef-total-net">0.00</th><th id="ksef-total-vat">0.00</th><th id="ksef-total-gross">0.00</th></tr></tfoot>
						</table>
					</div>
				</div>

				<!-- Karta: Kaucja -->
				<div class="ksef-card ksef-card-toggle">
					<label class="ksef-toggle-row">
						<input type="checkbox" name="deposit_toggle" id="deposit_toggle">
						<span class="ksef-check"></span>
						<div class="t">
							<strong><?php esc_html_e( 'Kaucja / Opakowania zwrotne', 'prostafaktura-ksef' ); ?></strong>
							<small><?php esc_html_e( 'nie podlega VAT — doliczana do kwoty', 'prostafaktura-ksef' ); ?></small>
						</div>
					</label>
					<div id="deposit-fields" style="display:none;margin-top:14px;">
						<div class="ksef-grid-2-inner">
							<div class="ksef-field">
								<label><?php esc_html_e( 'Opis', 'prostafaktura-ksef' ); ?></label>
								<input type="text" name="deposit_label" placeholder="<?php esc_attr_e( 'np. Kaucja za palety', 'prostafaktura-ksef' ); ?>">
							</div>
							<div class="ksef-field">
								<label><?php esc_html_e( 'Kwota', 'prostafaktura-ksef' ); ?></label>
								<div class="ksef-input-with-suffix">
									<input type="number" name="deposit_amount" step="0.01" min="0" value="0.00">
									<span class="suffix">PLN</span>
								</div>
							</div>
						</div>
					</div>
				</div>

				<!-- Karta: Rachunki bankowe -->
				<div class="ksef-card">
					<div class="ksef-card-h">
						<span class="s-ic gray"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 10h18M8 14h.01M12 14h.01"/></svg></span>
						<div class="t">
							<h2><?php esc_html_e( 'Rachunki bankowe', 'prostafaktura-ksef' ); ?></h2>
							<small><?php esc_html_e( 'Konta, na które klient zapłaci', 'prostafaktura-ksef' ); ?></small>
						</div>
						<div class="ksef-card-actions">
							<button type="button" class="ksef-btn ksef-btn-brand-soft" id="add-bank-btn">+ <?php esc_html_e( 'Dodaj konto', 'prostafaktura-ksef' ); ?></button>
						</div>
					</div>
					<div id="banks-list" style="margin-top:10px;">
						<div class="ksef-empty-state" id="banks-empty">
							<div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 10h18"/></svg></div>
							<b><?php esc_html_e( 'Brak rachunków bankowych', 'prostafaktura-ksef' ); ?></b>
							<p><?php esc_html_e( 'Dodaj pierwsze konto, na które klient ma przesłać płatność — pojawi się na fakturze.', 'prostafaktura-ksef' ); ?></p>
						</div>
					</div>
				</div>

				<!-- Karta: Opcje i oznaczenia -->
				<div class="ksef-card">
					<div class="ksef-card-h">
						<span class="s-ic amber"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m20.59 13.41-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"/><path d="M7 7h.01"/></svg></span>
						<div class="t">
							<h2><?php esc_html_e( 'Opcje i oznaczenia faktury', 'prostafaktura-ksef' ); ?></h2>
							<small><?php esc_html_e( 'Waluta, oznaczenia KSeF, procedury VAT', 'prostafaktura-ksef' ); ?></small>
						</div>
					</div>
					<div class="ksef-field" style="max-width:260px;">
						<label for="currency"><?php esc_html_e( 'Waluta', 'prostafaktura-ksef' ); ?></label>
						<select id="currency" name="currency">
							<option value="PLN" selected>PLN — Polski złoty</option>
						</select>
						<small style="display:block;margin-top:4px;font-size:11px;color:var(--ink-4,#999);"><?php esc_html_e( 'Faktury w innych walutach (EUR, USD, GBP…) — w wersji Pro.', 'prostafaktura-ksef' ); ?></small>
					</div>

					<div class="ksef-field" id="fx-rate-field" style="max-width:420px;display:none;">
						<label for="exchange_rate"><?php esc_html_e( 'Kurs wymiany na PLN', 'prostafaktura-ksef' ); ?> <span class="req">*</span></label>
						<div style="display:flex;gap:8px;align-items:flex-start;">
							<input id="exchange_rate" name="exchange_rate" type="text" inputmode="decimal" placeholder="np. 4,3210" style="max-width:130px;">
							<input id="exchange_rate_date" name="exchange_rate_date" type="hidden">
							<button type="button" class="ksef-btn ksef-btn-secondary" id="fetch-nbp-rate"><?php esc_html_e( 'Pobierz kurs NBP', 'prostafaktura-ksef' ); ?></button>
						</div>
						<small id="fx-rate-hint" style="display:block;margin-top:4px;font-size:11px;color:var(--ink-4,#999);"><?php esc_html_e( 'Kurs średni NBP (tab. A) z ostatniego dnia roboczego przed datą sprzedaży. VAT zostanie przeliczony na PLN (P_14_xW).', 'prostafaktura-ksef' ); ?></small>
					</div>

					<h4 class="ksef-section-sub"><?php esc_html_e( 'OZNACZENIA FA(3)', 'prostafaktura-ksef' ); ?></h4>
					<div class="ksef-markers-grid">
						<?php
						$markers = [
							'FP'          => [ 'Faktura do paragonu', 'FP' ],
							'P_18A'       => [ 'Podzielona płatność', 'P_18A' ],
							'TP'          => [ 'Powiązania między stronami', 'TP' ],
							'fa_za_okres' => [ 'Faktura za okres', '' ],
							'P_19'        => [ 'Zwolnienie z VAT (art. 43 ust. 1, art. 113 ust. 1 i 9)', 'P_19' ],
							'P_16'        => [ 'Metoda kasowa', 'P_16' ],
							'P_18'        => [ 'Odwrotne obciążenie', 'P_18' ],
							'P_23'        => [ 'WTT (procedura uproszczona)', 'P_23' ],
							'PMarzy'      => [ 'Procedura marży', 'PMarzy' ],
							'P_22'        => [ 'WDT nowych środków transportu', 'P_22' ],
							'OSS'         => [ 'Procedura OSS VAT', 'OSS' ],
						];
						foreach ( $markers as $code => $m ) :
							$is_period = ( $code === 'fa_za_okres' );
						?>
							<label class="ksef-marker">
								<input type="checkbox" name="markers[<?php echo esc_attr( $code ); ?>]" value="1" <?php echo $is_period ? 'id="marker_fa_za_okres"' : ''; ?>>
								<span class="ksef-marker-text"><?php echo esc_html( $m[0] ); ?></span>
								<?php if ( $m[1] !== '' ) : ?><span class="ksef-marker-code"><?php echo esc_html( $m[1] ); ?></span><?php endif; ?>
							</label>
						<?php endforeach; ?>
					</div>

					<div id="ksef-auto-markers-note" style="display:none;margin-top:14px;padding:12px 14px;border:1px solid #FCD34D;background:#FFFBEB;border-radius:10px;color:#78350F;font-size:13px;line-height:1.5;">
						<strong>⚠️ Zaznaczono automatycznie — zweryfikuj samodzielnie</strong>
						<div style="margin:4px 0 6px;">System zaznaczył poniższe oznaczenia na podstawie danych faktury. Sprawdź, czy są poprawne dla tej transakcji — za prawidłowość danych na fakturze odpowiada wystawca.</div>
						<ul class="amn-list" style="margin:0;padding-left:18px;"></ul>
					</div>

					<div id="row-fa-za-okres" style="display:none;margin-top:14px;">
						<div class="ksef-grid-2-inner" style="max-width:600px;">
							<div class="ksef-field"><label><?php esc_html_e( 'Okres od', 'prostafaktura-ksef' ); ?></label><input type="date" name="period_from"></div>
							<div class="ksef-field"><label><?php esc_html_e( 'Okres do', 'prostafaktura-ksef' ); ?></label><input type="date" name="period_to"></div>
						</div>
					</div>

					<!-- Podstawa prawna zwolnienia z VAT — wymagana gdy zaznaczono P_19 -->
					<div id="row-zwolnienie" style="display:none;margin-top:14px;">
						<div class="ksef-grid-2-inner" style="max-width:760px;">
							<div class="ksef-field">
								<label for="exemption_kind"><?php esc_html_e( 'Rodzaj podstawy zwolnienia', 'prostafaktura-ksef' ); ?></label>
								<select id="exemption_kind" name="exemption_kind">
									<option value="A" selected><?php esc_html_e( 'Przepis ustawy o VAT (P_19A)', 'prostafaktura-ksef' ); ?></option>
									<option value="B"><?php esc_html_e( 'Przepis dyrektywy 2006/112/WE (P_19B)', 'prostafaktura-ksef' ); ?></option>
									<option value="C"><?php esc_html_e( 'Inna podstawa prawna (P_19C)', 'prostafaktura-ksef' ); ?></option>
								</select>
							</div>
							<div class="ksef-field">
								<label for="exemption_preset"><?php esc_html_e( 'Najczęstsze podstawy (wg rodzaju)', 'prostafaktura-ksef' ); ?></label>
								<select id="exemption_preset">
									<option value=""><?php esc_html_e( '— wybierz, aby wstawić —', 'prostafaktura-ksef' ); ?></option>
								</select>
							</div>
						</div>
						<div class="ksef-field" style="max-width:760px;">
							<label for="exemption_basis"><?php esc_html_e( 'Podstawa prawna zwolnienia (treść na fakturze)', 'prostafaktura-ksef' ); ?> <span style="color:#DC2626">*</span></label>
							<input type="text" id="exemption_basis" name="exemption_basis" placeholder="np. art. 43 ust. 1 pkt 19 ustawy o VAT">
							<small style="color:var(--ink-4,#777);"><?php esc_html_e( 'Wymagane przepisami przy stawce „zw". Pole obowiązkowe gdy któraś pozycja ma stawkę zwolnioną.', 'prostafaktura-ksef' ); ?></small>
						</div>
					</div>

					<!-- Procedura marży — wymaga wyboru rodzaju (KSeF: P_PMarzy_2 / 3_1 / 3_2 / 3_3) -->
					<div id="row-pmarzy" style="display:none;margin-top:14px;">
						<div class="ksef-field" style="max-width:760px;">
							<label for="pmarzy_kind"><?php esc_html_e( 'Rodzaj procedury marży', 'prostafaktura-ksef' ); ?> <span style="color:#DC2626">*</span></label>
							<select id="pmarzy_kind" name="pmarzy_kind">
								<option value=""><?php esc_html_e( '— wybierz rodzaj —', 'prostafaktura-ksef' ); ?></option>
								<option value="turystyka"><?php esc_html_e( 'Usługi turystyki — art. 119 (P_PMarzy_2)', 'prostafaktura-ksef' ); ?></option>
								<option value="uzywane"><?php esc_html_e( 'Towary używane — art. 120 (P_PMarzy_3_1)', 'prostafaktura-ksef' ); ?></option>
								<option value="sztuka"><?php esc_html_e( 'Dzieła sztuki — art. 120 (P_PMarzy_3_2)', 'prostafaktura-ksef' ); ?></option>
								<option value="kolekcjonerskie"><?php esc_html_e( 'Przedmioty kolekcjonerskie i antyki — art. 120 (P_PMarzy_3_3)', 'prostafaktura-ksef' ); ?></option>
							</select>
							<small style="color:var(--ink-4,#777);"><?php esc_html_e( 'KSeF wymaga wskazania konkretnego rodzaju marży. Bez wyboru faktura zostanie wysłana ze znacznikiem braku (P_PMarzyN).', 'prostafaktura-ksef' ); ?></small>
						</div>
					</div>

					<!-- WDT nowych środków transportu (P_22) — dane pojazdu wymagane przez KSeF -->
					<div id="row-p22" style="display:none;margin-top:14px;">
						<div class="ksef-grid-3" style="max-width:880px;">
							<div class="ksef-field"><label><?php esc_html_e( 'Nr nadwozia / VIN', 'prostafaktura-ksef' ); ?></label><input type="text" name="nst_vin" placeholder="np. WVWZZZ..."></div>
							<div class="ksef-field"><label><?php esc_html_e( 'Data dopuszczenia do użytku', 'prostafaktura-ksef' ); ?></label><input type="date" name="nst_data_dopuszczenia"></div>
							<div class="ksef-field"><label><?php esc_html_e( 'Przebieg (km)', 'prostafaktura-ksef' ); ?></label><input type="number" name="nst_przebieg" min="0" step="1" placeholder="np. 1500"></div>
						</div>
						<small style="color:var(--ink-4,#777);"><?php esc_html_e( 'Wypełnij dla wewnątrzwspólnotowej dostawy nowego środka transportu. Pozostaw puste, jeśli nie dotyczy — wyślemy znacznik braku (P_22N).', 'prostafaktura-ksef' ); ?></small>
					</div>
				</div>

				<!-- Karta: Dokumenty powiązane -->
				<div class="ksef-card">
					<div class="ksef-card-h">
						<span class="s-ic violet"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></span>
						<div class="t">
							<h2><?php esc_html_e( 'Dokumenty powiązane', 'prostafaktura-ksef' ); ?></h2>
							<small><?php esc_html_e( 'Zamówienie, dokument WZ, oferta', 'prostafaktura-ksef' ); ?></small>
						</div>
					</div>
					<div class="ksef-grid-3">
						<div class="ksef-field"><label><?php esc_html_e( 'Nr zamówienia', 'prostafaktura-ksef' ); ?></label><input type="text" name="rel_order_no" placeholder="np. PO-2026/001"></div>
						<div class="ksef-field"><label><?php esc_html_e( 'Data zamówienia', 'prostafaktura-ksef' ); ?></label><input type="date" name="rel_order_date"></div>
						<div class="ksef-field"><label><?php esc_html_e( 'Nr WZ', 'prostafaktura-ksef' ); ?></label><input type="text" name="rel_wz_no" placeholder="np. WZ/2026/001"></div>
					</div>
				</div>

				<!-- Karta: Dane dodatkowe -->
				<div class="ksef-card">
					<div class="ksef-card-h">
						<span class="s-ic gray"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg></span>
						<div class="t">
							<h2><?php esc_html_e( 'Dane dodatkowe', 'prostafaktura-ksef' ); ?></h2>
							<small><?php esc_html_e( 'Kontakt sprzedawcy, miejsce wystawienia, adres dostawy', 'prostafaktura-ksef' ); ?></small>
						</div>
					</div>
					<div class="extra-preset-bar" id="extra-preset-bar">
						<select id="extra_preset_pick"><option value=""><?php esc_html_e( '— zapisany zestaw danych —', 'prostafaktura-ksef' ); ?></option></select>
						<button type="button" class="button button-small" id="save-extra-preset-btn">💾 <?php esc_html_e( 'Zapisz jako zestaw', 'prostafaktura-ksef' ); ?></button>
						<button type="button" class="button button-small" id="extra-preset-default-btn" title="<?php esc_attr_e( 'Ustaw wybrany jako domyślny', 'prostafaktura-ksef' ); ?>">★ <?php esc_html_e( 'Domyślny', 'prostafaktura-ksef' ); ?></button>
						<button type="button" class="button button-small" id="extra-preset-del-btn" title="<?php esc_attr_e( 'Usuń wybrany zestaw', 'prostafaktura-ksef' ); ?>">🗑</button>
					</div>
					<div class="ksef-grid-4">
						<div class="ksef-field"><label><?php esc_html_e( 'Email sprzedawcy', 'prostafaktura-ksef' ); ?></label><input type="email" name="seller_email" placeholder="<?php esc_attr_e( 'Z kredencjału KSeF', 'prostafaktura-ksef' ); ?>"></div>
						<div class="ksef-field"><label><?php esc_html_e( 'Telefon sprzedawcy', 'prostafaktura-ksef' ); ?></label><input type="text" name="seller_phone" placeholder="<?php esc_attr_e( 'Z kredencjału KSeF', 'prostafaktura-ksef' ); ?>"></div>
						<div class="ksef-field"><label><?php esc_html_e( 'Miejsce wystawienia', 'prostafaktura-ksef' ); ?></label><input type="text" name="issue_place" placeholder="<?php esc_attr_e( 'Z miasta sprzedawcy', 'prostafaktura-ksef' ); ?>"></div>
							<div class="ksef-field" style="grid-column:span 2;"><label><?php esc_html_e( 'Email nabywcy', 'prostafaktura-ksef' ); ?> <span style="color:var(--ink-4,#999);font-weight:400;font-size:11px;">(<?php esc_html_e( 'auto-wysyłka faktury po wystawieniu', 'prostafaktura-ksef' ); ?>)</span></label><input type="email" id="buyer_email" name="buyer_email" placeholder="np. klient@example.com"></div>
							<div class="ksef-field"><label><?php esc_html_e( 'Nr klienta', 'prostafaktura-ksef' ); ?> <span style="color:var(--ink-4,#999);font-weight:400;font-size:11px;">(<?php esc_html_e( 'nabywcy', 'prostafaktura-ksef' ); ?>)</span></label><input type="text" name="customer_no" placeholder="np. K-00123"></div>
					</div>
					<label class="ksef-toggle-row" style="margin-top:14px;">
						<input type="checkbox" id="toggle_delivery_addr">
						<strong><?php esc_html_e( 'Adres dostawy (inny niż nabywca)', 'prostafaktura-ksef' ); ?></strong>
					</label>
					<div id="delivery-addr-fields" style="display:none;margin-top:10px;">
						<div class="ksef-grid-3">
							<div class="ksef-field"><label><?php esc_html_e( 'Nazwa / odbiorca', 'prostafaktura-ksef' ); ?></label><input type="text" name="delivery_name"></div>
							<div class="ksef-field"><label><?php esc_html_e( 'Ulica i nr', 'prostafaktura-ksef' ); ?></label><input type="text" name="delivery_street"></div>
							<div class="ksef-field"><label><?php esc_html_e( 'Kod / Miasto / Kraj', 'prostafaktura-ksef' ); ?></label>
								<div style="display:flex;gap:6px;"><input name="delivery_postal" placeholder="00-000" style="width:100px;"><input name="delivery_city" placeholder="Miasto"><input name="delivery_country" maxlength="2" value="PL" style="width:60px;"></div>
							</div>
						</div>
					</div>
				</div>

				<!-- Karty: Uwagi + Notatki KSeF (2 obok siebie) -->
				<div class="ksef-grid-2">
					<div class="ksef-card">
						<div class="ksef-card-h">
							<span class="s-ic gray"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg></span>
							<div class="t">
								<h2><?php esc_html_e( 'Uwagi do faktury', 'prostafaktura-ksef' ); ?></h2>
								<small><?php esc_html_e( 'Widoczne u Ciebie — nie idą do KSeF', 'prostafaktura-ksef' ); ?></small>
							</div>
						</div>
						<textarea name="internal_notes" rows="4" placeholder="<?php esc_attr_e( 'Wpisz uwagi, które mają się pojawić na fakturze…', 'prostafaktura-ksef' ); ?>"></textarea>
					</div>

					<div class="ksef-card">
						<div class="ksef-card-h">
							<span class="s-ic brand"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2 2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/></svg></span>
							<div class="t">
								<h2><?php esc_html_e( 'Notatki KSeF', 'prostafaktura-ksef' ); ?></h2>
								<small><?php esc_html_e( 'Pola key/value wysyłane razem z fakturą', 'prostafaktura-ksef' ); ?></small>
							</div>
							<div class="ksef-card-actions">
								<button type="button" class="ksef-btn ksef-btn-brand-soft" id="add-ksef-note-btn">+ <?php esc_html_e( 'Dodaj', 'prostafaktura-ksef' ); ?></button>
							</div>
						</div>
						<div id="ksef-notes-list"></div>
					</div>
				</div>

				<?php // Status faktury w KSeF (zaakceptowana / wyslana / odrzucona) pokazujemy na GORZE, pod naglowkiem. ?>

				<div id="ksef-submit-result" style="margin-top:14px;"></div>

				<!-- Sticky footer (Anuluj / Draft / Submit) -->
				<div class="ksef-sticky-footer">
					<div class="ksf-status">
						<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg>
						<span id="ksf-status-text"><?php esc_html_e( 'Szkic zapisany automatycznie', 'prostafaktura-ksef' ); ?></span>
					</div>
					<div class="ksf-actions">
						<a href="<?php echo esc_url( admin_url( 'admin.php?page=' . ( 'incoming' === $inv_type ? 'ksef-incoming' : 'ksef-outgoing' ) ) ); ?>" class="ksef-btn ksef-btn-ghost"><?php esc_html_e( 'Wróć', 'prostafaktura-ksef' ); ?></a>
						<?php if ( $is_edit && $inv_id > 0 ) : ?>
							<button type="button" class="ksef-btn ksef-btn-ghost" id="ksef-delete-draft" data-draft-id="<?php echo (int) $inv_id; ?>" style="color:#dc2626;">
								<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2m3 0v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/></svg>
								<?php esc_html_e( 'Usuń szkic', 'prostafaktura-ksef' ); ?>
							</button>
						<?php endif; ?>
						<?php if ( $is_view && 'incoming' !== $inv_type ) : ?>
							<a href="<?php echo esc_url( add_query_arg( [ 'action' => 'ksef_invoice_pdf', 'invoice_id' => (int) $inv_id, '_ajax_nonce' => $nonce ], admin_url( 'admin-ajax.php' ) ) ); ?>" target="_blank" class="ksef-btn ksef-btn-secondary">
								<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
								<?php esc_html_e( 'PDF', 'prostafaktura-ksef' ); ?>
							</a>
							<?php if ( $existing_inv && ! empty( $existing_inv['ksef_reference_number'] ) ) : ?>
								<a href="<?php echo esc_url( admin_url( 'admin.php?page=ksef-manual-invoice&action=correct&id=' . (int) $inv_id ) ); ?>" class="ksef-btn ksef-btn-primary"><?php esc_html_e( 'Wystaw korektę', 'prostafaktura-ksef' ); ?></a>
							<?php elseif ( $existing_inv && in_array( (string) ( $existing_inv['status'] ?? '' ), [ 'issued', 'failed', 'rejected' ], true ) ) :
								$send_lbl = in_array( (string) ( $existing_inv['status'] ?? '' ), [ 'failed', 'rejected' ], true ) ? __( 'Ponów wysyłkę', 'prostafaktura-ksef' ) : __( 'Wyślij do KSeF', 'prostafaktura-ksef' );
							?>
								<a href="<?php echo esc_url( admin_url( 'admin.php?page=ksef-manual-invoice&action=edit&id=' . (int) $inv_id . '&type=outgoing' ) ); ?>" class="ksef-btn ksef-btn-secondary">✎ <?php esc_html_e( 'Edytuj i wyślij', 'prostafaktura-ksef' ); ?></a>
								<button type="button" class="ksef-btn ksef-btn-primary" id="ksef-view-send-draft" data-draft-id="<?php echo (int) $inv_id; ?>">📤 <?php echo esc_html( $send_lbl ); ?></button>
							<?php endif; ?>
						<?php elseif ( ! $is_view ) : ?>
							<button type="button" class="ksef-btn ksef-btn-secondary" id="ksef-draft-btn">
								<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><path d="M17 21v-8H7v8M7 3v5h8"/></svg>
								<?php echo $is_edit ? esc_html__( 'Zapisz zmiany', 'prostafaktura-ksef' ) : esc_html__( 'Zapisz jako szkic', 'prostafaktura-ksef' ); ?>
							</button>
							<button type="submit" class="ksef-btn ksef-btn-primary" id="ksef-submit-btn">
								<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m22 2-7 20-4-9-9-4 20-7z"/><path d="M22 2 11 13"/></svg>
								<?php echo $is_edit ? esc_html__( 'Wyślij do KSeF', 'prostafaktura-ksef' ) : esc_html__( 'Wystaw i wyślij do KSeF', 'prostafaktura-ksef' ); ?>
							</button>
							<span id="ksef-submit-spinner" class="spinner" style="float:none;display:none;margin:0;"></span>
						<?php endif; ?>
					</div>
				</div>
			</form>

			<!-- Sticky sidebar — HIDDEN (footer zastępuje) — pozostawione żeby JS znajdował elementy -->
			<aside class="ksef-app-sidebar" style="display:none !important;">
				<div class="ksef-side-card ksef-side-summary">
					<div class="ksef-side-card-h">
						<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>
						<span><?php esc_html_e( 'Podsumowanie', 'prostafaktura-ksef' ); ?></span>
					</div>
					<div class="ksef-side-vat-table" id="side-vat-summary">
						<div class="ksef-side-empty">brak pozycji</div>
					</div>
					<div class="ksef-side-row"><span>Netto</span><strong id="side-net">0,00</strong></div>
					<div class="ksef-side-row"><span>VAT</span><strong id="side-vat">0,00</strong></div>
					<div class="ksef-side-row ksef-side-row-bold"><span>Brutto</span><strong id="side-gross">0,00</strong></div>
					<div class="ksef-side-row" id="side-deposit-row" style="display:none;">
						<span>+ Kaucja</span><strong id="side-deposit">0,00</strong>
					</div>
					<div class="ksef-side-total">
						<div class="ksef-side-total-label">Do zapłaty</div>
						<div class="ksef-side-total-value"><span id="side-payable">0,00</span> <span id="side-currency">PLN</span></div>
					</div>
				</div>

				<div class="ksef-side-card">
					<div class="ksef-side-card-h">
						<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
						<span><?php esc_html_e( 'Stan', 'prostafaktura-ksef' ); ?></span>
					</div>
					<div class="ksef-side-meta">
						<div><span class="lbl">Sprzedawca:</span> <span id="side-lokal">—</span></div>
						<div><span class="lbl">Nabywca:</span> <span id="side-buyer">—</span></div>
						<div><span class="lbl">Pozycje:</span> <span id="side-items-count">0</span></div>
						<div><span class="lbl">Termin:</span> <span id="side-due">—</span></div>
					</div>
				</div>

				<div class="ksef-side-card ksef-side-actions">
					<button type="button" class="ksef-btn ksef-btn-block ksef-btn-secondary" id="ksef-draft-btn">
						<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 21H5a2 2 0 01-2-2V5a2 2 0 012-2h11l5 5v11a2 2 0 01-2 2z"/></svg>
						<?php echo $is_edit ? esc_html__( 'Zapisz zmiany', 'prostafaktura-ksef' ) : esc_html__( 'Zapisz draft', 'prostafaktura-ksef' ); ?>
					</button>
					<button type="submit" form="ksef-manual-invoice-form"
						class="ksef-btn ksef-btn-block ksef-btn-primary" id="ksef-submit-btn">
						<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
						<?php echo $is_edit ? esc_html__( 'Wyślij do KSeF', 'prostafaktura-ksef' ) : esc_html__( 'Wystaw i wyślij', 'prostafaktura-ksef' ); ?>
					</button>
					<span id="ksef-submit-spinner" class="spinner" style="float:none;margin:8px auto 0;display:block;"></span>
				</div>
			</aside>
			</div><!-- /.ksef-app-layout -->

		<!-- Modal: Nowy/Edytuj kontrahent -->
		<div id="contractor-modal" class="ksef-modal-overlay" style="display:none;">
			<div class="ksef-modal-card">
				<button class="ksef-modal-close" type="button">&times;</button>
				<h3 id="contractor-modal-title"><?php esc_html_e( 'Nowy kontrahent', 'prostafaktura-ksef' ); ?></h3>
				<input type="hidden" id="cm_id" value="">
				<div class="ksef-field"><label>Typ</label>
					<select id="cm_buyer_type">
						<option value="pl_firm">Firma polska (NIP)</option>
						<option value="b2c">Osoba prywatna (BrakID)</option>
						<option value="ue">Firma UE (NrVatUE)</option>
						<option value="non_ue">Firma spoza UE</option>
					</select>
				</div>
				<div class="ksef-field"><label>Nazwa / Imię i nazwisko</label><input type="text" id="cm_name"></div>
				<div class="ksef-grid-2-inner">
					<div class="ksef-field"><label>NIP</label><input type="text" id="cm_nip" maxlength="10"></div>
					<div class="ksef-field"><label>Email</label><input type="email" id="cm_email"></div>
				</div>
				<div class="ksef-grid-2-inner">
					<div class="ksef-field"><label>Telefon</label><input type="text" id="cm_phone"></div>
					<div class="ksef-field"><label>Nr klienta</label><input type="text" id="cm_customer_no"></div>
				</div>
				<div class="ksef-field"><label>Ulica i nr</label><input type="text" id="cm_street"></div>
				<div class="ksef-grid-2-inner">
					<div class="ksef-field"><label>Kod / Miasto</label>
						<div style="display:flex;gap:6px;"><input id="cm_postal" placeholder="00-000" style="width:100px;"><input id="cm_city" placeholder="Miasto"></div>
					</div>
					<div class="ksef-field"><label>Kraj (kod 2 znaki)</label><input type="text" id="cm_country" maxlength="2" value="PL"></div>
				</div>
				<div id="cm_ue_row" style="display:none;" class="ksef-field"><label>VAT-UE</label><input type="text" id="cm_vat_ue" placeholder="DE123456789"></div>
				<div id="cm_nrid_row" style="display:none;" class="ksef-field"><label>Nr ID (poza UE)</label><input type="text" id="cm_nr_id"></div>
				<div style="display:flex;gap:8px;justify-content:flex-end;margin-top:14px;">
					<button type="button" class="button" id="cm-cancel"><?php esc_html_e( 'Anuluj', 'prostafaktura-ksef' ); ?></button>
					<button type="button" class="button button-primary" id="cm-save"><?php esc_html_e( 'Zapisz kontrahenta', 'prostafaktura-ksef' ); ?></button>
				</div>
			</div>
		</div>

		<!-- Modal: Wybierz produkt WC -->
		<div id="wc-modal" class="ksef-modal-overlay" style="display:none;">
			<div class="ksef-modal-card">
				<button class="ksef-modal-close" type="button">&times;</button>
				<h3><?php esc_html_e( 'Wybierz produkt z WooCommerce', 'prostafaktura-ksef' ); ?></h3>
				<input type="text" id="wc-search" placeholder="<?php esc_attr_e( 'Wyszukaj produkt po nazwie lub SKU…', 'prostafaktura-ksef' ); ?>" style="width:100%;">
				<div id="wc-products-list" style="max-height:400px;overflow-y:auto;margin-top:10px;"></div>
			</div>
		</div>

		<!-- Modal: Nowy rachunek bankowy -->
		<div id="bank-modal" class="ksef-modal-overlay" style="display:none;">
			<div class="ksef-modal-card" style="max-width:540px;">
				<button class="ksef-modal-close" type="button">&times;</button>
				<h3 id="bk-modal-title"><?php esc_html_e( 'Dodaj rachunek bankowy', 'prostafaktura-ksef' ); ?></h3>
				<input type="hidden" id="bk_id" value="">
				<div class="ksef-field"><label>Numer konta (IBAN)</label><input type="text" id="bk_account" placeholder="PL12 3456 7890..."></div>
				<div class="ksef-grid-2-inner">
					<div class="ksef-field"><label>Nazwa banku</label><input type="text" id="bk_name"></div>
					<div class="ksef-field"><label>SWIFT/BIC</label><input type="text" id="bk_swift"></div>
				</div>
				<div class="ksef-grid-2-inner">
					<div class="ksef-field"><label>Waluta</label>
						<select id="bk_currency"><option>PLN</option><option>EUR</option><option>USD</option><option>GBP</option></select>
					</div>
					<div class="ksef-field"><label><input type="checkbox" id="bk_default"> Domyślny dla tego konta KSeF</label></div>
				</div>
				<div style="display:flex;gap:8px;justify-content:flex-end;margin-top:14px;">
					<button type="button" class="button" id="bk-cancel">Anuluj</button>
					<button type="button" class="button button-primary" id="bk-save">Zapisz konto</button>
				</div>
			</div>
		</div>

		<input type="hidden" name="bank_account_id" id="bank_account_id" value="">

		</div><!-- /.ksef-app -->

		<?php ob_start(); ?>
		/* ===== Reset wordpressowych elementów na tej stronie ===== */
		body.toplevel_page_ksef-dashboard #wpcontent,
		body[class*="page_ksef-manual-invoice"] #wpcontent { padding-left: 0 !important; background: var(--bg) !important; }
		body[class*="page_ksef-manual-invoice"] #wpbody-content > .notice,
		body[class*="page_ksef-manual-invoice"] #wpbody-content > .updated,
		body[class*="page_ksef-manual-invoice"] #wpbody-content > .error,
		body[class*="page_ksef-manual-invoice"] #wpfooter { display: none !important; }
		body[class*="page_ksef-manual-invoice"] .update-nag { display:none !important; }

		.ksef-app, .ksef-app * { box-sizing: border-box; }
		.ksef-app {
			--bg: #f5f6f9;
			--bg-card: #ffffff;
			--border: #e7eaee;
			--border-strong: #d3d7dd;
			--text: #1a1d21;
			--text-2: #5a6473;
			--text-3: #97a0ad;
			--primary: #d9531e;
			--primary-dark: #b8451a;
			--primary-light: #fff2eb;
			--accent: #2563eb;
			--success: #16a34a;
			--warning: #f59e0b;
			--danger: #dc2626;
			--radius: 10px;
			--radius-sm: 6px;
			--shadow-sm: 0 1px 2px rgba(16,24,40,0.04);
			--shadow: 0 1px 3px rgba(16,24,40,0.08), 0 1px 2px rgba(16,24,40,0.04);
			--shadow-md: 0 4px 12px rgba(16,24,40,0.08);
			font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
			color: var(--text);
			background: var(--bg);
			min-height: 100vh;
			padding: 0;
			margin: 0 -20px 0 -20px;
		}

		/* ===== Header ===== */
		.ksef-app-header {
			background: #fff;
			border-bottom: 1px solid var(--border);
			padding: 18px 32px;
			position: sticky;
			top: 32px;
			z-index: 90;
		}
		.ksef-app-breadcrumb { font-size: 12.5px; color: var(--text-3); margin-bottom: 6px; }
		.ksef-app-breadcrumb a { color: var(--text-2); text-decoration: none; }
		.ksef-app-breadcrumb a:hover { color: var(--primary); }
		.ksef-app-breadcrumb .ksef-sep { margin: 0 6px; color: var(--text-3); }
		.ksef-app-title-row { display: flex; justify-content: space-between; align-items: center; gap: 20px; }
		.ksef-app-title-row h1 { font-size: 22px; font-weight: 700; margin: 0; display: flex; align-items: center; gap: 12px; line-height: 1.2; }
		.ksef-app-actions { display: flex; gap: 8px; align-items: center; }

		/* ===== Pill ===== */
		.ksef-pill { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px; border-radius: 100px; font-size: 11.5px; font-weight: 600; }
		.ksef-pill .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
		.ksef-pill-draft { background: #f3f4f6; color: #6b7280; }
		.ksef-pill-sent  { background: #dbeafe; color: #1e40af; }
		.ksef-pill-paid  { background: #dcfce7; color: #166534; }

		/* ===== Buttons ===== */
		.ksef-btn {
			display: inline-flex; align-items: center; gap: 7px;
			padding: 8px 14px; border-radius: 8px; font-size: 13px; font-weight: 500;
			border: 1px solid var(--border-strong); background: #fff; color: var(--text);
			cursor: pointer; transition: all 0.15s ease; text-decoration: none;
			font-family: inherit;
		}
		.ksef-btn:hover { background: #f9fafb; border-color: #b9bec6; }
		.ksef-btn-primary { background: var(--primary); border-color: var(--primary); color: #fff; box-shadow: 0 1px 2px rgba(217,83,30,0.2); }
		.ksef-btn-primary:hover { background: var(--primary-dark); border-color: var(--primary-dark); color: #fff; }
		.ksef-btn-secondary { background: #fff; border-color: var(--border-strong); }
		.ksef-btn-ghost { background: transparent; border-color: transparent; color: var(--text-2); }
		.ksef-btn-ghost:hover { background: #f3f4f6; color: var(--text); }
		.ksef-btn-block { width: 100%; justify-content: center; padding: 10px 14px; }
		.ksef-btn:disabled,
		.ksef-btn-disabled { opacity: 0.55; cursor: not-allowed; pointer-events: none; background: #9ca3af; border-color: #9ca3af; color: #fff; box-shadow: none; }
		.ksef-btn-primary.ksef-btn-disabled,
		.ksef-btn-primary:disabled { background: #9ca3af; border-color: #9ca3af; color: #fff; }

		/* ===== Layout (main; panel boczny ukryty — akcje i sumy w nagłówku/stopce) ===== */
		.ksef-app-layout { display: grid; grid-template-columns: 1fr; gap: 24px; padding: 24px 32px 80px; max-width: 1100px; margin: 0 auto; }
		.ksef-app-main { min-width: 0; }
		.ksef-app-sidebar { display: none; }

		/* ===== Cards (form sections) ===== */
		.ksef-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px 22px; margin-bottom: 16px; box-shadow: var(--shadow-sm); }
		.ksef-card h2 { font-size: 15px; margin: 0 0 16px 0; font-weight: 600; letter-spacing: -0.01em; color: var(--text); }
		.ksef-card h4.ksef-section-sub { color: var(--text-3); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; margin: 16px 0 10px; font-weight: 600; }

		/* ===== Grids ===== */
		.ksef-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px; }
		.ksef-grid-2-inner { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
		.ksef-grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; }
		.ksef-grid-4 { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 12px; }
		.extra-preset-bar { display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:14px;padding:10px 12px;background:var(--section,#f7f8fa);border:1px solid var(--border);border-radius:var(--radius-sm); }
		.extra-preset-bar select { min-width:200px;max-width:280px; }

		/* ===== Fields ===== */
		.ksef-field { margin-bottom: 14px; }
		.ksef-field > label { display: block; font-size: 12px; color: var(--text-2); margin-bottom: 5px; font-weight: 500; }
		.ksef-field > label .req { color: var(--danger); margin-left: 3px; }
		.ksef-field input[type=text],
		.ksef-field input[type=email],
		.ksef-field input[type=date],
		.ksef-field input[type=number],
		.ksef-field select,
		.ksef-field textarea,
		.ksef-card textarea,
		.ksef-modal-card input[type=text],
		.ksef-modal-card input[type=email],
		.ksef-modal-card input[type=date],
		.ksef-modal-card select {
			width: 100%; padding: 9px 12px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
			font-size: 13px; background: #fff; font-family: inherit; color: var(--text);
			transition: border-color 0.15s, box-shadow 0.15s;
		}
		.ksef-field input:focus, .ksef-field select:focus, .ksef-field textarea:focus,
		.ksef-card textarea:focus {
			outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(217,83,30,0.12);
		}
		.ksef-field input[readonly] { background: #f8f9fb; color: var(--text-2); }
		.ksef-hint { font-size: 11.5px; color: var(--text-3); margin: 5px 0 0; }
		.ksef-hint code { background: #f3f4f6; padding: 1px 5px; border-radius: 3px; font-size: 11px; }

		/* ===== Toggles ===== */
		.ksef-toggle-mini { font-size: 12px; color: var(--text-2); font-weight: 500; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; }
		.ksef-toggle-row { display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: 13.5px; padding: 6px 0; }

		/* ===== Segmented ===== */
		.ksef-segmented { display: inline-flex; background: #f1f3f5; border-radius: 8px; padding: 3px; gap: 2px; }
		.ksef-segmented input { display: none; }
		.ksef-segmented label { padding: 7px 16px; cursor: pointer; background: transparent; font-size: 12.5px; font-weight: 500; color: var(--text-2); border-radius: 6px; transition: all 0.15s; }
		.ksef-segmented label:hover { color: var(--text); }
		.ksef-segmented input:checked + label { background: #fff; color: var(--primary); box-shadow: var(--shadow-sm); }
		.ksef-segmented-sm label { padding: 5px 12px; font-size: 12px; }
		.ksef-segmented-sm input:checked + label { color: var(--accent); }

		/* ===== Items table ===== */
		.ksef-items-table { width: 100%; border-collapse: collapse; font-size: 13px; }
		.ksef-items-table th, .ksef-items-table td { padding: 8px 10px; border-bottom: 1px solid var(--border); text-align: left; vertical-align: middle; }
		.ksef-items-table thead th { background: #fafbfc; font-weight: 500; color: var(--text-3); font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; padding: 10px 10px; }
		.ksef-items-table tbody tr:hover { background: #fafbfc; }
		.ksef-items-table input, .ksef-items-table select { width: 100%; padding: 6px 8px; border: 1px solid transparent; background: transparent; font-size: 13px; border-radius: 4px; font-family: inherit; color: var(--text); }
		.ksef-items-table input:hover, .ksef-items-table select:hover { background: #f3f4f6; }
		.ksef-items-table input:focus, .ksef-items-table select:focus { border-color: var(--primary); background: #fff; outline: none; box-shadow: 0 0 0 2px rgba(217,83,30,0.1); }
		.ksef-items-table .item-lp { color: var(--text-3); font-size: 12px; }
		.ksef-items-table .item-net, .ksef-items-table .item-gross { font-variant-numeric: tabular-nums; color: var(--text); font-weight: 500; }
		.ksef-items-table .ksef-remove-item { background: transparent; border: none; color: var(--text-3); cursor: pointer; padding: 4px; border-radius: 4px; font-size: 14px; }
		.ksef-items-table .ksef-remove-item:hover { background: #fee2e2; color: var(--danger); }
		/* Pola rosną do zawartości — nie ucinają wielocyfrowych liczb (nowoczesne field-sizing
		   + fallback min-width). max-width ogranicza rozdmuchanie przy ekstremalnych wartościach,
		   a wrapper poniżej daje czysty scroll w obrębie karty zamiast wycinania kolumn. */
		.ksef-items-table input, .ksef-items-table select { field-sizing: content; box-sizing: border-box; }
		.ksef-items-table .item-qty      { width: auto; min-width: 64px; max-width: 110px; text-align: right; }
		.ksef-items-table .item-discount { width: auto; min-width: 64px; max-width: 80px;  text-align: right; }
		.ksef-items-table .item-price    { width: auto; min-width: 88px; max-width: 150px; text-align: right; }
		.ksef-items-table .item-vat      { width: auto; min-width: 66px; max-width: 92px; }
		.ksef-items-table .item-unit     { width: auto; min-width: 54px; max-width: 110px; }
		.ksef-items-table .item-pkwiu    { width: auto; min-width: 76px; max-width: 130px; }
		.ksef-items-table .item-gtu      { width: auto; min-width: 78px; max-width: 110px; }
		.ksef-items-table .item-net, .ksef-items-table .item-gross { white-space: nowrap; }
		/* Scroll poziomy w obrębie karty — ZAWSZE (nie tylko mobile). Dzięki temu rozpychanie
		   pól przez field-sizing nigdy nie wycina GTU/kosza poza kartę — pojawia się pasek. */
		#ksef-items-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
		#ksef-items-table-wrap::-webkit-scrollbar { height: 8px; }
		#ksef-items-table-wrap::-webkit-scrollbar-thumb { background: #d8dade; border-radius: 8px; }
		#ksef-items-table-wrap::-webkit-scrollbar-track { background: transparent; }
		#ksef-add-item { color: var(--primary); font-weight: 600; cursor: pointer; background: none; border: none; padding: 8px 0; font-size: 13.5px; }
		#ksef-add-item:hover { color: var(--primary-dark); }

		/* ===== Items summary (in main) ===== */
		.ksef-items-summary { display: flex; justify-content: flex-end; margin-top: 14px; }
		.ksef-items-summary table { font-size: 12.5px; min-width: 380px; }
		.ksef-items-summary th, .ksef-items-summary td { padding: 5px 16px 5px 0; text-align: right; font-variant-numeric: tabular-nums; }
		.ksef-items-summary thead th { color: var(--text-3); font-weight: 500; font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; }
		.ksef-items-summary tfoot th { padding-top: 10px; border-top: 1px solid var(--border-strong); font-weight: 700; font-size: 14px; }

		/* ===== Markers grid ===== */
		.ksef-markers-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
		.ksef-marker { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border: 1px solid transparent; border-radius: 8px; cursor: pointer; font-size: 13px; transition: background 0.15s; }
		.ksef-marker:hover { background: #fafbfc; }
		.ksef-marker input { margin: 0; accent-color: var(--primary); width: 16px; height: 16px; }
		.ksef-marker input:checked + .ksef-marker-text { color: var(--primary); font-weight: 500; }
		.ksef-marker-text { flex: 1; }
		.ksef-marker-code { color: var(--text-3); font-size: 11px; font-family: 'SF Mono', Menlo, monospace; }

		/* ===== Sidebar ===== */
		.ksef-app-sidebar { position: sticky; top: 130px; align-self: start; display: flex; flex-direction: column; gap: 12px; }
		.ksef-side-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px 18px; box-shadow: var(--shadow-sm); }
		.ksef-side-card-h { display: flex; align-items: center; gap: 8px; font-size: 12.5px; font-weight: 600; color: var(--text-2); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 12px; }
		.ksef-side-card-h svg { color: var(--text-3); }
		.ksef-side-vat-table { font-size: 11.5px; color: var(--text-3); margin-bottom: 10px; }
		.ksef-side-vat-table .row { display: flex; justify-content: space-between; padding: 2px 0; }
		.ksef-side-empty { color: var(--text-3); font-style: italic; font-size: 12px; padding: 4px 0; }
		.ksef-side-row { display: flex; justify-content: space-between; align-items: center; padding: 6px 0; font-size: 13px; color: var(--text-2); }
		.ksef-side-row strong { color: var(--text); font-variant-numeric: tabular-nums; font-weight: 600; }
		.ksef-side-row-bold { border-top: 1px solid var(--border); margin-top: 4px; padding-top: 8px; }
		.ksef-side-row-bold span, .ksef-side-row-bold strong { font-weight: 600; color: var(--text); font-size: 13.5px; }
		.ksef-side-total { background: linear-gradient(135deg, #fff2eb 0%, #ffe6d7 100%); border-radius: 8px; padding: 14px 16px; margin-top: 14px; }
		.ksef-side-total-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--primary-dark); font-weight: 600; }
		.ksef-side-total-value { font-size: 22px; font-weight: 700; color: var(--primary-dark); margin-top: 4px; font-variant-numeric: tabular-nums; }
		.ksef-side-meta { font-size: 12.5px; color: var(--text); line-height: 1.7; }
		.ksef-side-meta .lbl { color: var(--text-3); margin-right: 6px; }
		.ksef-side-actions { display: flex; flex-direction: column; gap: 8px; padding: 14px 18px; }

		/* ===== Contractor picker ===== */
		.ksef-contractor-picker { position: relative; display: flex; gap: 6px; }
		.ksef-contractor-picker input { flex: 1; }
		.ksef-suggestions { position: absolute; top: calc(100% + 4px); left: 0; right: 0; background: #fff; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); max-height: 240px; overflow-y: auto; z-index: 10; display: none; box-shadow: var(--shadow-md); }
		.ksef-suggestions.open { display: block; }
		.ksef-suggestion { padding: 10px 12px; cursor: pointer; border-bottom: 1px solid #f0f1f3; font-size: 13px; }
		.ksef-suggestion:hover { background: var(--primary-light); }
		.ksef-suggestion strong { color: var(--text); }
		.ksef-suggestion small { color: var(--text-3); }
		.ksef-contractor-summary { margin-top: 10px; padding: 10px 12px; background: var(--primary-light); border-radius: var(--radius-sm); font-size: 12.5px; display: none; border: 1px solid #ffd7be; }
		.ksef-contractor-summary.show { display: block; }
		.ksef-contractor-summary a { color: var(--primary); font-size: 11px; text-decoration: none; }

		/* ===== Modal ===== */
		.ksef-modal-overlay { position: fixed; inset: 0; background: rgba(15,18,21,0.6); display: flex; align-items: center; justify-content: center; z-index: 9999; backdrop-filter: blur(2px); }
		.ksef-modal-card { background: var(--bg-card); border-radius: var(--radius); width: 90%; max-width: 720px; padding: 24px 28px; position: relative; max-height: 88vh; overflow-y: auto; box-shadow: 0 20px 60px rgba(0,0,0,0.3); }
		.ksef-modal-card h3 { margin: 0 0 16px; font-size: 17px; font-weight: 600; }
		.ksef-modal-close { position: absolute; top: 14px; right: 16px; background: none; border: none; font-size: 22px; cursor: pointer; color: var(--text-3); width: 32px; height: 32px; border-radius: 8px; display: flex; align-items: center; justify-content: center; }
		.ksef-modal-close:hover { background: #f3f4f6; color: var(--text); }

		.wc-product-row { padding: 12px 14px; border-bottom: 1px solid var(--border); cursor: pointer; display: flex; justify-content: space-between; align-items: center; transition: background 0.15s; border-radius: var(--radius-sm); }
		.wc-product-row:hover { background: var(--primary-light); }
		.wc-product-name { font-weight: 500; }
		.wc-product-meta { font-size: 11.5px; color: var(--text-3); margin-top: 2px; }

		.bank-row { display:flex;justify-content:space-between;align-items:flex-start;gap:10px;padding:10px 14px;border:1px solid var(--border);border-radius:var(--radius-sm);margin-bottom:6px;background:#fff;font-size:13px; }
		.bank-row.selected { border-color: var(--primary); background: var(--primary-light); }
		.bank-acc { font-family: 'SF Mono', Menlo, monospace; font-size: 12.5px; }
		.bank-info { display:flex;flex-direction:column;gap:3px;min-width:0; }
		.bank-line1 { display:flex;align-items:center;gap:6px; }
		.bank-iban { letter-spacing:.3px; }
		.bank-meta { color: var(--muted); font-size: 12px; }
		.bank-def { font-style:normal;font-size:11px;font-weight:600;color:var(--primary);background:var(--primary-light);padding:1px 7px;border-radius:999px; }
		.bank-actions { display:flex;gap:4px;flex-shrink:0; }

		.ksef-knote-row { display:grid;grid-template-columns:1fr 1fr 36px;gap:8px;margin-bottom:8px; }
		.ksef-knote-row input { width:100%; padding:8px 12px; border:1px solid var(--border-strong); border-radius:var(--radius-sm); font-size:13px; font-family: inherit; }
		.ksef-knote-row .del-knote { background:transparent;border:1px solid var(--border);border-radius:var(--radius-sm);cursor:pointer;color:var(--text-3); }
		.ksef-knote-row .del-knote:hover { background:#fee2e2;color:var(--danger);border-color:#fee2e2; }

		/* ===== Toast notice (replaces inline submit-result) ===== */
		#ksef-submit-result .notice { border-radius: var(--radius); border-left-width: 4px; padding: 14px 18px !important; box-shadow: var(--shadow-md); }

		/* ===== Tryb podglądu — statyczny tekst zamiast pól ===== */
		.ksef-view-static { display: block; font-size: 13px; color: var(--text); padding: 8px 2px; line-height: 1.45; word-break: break-word; overflow-wrap: anywhere; white-space: normal; min-height: 18px; }
		.ksef-view-multiline { white-space: pre-wrap; }
		.ksef-items-table .ksef-view-static { padding: 4px 2px; }
		.ksef-items-table td { vertical-align: top; }

		/* ===== Czytelny PODGLĄD (read-only): wyraźna hierarchia etykieta → wartość =====
		   Wcześniej etykieta (12px szara) i wartość (13px) wyglądały podobnie → „zlane".
		   Teraz: etykieta mała/UPPERCASE wyciszona, wartość większa, pogrubiona, w kafelku. */
		.ksef-app-readonly .ksef-field { margin-bottom: 16px; }
		.ksef-app-readonly .ksef-field > label {
			font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
			color: #98968F; font-weight: 600; margin-bottom: 5px;
		}
		.ksef-app-readonly .ksef-view-static {
			font-size: 15px; font-weight: 600; color: #14171A;
			background: #F7F7F4; border: 1px solid #ECEAE4; border-radius: 9px;
			padding: 10px 13px; min-height: 0; line-height: 1.4;
		}
		.ksef-app-readonly .ksef-view-multiline { font-weight: 400; font-size: 14px; }
		/* Pozycje faktury: bez kafelków (czytelniej jako kompaktowa tabela) */
		.ksef-app-readonly .ksef-items-table .ksef-view-static {
			background: none; border: 0; padding: 6px 6px; font-size: 13px; font-weight: 500; color: #14171A;
		}
		.ksef-app-readonly .ksef-items-table .item-net,
		.ksef-app-readonly .ksef-items-table .item-gross { font-weight: 700; }
		/* Karty podglądu — trochę więcej oddechu między polami */
		.ksef-app-readonly .ksef-card { padding: 20px 22px; }
		/* Elementy istotne tylko przy WYSTAWIANIU — w podglądzie zbędne/mylące. */
		.ksef-app-readonly .ksef-issue-only { display: none !important; }
		/* Elementy widoczne TYLKO w podglądzie / TYLKO przy wystawianiu */
		.ksef-view-only { display: none; }
		.ksef-app-readonly .ksef-view-only { display: grid; }
		.ksef-app-readonly .ksef-hide-in-view { display: none !important; }
		/* Strony faktury w podglądzie: Sprzedawca + Nabywca obok siebie */
		/* Rozliczenie zakupu (podgląd) — segment statusu płatności + hint zapisu */
		.ksef-pay-seg { display: inline-flex; background: #F1EFEA; border: 1px solid #E7E5E1; border-radius: 999px; padding: 3px; gap: 2px; }
		.ksef-pay-seg button { border: none; background: none; padding: 7px 16px; font-size: 13px; font-weight: 500; color: #5a6473; border-radius: 999px; cursor: pointer; }
		.ksef-pay-seg button:hover { color: #14171A; }
		.ksef-pay-seg button.is-active { background: #fff; color: #14171A; box-shadow: 0 1px 2px rgba(10,10,11,.1); font-weight: 600; }
		.ksef-saved-hint { display: inline-block; margin-top: 6px; font-size: 12px; min-height: 16px; }
		#ksef-zakup-rozliczenie select { width: 100%; padding: 9px 12px; border: 1px solid #E7E5E1; border-radius: 9px; font-size: 14px; background: #fff; }
		.ksef-view-parties { grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 16px; }
		.ksef-vp { background: #F7F7F4; border: 1px solid #ECEAE4; border-radius: 10px; padding: 12px 14px; }
		.ksef-vp-label { font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: #98968F; font-weight: 600; margin-bottom: 6px; }
		.ksef-vp-name { font-size: 15px; font-weight: 700; color: #14171A; line-height: 1.35; }
		.ksef-vp-meta { font-size: 12.5px; color: #5a6473; line-height: 1.5; margin-top: 3px; white-space: pre-line; }
		@media (max-width: 600px){ .ksef-view-parties { grid-template-columns: 1fr; } }
		.ksef-items-table td input[type=text] { white-space: normal; }

		/* ===== Mobile ===== */
		@media (max-width: 1100px) {
			.ksef-app-layout { grid-template-columns: 1fr; }
			.ksef-app-sidebar { position: static; }
		}
		@media (max-width: 900px) {
			.ksef-grid-2, .ksef-grid-2-inner, .ksef-grid-3, .ksef-grid-4 { grid-template-columns: 1fr; }
			.ksef-markers-grid { grid-template-columns: 1fr; }
			.ksef-app-header { padding: 14px 18px; }
			.ksef-app-layout { padding: 16px 18px 60px; }
			/* Tabela pozycji (12 kolumn input) — przewijanie poziome zamiast ściskania.
			   Sensowne stackowanie pól wprowadzania nie ma sensu; scroll jest czytelny. */
			#ksef-items-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; border-radius: 10px; }
			#ksef-items-table { min-width: 720px; }
			/* Tabela podsumowania VAT również */
			#ksef-vat-summary, .ksef-vat-summary-table { font-size: 12px; }
		}
		@media (max-width: 600px) {
			.ksef-app-layout { padding: 12px 12px 60px; }
			.ksef-app-header { padding: 12px 12px; }
			/* Modale wystawiania (kontrahent / bank / produkty Woo) prawie pełny ekran */
			.ksef-modal .ksef-modal-card, .ksef-modal-card { width: 96% !important; max-width: none !important; padding: 16px 14px !important; }
			.ksef-knote-row { grid-template-columns: 1fr 1fr; }
		}

		/* =====================================================================
		   MODERN OVERRIDES (screenshots: Mercury × Linear × Stripe)
		   - indigo brand #5B5BD6, layout 1-col, sticky footer, no bleed.
		   ===================================================================== */
		.ksef-app {
			/* Indigo brand */
			--primary: #5B5BD6;
			--primary-dark: #4A4AC9;
			--primary-light: #EEF0FF;
			/* Inside WP shell — no full-bleed margins */
			margin: 0;
			background: transparent;
			min-height: auto;
		}
		.ksef-app-layout {
			grid-template-columns: 1fr !important;
			padding: 0 !important;
			gap: 16px;
		}
		.ksef-app-main { gap: 16px; padding-bottom: 80px; }
		.ksef-app-sidebar { display: none !important; }

		/* Cards — soft shadow, larger radius, header with icon-in-box */
		.ksef-card {
			border-radius: 14px;
			border: 1px solid #E7E5E1;
			background: #fff;
			padding: 22px 24px;
			box-shadow: 0 1px 0 rgba(10,10,11,0.02);
		}
		.ksef-card-h {
			display: flex; align-items: center; gap: 14px; margin-bottom: 16px;
		}
		.ksef-card-h h2 {
			margin: 0; font-size: 16px; font-weight: 600;
			text-transform: none; letter-spacing: 0; color: var(--text);
		}
		.ksef-card-h .t { flex: 1; min-width: 0; }
		.ksef-card-h .t small {
			display: block; margin-top: 2px;
			font-size: 12.5px; color: #98968F; font-weight: 400;
		}
		.ksef-card-h .ksef-card-actions {
			display: flex; align-items: center; gap: 8px; flex-shrink: 0;
		}
		.s-ic {
			width: 38px; height: 38px; border-radius: 10px;
			display: grid; place-items: center; flex-shrink: 0;
			color: #fff;
		}
		.s-ic svg { width: 18px; height: 18px; stroke-width: 2; }
		.s-ic.brand   { background: #5B5BD6; }
		.s-ic.emerald { background: #10B981; }
		.s-ic.sky     { background: #0EA5E9; }
		.s-ic.amber   { background: #F59E0B; }
		.s-ic.violet  { background: #8B5CF6; }
		.s-ic.gray    { background: #3F3F46; }

		/* Inputs — larger, modern */
		.ksef-app input[type="text"],
		.ksef-app input[type="number"],
		.ksef-app input[type="email"],
		.ksef-app input[type="date"],
		.ksef-app select,
		.ksef-app textarea {
			border-radius: 10px;
			border: 1px solid #E7E5E1;
			padding: 10px 13px;
			font-size: 13.5px;
			background: #fff;
			color: var(--text);
			transition: border-color .15s, box-shadow .15s;
		}
		.ksef-app input:focus, .ksef-app select:focus, .ksef-app textarea:focus {
			outline: none; border-color: #5B5BD6;
			box-shadow: 0 0 0 3px rgba(91,91,214,0.12);
		}
		.ksef-field > label {
			font-size: 13px; font-weight: 500; color: var(--text);
			margin-bottom: 6px;
		}
		.ksef-field .req { color: #DC2626; }
		.ksef-hint, .ksef-field small { font-size: 11.5px; color: #98968F; }
		.ksef-field code {
			background: #F7F5F0; border: 1px solid #E7E5E1; border-radius: 4px;
			padding: 1px 6px; font-size: 11px;
		}

		/* Contractor picker */
		.ksef-contractor-picker { display: flex; gap: 8px; position: relative; }
		.ksef-contractor-picker input { flex: 1; }

		/* Brand-soft button (light indigo, used for + Nowy / + Dodaj konto / Z produktów Woo) */
		.ksef-btn-brand-soft {
			background: #EEF0FF; color: #4A4AC9; border-color: #DFE2FF; font-weight: 500;
		}
		.ksef-btn-brand-soft:hover { background: #DFE2FF; color: #3D3DB8; border-color: #C7CFFF; }

		.ksef-btn-primary {
			background: #5B5BD6 !important; border-color: #5B5BD6 !important; color: #fff !important;
			box-shadow: 0 1px 2px rgba(91,91,214,0.25);
		}
		.ksef-btn-primary:hover {
			background: #4A4AC9 !important; border-color: #4A4AC9 !important;
		}

		/* Segmented */
		.ksef-segmented {
			display: inline-flex; gap: 0; background: #F7F5F0;
			border-radius: 10px; padding: 3px; border: 1px solid #E7E5E1;
		}
		.ksef-segmented input { display: none; }
		.ksef-segmented label {
			padding: 6px 14px; font-size: 12.5px; font-weight: 500; color: var(--text-2);
			border-radius: 8px; cursor: pointer; transition: all .15s;
		}
		.ksef-segmented input:checked + label {
			background: #fff; color: var(--text); box-shadow: 0 1px 2px rgba(10,10,11,.08);
			font-weight: 600;
		}

		/* Status pill (gold for Szkic / Plan Free) */
		.ksef-app .status-pill {
			display: inline-flex; align-items: center; gap: 6px;
			padding: 4px 12px 4px 10px; border-radius: 99px;
			font-size: 12px; font-weight: 500;
			background: #fff; border: 1px solid #FED7AA;
			color: #9A3412;
		}
		.ksef-app .status-pill::before {
			content: ""; width: 7px; height: 7px; border-radius: 50%; background: #F59E0B;
		}
		.ksef-app .status-pill.draft { background: #FFFBEB; border-color: #FCD34D; color: #78350F; }
		.ksef-app .status-pill.sent  { background: #EFF6FF; border-color: #BFDBFE; color: #1E40AF; }
		.ksef-app .status-pill.sent::before { background: #3B82F6; }
		.ksef-app .status-pill.paid  { background: #ECFDF5; border-color: #A7F3D0; color: #065F46; }
		.ksef-app .status-pill.paid::before { background: #10B981; }

		/* Quota banner — orange card */
		.ksef-quota-banner {
			display: flex; gap: 14px; align-items: center;
			background: #FFFBEB; border: 1px solid #FCD34D;
			border-radius: 14px; padding: 14px 18px; margin-bottom: 4px;
		}
		.ksef-quota-banner.is-exceeded { background: #FFFBEB; border-color: #F59E0B; }
		.qb-icon {
			width: 40px; height: 40px; border-radius: 10px;
			background: #F59E0B; color: #fff;
			display: grid; place-items: center; flex-shrink: 0;
		}
		.qb-icon svg { width: 20px; height: 20px; stroke-width: 2; }
		.qb-text { flex: 1; min-width: 0; }
		.qb-text b { font-size: 14px; color: #78350F; display: block; }
		.qb-text p { margin: 4px 0 0; font-size: 12.5px; color: #92400E; line-height: 1.45; }
		.qb-actions { display: flex; gap: 8px; flex-shrink: 0; }
		.qb-btn {
			display: inline-flex; align-items: center; padding: 9px 16px;
			border-radius: 10px; font-size: 13px; font-weight: 500;
			text-decoration: none; cursor: pointer; transition: all .15s; border: 1px solid transparent;
		}
		.qb-btn-ghost { background: #fff; border-color: #E7E5E1; color: var(--text); }
		.qb-btn-ghost:hover { background: #F7F5F0; }
		.qb-btn-upgrade { background: #10B981; color: #fff; }
		.qb-btn-upgrade:hover { background: #059669; color: #fff; }

		/* Lokal select — fancy chip on right */
		#credential_id { padding-left: 38px; background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2398968F' stroke-width='2'><path d='M3 9.5 12 3l9 6.5V20a1 1 0 0 1-1 1h-5v-7h-6v7H4a1 1 0 0 1-1-1z'/></svg>"); background-repeat: no-repeat; background-position: 12px center; background-size: 16px; }

		/* Items table — softer borders */
		.ksef-items-table { border-radius: 10px; border: 1px solid #E7E5E1; }
		.ksef-items-table thead th { background: #F7F5F0; color: #98968F; font-weight: 600; font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em; padding: 11px 10px; }
		.ksef-items-table tbody td { padding: 10px; }
		.ksef-items-table tfoot th { background: #FAFAF7; }

		/* Items summary table — clean */
		.ksef-items-summary { margin-top: 14px; background: #FAFAF7; padding: 14px 18px; border-radius: 10px; }
		.ksef-items-summary table { width: 100%; }
		.ksef-items-summary tfoot th { color: var(--text); }

		/* Markers grid — 2 col with chip codes */
		.ksef-markers-grid { gap: 2px; }
		.ksef-marker { padding: 9px 12px; }
		.ksef-marker input { accent-color: #5B5BD6; }
		.ksef-marker input:checked + .ksef-marker-text { color: var(--text); font-weight: 500; }
		.ksef-marker-code {
			background: #F7F5F0; padding: 2px 8px; border-radius: 4px;
			color: #98968F; font-family: 'JetBrains Mono', monospace;
		}
		.ksef-section-sub {
			text-transform: uppercase; letter-spacing: .06em; font-size: 11px;
			font-weight: 600; color: #98968F; margin: 24px 0 10px;
		}

		/* Toggle row (Kaucja / Adres dostawy) — checkbox + tytuł + hint */
		.ksef-card-toggle .ksef-toggle-row,
		.ksef-card .ksef-toggle-row {
			display: flex; align-items: center; gap: 12px; cursor: pointer;
			margin: 0;
		}
		.ksef-toggle-row input[type="checkbox"] { display: none; }
		.ksef-toggle-row .ksef-check {
			width: 22px; height: 22px; border-radius: 6px;
			border: 1.5px solid #E7E5E1; background: #fff;
			display: inline-grid; place-items: center; flex-shrink: 0;
			transition: all .15s;
		}
		.ksef-toggle-row input:checked + .ksef-check {
			background: #5B5BD6; border-color: #5B5BD6;
		}
		.ksef-toggle-row input:checked + .ksef-check::after {
			content: ""; width: 12px; height: 12px;
			background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3'><polyline points='20 6 9 17 4 12'/></svg>") center/contain no-repeat;
		}
		.ksef-toggle-row .t strong { font-size: 14px; font-weight: 600; color: var(--text); display: block; }
		.ksef-toggle-row .t small { font-size: 12.5px; color: #98968F; }

		/* Input with currency suffix (PLN) */
		.ksef-input-with-suffix { position: relative; }
		.ksef-input-with-suffix input { padding-right: 50px !important; }
		.ksef-input-with-suffix .suffix {
			position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
			background: #F7F5F0; border: 1px solid #E7E5E1; border-radius: 4px;
			padding: 1px 7px; font-size: 11px; color: #98968F; font-weight: 500;
		}

		/* Empty state inside card */
		.ksef-empty-state {
			border: 1px dashed #E7E5E1; border-radius: 12px;
			padding: 32px 16px; text-align: center;
			background: #FAFAF7;
		}
		.ksef-empty-state .ic {
			width: 44px; height: 44px; border-radius: 50%;
			background: #fff; border: 1px solid #E7E5E1;
			display: grid; place-items: center; margin: 0 auto 10px;
			color: #98968F;
		}
		.ksef-empty-state .ic svg { width: 20px; height: 20px; }
		.ksef-empty-state b { display: block; font-size: 14px; color: var(--text); font-weight: 600; margin-bottom: 4px; }
		.ksef-empty-state p { margin: 0; font-size: 13px; color: #98968F; max-width: 480px; margin: 0 auto; }

		/* Sticky footer */
		.ksef-sticky-footer {
			position: sticky; bottom: 0;
			background: #fff; border: 1px solid #E7E5E1; border-radius: 14px;
			padding: 14px 22px;
			display: flex; align-items: center; gap: 14px;
			margin-top: 8px;
			box-shadow: 0 -4px 12px rgba(10,10,11,0.04);
			z-index: 50;
		}
		.ksf-status { display: flex; align-items: center; gap: 8px; color: #98968F; font-size: 12.5px; flex: 1; min-width: 0; }
		.ksf-status svg { color: #98968F; }
		.ksf-actions { display: flex; gap: 8px; align-items: center; flex-shrink: 0; }

		/* Hero pills follow the page-title — gold/orange for Szkic + Plan Free */
		.ksef-modern-wrap .page-title .status-pill {
			font-size: 12px;
			padding: 4px 12px 4px 10px;
		}
		<?php Modern_Shell::inline_style( 'ksef-manual-invoice-b', ob_get_clean() ); ?>

		<?php $this->render_inline_scripts( $nonce, $ajax ); ?>
		<?php
	}

	private function render_inline_scripts( string $nonce, string $ajax ): void {
		?>
		<?php ob_start(); ?>
		(function(){
			const AJAX = <?php echo wp_json_encode( $ajax ); ?>;
			const NONCE = <?php echo wp_json_encode( $nonce ); ?>;
			const tbody = document.getElementById('ksef-items-body');
			// Daty z atrybutem max (wystawienie/sprzedaż/wpłaty częściowe): ręcznie wpisana
			// data przyszła jest natychmiast cofana do „dziś" (max) + komunikat przy polu.
			// Delegacja → działa też dla dynamicznie dodanych pól wpłat częściowych.
			['change','blur'].forEach(evt => document.addEventListener(evt, function(ev){
				const el = ev.target;
				if (el && el.matches && el.matches('input[type="date"][max]') && el.value && el.max && el.value > el.max) {
					el.value = el.max;
					let note = el._futureNote;
					if (!note || !note.parentNode) {
						note = document.createElement('div');
						note.className = 'ksef-date-future-note';
						note.style.cssText = 'color:#b91c1c;font-size:12px;margin-top:3px;';
						el.insertAdjacentElement('afterend', note);
						el._futureNote = note;
					}
					note.textContent = 'Data nie może być datą przyszłą — ustawiono na dziś.';
					clearTimeout(el._futureNoteT);
					el._futureNoteT = setTimeout(function(){ if (note.parentNode) note.parentNode.removeChild(note); el._futureNote = null; }, 4000);
				}
			}, true));
			const totalNet = document.getElementById('ksef-total-net');
			const totalVat = document.getElementById('ksef-total-vat');
			const totalGross = document.getElementById('ksef-total-gross');
			const vatSummary = document.getElementById('ksef-vat-summary');
			const currInput = document.getElementById('currency');
			const currDisplay = document.getElementById('curr-display');

			function esc(s){ return String(s ?? '').replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c])); }

			currInput.addEventListener('change', () => { currDisplay.textContent = currInput.value; });

			// === Items table ===
			function addItem(preset){
				preset = preset || {};
				const idx = tbody.children.length;
				const tr = document.createElement('tr');
				tr.innerHTML = `
					<td class="item-lp">${idx + 1}</td>
					<td><input type="text" name="items[${idx}][description]" required placeholder="wpisz nazwę produktu" value="${esc(preset.name || '')}"></td>
					<td><input type="text" name="items[${idx}][pkwiu]" value="${esc(preset.pkwiu || '')}" class="item-pkwiu"></td>
					<td><input type="text" name="items[${idx}][unit]" value="${esc(preset.unit || 'szt.')}" class="item-unit"></td>
					<td><input type="number" step="any" min="0" name="items[${idx}][quantity]" value="${preset.quantity || 1}" class="item-qty"></td>
					<td><input type="number" step="0.01" min="0" name="items[${idx}][unit_price_net]" value="${(Number(preset.unit_price) || 0).toFixed(2)}" class="item-price"></td>
					<td><input type="number" step="0.01" min="0" max="100" name="items[${idx}][discount_pct]" value="0" class="item-discount"></td>
					<td>
						<select name="items[${idx}][vat_rate]" class="item-vat">
							<option value="23" ${(preset.vat_rate ?? 23) == 23 ? 'selected' : ''}>23%</option>
							<option value="8" ${preset.vat_rate == 8 ? 'selected' : ''}>8%</option>
							<option value="5" ${preset.vat_rate == 5 ? 'selected' : ''}>5%</option>
							<option value="0" ${preset.vat_rate == 0 ? 'selected' : ''}>0%</option>
							<option value="zw">zw.</option>
							<option value="np">np.</option>
							<option value="oo">o.o.</option>
						</select>
					</td>
					<td class="item-net" style="text-align:right;">0.00</td>
					<td class="item-gross" style="text-align:right;">0.00</td>
					<td>
						<select name="items[${idx}][gtu]" class="item-gtu">
							<option value="">brak</option>
							${['GTU_01','GTU_02','GTU_03','GTU_04','GTU_05','GTU_06','GTU_07','GTU_08','GTU_09','GTU_10','GTU_11','GTU_12','GTU_13'].map(g => `<option value="${g}" ${preset.gtu === g ? 'selected' : ''}>${g}</option>`).join('')}
						</select>
					</td>
					<td><button type="button" class="button button-small ksef-remove-item" title="Usuń wiersz">🗑</button></td>
				`;
				tbody.appendChild(tr);
				tr.querySelectorAll('.item-qty, .item-price, .item-discount, .item-vat').forEach(el => el.addEventListener('input', recalc));
				tr.querySelector('.ksef-remove-item').addEventListener('click', () => { tr.remove(); renumber(); recalc(); });
				recalc();
			}
			// Wypełnia istniejący pusty wiersz wartościami presetu (zamiast dodawać kolejny).
			function fillRow(tr, preset){
				const set = (sel, val) => { const el = tr.querySelector(sel); if (el != null) el.value = val; };
				set('input[name$="[description]"]', preset.name || '');
				set('input[name$="[pkwiu]"]', preset.pkwiu || '');
				set('input[name$="[unit]"]', preset.unit || 'szt.');
				set('.item-qty', preset.quantity || 1);
				set('.item-price', (Number(preset.unit_price) || 0).toFixed(2));
				const vat = tr.querySelector('.item-vat'); if (vat && preset.vat_rate != null) vat.value = String(preset.vat_rate);
				const gtu = tr.querySelector('select[name$="[gtu]"]'); if (gtu && preset.gtu) gtu.value = preset.gtu;
			}
			// Dodaje pozycję, ale jeśli istnieje pusty wiersz (pusta nazwa) — wypełnia go zamiast dublować.
			function addOrFillItem(preset){
				const rows = Array.from(tbody.querySelectorAll('tr'));
				const empty = rows.find(tr => !((tr.querySelector('input[name$="[description]"]')?.value || '').trim()));
				if (empty) { fillRow(empty, preset); recalc(); }
				else { addItem(preset); }
			}
			function renumber(){ let i = 1; tbody.querySelectorAll('tr').forEach(tr => tr.querySelector('.item-lp').textContent = i++); }
			function recalc(){
				const isGrossMode = document.querySelector('input[name=price_mode]:checked')?.value === 'gross';
				const buckets = {};
				let totalN = 0, totalG = 0;
				tbody.querySelectorAll('tr').forEach(tr => {
					const q = parseFloat(tr.querySelector('.item-qty').value) || 0;
					const p = parseFloat(tr.querySelector('.item-price').value) || 0;
					const d = parseFloat(tr.querySelector('.item-discount').value) || 0;
					const vRaw = tr.querySelector('.item-vat').value;
					const v = isNaN(parseFloat(vRaw)) ? 0 : parseFloat(vRaw);
					const isStr = isNaN(parseFloat(vRaw));
					// VAT liczony w GROSZACH (half-up) — inaczej float gubi grosz (19.90*1.05=20.8949… → 20.89).
					let net, gross, vat;
					if (isGrossMode) {
						const grossG = Math.round(q * p * (1 - d/100) * 100);
						const baseG = isStr ? grossG : Math.round(grossG / (1 + v/100));
						net = baseG / 100; gross = grossG / 100; vat = (grossG - baseG) / 100;
					} else {
						const baseG = Math.round(q * p * (1 - d/100) * 100);
						const vatG = isStr ? 0 : Math.round(baseG * v / 100);
						net = baseG / 100; vat = vatG / 100; gross = (baseG + vatG) / 100;
					}
					tr.querySelector('.item-net').textContent = net.toFixed(2);
					tr.querySelector('.item-gross').textContent = gross.toFixed(2);
					totalN += net;
					totalG += gross;
					const k = isStr ? vRaw : String(Math.round(v));
					if (!buckets[k]) buckets[k] = { rate: isStr ? vRaw : v, net: 0, vat: 0 };
					buckets[k].net += net;
					buckets[k].vat += vat;
				});
				totalNet.textContent = totalN.toFixed(2);
				totalGross.textContent = totalG.toFixed(2);
				totalVat.textContent = (totalG - totalN).toFixed(2);
				vatSummary.innerHTML = Object.values(buckets).map(b => {
					const label = typeof b.rate === 'number' ? (b.rate + '%') : b.rate;
					return `<tr><td>${esc(label)}</td><td>${b.net.toFixed(2)}</td><td>${b.vat.toFixed(2)}</td><td>${(b.net + b.vat).toFixed(2)}</td></tr>`;
				}).join('') || '<tr><td colspan="4" style="color:#999;">brak pozycji</td></tr>';
				syncCompliance(totalG);
				refreshAutoNote();
			}

			// Reguły zgodności VAT odzwierciedlone w UI:
			//  • kwota brutto > 15 000 zł (PLN) → auto-zaznacz „Podzielona płatność" (P_18A)
			//  • pozycja ze stawką „zw" → wymagaj podstawy prawnej zwolnienia (P_19)
			function refreshAutoNote(){
					const note = document.getElementById('ksef-auto-markers-note');
					if (!note) return;
					const list = note.querySelector('.amn-list');
					const auto = [];
					const p18a = document.querySelector('input[name="markers[P_18A]"]');
					if (p18a && p18a.checked && p18a.dataset.autoMpp === '1') auto.push('<b>P_18A</b> — podzielona płatność: kwota brutto przekracza 15 000 zł.');
					const hasZw = Array.from(tbody.querySelectorAll('.item-vat')).some(s => (s.value || '').toLowerCase() === 'zw');
					if (hasZw) auto.push('<b>P_19</b> — zwolnienie z VAT: pozycja ze stawką „zw" (uzupełnij podstawę prawną zwolnienia).');
					const p18 = document.querySelector('input[name="markers[P_18]"]');
					if (p18 && p18.checked && p18.dataset.autoOo === '1') auto.push('<b>P_18</b> — odwrotne obciążenie: pozycja ze stawką „oo".');
					if (auto.length && list){ list.innerHTML = auto.map(t => '<li style="margin:2px 0;">' + t + '</li>').join(''); note.style.display = ''; }
					else { note.style.display = 'none'; }
				}
				function syncCompliance(totalG){
				const p18a = document.querySelector('input[name="markers[P_18A]"]');
				const p19  = document.querySelector('input[name="markers[P_19]"]');
				const curr = (document.getElementById('currency')?.value || 'PLN').toUpperCase();
				// P_18A — auto przy > 15 000 zł (tylko PLN; dla walut obcych nie znamy kursu)
				if (p18a){
					if (curr === 'PLN' && totalG > 15000){
						if (!p18a.checked){ p18a.checked = true; }
						p18a.dataset.autoMpp = '1';
						const lbl = p18a.closest('.ksef-marker');
						if (lbl) lbl.title = 'Zaznaczone automatycznie: kwota brutto przekracza 15 000 zł (mechanizm podzielonej płatności).';
					} else if (p18a.dataset.autoMpp === '1'){
						// auto-odznacz tylko gdy wcześniej sami zaznaczyliśmy
						p18a.checked = false;
						p18a.dataset.autoMpp = '';
					}
				}
				// „zw" w pozycjach → włącz P_19 + pokaż podstawę prawną
				const hasZw = Array.from(tbody.querySelectorAll('.item-vat')).some(s => (s.value || '').toLowerCase() === 'zw');
				const zwRow = document.getElementById('row-zwolnienie');
				if (hasZw && p19 && !p19.checked){ p19.checked = true; }
				if (zwRow){ zwRow.style.display = ( (p19 && p19.checked) || hasZw ) ? '' : 'none'; }
					// „oo" (odwrotne obciążenie) w pozycjach → auto P_18
					const p18 = document.querySelector('input[name="markers[P_18]"]');
					const hasOO = Array.from(tbody.querySelectorAll('.item-vat')).some(s => (s.value || '').toLowerCase() === 'oo');
					if (p18){
						if (hasOO){
							if (!p18.checked){ p18.checked = true; }
							p18.dataset.autoOo = '1';
							const l18 = p18.closest('.ksef-marker');
							if (l18) l18.title = 'Zaznaczone automatycznie: pozycja ze stawką „odwrotne obciążenie".';
						} else if (p18.dataset.autoOo === '1'){
							p18.checked = false;
							p18.dataset.autoOo = '';
						}
					}
			}
			document.querySelectorAll('input[name=price_mode]').forEach(r => r.addEventListener('change', recalc));
			document.getElementById('ksef-add-item').addEventListener('click', () => addItem());
			addItem();

			// === Numer faktury — wybór schematu numeracji + Własny numer toggle ===
			const numInput = document.getElementById('invoice_number');
			const autoFlag = document.getElementById('auto_number');
			const schemeSel = document.getElementById('numbering_scheme_id');
			const schemeWrap = document.getElementById('numbering-scheme-wrap');
			function schemePreview(){
				if (!schemeSel) return '';
				const opt = schemeSel.options[schemeSel.selectedIndex];
				if (!opt) return '';
				const now = new Date();
				const Y = String(now.getFullYear()), y = Y.slice(2);
				const m = String(now.getMonth()+1).padStart(2,'0'), d = String(now.getDate()).padStart(2,'0');
				const pad = Math.max(1, Math.min(10, parseInt(opt.dataset.padding||'4',10)));
				let s = String(opt.dataset.template||'').replace(/\{Y\}/g,Y).replace(/\{y\}/g,y).replace(/\{m\}/g,m).replace(/\{d\}/g,d).replace(/\{prefix\}/g,opt.dataset.prefix||'');
				s = s.replace(/\{n:(\d+)\}/g,(_,n)=>String(1).padStart(parseInt(n,10),'0'));
				s = s.replace(/\{n\}/g,String(1).padStart(pad,'0'));
				return s;
			}
			if (schemeSel) schemeSel.addEventListener('change', function(){ if (!numInput.readOnly && autoFlag.value==='0') return; numInput.placeholder = schemePreview(); });
			document.getElementById('custom_number').addEventListener('change', function(){
				if (this.checked) {
					numInput.readOnly = false; numInput.focus(); autoFlag.value = '0';
					if (schemeWrap) schemeWrap.style.display = 'none';
				} else {
					numInput.readOnly = true; numInput.value = ''; autoFlag.value = '1';
					if (schemeWrap) schemeWrap.style.display = '';
					numInput.placeholder = schemePreview() || numInput.placeholder;
				}
			});

			// === Szczegóły płatności: sposób zapłaty (całość) / wpłaty częściowe ===
			(function(){
				const detail = document.getElementById('pay-detail');
				if (!detail) return;
				const paidBox = document.getElementById('pay-paid');
				const partialBox = document.getElementById('pay-partial');
				const partialRows = document.getElementById('partial-rows');
				const issueEl = document.getElementById('issue_date');
				const methodOpts = '<option value="przelew">Przelew</option><option value="gotowka">Gotówka</option><option value="kompensata">Kompensata</option><option value="online">Online</option><option value="inne">Inne</option>';
				let pi = 0;
				function addPartial(){
					const i = pi++;
					const div = document.createElement('div');
					div.className = 'partial-row';
					div.style.cssText = 'display:grid;grid-template-columns:1fr 1fr 1fr auto;gap:6px;margin-bottom:6px;';
					div.innerHTML = '<input type="number" step="0.01" min="0" name="partial_payments['+i+'][amount]" placeholder="Kwota" style="width:100%;">'
						+ '<input type="date" name="partial_payments['+i+'][date]" max="'+(new Date().toISOString().slice(0,10))+'" value="'+(issueEl ? issueEl.value : '')+'" style="width:100%;">'
						+ '<select name="partial_payments['+i+'][method]" style="width:100%;">'+methodOpts+'</select>'
						+ '<button type="button" class="ksef-btn ksef-btn-ghost rm-partial" title="Usuń">✕</button>';
					div.querySelector('.rm-partial').addEventListener('click', () => div.remove());
					partialRows.appendChild(div);
				}
				document.getElementById('add-partial')?.addEventListener('click', addPartial);
				function sync(){
					const v = document.querySelector('input[name="initial_payment_status"]:checked')?.value || 'unpaid';
					if (v === 'paid') { detail.style.display = ''; paidBox.style.display = ''; partialBox.style.display = 'none'; }
					else if (v === 'partial') { detail.style.display = ''; paidBox.style.display = 'none'; partialBox.style.display = ''; if (!partialRows.children.length) addPartial(); }
					else { detail.style.display = 'none'; }
				}
				document.querySelectorAll('input[name="initial_payment_status"]').forEach(r => r.addEventListener('change', sync));
				sync();
			})();

			// === Faktura za okres toggle ===
			document.getElementById('marker_fa_za_okres').addEventListener('change', function(){
				document.getElementById('row-fa-za-okres').style.display = this.checked ? '' : 'none';
			});
			// === Zwolnienie z VAT (P_19) toggle + reakcja na zmianę waluty ===
			document.querySelector('input[name="markers[P_19]"]')?.addEventListener('change', function(){
				const zwRow = document.getElementById('row-zwolnienie');
				if (zwRow) zwRow.style.display = this.checked ? '' : 'none';
			});
			// === Procedura marży (PMarzy) toggle → pokaż wybór rodzaju ===
			document.querySelector('input[name="markers[PMarzy]"]')?.addEventListener('change', function(){
				const r = document.getElementById('row-pmarzy');
				if (r) r.style.display = this.checked ? '' : 'none';
				if (!this.checked) { const s = document.getElementById('pmarzy_kind'); if (s) s.value = ''; }
			});
			// === WDT nowych środków transportu (P_22) toggle → pokaż dane pojazdu ===
			document.querySelector('input[name="markers[P_22]"]')?.addEventListener('change', function(){
				const r = document.getElementById('row-p22');
				if (r) r.style.display = this.checked ? '' : 'none';
			});
			document.getElementById('currency')?.addEventListener('change', recalc);

			// === Kurs wymiany (waluta obca) — pokaż pole + pobierz kurs NBP (tab. A) ===
			(function(){
				const curSel = document.getElementById('currency');
				const fxField = document.getElementById('fx-rate-field');
				const fxRate = document.getElementById('exchange_rate');
				const fxDate = document.getElementById('exchange_rate_date');
				const fxHint = document.getElementById('fx-rate-hint');
				const fetchBtn = document.getElementById('fetch-nbp-rate');
				if (!curSel || !fxField) return;
				const baseHint = fxHint ? fxHint.textContent : '';
				function toggleFx(){
					const foreign = (curSel.value || 'PLN').toUpperCase() !== 'PLN';
					fxField.style.display = foreign ? '' : 'none';
					if (!foreign) { if (fxRate) fxRate.value=''; if (fxDate) fxDate.value=''; if (fxHint) fxHint.textContent = baseHint; }
				}
				curSel.addEventListener('change', toggleFx);
				toggleFx();
				async function fetchNbp(){
					const cur = (curSel.value||'PLN').toUpperCase();
					if (cur === 'PLN') return;
					const saleDate = (document.getElementById('sale_date')?.value) || (document.getElementById('issue_date')?.value) || '';
					if (fxHint) fxHint.textContent = 'Pobieram kurs NBP…';
					try{
						const fd = new FormData();
						fd.append('action','ksef_fetch_nbp_rate'); fd.append('_ajax_nonce', NONCE);
						fd.append('currency', cur); fd.append('date', saleDate);
						const r = await fetch(AJAX, {method:'POST', body:fd, credentials:'same-origin'});
						const j = await r.json();
						if (j && j.success && j.data && j.data.rate) {
							if (fxRate) fxRate.value = String(j.data.rate).replace('.', ',');
							if (fxDate) fxDate.value = j.data.date || '';
							if (fxHint) fxHint.textContent = 'Kurs NBP ' + cur + ': ' + j.data.rate + ' PLN (tab. ' + (j.data.table||'A') + ' z ' + (j.data.date||'') + ').';
							if (typeof recalc === 'function') recalc();
						} else {
							if (fxHint) fxHint.textContent = (j && j.data && j.data.message) ? j.data.message : 'Nie udało się pobrać kursu NBP — wpisz ręcznie.';
						}
					}catch(e){ if (fxHint) fxHint.textContent = 'Błąd pobierania kursu NBP — wpisz ręcznie.'; }
				}
				if (fetchBtn) fetchBtn.addEventListener('click', fetchNbp);
			})();
			// === Zwolnienie z VAT — druga lista zależna od rodzaju podstawy (P_19A/B/C) ===
			const EXEMPTION_PRESETS = {
				// A — przepis ustawy o VAT (krajowa podstawa zwolnienia)
				A: [
					['art. 113 ust. 1 i 9 ustawy o VAT', 'Zwolnienie podmiotowe — art. 113 ust. 1 i 9 (limit 200 000 zł)'],
					['art. 43 ust. 1 pkt 2 ustawy o VAT', 'pkt 2 — towary używane (cele zwolnione)'],
					['art. 43 ust. 1 pkt 7 ustawy o VAT', 'pkt 7 — transakcje walutowe'],
					['art. 43 ust. 1 pkt 9 ustawy o VAT', 'pkt 9 — tereny niezabudowane (inne niż budowlane)'],
					['art. 43 ust. 1 pkt 10 ustawy o VAT', 'pkt 10 — dostawa budynków, budowli'],
					['art. 43 ust. 1 pkt 10a ustawy o VAT', 'pkt 10a — dostawa budynków, budowli'],
					['art. 43 ust. 1 pkt 18 ustawy o VAT', 'pkt 18 — usługi opieki medycznej'],
					['art. 43 ust. 1 pkt 19 ustawy o VAT', 'pkt 19 — usługi medyczne (zawody)'],
					['art. 43 ust. 1 pkt 21 ustawy o VAT', 'pkt 21 — niezależne grupy osób'],
					['art. 43 ust. 1 pkt 26 ustawy o VAT', 'pkt 26 — usługi edukacyjne (system oświaty)'],
					['art. 43 ust. 1 pkt 27 ustawy o VAT', 'pkt 27 — prywatne nauczanie'],
					['art. 43 ust. 1 pkt 28 ustawy o VAT', 'pkt 28 — nauczanie języków obcych'],
					['art. 43 ust. 1 pkt 29 ustawy o VAT', 'pkt 29 — kształcenie zawodowe'],
					['art. 43 ust. 1 pkt 33 ustawy o VAT', 'pkt 33 — usługi kulturalne'],
					['art. 43 ust. 1 pkt 36 ustawy o VAT', 'pkt 36 — wynajem nieruchomości mieszkalnych'],
					['art. 43 ust. 1 pkt 37 ustawy o VAT', 'pkt 37 — usługi ubezpieczeniowe'],
					['art. 43 ust. 1 pkt 38 ustawy o VAT', 'pkt 38 — udzielanie kredytów i pożyczek'],
					['art. 43 ust. 1 pkt 39 ustawy o VAT', 'pkt 39 — poręczenia i gwarancje'],
					['art. 43 ust. 1 pkt 40 ustawy o VAT', 'pkt 40 — depozyty, rachunki, płatności'],
					['art. 43 ust. 1 pkt 41 ustawy o VAT', 'pkt 41 — instrumenty finansowe'],
					['art. 82 ust. 3 ustawy o VAT', 'art. 82 ust. 3 — zwolnienie z rozporządzenia'],
				],
				// B — przepis dyrektywy 2006/112/WE
				B: [
					['art. 132 dyrektywy 2006/112/WE', 'art. 132 — czynności w interesie publicznym'],
					['art. 135 dyrektywy 2006/112/WE', 'art. 135 — usługi finansowe i ubezpieczeniowe'],
					['art. 136 dyrektywy 2006/112/WE', 'art. 136 — towary na cele zwolnione'],
					['art. 138 dyrektywy 2006/112/WE', 'art. 138 — wewnątrzwspólnotowa dostawa towarów'],
					['art. 143 dyrektywy 2006/112/WE', 'art. 143 — zwolnienia w imporcie'],
					['art. 146 dyrektywy 2006/112/WE', 'art. 146 — eksport towarów'],
					['art. 148 dyrektywy 2006/112/WE', 'art. 148 — transport morski i lotniczy'],
					['art. 151 dyrektywy 2006/112/WE', 'art. 151 — misje dyplomatyczne, organizacje międzynarodowe'],
				],
				// C — inna podstawa prawna (rozporządzenie / przepis szczególny)
				C: [
					['§ rozporządzenia Ministra Finansów w sprawie zwolnień od podatku VAT', 'Rozporządzenie MF ws. zwolnień (uzupełnij §)'],
					['umowa międzynarodowa / przepis szczególny', 'Umowa międzynarodowa / przepis szczególny'],
				],
			};
			function fillExemptionPresets(){
				const k = (document.getElementById('exemption_kind')?.value || 'A').toUpperCase();
				const sel = document.getElementById('exemption_preset');
				if (!sel) return;
				const list = EXEMPTION_PRESETS[k] || EXEMPTION_PRESETS.A;
				let html = '<option value="">— wybierz, aby wstawić —</option>';
				list.forEach(function(o){
					html += '<option value="' + o[0].replace(/"/g,'&quot;') + '">' + o[1].replace(/&/g,'&amp;').replace(/</g,'&lt;') + '</option>';
				});
				sel.innerHTML = html;
			}
			document.getElementById('exemption_kind')?.addEventListener('change', fillExemptionPresets);
			fillExemptionPresets();
			// Preset podstawy zwolnienia → wstaw do pola tekstowego
			document.getElementById('exemption_preset')?.addEventListener('change', function(){
				if (this.value) { const b = document.getElementById('exemption_basis'); if (b) b.value = this.value; }
			});
			// === Delivery toggle ===
			document.getElementById('toggle_delivery_addr').addEventListener('change', function(){
				document.getElementById('delivery-addr-fields').style.display = this.checked ? '' : 'none';
			});
			// === Deposit toggle ===
			document.getElementById('deposit_toggle').addEventListener('change', function(){
				document.getElementById('deposit-fields').style.display = this.checked ? '' : 'none';
			});

			// === Contractor picker ===
			const contractorSearch = document.getElementById('contractor_search');
			const contractorSugg = document.getElementById('contractor-suggestions');
			const contractorSum = document.getElementById('contractor-summary');
			let contractorTimer;
			contractorSearch.addEventListener('input', function(){
				clearTimeout(contractorTimer);
				const q = this.value.trim();
				if (q.length < 2) { contractorSugg.classList.remove('open'); return; }
				contractorTimer = setTimeout(async () => {
					const url = `${AJAX}?action=ksef_search_contractors&_ajax_nonce=${NONCE}&q=${encodeURIComponent(q)}`;
					try {
						const r = await fetch(url, { credentials: 'same-origin' });
						const j = await r.json();
						if (j.success) {
							const items = j.data.items;
							contractorSugg.innerHTML = items.length === 0
								? '<div class="ksef-suggestion" style="color:#999;">brak — kliknij "Nowy" by dodać</div>'
								: items.map(c => `<div class="ksef-suggestion" data-id="${c.id}"><strong>${esc(c.contractor_name)}</strong> ${c.contractor_nip ? '· NIP ' + esc(c.contractor_nip) : ''}<br><small>${esc((c.city || '') + ' ' + (c.street || ''))}</small></div>`).join('');
							contractorSugg.classList.add('open');
							contractorSugg.querySelectorAll('.ksef-suggestion[data-id]').forEach(el => {
								el.addEventListener('click', () => pickContractor(items.find(c => c.id == el.dataset.id)));
							});
						}
					} catch(e) { console.error(e); }
				}, 250);
			});
			document.addEventListener('click', e => {
				if (!contractorSugg.contains(e.target) && e.target !== contractorSearch) contractorSugg.classList.remove('open');
			});
			function pickContractor(c){
				document.getElementById('contractor_id').value = c.id;
				document.getElementById('buyer_type').value = c.buyer_type || (c.contractor_nip ? 'pl_firm' : 'b2c');
				contractorSearch.value = c.contractor_name;
				contractorSugg.classList.remove('open');
				const parts = [
					c.contractor_nip ? 'NIP: ' + c.contractor_nip : '',
					[c.street, c.street_number].filter(Boolean).join(' '),
					[c.postal_code, c.city].filter(Boolean).join(' '),
					c.country_code || '',
				].filter(Boolean);
				contractorSum.innerHTML = `<strong>${esc(c.contractor_name)}</strong><br>${esc(parts.join(' · '))}<br><a href="#" id="contractor-clear">× usuń wybór</a>`;
				contractorSum.classList.add('show');
				document.getElementById('contractor-clear').addEventListener('click', e => {
					e.preventDefault();
					document.getElementById('contractor_id').value = '';
					document.getElementById('buyer_type').value = 'b2c';
					contractorSearch.value = '';
					contractorSum.classList.remove('show');
				});
				// Hidden buyer_* fields for backend
				ensureBuyerHidden('buyer_name', c.contractor_name || '');
				ensureBuyerHidden('buyer_nip', c.contractor_nip || '');
				ensureBuyerHidden('buyer_country', c.country_code || 'PL');
				ensureBuyerHidden('buyer_street', [c.street, c.street_number].filter(Boolean).join(' '));
				ensureBuyerHidden('buyer_postal', c.postal_code || '');
				ensureBuyerHidden('buyer_city', c.city || '');
				ensureBuyerHidden('buyer_country_ue', c.country_code || '');
				ensureBuyerHidden('buyer_vat_ue', c.vat_ue || '');
				ensureBuyerHidden('buyer_country_code', c.country_code || '');
				ensureBuyerHidden('buyer_nr_id', c.nr_id || '');
			}
			function ensureBuyerHidden(name, value){
				let el = document.querySelector(`input[name="${name}"]`);
				if (!el) { el = document.createElement('input'); el.type = 'hidden'; el.name = name; document.getElementById('ksef-manual-invoice-form').appendChild(el); }
				el.value = value;
			}

			// === Contractor modal ===
			const cmModal = document.getElementById('contractor-modal');
			document.getElementById('contractor-new-btn').addEventListener('click', () => { openCMModal(); });
			function openCMModal(c){
				c = c || {};
				document.getElementById('cm_id').value = c.id || '';
				document.getElementById('cm_buyer_type').value = c.buyer_type || 'pl_firm';
				document.getElementById('cm_name').value = c.contractor_name || '';
				document.getElementById('cm_nip').value = c.contractor_nip || '';
				document.getElementById('cm_email').value = c.email || '';
				document.getElementById('cm_phone').value = c.phone || '';
				document.getElementById('cm_customer_no').value = c.customer_no || '';
				document.getElementById('cm_street').value = [c.street, c.street_number].filter(Boolean).join(' ');
				document.getElementById('cm_postal').value = c.postal_code || '';
				document.getElementById('cm_city').value = c.city || '';
				document.getElementById('cm_country').value = c.country_code || 'PL';
				document.getElementById('cm_vat_ue').value = c.vat_ue || '';
				document.getElementById('cm_nr_id').value = c.nr_id || '';
				cmModal.style.display = 'flex';
				toggleCMRows();
			}
			document.getElementById('cm_buyer_type').addEventListener('change', toggleCMRows);
			function toggleCMRows(){
				const t = document.getElementById('cm_buyer_type').value;
				document.getElementById('cm_ue_row').style.display = t === 'ue' ? '' : 'none';
				document.getElementById('cm_nrid_row').style.display = t === 'non_ue' ? '' : 'none';
			}
			document.getElementById('cm-cancel').addEventListener('click', () => cmModal.style.display = 'none');
			document.querySelectorAll('.ksef-modal-close').forEach(el => el.addEventListener('click', () => el.closest('.ksef-modal-overlay').style.display = 'none'));
			document.getElementById('cm-save').addEventListener('click', async () => {
				const fd = new FormData();
				fd.append('action', 'ksef_save_contractor');
				fd.append('_ajax_nonce', NONCE);
				fd.append('id', document.getElementById('cm_id').value);
				fd.append('contractor_name', document.getElementById('cm_name').value);
				fd.append('contractor_nip', document.getElementById('cm_nip').value);
				fd.append('buyer_type', document.getElementById('cm_buyer_type').value);
				fd.append('country_code', document.getElementById('cm_country').value);
				fd.append('vat_ue', document.getElementById('cm_vat_ue').value);
				fd.append('nr_id', document.getElementById('cm_nr_id').value);
				fd.append('email', document.getElementById('cm_email').value);
				fd.append('phone', document.getElementById('cm_phone').value);
				fd.append('customer_no', document.getElementById('cm_customer_no').value);
				const fullStreet = document.getElementById('cm_street').value;
				const lastSpace = fullStreet.lastIndexOf(' ');
				if (lastSpace > 0 && /\d/.test(fullStreet.substring(lastSpace))) {
					fd.append('street', fullStreet.substring(0, lastSpace));
					fd.append('street_number', fullStreet.substring(lastSpace + 1));
				} else {
					fd.append('street', fullStreet);
				}
				fd.append('postal_code', document.getElementById('cm_postal').value);
				fd.append('city', document.getElementById('cm_city').value);
				try {
					const r = await fetch(AJAX, { method: 'POST', body: fd, credentials: 'same-origin' });
					const j = await r.json();
					if (j.success) { cmModal.style.display = 'none'; pickContractor(j.data); }
					else alert('Błąd: ' + (j.data?.message || 'nieznany'));
				} catch(e) { alert('Network: ' + e); }
			});

			// === WC products modal ===
			const wcModal = document.getElementById('wc-modal');
			const wcSearch = document.getElementById('wc-search');
			const wcList = document.getElementById('wc-products-list');
			let wcTimer;
			document.getElementById('wc-products-btn').addEventListener('click', () => { wcModal.style.display = 'flex'; wcSearch.focus(); wcLoad(''); });
			wcSearch.addEventListener('input', function(){
				clearTimeout(wcTimer);
				wcTimer = setTimeout(() => wcLoad(this.value.trim()), 250);
			});
			async function wcLoad(q){
				const url = `${AJAX}?action=ksef_search_wc_products&_ajax_nonce=${NONCE}&q=${encodeURIComponent(q)}`;
				wcList.innerHTML = '<p style="color:#999;padding:10px;">Ładowanie…</p>';
				try {
					const r = await fetch(url, { credentials: 'same-origin' });
					const j = await r.json();
					if (j.success) {
						const items = j.data.items;
						if (items.length === 0) {
							const isEmpty = !q;
							const adminProductsUrl = '<?php echo esc_url( admin_url( "edit.php?post_type=product" ) ); ?>';
							const newProductUrl = '<?php echo esc_url( admin_url( "post-new.php?post_type=product" ) ); ?>';
							wcList.innerHTML = isEmpty
								? '<div style="padding:20px;text-align:center;color:#666;">' +
									'<p><strong>🛒 Brak produktów w WooCommerce</strong></p>' +
									'<p style="margin-top:8px;font-size:13px;">Dodaj produkty do sklepu — automatycznie będą dostępne tutaj z ceną netto, stawką VAT i opcjonalnym PKWiU / GTU (meta pola <code>_pkwiu</code>, <code>_ksef_gtu</code>).</p>' +
									'<p style="margin-top:12px;"><a href="' + newProductUrl + '" target="_blank" class="button button-primary">+ Dodaj produkt do WC</a> &nbsp; ' +
									'<a href="' + adminProductsUrl + '" target="_blank" class="button">Lista produktów</a></p>' +
									'<p style="margin-top:12px;font-size:12px;color:#999;">Lub po prostu zamknij okno i wpisz pozycję ręcznie poniżej w tabeli.</p>' +
								  '</div>'
								: '<p style="color:#999;padding:10px;">Brak produktów dla zapytania <strong>"' + esc(q) + '"</strong>.</p>';
							return;
						}
						wcList.innerHTML = items.map(p => `<div class="wc-product-row" data-id="${p.id}"><div><div class="wc-product-name">${esc(p.name)}</div><div class="wc-product-meta">${esc(p.sku || '')} · ${p.unit_price.toFixed(2)} ${esc(currInput.value)} · VAT ${p.vat_rate}%</div></div><button type="button" class="button button-small">+ Dodaj</button></div>`).join('');
						wcList.querySelectorAll('.wc-product-row').forEach(row => {
							row.addEventListener('click', () => {
								const p = items.find(x => x.id == row.dataset.id);
								addOrFillItem({ name: p.name, pkwiu: p.pkwiu, unit: p.unit, quantity: 1, unit_price: p.unit_price, vat_rate: p.vat_rate, gtu: p.gtu });
								wcModal.style.display = 'none';
							});
						});
					} else {
						wcList.innerHTML = '<p style="color:#c00;padding:10px;">Błąd: ' + esc(j.data?.message || 'nieznany') + '</p>';
					}
				} catch(e) { wcList.innerHTML = '<p style="color:#c00;padding:10px;">Network: ' + esc(e.toString()) + '</p>'; }
			}

			// === Banks ===
			const banksList = document.getElementById('banks-list');
			const banksEmpty = document.getElementById('banks-empty');
			const bankAccId = document.getElementById('bank_account_id');
			document.getElementById('credential_id').addEventListener('change', loadBanks);
			loadBanks();
			const BANKS_EMPTY_HTML = '<div class="ksef-empty-state" id="banks-empty"><div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 10h18"/></svg></div><b>Brak rachunków bankowych</b><p>Dodaj pierwsze konto, na które klient ma przesłać płatność — pojawi się na fakturze.</p></div>';
			async function loadBanks(){
				const credId = document.getElementById('credential_id').value;
				if (!credId) { banksList.innerHTML = BANKS_EMPTY_HTML; return; }
				const url = `${AJAX}?action=ksef_list_bank_accounts&_ajax_nonce=${NONCE}&credential_id=${credId}`;
				try {
					const r = await fetch(url, { credentials: 'same-origin' });
					const j = await r.json();
					if (j.success) renderBanks(j.data.items);
				} catch(e) { console.error(e); }
			}
			let banksCache = [];
			function fmtIban(v){ return String(v || '').replace(/\s+/g,'').replace(/(.{4})/g,'$1 ').trim(); }
			function renderBanks(items){
				banksCache = items || [];
				if (items.length === 0) { banksList.innerHTML = BANKS_EMPTY_HTML; return; }
				const defId = items.find(b => b.is_default == 1)?.id || items[0].id;
				bankAccId.value = bankAccId.value || defId;
				banksList.innerHTML = items.map(b => {
					const sel = b.id == bankAccId.value;
					const meta = [];
					if (b.swift) meta.push(`SWIFT: <span class="bank-acc">${esc(b.swift)}</span>`);
					meta.push(`Waluta: ${esc(b.currency || 'PLN')}`);
					return `<label class="bank-row ${sel ? 'selected' : ''}">
						<span class="bank-info">
							<span class="bank-line1"><input type="radio" name="bank_acc_pick" value="${b.id}" ${sel ? 'checked' : ''}> <strong>${esc(b.bank_name || 'Rachunek')}</strong>${b.is_default == 1 ? ' <em class="bank-def">domyślny</em>' : ''}</span>
							<span class="bank-acc bank-iban">${esc(fmtIban(b.account_number))}</span>
							<span class="bank-meta">${meta.join(' · ')}</span>
						</span>
						<span class="bank-actions">
							<button type="button" class="button button-small edit-bank" data-id="${b.id}" title="Edytuj">✏️</button>
							<button type="button" class="button button-small del-bank" data-id="${b.id}" title="Usuń">🗑</button>
						</span></label>`;
				}).join('');
				banksList.querySelectorAll('input[name=bank_acc_pick]').forEach(r => r.addEventListener('change', e => { bankAccId.value = e.target.value; loadBanks(); }));
				banksList.querySelectorAll('.edit-bank').forEach(btn => btn.addEventListener('click', e => {
					e.preventDefault(); e.stopPropagation();
					const b = banksCache.find(x => x.id == btn.dataset.id);
					if (b) openBankModal(b);
				}));
				banksList.querySelectorAll('.del-bank').forEach(b => b.addEventListener('click', async e => {
					e.preventDefault(); e.stopPropagation();
					if (!confirm('Usunąć konto bankowe?')) return;
					const fd = new FormData(); fd.append('action', 'ksef_delete_bank_account'); fd.append('_ajax_nonce', NONCE); fd.append('id', b.dataset.id);
					await fetch(AJAX, { method: 'POST', body: fd, credentials: 'same-origin' });
					loadBanks();
				}));
			}
			const bankModal = document.getElementById('bank-modal');
			function openBankModal(b){
				document.getElementById('bk_id').value     = b ? (b.id || '') : '';
				document.getElementById('bk_account').value = b ? (b.account_number || '') : '';
				document.getElementById('bk_name').value    = b ? (b.bank_name || '') : '';
				document.getElementById('bk_swift').value   = b ? (b.swift || '') : '';
				document.getElementById('bk_currency').value = b && b.currency ? b.currency : 'PLN';
				document.getElementById('bk_default').checked = b ? (b.is_default == 1) : false;
				document.getElementById('bk-modal-title').textContent = b ? 'Edytuj rachunek bankowy' : 'Dodaj rachunek bankowy';
				document.getElementById('bk-save').textContent = b ? 'Zapisz zmiany' : 'Zapisz konto';
				bankModal.style.display = 'flex';
			}
			document.getElementById('add-bank-btn').addEventListener('click', () => {
				if (!document.getElementById('credential_id').value) { alert('Najpierw wybierz konto KSeF.'); return; }
				openBankModal(null);
			});
			document.getElementById('bk-cancel').addEventListener('click', () => bankModal.style.display = 'none');
			document.getElementById('bk-save').addEventListener('click', async () => {
				const fd = new FormData();
				fd.append('action', 'ksef_save_bank_account');
				fd.append('_ajax_nonce', NONCE);
				fd.append('credential_id', document.getElementById('credential_id').value);
				const editId = document.getElementById('bk_id').value;
				if (editId) fd.append('id', editId);
				fd.append('account_number', document.getElementById('bk_account').value);
				fd.append('bank_name', document.getElementById('bk_name').value);
				fd.append('swift', document.getElementById('bk_swift').value);
				fd.append('currency', document.getElementById('bk_currency').value);
				if (document.getElementById('bk_default').checked) fd.append('is_default', '1');
				const r = await fetch(AJAX, { method: 'POST', body: fd, credentials: 'same-origin' });
				const j = await r.json();
				if (j.success) {
					bankModal.style.display = 'none';
					['bk_id','bk_account','bk_name','bk_swift'].forEach(id => document.getElementById(id).value = '');
					document.getElementById('bk_default').checked = false;
					loadBanks();
				}
				else alert('Błąd: ' + (j.data?.message || 'nieznany'));
			});

			// === Presety „Dane dodatkowe" (zestawy danych sprzedawcy) ===
			const extraPick = document.getElementById('extra_preset_pick');
			let extraPresets = [];
			function applyExtraPreset(p){
				if (!p) return;
				const set = (name, v) => { const el = document.getElementsByName(name)[0]; if (el && v != null && v !== '') el.value = v; };
				set('seller_email', p.seller_email);
				set('seller_phone', p.seller_phone);
				set('issue_place', p.issue_place);
			}
			function renderExtraPresets(items, autoApplyDefault){
				extraPresets = items || [];
				const cur = extraPick.value;
				extraPick.innerHTML = '<option value="">— zapisany zestaw danych —</option>' +
					extraPresets.map(p => `<option value="${p.id}">${esc(p.name)}${p.is_default == 1 ? ' ★' : ''}</option>`).join('');
				if (cur) extraPick.value = cur;
				if (autoApplyDefault) {
					const def = extraPresets.find(p => p.is_default == 1);
					if (def) { extraPick.value = def.id; applyExtraPreset(def); }
				}
			}
			async function loadExtraPresets(autoApplyDefault){
				try {
					// Filtr wg wybranego konta KSeF (sprzedawcy): zwraca zestawy tego konta + globalne („wszystkie").
					const credId = document.getElementById('credential_id')?.value || '';
					const r = await fetch(`${AJAX}?action=ksef_list_extra_presets&_ajax_nonce=${NONCE}&credential_id=${encodeURIComponent(credId)}`, { credentials: 'same-origin' });
					const j = await r.json();
					if (j.success) renderExtraPresets(j.data.items, autoApplyDefault);
				} catch(e) { console.error(e); }
			}
			// Zmiana konta KSeF → przeładuj zestawy danych i zastosuj domyślny dla tego sprzedawcy.
			document.getElementById('credential_id')?.addEventListener('change', () => loadExtraPresets(true));
			extraPick?.addEventListener('change', () => {
				const p = extraPresets.find(x => x.id == extraPick.value);
				if (p) applyExtraPreset(p);
			});
			function fieldVal(name){ const el = document.getElementsByName(name)[0]; return el ? el.value : ''; }
			document.getElementById('save-extra-preset-btn')?.addEventListener('click', async () => {
				const sel = extraPresets.find(x => x.id == extraPick.value);
				const name = prompt('Nazwa zestawu danych:', sel ? sel.name : '');
				if (name == null || !name.trim()) return;
				const fd = new FormData();
				fd.append('action', 'ksef_save_extra_preset');
				fd.append('_ajax_nonce', NONCE);
				if (sel && sel.name === name.trim()) fd.append('id', sel.id);
				fd.append('name', name.trim());
				fd.append('seller_email', fieldVal('seller_email'));
				fd.append('seller_phone', fieldVal('seller_phone'));
				fd.append('customer_no', fieldVal('customer_no'));
				fd.append('issue_place', fieldVal('issue_place'));
				fd.append('credential_id', document.getElementById('credential_id')?.value || '0');
				const r = await fetch(AJAX, { method: 'POST', body: fd, credentials: 'same-origin' });
				const j = await r.json();
				if (j.success) { renderExtraPresets(j.data.items, false); extraPick.value = j.data.id; }
				else alert('Błąd: ' + (j.data?.message || 'nieznany'));
			});
			document.getElementById('extra-preset-default-btn')?.addEventListener('click', async () => {
				const sel = extraPresets.find(x => x.id == extraPick.value);
				if (!sel) { alert('Najpierw wybierz zestaw z listy.'); return; }
				const fd = new FormData();
				fd.append('action', 'ksef_save_extra_preset');
				fd.append('_ajax_nonce', NONCE);
				fd.append('id', sel.id); fd.append('name', sel.name);
				fd.append('seller_email', sel.seller_email || ''); fd.append('seller_phone', sel.seller_phone || ''); fd.append('issue_place', sel.issue_place || '');
				fd.append('credential_id', sel.credential_id || '0');
				fd.append('is_default', '1');
				const r = await fetch(AJAX, { method: 'POST', body: fd, credentials: 'same-origin' });
				const j = await r.json();
				if (j.success) renderExtraPresets(j.data.items, false);
			});
			document.getElementById('extra-preset-del-btn')?.addEventListener('click', async () => {
				const sel = extraPresets.find(x => x.id == extraPick.value);
				if (!sel) { alert('Najpierw wybierz zestaw z listy.'); return; }
				if (!confirm('Usunąć zestaw „' + sel.name + '"?')) return;
				const fd = new FormData();
				fd.append('action', 'ksef_delete_extra_preset'); fd.append('_ajax_nonce', NONCE); fd.append('id', sel.id);
				const r = await fetch(AJAX, { method: 'POST', body: fd, credentials: 'same-origin' });
				const j = await r.json();
				if (j.success) { extraPick.value = ''; renderExtraPresets(j.data.items, false); }
			});
			loadExtraPresets(true);

			// === KSeF custom notes (key-value) ===
			const knotesList = document.getElementById('ksef-notes-list');
			document.getElementById('add-ksef-note-btn').addEventListener('click', () => addKnote());
			addKnote(); // jedna pusta na start
			function addKnote(){
				const idx = knotesList.children.length;
				const row = document.createElement('div');
				row.className = 'ksef-knote-row';
				row.innerHTML = `<input type="text" name="ksef_notes[${idx}][key]" placeholder="Klucz"><input type="text" name="ksef_notes[${idx}][value]" placeholder="Wartość"><button type="button" class="button button-small del-knote">🗑</button>`;
				row.querySelector('.del-knote').addEventListener('click', () => row.remove());
				knotesList.appendChild(row);
			}

			// === Live sidebar sync ===
			function fmt(n){ return Number(n || 0).toLocaleString('pl-PL', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }
			function updateSidebar(){
				const cur = currInput.value;
				document.getElementById('side-currency').textContent = cur;
				document.getElementById('side-net').textContent = fmt(parseFloat(totalNet.textContent) || 0);
				document.getElementById('side-vat').textContent = fmt(parseFloat(totalVat.textContent) || 0);
				const gross = parseFloat(totalGross.textContent) || 0;
				document.getElementById('side-gross').textContent = fmt(gross);
				const depToggle = document.getElementById('deposit_toggle');
				const depAmount = depToggle?.checked ? (parseFloat(document.querySelector('[name=deposit_amount]')?.value) || 0) : 0;
				if (depAmount > 0) {
					document.getElementById('side-deposit-row').style.display = '';
					document.getElementById('side-deposit').textContent = fmt(depAmount);
				} else {
					document.getElementById('side-deposit-row').style.display = 'none';
				}
				document.getElementById('side-payable').textContent = fmt(gross + depAmount);

				// Mini VAT table w sidebar
				const sideVat = document.getElementById('side-vat-summary');
				const rows = Array.from(vatSummary.querySelectorAll('tr')).map(r => {
					const cells = r.querySelectorAll('td');
					return cells.length === 4 ? { rate: cells[0].textContent, gross: cells[3].textContent } : null;
				}).filter(Boolean);
				if (rows.length === 0) {
					sideVat.innerHTML = '<div class="ksef-side-empty">brak pozycji</div>';
				} else {
					sideVat.innerHTML = rows.map(r => '<div class="row"><span>' + esc(r.rate) + '</span><span>' + esc(r.gross) + '</span></div>').join('');
				}

				// Meta
				const credSel = document.getElementById('credential_id');
				let credText = '—';
				if (credSel && credSel.value) {
					if (credSel.tagName === 'SELECT' && credSel.selectedIndex >= 0) {
						credText = credSel.options[credSel.selectedIndex].text.trim();
					} else {
						const fixed = document.querySelector('.ksef-seller-fixed');
						credText = fixed ? fixed.textContent.trim() : credSel.value;
					}
				}
				document.getElementById('side-lokal').textContent = credText;
				document.getElementById('side-buyer').textContent = contractorSearch.value || '—';
				document.getElementById('side-items-count').textContent = tbody.querySelectorAll('tr').length;
				document.getElementById('side-due').textContent = document.getElementById('payment_due').value || '—';
			}
			// hook do recalc
			const origRecalc = recalc;
			window.recalc = function(){ origRecalc(); updateSidebar(); };
			// initial + listeners
			['credential_id','payment_due'].forEach(id => document.getElementById(id)?.addEventListener('change', updateSidebar));
			document.querySelector('[name=deposit_amount]')?.addEventListener('input', updateSidebar);
			document.getElementById('deposit_toggle')?.addEventListener('change', updateSidebar);
			document.getElementById('contractor_search')?.addEventListener('input', () => setTimeout(updateSidebar, 50));
			updateSidebar();

			// === Submit ===
			const form = document.getElementById('ksef-manual-invoice-form');
			const result = document.getElementById('ksef-submit-result');
			const spinner = document.getElementById('ksef-submit-spinner');
			const submitBtn = document.getElementById('ksef-submit-btn');
			const submitBtnTop = document.getElementById('ksef-submit-btn-top');
			const draftBtn = document.getElementById('ksef-draft-btn');
			const draftBtnTop = document.getElementById('ksef-draft-btn-top');
			let mode = 'send';
			draftBtn.addEventListener('click', () => { mode = 'draft'; form.requestSubmit(); });
			submitBtn.addEventListener('click', () => { mode = 'send'; });
			if (draftBtnTop) draftBtnTop.addEventListener('click', () => { mode = 'draft'; form.requestSubmit(); });
			if (submitBtnTop) submitBtnTop.addEventListener('click', () => { mode = 'send'; });
				// Usuń szkic
				const delBtn = document.getElementById('ksef-delete-draft');
				if (delBtn) delBtn.addEventListener('click', async function(){
					const id = delBtn.getAttribute('data-draft-id');
					if (!id) return;
					if (!confirm('Usunąć ten szkic? Tej operacji nie można cofnąć.')) return;
					delBtn.disabled = true;
					try {
						const fd = new FormData();
						fd.append('action','ksef_delete_draft');
						fd.append('ksef_nonce', (document.querySelector('input[name=ksef_nonce]') || {}).value || '');
						fd.append('draft_id', id);
						const resp = await fetch(AJAX, { method:'POST', body:fd, credentials:'same-origin' });
						const j = await resp.json();
						if (j && j.success) {
							window.location.href = <?php echo wp_json_encode( admin_url( 'admin.php?page=ksef-outgoing&status=draft' ) ); ?>;
						} else {
							alert('Nie udało się usunąć szkicu:\n' + ((j && j.data && j.data.message) || 'nieznany błąd'));
							delBtn.disabled = false;
						}
					} catch(e){ alert('Błąd połączenia przy usuwaniu szkicu.'); delBtn.disabled = false; }
				});

				// Wyślij do KSeF fakturę wystawioną lokalnie / po nieudanej wysyłce (status issued/failed).
				const sendKsefBtn = document.getElementById('ksef-view-send-draft');
				if (sendKsefBtn) sendKsefBtn.addEventListener('click', async function(){
					const id = sendKsefBtn.getAttribute('data-draft-id');
					if (!id) return;
					if (!confirm('Wysłać tę fakturę do KSeF?')) return;
					const orig = sendKsefBtn.innerHTML;
					sendKsefBtn.disabled = true; sendKsefBtn.innerHTML = 'Wysyłanie…';
					try {
						const fd = new FormData();
						fd.append('action','ksef_send_draft_invoice');
						fd.append('nonce', <?php echo wp_json_encode( $nonce ); ?>);
						fd.append('draft_id', id);
						const resp = await fetch(AJAX, { method:'POST', body:fd, credentials:'same-origin' });
						const j = await resp.json();
						if (j && j.success) { sendKsefBtn.innerHTML = '✓ Wysłano'; setTimeout(()=>location.reload(), 700); }
						else { alert('Nie udało się wysłać do KSeF:\n' + ((j && j.data && j.data.message) || 'nieznany błąd')); sendKsefBtn.disabled=false; sendKsefBtn.innerHTML=orig; }
					} catch(e){ alert('Błąd połączenia przy wysyłce do KSeF.'); sendKsefBtn.disabled=false; sendKsefBtn.innerHTML=orig; }
				});

			form.addEventListener('submit', async function(e){
				e.preventDefault();
				// Walidacja zgodności: stawka „zw" wymaga podstawy prawnej zwolnienia (P_19).
				{
					const hasZwSubmit = Array.from(tbody.querySelectorAll('.item-vat')).some(s => (s.value || '').toLowerCase() === 'zw');
					const p19chk = document.querySelector('input[name="markers[P_19]"]');
					const basisEl = document.getElementById('exemption_basis');
					if ( (hasZwSubmit || (p19chk && p19chk.checked)) && basisEl && basisEl.value.trim() === '' ) {
						alert('Wybrano stawkę „zw" (zwolnienie z VAT) lub znacznik „Zwolnienie z VAT".\n\nPrzepisy wymagają podania podstawy prawnej zwolnienia (np. art. 43 ust. 1 albo art. 113 ust. 1 i 9 ustawy o VAT).\n\nUzupełnij pole „Podstawa prawna zwolnienia".');
						const zwRow = document.getElementById('row-zwolnienie');
						if (zwRow){ zwRow.style.display = ''; }
						basisEl.focus();
						return;
					}
				}
				submitBtn.disabled = draftBtn.disabled = true;
				if (submitBtnTop) submitBtnTop.disabled = true;
				if (draftBtnTop) draftBtnTop.disabled = true;
				spinner.style.visibility = 'visible'; spinner.classList.add('is-active');
				result.innerHTML = '';
				const fd = new FormData(form);
				fd.append('action', mode === 'draft' ? 'ksef_save_manual_draft' : 'ksef_send_manual_invoice');
				try {
					const resp = await fetch(AJAX, { method: 'POST', body: fd, credentials: 'same-origin' });
					const json = await resp.json();
					if (json.success) {
						const d = json.data;
						if (mode === 'draft') {
							result.innerHTML = '<div class="notice notice-success" style="padding:12px;"><p><strong>💾 Draft zapisany</strong> (nr <code>' + esc(d.invoice_number) + '</code>, ID #' + d.draft_id + ')</p><p>Znajdziesz go w <a href="<?php echo esc_url( admin_url( 'admin.php?page=ksef-outgoing&status=draft' ) ); ?>">Faktury wysyłane → status: draft</a>.</p></div>';
								const _ex = document.getElementById('ksef-existing-id'); if (_ex && d.draft_id) { _ex.value = d.draft_id; }
						} else {
							if (d.status === 'confirmed') {
								const upo = d.invoice_id ? ' · <a href="' + AJAX + '?action=ksef_download_upo&invoice_id=' + d.invoice_id + '&_ajax_nonce=' + NONCE + '" target="_blank">⬇ Pobierz UPO</a>' : '';
								result.innerHTML = '<div class="notice notice-success" style="padding:14px;border-left-width:5px;"><p style="font-size:15px;margin:0 0 6px;"><strong>✓ Faktura zaakceptowana przez KSeF</strong></p><p style="margin:0;">Numer KSeF: <code>' + esc(d.ksef_number || '—') + '</code>' + upo + '</p></div>';
							} else if (d.status === 'rejected') {
								result.innerHTML = '<div class="notice notice-error" style="padding:14px;border-left-width:5px;"><p style="font-size:15px;margin:0 0 6px;"><strong>✗ KSeF odrzucił fakturę</strong></p><p style="margin:0;">' + esc(d.reject_reason || 'Nieznany powód.') + '</p><p style="margin:8px 0 0;color:#6b7280;">Popraw dane i wyślij ponownie (jeśli to duplikat — użyj innego numeru).</p></div>';
							} else {
								result.innerHTML = '<div class="notice notice-warning" style="padding:14px;border-left-width:5px;"><p style="font-size:15px;margin:0 0 6px;"><strong>⏳ Faktura wysłana — czeka na potwierdzenie MF</strong></p><p style="margin:0;">KSeF przyjął fakturę i ją przetwarza. Numer KSeF i UPO pojawią się za chwilę — odśwież listę faktur sprzedaży.</p></div>';
							}
							// Po wysłaniu rekord źródłowy (szkic/odrzucona) jest sprzątany na serwerze;
							// nowym, właściwym rekordem jest d.invoice_id — przepnij na niego existing_id,
							// żeby ewentualna ponowna wysyłka/zapis nie tworzyły kolejnych duplikatów.
							if (mode !== 'draft' && d.invoice_id) {
								const _ex = document.getElementById('ksef-existing-id'); if (_ex) _ex.value = d.invoice_id;
								if (d.status !== 'rejected') {
									['ksef-draft-btn','ksef-submit-btn','ksef-delete-draft','ksef-draft-btn-top','ksef-submit-btn-top'].forEach(function(idv){ const el = document.getElementById(idv); if (el) el.style.display = 'none'; });
									const _st = document.getElementById('ksf-status-text'); if (_st) _st.textContent = 'Faktura wysłana — przechodzę do podglądu…';
									const _go = <?php echo wp_json_encode( admin_url( 'admin.php?page=ksef-manual-invoice&action=view&id=' ) ); ?> + d.invoice_id;
									setTimeout(function(){ window.location.href = _go; }, 2200);
								}
							}
						}
						window.scrollTo({ top: result.offsetTop - 80, behavior: 'smooth' });
					} else {
						const er = json.data || {};
						let extra = '';
						if (er.details) extra = '<details><summary>Szczegóły</summary><pre style="white-space:pre-wrap;font-size:11px;">' + esc(JSON.stringify(er.details, null, 2)) + '</pre></details>';
						const hint = er.hint ? '<p style="margin:6px 0 0;color:#6b7280;">' + esc(er.hint) + '</p>' : '';
						result.innerHTML = '<div class="notice notice-error" style="padding:14px;border-left-width:5px;"><p style="font-size:15px;margin:0;"><strong>' + esc(er.message || 'Błąd wysyłki') + '</strong></p>' + hint + extra + '</div>';
					}
				} catch (err) {
					result.innerHTML = '<div class="notice notice-error" style="padding:12px;"><p>Network error: ' + esc(String(err)) + '</p></div>';
				} finally {
					submitBtn.disabled = draftBtn.disabled = false;
					if (submitBtnTop) submitBtnTop.disabled = false;
					if (draftBtnTop) draftBtnTop.disabled = false;
					spinner.style.visibility = 'hidden'; spinner.classList.remove('is-active');
				}
			});

			// ===================================================================
			// === PREFILL (tryb edit / view) — wczytaj payload do formularza ===
			// ===================================================================
			const appEl = document.querySelector('.ksef-app-invoice-editor');
			const appMode = appEl ? appEl.dataset.mode : 'new';
			let prefill = null;
			let prefillParseErr = '';
			try { prefill = JSON.parse(appEl?.dataset.prefill || 'null'); }
			catch(e) { prefill = null; prefillParseErr = e.message; }

			function setVal(name, value){
				const el = form.querySelector('[name="' + name + '"]');
				if (el && value != null && value !== '') el.value = value;
			}

			const isPrefillMode = (appMode === 'view' || appMode === 'edit' || appMode === 'correct');
			if (isPrefillMode && !prefill && result) {
				result.innerHTML = '<div class="notice notice-warning" style="padding:12px;">'
					+ 'Tryb <strong>' + esc(appMode) + '</strong> — brak danych payloadu do wczytania.'
					+ (prefillParseErr ? ' Błąd JSON: ' + esc(prefillParseErr) : '')
					+ ' (dataset.prefill length: ' + (appEl && appEl.dataset.prefill ? appEl.dataset.prefill.length : 0) + ')</div>';
			}

			try {
			if (prefill && isPrefillMode) {
				// Kredencjał (lokal)
				const credId = appEl.dataset.credentialId;
				if (credId) { const cs = document.getElementById('credential_id'); if (cs) cs.value = credId; }

				// Numer faktury — w trybie korekty NIE kopiujemy (świeży numer); w view/edit pokazujemy istniejący
				const numInp = document.getElementById('invoice_number');
				const custCb = document.getElementById('custom_number');
				if (appMode !== 'correct' && prefill.invoice_number && numInp) {
					numInp.value = prefill.invoice_number;
					numInp.readOnly = false;
					if (custCb) custCb.checked = true;
					if (autoFlag) autoFlag.value = '0';
				}

				// Daty
				setVal('issue_date', prefill.issue_date);
				setVal('sale_date', prefill.sale_date);
				setVal('currency', prefill.currency);
				if (currDisplay) currDisplay.textContent = prefill.currency || 'PLN';

				// Płatność
				if (prefill.payment) {
					setVal('payment_due', prefill.payment.due_date);
					(function(){ const pfRaw = String(prefill.payment.form || '6'); const pfMap = {'9':'3','10':'4','99':'6','8':'6'}; setVal('payment_form', ['1','2','3','4','5','6','7'].includes(pfRaw) ? pfRaw : (pfMap[pfRaw] || '6')); })();
					const paid = parseFloat(prefill.payment.paid || 0);
					const psRadio = paid > 0
						? document.getElementById('ps_paid')
						: document.getElementById('ps_unpaid');
					if (psRadio) psRadio.checked = true;
				}

				// Nabywca
				const buyer = prefill.buyer || {};
				if (buyer.name) {
					document.getElementById('contractor_search').value = buyer.name;
					document.getElementById('buyer_type').value = prefill.is_b2c ? 'b2c'
						: (buyer.nip ? 'pl_firm' : (buyer.vat_ue ? 'ue' : (buyer.nr_id ? 'non_ue' : 'b2c')));
					// hidden buyer fields
					const ba = buyer.address || {};
					[['buyer_name', buyer.name], ['buyer_nip', buyer.nip || ''],
					 ['buyer_country', ba.country || 'PL'], ['buyer_street', ba.street || ''],
					 ['buyer_postal', ba.postal_code || ''], ['buyer_city', ba.city || ''],
					 ['buyer_country_ue', buyer.country_ue || ''], ['buyer_vat_ue', buyer.vat_ue || ''],
					 ['buyer_country_code', buyer.country_code || ''], ['buyer_nr_id', buyer.nr_id || '']
					].forEach(([n, v]) => {
						let el = form.querySelector('input[name="' + n + '"]');
						if (!el) { el = document.createElement('input'); el.type = 'hidden'; el.name = n; form.appendChild(el); }
						el.value = v;
					});
					const cs = document.getElementById('contractor-summary');
					if (cs) {
						cs.innerHTML = '<strong>' + esc(buyer.name) + '</strong>' +
							(buyer.nip ? '<br>NIP: ' + esc(buyer.nip) : '');
						cs.classList.add('show');
					}
				}

				// Pozycje — wyczyść i odbuduj
				tbody.innerHTML = '';
				(prefill.items || []).forEach(it => {
					addItem({
						name: it.description, pkwiu: it.pkwiu, unit: it.unit,
						quantity: it.quantity, unit_price: parseFloat(it.unit_price_net || 0),
						vat_rate: it.vat_rate, gtu: it.gtu
					});
					// rabat + stawka VAT — ustaw ręcznie na ostatnim wierszu
					const lastRow = tbody.lastElementChild;
					if (lastRow) {
						if (it.discount_pct) {
							const d = lastRow.querySelector('.item-discount');
							if (d) d.value = it.discount_pct;
						}
						const vs = lastRow.querySelector('.item-vat');
						if (vs && it.vat_rate != null) {
							vs.value = String(it.vat_rate);
						}
					}
				});
				if (tbody.children.length === 0) addItem();
				recalc();

				// Markery
				const markers = prefill.markers || {};
				Object.keys(markers).forEach(code => {
					const cb = form.querySelector('[name="markers[' + code + ']"]');
					if (cb) { cb.checked = true; cb.dispatchEvent(new Event('change')); }
				});
				if (markers.fa_za_okres) {
					document.getElementById('row-fa-za-okres').style.display = '';
					setVal('period_from', prefill.period_from);
					setVal('period_to', prefill.period_to);
				}
				// Procedura marży — odtwórz rodzaj
				const adn = prefill.adnotacje || {};
				if (adn.P_PMarzy) { document.getElementById('row-pmarzy').style.display = ''; setVal('pmarzy_kind', adn.P_PMarzy); }
				// WDT nowych środków transportu — odtwórz dane pojazdu
				const nst = prefill.nst || {};
				if (nst.data_dopuszczenia) {
					document.getElementById('row-p22').style.display = '';
					setVal('nst_data_dopuszczenia', nst.data_dopuszczenia);
					setVal('nst_przebieg', nst.przebieg);
					setVal('nst_vin', nst.vin);
				}

				// Dokumenty powiązane
				const rel = prefill.related_docs || {};
				if (rel.order) { setVal('rel_order_no', rel.order.number); setVal('rel_order_date', rel.order.date); }
				if (rel.wz)    { setVal('rel_wz_no', rel.wz.number); }

				// Dane dodatkowe
				const ex = prefill.extra_data || {};
				setVal('issue_place', ex.issue_place);
				if (prefill.seller) { setVal('seller_email', prefill.seller.email); setVal('seller_phone', prefill.seller.phone); }
				setVal('buyer_email', (prefill.buyer && prefill.buyer.email) || '');

				// Adres dostawy
				const del = prefill.delivery_address;
				if (del && (del.street || del.city || del.name)) {
					const t = document.getElementById('toggle_delivery_addr');
					if (t) { t.checked = true; document.getElementById('delivery-addr-fields').style.display = ''; }
					setVal('delivery_name', del.name); setVal('delivery_street', del.street);
					setVal('delivery_postal', del.postal_code); setVal('delivery_city', del.city);
					setVal('delivery_country', del.country);
				}

				// Kaucja
				if (prefill.deposit_amount && parseFloat(prefill.deposit_amount) > 0) {
					const dt = document.getElementById('deposit_toggle');
					if (dt) { dt.checked = true; document.getElementById('deposit-fields').style.display = ''; }
					setVal('deposit_label', prefill.deposit_label);
					setVal('deposit_amount', prefill.deposit_amount);
				}

				// Uwagi + Notatki KSeF
				setVal('internal_notes', prefill.internal_notes || prefill.notes);
				const kn = prefill.ksef_custom_notes || [];
				if (kn.length) {
					knotesList.innerHTML = '';
					kn.forEach(() => addKnote());
					const rows = knotesList.querySelectorAll('.ksef-knote-row');
					kn.forEach((kv, i) => {
						if (rows[i]) {
							rows[i].querySelector('[name$="[key]"]').value = kv.key || '';
							rows[i].querySelector('[name$="[value]"]').value = kv.value || '';
						}
					});
				}

				if (typeof updateSidebar === 'function') updateSidebar();
			}
			} catch (prefillErr) {
				console.error('KSEF prefill error:', prefillErr);
				if (result) {
					result.innerHTML = '<div class="notice notice-error" style="padding:12px;"><strong>Błąd wczytywania danych faktury (JS):</strong> '
						+ esc(prefillErr.message) + '<br><small>' + esc(String(prefillErr.stack || '').slice(0, 400)) + '</small></div>';
				}
			}
			if (prefillParseErr && result) {
				result.innerHTML = '<div class="notice notice-error" style="padding:12px;"><strong>Błąd JSON payloadu:</strong> ' + esc(prefillParseErr) + '</div>';
			}

			// === Tryb VIEW — zamień pola na statyczny tekst (czysty podgląd) ===
			if (appMode === 'view') {
				// Wypełnij jawne, poprawnie podpisane bloki stron faktury z danych XML.
				(function(){
					function partyMeta(p){
						p = p || {}; const a = p.address || {}; const out = [];
						if (p.nip) out.push('NIP: ' + p.nip);
						else if (p.vat_ue) out.push('VAT-UE: ' + p.vat_ue);
						else if (p.nr_id) out.push('ID: ' + p.nr_id);
						const street = [a.street, a.street_number].filter(Boolean).join(' ');
						if (street) out.push(street);
						const city = [a.postal_code, a.city].filter(Boolean).join(' ');
						if (city) out.push(city);
						if (a.country && a.country !== 'PL') out.push('Kraj: ' + a.country);
						return out.join('\n');
					}
					const s = (prefill && prefill.seller) || {};
					const b = (prefill && prefill.buyer) || {};
					const sn = document.getElementById('vp-seller-name');
					const sm = document.getElementById('vp-seller-meta');
					const bn = document.getElementById('vp-buyer-name');
					const bm = document.getElementById('vp-buyer-meta');
					if (sn) sn.textContent = s.name || '—';
					if (sm) sm.textContent = partyMeta(s);
					if (bn) bn.textContent = b.name || '—';
					if (bm) bm.textContent = partyMeta(b);
				})();
				// select → statyczny tekst (etykieta zaznaczonej opcji).
				// Pomijamy kontrolki w .ksef-keep-interactive (rozliczenie zakupu zostaje edytowalne).
				form.querySelectorAll('select').forEach(sel => {
					if (sel.closest('.ksef-keep-interactive')) return;
					const span = document.createElement('span');
					span.className = 'ksef-view-static';
					const opt = sel.options[sel.selectedIndex];
					span.textContent = opt ? opt.text : (sel.value || '—');
					sel.parentNode.insertBefore(span, sel);
					sel.style.display = 'none';
				});
				// input tekst/email/date/number (też bez atrybutu type) → statyczny tekst
				form.querySelectorAll('input[type=text], input[type=email], input[type=date], input[type=number], input:not([type])').forEach(inp => {
					if (inp.closest('.ksef-keep-interactive')) return;
					// Wyszukiwarka kontrahenta dubluje dane z pomarańczowego boxu (#contractor-summary)
					// — w podglądzie ją chowamy, zostaje czytelny box z nazwą i NIP-em.
					if (inp.id === 'contractor_search') { inp.style.display = 'none'; return; }
					const span = document.createElement('span');
					span.className = 'ksef-view-static';
					span.textContent = (inp.value !== '' ? inp.value : '—');
					inp.parentNode.insertBefore(span, inp);
					inp.style.display = 'none';
				});
				// textarea → wieloliniowy tekst
				form.querySelectorAll('textarea').forEach(ta => {
					const div = document.createElement('div');
					div.className = 'ksef-view-static ksef-view-multiline';
					div.textContent = (ta.value !== '' ? ta.value : '—');
					ta.parentNode.insertBefore(div, ta);
					ta.style.display = 'none';
				});
				// checkbox/radio — zostaw disabled (renderują się poprawnie)
				form.querySelectorAll('input[type=checkbox], input[type=radio]').forEach(el => {
					if (el.closest('.ksef-keep-interactive')) return;
					el.disabled = true;
				});

				// Twarda blokada edycji w podglądzie: ukryj przyciski akcji (dodaj konto, zapisz/
				// usuń zestaw, +wiersz, edytuj/usuń rachunek) i zablokuj kontrolki doczytane async
				// (lista rachunków, presety). Wyjątek: .ksef-keep-interactive (status płatności).
				const lockViewEdits = () => {
					form.querySelectorAll('button').forEach(btn => {
						if (btn.closest('.ksef-keep-interactive')) return;
						btn.style.display = 'none';
					});
					form.querySelectorAll('input:not([type=radio]):not([type=checkbox]), select, textarea').forEach(el => {
						if (el.closest('.ksef-keep-interactive')) return;
						el.readOnly = true; el.tabIndex = -1;
						if (el.tagName === 'SELECT') { el.disabled = true; }
					});
				};
				lockViewEdits();
				setTimeout(lockViewEdits, 700);
				setTimeout(lockViewEdits, 1800);

				// Podgląd: aktywny status płatności (zapis od razu) + kategoria wydatku (zakup).
				(function(){
					const ajaxUrl = <?php echo wp_json_encode( admin_url( 'admin-ajax.php' ) ); ?>;
					const nonceV  = <?php echo wp_json_encode( wp_create_nonce( 'ksef-nonce' ) ); ?>;
					function flash(el, ok){ if(!el) return; el.textContent = ok ? '✓ zapisano' : '✗ błąd'; el.style.color = ok ? '#16a34a' : '#dc2626'; setTimeout(()=>{ el.textContent=''; }, 2500); }

					// Status płatności — istniejący segment, aktywny w podglądzie, zapis na zmianę.
					const psf = document.getElementById('ksef-paystatus-field');
					if (psf) {
						const id = psf.getAttribute('data-invoice-id');
						const type = psf.getAttribute('data-inv-type') || 'outgoing';
						const cur = psf.getAttribute('data-current') || 'unpaid';
						const rb = psf.querySelector('#ps_' + cur);
						if (rb) rb.checked = true;
						psf.querySelectorAll('input[name="initial_payment_status"]').forEach(r => {
							r.disabled = false;
							r.addEventListener('change', async function(){
								try{
									const fd = new FormData();
									fd.append('action','ksef_set_payment_status'); fd.append('_ajax_nonce',nonceV);
									fd.append('invoice_id',id); fd.append('type',type); fd.append('status',r.value);
									const resp = await fetch(ajaxUrl,{method:'POST',body:fd,credentials:'same-origin'});
									const j = await resp.json(); flash(document.getElementById('ksef-paystatus-saved'), j.success);
								}catch(e){ flash(document.getElementById('ksef-paystatus-saved'), false); }
							});
						});
					}

					// Kategoria wydatku (tylko zakup) — zapis na zmianę.
					const katField = document.getElementById('ksef-zakup-kat-field');
					const cat = document.getElementById('zakup-kategoria');
					if (katField && cat) {
						const cid = katField.getAttribute('data-invoice-id');
						cat.addEventListener('change', async function(){
							try{
								const fd = new FormData();
								fd.append('action','ksef_set_incoming_category'); fd.append('_ajax_nonce',nonceV);
								fd.append('invoice_id',cid); fd.append('category',cat.value);
								const r = await fetch(ajaxUrl,{method:'POST',body:fd,credentials:'same-origin'});
								const j = await r.json(); flash(document.getElementById('zakup-cat-saved'), j.success);
							}catch(e){ flash(document.getElementById('zakup-cat-saved'), false); }
						});
					}
				})();
				// Ukryj przyciski dodawania / akcji edycji
				['ksef-add-item', 'wc-products-btn', 'contractor-new-btn', 'add-bank-btn',
				 'add-ksef-note-btn', 'ksef-submit-btn', 'ksef-draft-btn'].forEach(id => {
					const el = document.getElementById(id);
					if (el) el.style.display = 'none';
				});
				document.querySelectorAll('.ksef-remove-item, .del-knote, .ksef-toggle-mini, #custom_number').forEach(b => {
					const wrap = b.closest('label') || b;
					wrap.style.display = 'none';
				});
				// Ukryj cały boczny panel (Podsumowanie + Stan + Akcje) i rozciągnij główną kolumnę
				const sidebar = document.querySelector('.ksef-app-sidebar');
				if (sidebar) sidebar.style.display = 'none';
				const layout = document.querySelector('.ksef-app-layout');
				if (layout) layout.style.gridTemplateColumns = '1fr';
			}
		})();
		<?php Modern_Shell::inline_script( 'ksef-manual-invoice-b', ob_get_clean() ); ?>
		<?php
	}

	/**
	 * AJAX: wystawia fakturę z payload + wysyła do KSeF.
	 */
	public static function ajax_send(): void {
		if ( ! current_user_can( 'ksef_create_invoice' ) ) {
			wp_send_json_error( [ 'message' => 'Brak uprawnień.' ], 403 );
		}
		check_ajax_referer( 'ksef_send_manual_invoice', 'ksef_nonce' );

		// Wersja darmowa: wystawianie bez limitów (brak bramki quota).

		$credential_id = intval( wp_unslash( $_POST['credential_id'] ?? 0 ) );
		if ( $credential_id <= 0 ) {
			wp_send_json_error( [ 'message' => 'Wybierz konto KSeF.' ], 400 );
		}

		global $wpdb;
		$credential = $wpdb->get_row(
			$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gksef_credentials WHERE id = %d", $credential_id ),
			ARRAY_A
		);
		if ( ! $credential ) {
			wp_send_json_error( [ 'message' => 'Kredencjał nie istnieje.' ], 404 );
		}

		try {
			$invoice_data = self::build_payload_from_post();
		} catch ( \Throwable $e ) {
			wp_send_json_error( [ 'message' => 'Błąd walidacji: ' . $e->getMessage() ], 400 );
		}

		try {
			$sender = V2_Bootstrap::invoice_sender_for_credential( $credential );
			$result = $sender->send_data( $invoice_data, $credential, null );
		} catch ( \Throwable $e ) {
			wp_send_json_error( [
				'message' => 'Wyjątek: ' . $e->getMessage(),
				'file'    => basename( $e->getFile() ) . ':' . $e->getLine(),
			], 500 );
		}

		if ( is_wp_error( $result ) ) {
			$fr   = \KSEF\WordPress\V2\Ksef_Client::friendly_error( (string) $result->get_error_code(), (string) $result->get_error_message() );
			$data = $result->get_error_data();
			$hint = $fr['hint'];
			if ( is_array( $data ) && ! empty( $data['remediation'] ) ) {
				$hint = (string) $data['remediation'];
			}
			wp_send_json_error( [
				'message'    => $fr['title'],
				'hint'       => $hint,
				'error_code' => $result->get_error_code(),
				'details'    => $data,
			], 200 );
		}

		// Zapis szczegółów płatności (sposób zapłaty całości / wpłaty częściowe).
		$new_inv_id = (int) ( $result['invoice_id'] ?? 0 );
		if ( $new_inv_id > 0 ) {
			self::record_payment_details_from_post( $new_inv_id );
		}

		// Wysłano z edycji niewysłanej faktury — usuń rekord ŹRÓDŁOWY, żeby nie został jako
		// duplikat (właściwą fakturą jest nowy wpis $new_inv_id z danymi z KSeF). Usuwamy tylko
		// stany lokalne (draft/rejected/issued/failed); faktury sent/confirmed nigdy nie ruszamy.
		$src_id = intval( wp_unslash( $_POST['existing_id'] ?? 0 ) );
		if ( $src_id > 0 && $src_id !== $new_inv_id ) {
			$src_status = (string) $wpdb->get_var( $wpdb->prepare( "SELECT status FROM {$wpdb->prefix}gksef_outgoing_invoices WHERE id = %d", $src_id ) );
			if ( in_array( $src_status, [ 'draft', 'rejected', 'issued', 'failed' ], true ) ) {
				$wpdb->delete( $wpdb->prefix . 'gksef_outgoing_invoices', [ 'id' => $src_id ] );
			}
		}

		$final = (string) ( $result['status'] ?? 'sent' ); // confirmed | rejected | pending | sent
		wp_send_json_success( [
			'status'            => $final,
			'invoice_id'        => $new_inv_id,
			'ksef_number'       => (string) ( $result['ksef_number'] ?? '' ),
			'reject_reason'     => (string) ( $result['reject_reason'] ?? '' ),
			'session_reference' => (string) ( $result['session_reference'] ?? '' ),
			'invoice_reference' => (string) ( $result['invoice_reference'] ?? '' ),
		] );
	}

	/**
	 * Zapisuje płatności podane przy wystawianiu faktury:
	 *  - status „paid"    → jedna wpłata na całość brutto z wybraną formą,
	 *  - status „partial" → lista wpłat (kwota, data, forma).
	 * Repozytorium płatności samo przelicza status płatności faktury.
	 */
	private static function record_payment_details_from_post( int $invoice_id ): void {
		$status = (string) sanitize_text_field( wp_unslash( $_POST['initial_payment_status'] ?? 'unpaid' ) );
		$method_labels = [
			'przelew' => 'Przelew', 'gotowka' => 'Gotówka', 'kompensata' => 'Kompensata',
			'online' => 'Online', 'inne' => 'Inna',
		];
		if ( 'paid' === $status ) {
			global $wpdb;
			$gross = (float) $wpdb->get_var( $wpdb->prepare( "SELECT gross_amount FROM {$wpdb->prefix}gksef_outgoing_invoices WHERE id = %d", $invoice_id ) );
			$m = (string) sanitize_text_field( wp_unslash( $_POST['paid_method'] ?? 'przelew' ) );
			\KSEF\WordPress\Payments_Repository::add( $invoice_id, [
				'amount'         => $gross,
				'payment_date'   => sanitize_text_field( wp_unslash( $_POST['issue_date'] ?? gmdate( 'Y-m-d' ) ) ),
				'payment_method' => $method_labels[ $m ] ?? 'Przelew',
			] );
		} elseif ( 'partial' === $status ) {
			$rows = is_array( $_POST['partial_payments'] ?? null ) ? map_deep( wp_unslash( $_POST['partial_payments'] ), 'sanitize_text_field' ) : [];
			foreach ( $rows as $r ) {
				$amount = round( (float) ( $r['amount'] ?? 0 ), 2 );
				if ( $amount <= 0 ) {
					continue;
				}
				$m = (string) ( $r['method'] ?? 'przelew' );
				\KSEF\WordPress\Payments_Repository::add( $invoice_id, [
					'amount'         => $amount,
					'payment_date'   => sanitize_text_field( (string) ( $r['date'] ?? gmdate( 'Y-m-d' ) ) ),
					'payment_method' => $method_labels[ $m ] ?? 'Przelew',
				] );
			}
		}
	}

	public static function ajax_save_draft(): void {
		if ( ! current_user_can( 'ksef_create_invoice' ) ) {
			wp_send_json_error( [ 'message' => 'Brak uprawnień.' ], 403 );
		}
		check_ajax_referer( 'ksef_send_manual_invoice', 'ksef_nonce' );

		$credential_id = intval( wp_unslash( $_POST['credential_id'] ?? 0 ) );
		global $wpdb;
		$credential = $wpdb->get_row(
			$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gksef_credentials WHERE id = %d", $credential_id ),
			ARRAY_A
		);
		if ( ! $credential ) {
			wp_send_json_error( [ 'message' => 'Kredencjał nie istnieje.' ], 404 );
		}

		// Edycja istniejącego draftu → UPDATE (bez duplikatu) + zachowanie numeru (bez konsumpcji numeracji).
		$existing_id = intval( wp_unslash( $_POST['existing_id'] ?? 0 ) );
		if ( $existing_id > 0 ) {
			$existing_num = (string) $wpdb->get_var( $wpdb->prepare(
				"SELECT invoice_number FROM {$wpdb->prefix}gksef_outgoing_invoices WHERE id = %d AND status = 'draft'",
				$existing_id
			) );
			if ( '' !== $existing_num ) {
				$_POST['invoice_number'] = $existing_num;
				$_POST['custom_number']  = '1';
			} else {
				$existing_id = 0;
			}
		}

		try {
			$invoice_data = self::build_payload_from_post();
		} catch ( \Throwable $e ) {
			wp_send_json_error( [ 'message' => 'Błąd walidacji: ' . $e->getMessage() ], 400 );
		}

		$sender = V2_Bootstrap::invoice_sender_for_credential( $credential );
		$result = $sender->save_draft( $invoice_data, $credential, $existing_id );
		if ( is_wp_error( $result ) ) {
			wp_send_json_error( [
				'message'    => $result->get_error_message(),
				'error_code' => $result->get_error_code(),
			], 200 );
		}

		wp_send_json_success( [
			'draft_id'       => (int) $result['draft_id'],
			'invoice_number' => (string) $result['invoice_number'],
		] );
	}

	public static function ajax_delete_draft(): void {
		if ( ! current_user_can( 'ksef_create_invoice' ) ) {
			wp_send_json_error( [ 'message' => 'Brak uprawnień.' ], 403 );
		}
		check_ajax_referer( 'ksef_send_manual_invoice', 'ksef_nonce' );
		global $wpdb;
		$draft_id = intval( wp_unslash( $_POST['draft_id'] ?? 0 ) );
		if ( $draft_id <= 0 ) {
			wp_send_json_error( [ 'message' => 'Brak draft_id.' ], 400 );
		}
		$table  = $wpdb->prefix . 'gksef_outgoing_invoices';
		$status = $wpdb->get_var( $wpdb->prepare( "SELECT status FROM {$table} WHERE id = %d", $draft_id ) );
		if ( null === $status ) {
			wp_send_json_error( [ 'message' => 'Faktura nie istnieje.' ], 404 );
		}
		if ( ! in_array( (string) $status, [ 'draft', 'rejected' ], true ) ) {
			wp_send_json_error( [ 'message' => 'Usunąć można tylko szkic lub fakturę odrzuconą — faktura wysłana do KSeF pozostaje w rejestrze MF.' ], 400 );
		}
		$wpdb->delete( $table, [ 'id' => $draft_id ] );
		wp_send_json_success( [ 'deleted' => $draft_id ] );
	}

	public static function ajax_copy_invoice(): void {
		if ( ! current_user_can( 'ksef_create_invoice' ) ) {
			wp_send_json_error( [ 'message' => 'Brak uprawnień.' ], 403 );
		}
		check_ajax_referer( 'ksef-nonce' );
		$src_id = intval( wp_unslash( $_POST['invoice_id'] ?? 0 ) );
		if ( $src_id <= 0 ) {
			wp_send_json_error( [ 'message' => 'Brak invoice_id.' ], 400 );
		}
		global $wpdb;
		$row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gksef_outgoing_invoices WHERE id = %d", $src_id ), ARRAY_A );
		if ( ! $row ) {
			wp_send_json_error( [ 'message' => 'Faktura nie istnieje.' ], 404 );
		}
		$payload = json_decode( (string) \KSEF\WordPress\Crypto::decrypt_from_storage( $row['payload_json'] ?? '' ), true );
		if ( ! is_array( $payload ) || empty( $payload ) ) {
			wp_send_json_error( [ 'message' => 'Brak danych faktury do skopiowania (np. faktura pobrana z KSeF bez pełnego payloadu).' ], 400 );
		}
		$credential = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gksef_credentials WHERE id = %d", (int) $row['credential_id'] ), ARRAY_A );
		if ( ! $credential ) {
			wp_send_json_error( [ 'message' => 'Kredencjał faktury nie istnieje.' ], 404 );
		}
		// Świeży numer + dzisiejsza data; zerujemy stan płatności i usuwamy oznaczenie korekty.
		$payload['invoice_number'] = Invoice_Numbering::next( null, 'sale' );
		$payload['issue_date']     = gmdate( 'Y-m-d' );
		$payload['sale_date']      = gmdate( 'Y-m-d' );
		if ( isset( $payload['payment'] ) && is_array( $payload['payment'] ) ) {
			$payload['payment']['paid'] = 0.0;
		}
		unset( $payload['correction'] );
		$sender = V2_Bootstrap::invoice_sender_for_credential( $credential );
		$result = $sender->save_draft( $payload, $credential );
		if ( is_wp_error( $result ) ) {
			wp_send_json_error( [ 'message' => $result->get_error_message() ], 500 );
		}
		wp_send_json_success( [
			'draft_id'       => (int) $result['draft_id'],
			'invoice_number' => (string) ( $result['invoice_number'] ?? '' ),
		] );
	}

	public static function ajax_send_draft(): void {
		if ( ! current_user_can( 'ksef_create_invoice' ) ) {
			wp_send_json_error( [ 'message' => 'Brak uprawnień.' ], 403 );
		}
		check_ajax_referer( 'ksef-nonce', 'nonce' );

		$draft_id = intval( wp_unslash( $_POST['draft_id'] ?? 0 ) );
		if ( $draft_id <= 0 ) {
			wp_send_json_error( [ 'message' => 'Brak draft_id.' ], 400 );
		}

		global $wpdb;
		$row = $wpdb->get_row(
			$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gksef_outgoing_invoices WHERE id = %d", $draft_id ),
			ARRAY_A
		);
		if ( ! $row ) {
			wp_send_json_error( [ 'message' => 'Draft nie istnieje.' ], 404 );
		}
		$credential = $wpdb->get_row(
			$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gksef_credentials WHERE id = %d", (int) $row['credential_id'] ),
			ARRAY_A
		);
		if ( ! $credential ) {
			wp_send_json_error( [ 'message' => 'Kredencjał draftu nie istnieje.' ], 404 );
		}

		$sender = V2_Bootstrap::invoice_sender_for_credential( $credential );
		$result = $sender->send_draft( $draft_id, $credential );
		if ( is_wp_error( $result ) ) {
			wp_send_json_error( [
				'message'    => $result->get_error_message(),
				'error_code' => $result->get_error_code(),
			], 200 );
		}
		wp_send_json_success( [
			'status'            => (string) ( $result['status'] ?? 'sent' ),
			'session_reference' => (string) ( $result['session_reference'] ?? '' ),
			'invoice_reference' => (string) ( $result['invoice_reference'] ?? '' ),
		] );
	}

	/**
	 * Buduje payload do Fa3_Builder z $_POST.
	 *
	 * @throws \InvalidArgumentException
	 * @return array<string,mixed>
	 */
	private static function build_payload_from_post(): array {
		$buyer_type    = (string) sanitize_text_field( wp_unslash( $_POST['buyer_type'] ?? 'b2c' ) );
		$contractor_id = intval( wp_unslash( $_POST['contractor_id'] ?? 0 ) );

		// Jeśli wybrano kontrahenta z bazy, dociągnij dane
		$contractor = null;
		if ( $contractor_id > 0 ) {
			global $wpdb;
			$contractor = $wpdb->get_row(
				$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gksef_contractor_mappings WHERE id = %d", $contractor_id ),
				ARRAY_A
			);
		}
		$buyer_name = trim( (string) sanitize_text_field( wp_unslash( $_POST['buyer_name'] ?? ( $contractor['contractor_name'] ?? '' ) ) ) );
		if ( $buyer_name === '' ) {
			throw new \InvalidArgumentException( 'Brak nazwy nabywcy — wybierz lub dodaj kontrahenta.' );
		}

		$buyer = [
			'name'    => $buyer_name,
			'email'   => sanitize_email( wp_unslash( $_POST['buyer_email'] ?? ( $contractor['email'] ?? '' ) ) ),
			'address' => [
				'country'     => strtoupper( (string) sanitize_text_field( wp_unslash( $_POST['buyer_country'] ?? ( $contractor['country_code'] ?? 'PL' ) ) ) ),
				'street'      => (string) sanitize_text_field( wp_unslash( $_POST['buyer_street'] ?? ( $contractor['street'] ?? '' ) ) ),
				'city'        => (string) sanitize_text_field( wp_unslash( $_POST['buyer_city'] ?? ( $contractor['city'] ?? '' ) ) ),
				'postal_code' => (string) sanitize_text_field( wp_unslash( $_POST['buyer_postal'] ?? ( $contractor['postal_code'] ?? '' ) ) ),
			],
		];

		$is_b2c = false;
		switch ( $buyer_type ) {
			case 'b2c':
				$is_b2c = true;
				break;
			case 'pl_firm':
				$buyer['nip'] = preg_replace( '/\D+/', '', (string) sanitize_text_field( wp_unslash( $_POST['buyer_nip'] ?? ( $contractor['contractor_nip'] ?? '' ) ) ) );
				if ( strlen( $buyer['nip'] ) !== 10 ) {
					throw new \InvalidArgumentException( 'NIP musi mieć 10 cyfr.' );
				}
				break;
			case 'ue':
				$buyer['country_ue'] = strtoupper( (string) sanitize_text_field( wp_unslash( $_POST['buyer_country_ue'] ?? ( $contractor['country_code'] ?? '' ) ) ) );
				$buyer['vat_ue']     = trim( (string) sanitize_text_field( wp_unslash( $_POST['buyer_vat_ue'] ?? ( $contractor['vat_ue'] ?? '' ) ) ) );
				if ( $buyer['country_ue'] === '' || $buyer['vat_ue'] === '' ) {
					throw new \InvalidArgumentException( 'Brak KodUE / VatUE.' );
				}
				break;
			case 'non_ue':
				$buyer['country_code'] = strtoupper( (string) sanitize_text_field( wp_unslash( $_POST['buyer_country_code'] ?? ( $contractor['country_code'] ?? '' ) ) ) );
				$buyer['nr_id']        = trim( (string) sanitize_text_field( wp_unslash( $_POST['buyer_nr_id'] ?? ( $contractor['nr_id'] ?? '' ) ) ) );
				if ( $buyer['country_code'] === '' || $buyer['nr_id'] === '' ) {
					throw new \InvalidArgumentException( 'Brak KodKraju / NrID.' );
				}
				break;
		}

		// Items
		$items_raw = (array) map_deep( wp_unslash( $_POST['items'] ?? [] ), 'sanitize_text_field' );
		if ( empty( $items_raw ) ) {
			throw new \InvalidArgumentException( 'Brak pozycji faktury.' );
		}
		$items       = [];
		$vat_buckets = [];
		$total_net   = 0.0;
		$total_gross = 0.0;
		$price_mode  = (string) sanitize_text_field( wp_unslash( $_POST['price_mode'] ?? 'net' ) );
		foreach ( $items_raw as $row ) {
			$qty       = (float) ( $row['quantity'] ?? 0 );
			$price     = (float) ( $row['unit_price_net'] ?? 0 );
			$rate_raw  = (string) ( $row['vat_rate'] ?? '23' );
			$discount  = max( 0.0, min( 100.0, (float) ( $row['discount_pct'] ?? 0 ) ) );
			$rate_num  = is_numeric( $rate_raw ) ? (float) $rate_raw : 0.0;
			$gross_or_net = $qty * $price * ( 1 - $discount / 100 );
			// VAT liczony w GROSZACH (half-up) — PHP round(0.005,2) gubi grosz przez float
			// (np. round(19.90*5/100,2)=round(0.995,2)=0.99 → brutto 20.89 zamiast 20.90).
			if ( 'gross' === $price_mode ) {
				$line_g  = round( $gross_or_net, 2 );
				$gross_g = (int) round( $line_g * 100 );
				$base_g  = is_numeric( $rate_raw ) ? (int) round( $gross_g / ( 1 + $rate_num / 100 ) ) : $gross_g;
				$base_n  = $base_g / 100;
				$vat_a   = ( $gross_g - $base_g ) / 100;
				$unit_price_net = $rate_num > 0 ? round( $price / ( 1 + $rate_num / 100 ), 2 ) : $price;
			} else {
				$base_n  = round( $gross_or_net, 2 );
				$base_g  = (int) round( $base_n * 100 );
				$vat_g   = is_numeric( $rate_raw ) ? (int) round( $base_g * $rate_num / 100 ) : 0;
				$vat_a   = $vat_g / 100;
				$line_g  = ( $base_g + $vat_g ) / 100;
				$unit_price_net = $price;
			}
			$items[] = [
				'description'    => trim( (string) ( $row['description'] ?? '' ) ),
				'pkwiu'          => trim( (string) ( $row['pkwiu'] ?? '' ) ),
				'unit'           => trim( (string) ( $row['unit'] ?? 'szt.' ) ) ?: 'szt.',
				'quantity'       => $qty,
				'unit_price_net' => $unit_price_net,
				'discount_pct'   => $discount,
				'vat_rate'       => is_numeric( $rate_raw ) ? $rate_num : $rate_raw,
				'gtu'            => trim( (string) ( $row['gtu'] ?? '' ) ),
				'line_net'       => $base_n,
				'line_gross'     => $line_g,
			];
			$key = is_numeric( $rate_raw ) ? (string) (int) round( $rate_num ) : $rate_raw;
			if ( ! isset( $vat_buckets[ $key ] ) ) {
				$vat_buckets[ $key ] = [ 'rate' => is_numeric( $rate_raw ) ? $rate_num : $rate_raw, 'base_net' => 0.0, 'vat_amount' => 0.0 ];
			}
			$vat_buckets[ $key ]['base_net']   += $base_n;
			$vat_buckets[ $key ]['vat_amount'] += $vat_a;
			$total_net   += $base_n;
			$total_gross += $line_g;
		}

		// Seller
		global $wpdb;
		$credential_id = intval( wp_unslash( $_POST['credential_id'] ?? 0 ) );
		$cred_row      = $wpdb->get_row(
			$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gksef_credentials WHERE id = %d", $credential_id ),
			ARRAY_A
		);
		$seller_nip = (string) ( $cred_row['nip'] ?? '' );
		$seller = [
			'nip'     => $seller_nip,
			'name'    => (string) ( $cred_row['seller_name'] ?: ( $cred_row['name'] ?? get_bloginfo( 'name' ) ) ),
			'email'   => trim( (string) sanitize_text_field( wp_unslash( $_POST['seller_email'] ?? '' ) ) ) ?: (string) ( $cred_row['seller_email'] ?? '' ),
			'phone'   => trim( (string) sanitize_text_field( wp_unslash( $_POST['seller_phone'] ?? '' ) ) ) ?: (string) ( $cred_row['seller_phone'] ?? '' ),
			'address' => [
				'country'       => (string) ( $cred_row['seller_country'] ?: 'PL' ),
				'street'        => (string) ( $cred_row['seller_street'] ?? '' ),
				'street_number' => (string) ( $cred_row['seller_building'] ?? '' ),
				'city'          => (string) ( $cred_row['seller_city'] ?? '' ),
				'postal_code'   => (string) ( $cred_row['seller_postal'] ?? '' ),
			],
		];

		// Status płatności
		$initial_status = (string) sanitize_text_field( wp_unslash( $_POST['initial_payment_status'] ?? 'unpaid' ) );
		$paid_in_full   = ( $initial_status === 'paid' );

		// Wpłaty częściowe (status „partial") → trafiają do XML jako ZaplataCzesciowa.
		$partial_payments = [];
		if ( 'partial' === $initial_status && is_array( $_POST['partial_payments'] ?? null ) ) {
			foreach ( map_deep( wp_unslash( $_POST['partial_payments'] ), 'sanitize_text_field' ) as $pp ) {
				$pp_amount = round( (float) ( $pp['amount'] ?? 0 ), 2 );
				if ( $pp_amount > 0 ) {
					$partial_payments[] = [ 'amount' => $pp_amount, 'date' => (string) ( $pp['date'] ?? '' ) ];
				}
			}
		}

		// Daty wystawienia/sprzedaży/wpłat częściowych nie mogą być z przyszłości (format Y-m-d porównywalny leksykalnie).
		$today_ymd = gmdate( 'Y-m-d' );
		$issue_ymd = (string) sanitize_text_field( wp_unslash( $_POST['issue_date'] ?? $today_ymd ) );
		$sale_ymd  = (string) sanitize_text_field( wp_unslash( $_POST['sale_date'] ?? $issue_ymd ) );
		if ( '' !== $issue_ymd && $issue_ymd > $today_ymd ) {
			throw new \InvalidArgumentException( 'Data wystawienia nie może być datą przyszłą.' );
		}
		if ( '' !== $sale_ymd && $sale_ymd > $today_ymd ) {
			throw new \InvalidArgumentException( 'Data sprzedaży nie może być datą przyszłą.' );
		}
		foreach ( $partial_payments as $pp ) {
			if ( '' !== (string) $pp['date'] && (string) $pp['date'] > $today_ymd ) {
				throw new \InvalidArgumentException( 'Data wpłaty częściowej nie może być datą przyszłą.' );
			}
		}

		// Numer faktury — korekta używa domyślnego schematu numeracji korekt.
		$numbering_kind = intval( wp_unslash( $_POST['correct_of_id'] ?? 0 ) ) > 0 ? 'correction' : 'sale';
		$invoice_number = trim( (string) sanitize_text_field( wp_unslash( $_POST['invoice_number'] ?? '' ) ) );
		$auto_number    = ! isset( $_POST['custom_number'] ) || empty( $_POST['custom_number'] );
		if ( $auto_number || $invoice_number === '' ) {
			// Wybrany przez użytkownika schemat (tylko dla sprzedaży; korekta ma własny).
			$scheme_id = sanitize_text_field( wp_unslash( $_POST['numbering_scheme_id'] ?? '' ) );
			$scheme_arg = ( 'sale' === $numbering_kind && '' !== $scheme_id ) ? $scheme_id : null;
			$invoice_number = Invoice_Numbering::next( $scheme_arg, $numbering_kind );
		}

		// Markers
		$markers_raw = (array) map_deep( wp_unslash( $_POST['markers'] ?? [] ), 'sanitize_text_field' );
		$markers     = [];
		foreach ( [ 'FP','P_18A','TP','fa_za_okres','P_19','P_16','P_18','P_23','PMarzy','P_22','OSS' ] as $code ) {
			if ( ! empty( $markers_raw[ $code ] ) ) {
				$markers[ $code ] = '1';
			}
		}

		$adnotacje = [];
		foreach ( [ 'P_16','P_17','P_18','P_18A','P_19','P_22','P_23' ] as $p ) {
			$adnotacje[ $p ] = isset( $markers[ $p ] ) ? '1' : '2';
		}

		// Auto P_18A (podzielona płatność) gdy kwota brutto > 15 000 zł (tylko PLN).
		// Wersja darmowa: tylko PLN (faktury w innych walutach są funkcją Pro).
		$_POST['currency'] = 'PLN';
		$currency_code = strtoupper( (string) sanitize_text_field( wp_unslash( $_POST['currency'] ?? 'PLN' ) ) );
		// Kurs wymiany (waluta obca) — wymagany dla P_14_xW + KursWalutyZ w FA(3).
		$exchange_rate      = (float) str_replace( ',', '.', (string) sanitize_text_field( wp_unslash( $_POST['exchange_rate'] ?? '0' ) ) );
		$exchange_rate_date = (string) sanitize_text_field( wp_unslash( $_POST['exchange_rate_date'] ?? '' ) );
		if ( 'PLN' !== $currency_code && $exchange_rate <= 0 ) {
			throw new \InvalidArgumentException( 'Faktura w walucie obcej wymaga kursu wymiany na PLN (kurs średni NBP z ostatniego dnia roboczego przed datą powstania obowiązku podatkowego).' );
		}
		if ( 'PLN' === $currency_code && $total_gross > 15000.0 ) {
			$adnotacje['P_18A'] = '1';
			$markers['P_18A']   = '1';
		}

		// Auto P_18 (odwrotne obciążenie) gdy którakolwiek pozycja ma stawkę „oo".
		$has_oo_item = false;
		foreach ( $items as $it ) {
			if ( is_string( $it['vat_rate'] ) && 'oo' === strtolower( trim( $it['vat_rate'] ) ) ) {
				$has_oo_item = true;
				break;
			}
		}
		if ( $has_oo_item ) {
			$adnotacje['P_18'] = '1';
			$markers['P_18']   = '1';
		}

		// Zwolnienie z VAT — pozycja „zw" wymaga znacznika P_19 + podstawy prawnej.
		$has_zw_item = false;
		foreach ( $items as $it ) {
			if ( is_string( $it['vat_rate'] ) && 'zw' === strtolower( trim( $it['vat_rate'] ) ) ) {
				$has_zw_item = true;
				break;
			}
		}
		$exemption_basis = trim( (string) sanitize_text_field( wp_unslash( $_POST['exemption_basis'] ?? '' ) ) );
		$exemption_kind  = strtoupper( (string) sanitize_text_field( wp_unslash( $_POST['exemption_kind'] ?? 'A' ) ) );
		if ( $has_zw_item || isset( $markers['P_19'] ) ) {
			$adnotacje['P_19'] = '1';
			if ( '' === $exemption_basis ) {
				throw new \InvalidArgumentException( 'Stawka „zw" (zwolnienie z VAT) wymaga podania podstawy prawnej zwolnienia (np. art. 43 ust. 1 albo art. 113 ust. 1 i 9 ustawy o VAT).' );
			}
			$adnotacje['P_19_basis'] = $exemption_basis;
			$adnotacje['P_19_kind']  = in_array( $exemption_kind, [ 'A', 'B', 'C' ], true ) ? $exemption_kind : 'A';
		}

		// Procedura marży — typ z dedykowanego pola (jeśli formularz go dostarcza).
		$pmarzy_kind = trim( (string) sanitize_text_field( wp_unslash( $_POST['pmarzy_kind'] ?? '' ) ) );
		if ( '' !== $pmarzy_kind ) {
			$adnotacje['P_PMarzy'] = $pmarzy_kind;
		}

		// WDT nowych środków transportu (P_22) — dane pojazdu lądowego (jeśli podane).
		$nst_payload = [];
		$nst_date    = trim( (string) sanitize_text_field( wp_unslash( $_POST['nst_data_dopuszczenia'] ?? '' ) ) );
		if ( isset( $markers['P_22'] ) && '' !== $nst_date ) {
			$nst_payload = [
				'data_dopuszczenia' => $nst_date,
				'przebieg'          => trim( (string) sanitize_text_field( wp_unslash( $_POST['nst_przebieg'] ?? '' ) ) ),
				'vin'               => trim( (string) sanitize_text_field( wp_unslash( $_POST['nst_vin'] ?? '' ) ) ),
			];
		}

		$period_from = trim( (string) sanitize_text_field( wp_unslash( $_POST['period_from'] ?? '' ) ) );
		$period_to   = trim( (string) sanitize_text_field( wp_unslash( $_POST['period_to'] ?? '' ) ) );

		// Dokumenty powiązane
		$related_docs = [];
		$rel_order_no = trim( (string) sanitize_text_field( wp_unslash( $_POST['rel_order_no'] ?? '' ) ) );
		if ( $rel_order_no !== '' ) {
			$related_docs['order'] = [
				'number' => $rel_order_no,
				'date'   => (string) sanitize_text_field( wp_unslash( $_POST['rel_order_date'] ?? '' ) ),
			];
		}
		$rel_wz_no = trim( (string) sanitize_text_field( wp_unslash( $_POST['rel_wz_no'] ?? '' ) ) );
		if ( $rel_wz_no !== '' ) {
			$related_docs['wz'] = [ 'number' => $rel_wz_no ];
		}

		// Dane dodatkowe
		$customer_no_val = trim( (string) sanitize_text_field( wp_unslash( $_POST['customer_no'] ?? ( $contractor['customer_no'] ?? '' ) ) ) );
		$extra_data = [
			'customer_no' => $customer_no_val,
			'issue_place' => trim( (string) sanitize_text_field( wp_unslash( $_POST['issue_place'] ?? '' ) ) ) ?: (string) ( $cred_row['seller_city'] ?? '' ),
		];
		// Wstrzykuj customer_no do buyer — Fa3_Builder emituje NrKlienta jako dziecko Podmiot2 (nie Fa)
		if ( $customer_no_val !== '' ) {
			$buyer['customer_no'] = $customer_no_val;
		}

		// Delivery address
		$delivery_address = null;
		if ( ! empty( $_POST['delivery_name'] ) || ! empty( $_POST['delivery_street'] ) || ! empty( $_POST['delivery_city'] ) ) {
			$delivery_address = [
				'name'        => trim( (string) sanitize_text_field( wp_unslash( $_POST['delivery_name'] ?? '' ) ) ),
				'street'      => trim( (string) sanitize_text_field( wp_unslash( $_POST['delivery_street'] ?? '' ) ) ),
				'postal_code' => trim( (string) sanitize_text_field( wp_unslash( $_POST['delivery_postal'] ?? '' ) ) ),
				'city'        => trim( (string) sanitize_text_field( wp_unslash( $_POST['delivery_city'] ?? '' ) ) ),
				'country'     => strtoupper( (string) sanitize_text_field( wp_unslash( $_POST['delivery_country'] ?? 'PL' ) ) ),
			];
		}

		$internal_notes = trim( (string) sanitize_textarea_field( wp_unslash( $_POST['internal_notes'] ?? '' ) ) );

		// KSeF custom key-value notes
		$ksef_notes_raw = (array) map_deep( wp_unslash( $_POST['ksef_notes'] ?? [] ), 'sanitize_text_field' );
		$ksef_notes     = [];
		foreach ( $ksef_notes_raw as $kv ) {
			$k = trim( (string) ( $kv['key'] ?? '' ) );
			$v = trim( (string) ( $kv['value'] ?? '' ) );
			if ( $k !== '' && $v !== '' ) {
				$ksef_notes[] = [ 'key' => $k, 'value' => $v ];
			}
		}

		// Deposit / kaucja
		$deposit_amount = 0.0;
		$deposit_label  = '';
		if ( ! empty( $_POST['deposit_toggle'] ) ) {
			$deposit_amount = round( floatval( wp_unslash( $_POST['deposit_amount'] ?? 0 ) ), 2 );
			$deposit_label  = trim( (string) sanitize_text_field( wp_unslash( $_POST['deposit_label'] ?? '' ) ) );
		}

		// Bank account
		$bank_account_id = intval( wp_unslash( $_POST['bank_account_id'] ?? 0 ) );
		$bank_account    = null;
		if ( $bank_account_id > 0 ) {
			$bank_account = $wpdb->get_row(
				$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gksef_bank_accounts WHERE id = %d", $bank_account_id ),
				ARRAY_A
			);
		}

		// Total brutto z kaucją (do zapłaty)
		$pay_amount = round( $total_gross + $deposit_amount, 2 );

		// Korekta — gdy formularz wystawia fakturę korygującą
		$correction   = null;
		$rodzaj       = 'VAT';
		$correct_of_id = intval( wp_unslash( $_POST['correct_of_id'] ?? 0 ) );
		if ( $correct_of_id > 0 ) {
			$orig = $wpdb->get_row(
				$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gksef_outgoing_invoices WHERE id = %d", $correct_of_id ),
				ARRAY_A
			);
			if ( $orig ) {
				$orig_payload = ! empty( $orig['payload_json'] ) ? json_decode( (string) \KSEF\WordPress\Crypto::decrypt_from_storage( $orig['payload_json'] ), true ) : [];
				// Podtyp korekty wg rodzaju faktury pierwotnej: VAT/UPR→KOR, ZAL→KOR_ZAL, ROZ→KOR_ROZ.
				$orig_rodzaj = strtoupper( (string) ( $orig_payload['rodzaj_faktury'] ?? '' ) );
				if ( '' === $orig_rodzaj ) {
					$oxml = (string) \KSEF\WordPress\Crypto::decrypt_from_storage( (string) ( $orig['generated_xml'] ?? '' ) );
					if ( preg_match( '#RodzajFaktury>([A-Z_]+)<#', $oxml, $om ) ) {
						$orig_rodzaj = $om[1];
					}
				}
				$rodzaj       = match ( $orig_rodzaj ) {
					'ZAL', 'KOR_ZAL' => 'KOR_ZAL',
					'ROZ', 'KOR_ROZ' => 'KOR_ROZ',
					default          => 'KOR',
				};
				$correction   = [
					'reason'               => trim( (string) sanitize_text_field( wp_unslash( $_POST['correction_reason'] ?? '' ) ) ),
					'type'                 => '1',
					'original_id'          => (int) $orig['id'],
					'original_number'      => (string) ( $orig['invoice_number'] ?? '' ),
					'original_date'        => (string) ( $orig_payload['issue_date'] ?? gmdate( 'Y-m-d', strtotime( (string) $orig['created_at'] ) ) ),
					'original_ksef_number' => (string) ( $orig['ksef_reference_number'] ?? '' ),
				];
			}
		}

		return [
			'seller'           => $seller,
			'buyer'            => $buyer,
			'contractor_id'    => $contractor_id,
			'is_b2c'           => $is_b2c,
			'currency'         => (string) sanitize_text_field( wp_unslash( $_POST['currency'] ?? 'PLN' ) ),
			'exchange_rate'      => $exchange_rate,
			'exchange_rate_date' => $exchange_rate_date,
			'invoice_number'   => $invoice_number,
			'issue_date'       => (string) sanitize_text_field( wp_unslash( $_POST['issue_date'] ?? gmdate( 'Y-m-d' ) ) ),
			'sale_date'        => (string) sanitize_text_field( wp_unslash( $_POST['sale_date'] ?? $_POST['issue_date'] ?? gmdate( 'Y-m-d' ) ) ),
			'rodzaj_faktury'   => $rodzaj,
			'correction'       => $correction,
			'items'            => $items,
			'vat_summary'      => array_values( $vat_buckets ),
			'total_net'        => round( $total_net, 2 ),
			'total_vat'        => round( $total_gross - $total_net, 2 ),
			'total_gross'      => round( $total_gross, 2 ),
			'deposit_amount'   => $deposit_amount,
			'deposit_label'    => $deposit_label,
			'total_payable'    => $pay_amount,
			'adnotacje'        => $adnotacje,
			'markers'          => $markers,
			'nst'              => $nst_payload,
			'period_from'      => $period_from,
			'period_to'        => $period_to,
			'related_docs'     => $related_docs,
			'extra_data'       => $extra_data,
			'delivery_address' => $delivery_address,
			'notes'            => $internal_notes, // legacy: visible only locally
			'internal_notes'   => $internal_notes,
			'ksef_custom_notes' => $ksef_notes,
			'bank_account'     => $bank_account,
			'payment'          => [
				// FA(3) TFormaPlatnosci dopuszcza tylko 1–7. Normalizujemy (legacy 9/10/99/8 → poprawny kod).
				'form'     => ( static function ( string $c ): string {
					return in_array( $c, [ '1', '2', '3', '4', '5', '6', '7' ], true ) ? $c : ( [ '9' => '3', '10' => '4', '99' => '6', '8' => '6' ][ $c ] ?? '6' );
				} )( (string) sanitize_text_field( wp_unslash( $_POST['payment_form'] ?? '6' ) ) ),
				'paid'     => $paid_in_full ? round( $pay_amount, 2 ) : 0.0,
				'partial'  => $partial_payments,
				'due_date' => (string) sanitize_text_field( wp_unslash( $_POST['payment_due'] ?? gmdate( 'Y-m-d', strtotime( '+14 days' ) ) ) ),
			],
		];
	}
}
