{{-- Themed file picker: the wireframe's upload zone (docs/wireframes-v12/add-project.html ~line 310) — a dashed, clickable area — with the real hidden inside it, plus the current-file row an edit screen needs. The zone and the current-file row were already built to the wireframe's own class names (`.upload-zone`, `.uploaded-file` and its `.file-icon` / `.file-details` / `.file-name` / `.file-meta` / `.file-actions` children); CR-2 checked all of them against v12's style.css and they match 1:1, so the only change here is the download button's variant (see below). Props: name Field name, in HTML form. Required. label Label text, rendered by the shared group above the zone. accept The `accept` attribute — a filter, never a control: the server rules in the FormRequest are what actually decide. hint The types-and-size line, e.g. "PDF, JPG, PNG · max 5 MB". Rendered *inside* the zone as the wireframe has it. required Red asterisk on the label + the `required` attribute. icon FontAwesome classes for the zone icon. Defaults to the upload cloud; the wireframe varies it per slot. current-name The stored *original* client filename on an edit screen. Attacker-controlled (§5 stores it verbatim), so it is rendered as escaped text and never as raw markup. current-url Download href for that file. The current-file row appears only when both halves are given — a name with no link is a dead end, a link with no name has nothing to label it. max-kb The slot's size cap in kilobytes, which arms the client-side guard: the input gets `data-max-kb` and the already-translated message to show, and nrems-upload-guard.js clears an over-cap pick before it can be submitted. Pass ProjectFileSlot::maxKilobytes() (or whatever enum owns the rule), never a literal — the `max:` rule in the FormRequest comes from the same method, and the server stays the one that decides. Omitted, no attribute is emitted and no guard runs. max-label How that cap reads in the message, e.g. "10 MB". Comes from the same enum (ProjectFileSlot::maxLabel()); left out, it is derived from max-kb the same way, which is the fallback for a caller with no enum behind it. group-class Extra classes for the wrapper, e.g. "col-md-6". Everything else — data-*, multiple, capture — passes through to the input. One caveat on `multiple`: nrems-upload-guard.js checks files[0] alone, so a multi-file slot needs the guard extended (loop, and a decision about what the cap means across a set) before the attribute is passed here — otherwise the second file a user picks is never size-checked. A file input cannot be repopulated from old input: after a failed submit the browser has no way to re-attach the user's file and the field comes back empty. So there is no :value prop and no old-input resolution here; what matters is that the *error* renders and the rest of the form keeps its values, which it does because every other field resolves old() as usual. The consequence for the user — re-pick the file — is the browser's rule, not something this component can work around. The prompt is an
because the wireframe styles `.upload-zone h5` and nothing else — the size and weight come from that selector. The cost is a real heading in the document outline for every zone (four meaningless stops on the project form when a screen-reader user navigates by heading); worth knowing before a screen grows a fifth. Accessibility: the zone is a