### Added

- Dedicated log file `var/log/punchout.log` (Monolog channel `punchout`, virtual type
  `ConneqtPunchoutLogger` in `etc/di.xml`) for everything the module logs. Error-level records are
  also handed to Magento's main logger, so `exception.log`/`system.log` alerting still sees them.
- Every login, setup request, session start, checkout redirect and cart return now logs its outcome
  with the flow, step and record ids, and every rejection says why (unknown identity, wrong
  password/shared secret, undecryptable secret, missing customer, website mismatch, stale or reused
  StartPage URL, empty cart, missing parameters, unreadable setup request). Many of these paths
  were silent before, e.g. `createsession` answered "Login token invalid." for three different
  causes without logging any of them.
- `conneqt_punchout_requestlog.status_message`: the rejection or failure reason, shown with the new
  **Status Message** and **Link ID** columns in the admin Request Log grid.
- Admin toggle **Log Full Payloads** (`conneqt_punchout_section/logging/payload_logging`, default
  off): also logs each full inbound and outbound payload at debug level, secrets masked, capped at
  64 KB.

### Fixed

- cXML punch-outs can log in again. Since `0.5.0` the request log stores the PunchOutSetupRequest
  with its `<SharedSecret>` masked, but `createsession` re-ran the full credential check on that
  stored copy, so the masked value never matched and every cXML session start (real traffic and
  the admin "Start Test Round-Trip" alike) ended in "There was an error trying to login."
  with `Invalid login details to login customer` in the log and the row stuck at
  `session_status = 3`. Auth now records the matched link on the new
  `requestlog.punchoutlink_id` column, and `createsession` logs that link's customer in via
  `Helper\CxmlLogin::loginAuthenticatedLink()` instead of comparing the secret again. The link's
  protocol, customer and website scope are still re-checked. OCI logins were not affected.

### Changed

- Log messages follow one format, `Punchout <flow> <step>: <what happened>`, with fixed context keys
  (`requestlog_id`, `punchoutlink_id`, `customer_id`, `reason`, ...). Buyer-supplied values are
  JSON-quoted and capped at 100 characters so they cannot forge log lines; buyer-system URLs are
  logged without their query string. Refused requests are logged at warning level, our own
  failures at error level. The simple-product-name fallback in `SnapshotBuilder` moved from debug
  to warning.
- `RequestLogInterface` gained `getPunchoutlinkId()` / `setPunchoutlinkId()` and
  `getStatusMessage()` / `setStatusMessage()`; custom implementations of that interface must add
  them. `Helper\Login` and `Helper\CxmlLogin` take a new `PayloadLogger` constructor argument, and
  `Helper\Login::registerRequestLog()` an optional 5th `$statusMessage` argument; subclasses that
  call `parent::__construct()` must pass it. `Helper\Data`'s constructor is unchanged. `setup:upgrade` adds the nullable
  `punchoutlink_id` column. **Flush the cache after upgrading** (at least `db_ddl`): Magento
  keeps the table's cached column list from before the upgrade, so until the flush every save
  silently drops `punchoutlink_id` and cXML session starts keep failing with "Login token invalid.".