Merge: t-paliad-157 Determinator Slice 1 — project picker + do/happened bifurcation

df04e50 — feat(fristenrechner/determinator): the legacy "Was möchten
Sie tun?" landing fork is replaced by:

  Step 1: filtered Akte picker + "Neue Akte anlegen" link (bare; the
    bounce-back to the wizard after creation is Slice 2 scope) +
    4 ad-hoc chips driving ?ad_hoc=upc|de|epa|dpma.
  Step 2: "Etwas einreichen" / "Etwas ist passiert" cards driving
    showPathway('a' | 'b'). Quick-pick chips moved here from the old
    fork. Pathway A/B back buttons return to Step 2.

Save CTA on Pathway A's wizard disables in ad-hoc mode with hint
"Ad-hoc — kein Projekt, kein Speichern" (DE+EN). The locked context
collapses to a one-line summary; Reselect re-expands.

URL contract:
  ?project=<uuid> | ?ad_hoc=upc|de|epa|dpma  — Step 1 result
  ?path=a|b                                   — Step 2 result (back-compat)
  ?mode=tree|filter                           — Pathway B sub-mode

Pathway A/B sub-routing primitives (showPathway, showBMode) unchanged
— Step 2 cards just drive the same hooks.

Still open:
  Slice 2 — /projects/new return-bounce on save.
  Slice 3+ — scoping the picker / cascade by project's proceeding-type
    + role; replacing the wizard with the Step 3a File/Draft/Enter
    chooser.
This commit is contained in:
m
2026-05-08 19:52:32 +02:00
5 changed files with 665 additions and 31 deletions

View File

@@ -494,7 +494,22 @@ function renderProcedureResults(data: DeadlineResponse) {
container.innerHTML = headerHtml + bodyHtml;
printBtn.style.display = "block";
if (saveBtn) saveBtn.style.display = "block";
if (saveBtn) {
// Ad-hoc explore-mode has no project to save against — show the
// CTA disabled with a hint so the user understands why the action
// is blocked (m's 2026-05-08 Slice 1 lock #2). Hiding it would
// leave the user wondering where the save went.
saveBtn.style.display = "block";
if (isAdhocMode()) {
saveBtn.disabled = true;
saveBtn.title = t("deadlines.save.cta.adhoc.hint");
saveBtn.dataset.adhocDisabled = "true";
} else {
saveBtn.disabled = false;
saveBtn.removeAttribute("title");
delete saveBtn.dataset.adhocDisabled;
}
}
if (toggle) toggle.style.display = "";
applyPendingFocus();
@@ -2325,12 +2340,31 @@ function setPathwayURL(path: Pathway, mode?: BMode, replace = false) {
}
function showPathway(path: Pathway, mode?: BMode) {
const fork = document.getElementById("fristen-pathway-fork");
// m's 2026-05-08 18:08 redesign retired the legacy fork; Step 1 and
// Step 2 sit where it used to live. The "fork" Pathway value now
// means "show Step 1 + Step 2 (Step 2 visibility gated by whether a
// project / ad-hoc context is selected — managed by initStep1Step2)";
// "a" / "b" still drive the existing wizard / cascade shells.
const step1 = document.getElementById("fristen-step1");
const step1Summary = document.getElementById("fristen-step1-summary");
const step2 = document.getElementById("fristen-step2");
const a = document.getElementById("fristen-pathway-a");
const b = document.getElementById("fristen-pathway-b");
if (!fork || !a || !b) return;
if (!a || !b) return;
fork.hidden = path !== "fork";
// Step 1 + 2 stay mounted under "fork". Step 2 visibility is also
// gated by the Step 1 context state — initStep1Step2 owns the
// toggle between Step 1 expanded vs collapsed-with-summary, and
// the "show Step 2" gate. We just hide them wholesale when not on
// the fork.
if (step1) step1.style.display = path === "fork" ? "" : "none";
if (step1Summary) {
// Summary stays visible from Step 2 onward so the user always
// sees their selected Akte. Hidden only when no context is set.
const ctx = readStep1ContextFromURL();
step1Summary.style.display = (ctx.kind !== "none" && path !== "fork") ? "" : step1Summary.style.display;
}
if (step2) step2.hidden = path !== "fork";
a.hidden = path !== "a";
b.hidden = path !== "b";
@@ -2374,29 +2408,226 @@ function navigateToPathway(path: Pathway, mode?: BMode) {
}
}
// ============================================================================
// m's 2026-05-08 18:08 Determinator redesign — Step 1 + Step 2 state
// ============================================================================
// Step 1: pick the project (Akte) that scopes everything downstream, OR
// pick an ad-hoc explore-mode chip (4 jurisdictions). Step 2: choose
// between outgoing intent (Pathway A / Verfahrensablauf) and incoming
// event (Pathway B / cascade). Step 3+ stay as today (Pathway A wizard,
// B1 cascade, B2 search). The legacy "Was möchten Sie tun?" fork is
// retired; back-buttons inside Pathway A/B return to Step 2.
type Step1ContextKind = "project" | "adhoc" | "none";
type AdhocForum = "upc" | "de" | "epa" | "dpma";
interface Step1Context {
kind: Step1ContextKind;
projectId?: string;
project?: ProjectOption;
adhocForum?: AdhocForum;
}
let currentStep1Context: Step1Context = { kind: "none" };
let cachedAkten: ProjectOption[] = [];
function readStep1ContextFromURL(): Step1Context {
const sp = new URLSearchParams(window.location.search);
const project = sp.get("project");
const adhoc = sp.get("ad_hoc");
if (project) return { kind: "project", projectId: project };
if (adhoc === "upc" || adhoc === "de" || adhoc === "epa" || adhoc === "dpma") {
return { kind: "adhoc", adhocForum: adhoc };
}
return { kind: "none" };
}
function writeStep1ContextToURL(ctx: Step1Context, replace = false) {
const url = new URL(window.location.href);
if (ctx.kind === "project" && ctx.projectId) {
url.searchParams.set("project", ctx.projectId);
url.searchParams.delete("ad_hoc");
} else if (ctx.kind === "adhoc" && ctx.adhocForum) {
url.searchParams.set("ad_hoc", ctx.adhocForum);
url.searchParams.delete("project");
} else {
url.searchParams.delete("project");
url.searchParams.delete("ad_hoc");
}
if (replace) window.history.replaceState({}, "", url.toString());
else window.history.pushState({}, "", url.toString());
}
// isAdhocMode is read by the save-to-project CTA — ad-hoc has no
// project to save against, so the CTA disables and renders a hint.
function isAdhocMode(): boolean {
return currentStep1Context.kind === "adhoc";
}
function adhocSummaryLabel(forum: AdhocForum): string {
switch (forum) {
case "upc": return "Ad-hoc UPC";
case "de": return "Ad-hoc DE";
case "epa": return "Ad-hoc EPA";
case "dpma": return "Ad-hoc DPMA";
}
}
function renderAkteList(query: string) {
const list = document.getElementById("fristen-akte-list");
if (!list) return;
const q = query.trim().toLowerCase();
const filtered = q === ""
? cachedAkten.slice(0, 12)
: cachedAkten.filter((p) =>
(p.title || "").toLowerCase().includes(q) ||
(p.reference || "").toLowerCase().includes(q));
if (filtered.length === 0) {
list.innerHTML = `<li class="fristen-akte-list-empty">${escHtml(t("deadlines.step1.search.empty"))}</li>`;
return;
}
list.innerHTML = filtered.map((p) => {
const ref = p.reference ? `<span class="fristen-akte-list-ref">${escHtml(p.reference)}</span> · ` : "";
return `<li><button type="button" class="fristen-akte-list-item" data-project-id="${escAttr(p.id)}">
${ref}<span class="fristen-akte-list-title">${escHtml(p.title)}</span>
</button></li>`;
}).join("");
list.querySelectorAll<HTMLButtonElement>(".fristen-akte-list-item").forEach((btn) => {
btn.addEventListener("click", () => {
const id = btn.dataset.projectId!;
const project = cachedAkten.find((p) => p.id === id);
if (project) selectProject(project);
});
});
}
function selectProject(project: ProjectOption) {
currentStep1Context = { kind: "project", projectId: project.id, project };
writeStep1ContextToURL(currentStep1Context);
renderStep1Summary();
showStep2Card();
}
function selectAdhoc(forum: AdhocForum) {
currentStep1Context = { kind: "adhoc", adhocForum: forum };
writeStep1ContextToURL(currentStep1Context);
renderStep1Summary();
showStep2Card();
}
function clearStep1Context() {
currentStep1Context = { kind: "none" };
writeStep1ContextToURL(currentStep1Context);
renderStep1Summary();
hideStep2Card();
}
function renderStep1Summary() {
const summary = document.getElementById("fristen-step1-summary") as HTMLElement | null;
const name = document.getElementById("fristen-step1-summary-name");
const meta = document.getElementById("fristen-step1-summary-meta");
const step1 = document.getElementById("fristen-step1") as HTMLElement | null;
if (!summary || !name || !step1) return;
if (currentStep1Context.kind === "none") {
summary.style.display = "none";
step1.style.display = "";
return;
}
if (currentStep1Context.kind === "project" && currentStep1Context.project) {
const p = currentStep1Context.project;
const ref = p.reference ? p.reference + " · " : "";
name.textContent = ref + p.title;
if (meta) meta.textContent = "";
} else if (currentStep1Context.kind === "adhoc" && currentStep1Context.adhocForum) {
name.textContent = adhocSummaryLabel(currentStep1Context.adhocForum);
if (meta) meta.textContent = " · " + t("deadlines.step1.summary.adhoc.suffix");
}
summary.style.display = "";
step1.style.display = "none";
}
function showStep2Card() {
const step2 = document.getElementById("fristen-step2");
if (step2) step2.hidden = false;
}
function hideStep2Card() {
const step2 = document.getElementById("fristen-step2");
if (step2) step2.hidden = true;
}
function initPathwayFork() {
// Set chip labels to active language before user sees them.
relabelChips();
// Initial render from URL (or saved preference if URL is bare).
// Hydrate Step 1 context from URL first — Step 2 visibility depends
// on whether a project / ad-hoc chip is already locked in.
currentStep1Context = readStep1ContextFromURL();
// Initial Pathway render. Inherits the URL ?path= semantic — Step 2
// having been satisfied is implied if path = a / b.
const initial = readPathwayFromURL();
const initialMode = readBModeFromURL();
showPathway(initial, initialMode);
// Persist initial choice from URL.
// Step 1 summary visibility flows from the context kind.
renderStep1Summary();
if (currentStep1Context.kind !== "none") {
showStep2Card();
}
if (initial !== "fork") {
try { localStorage.setItem(PATHWAY_STORAGE_KEY, initial); } catch { /* */ }
}
// Click handlers on the two fork cards.
document.getElementById("fristen-pathway-a-cta")?.addEventListener("click", () => {
// Step 1 — fetch projects + render filtered list. Search filters the
// list in-place; click on a row drops the user into Step 2.
void (async () => {
cachedAkten = await fetchProjects();
if (currentStep1Context.kind === "project" && currentStep1Context.projectId) {
currentStep1Context.project = cachedAkten.find((p) => p.id === currentStep1Context.projectId);
renderStep1Summary();
}
renderAkteList("");
})();
const akteSearch = document.getElementById("fristen-akte-search") as HTMLInputElement | null;
if (akteSearch) {
akteSearch.addEventListener("input", () => renderAkteList(akteSearch.value));
}
// Ad-hoc chips — explore-mode escape hatch. No DB write; the
// save-modal CTA disables itself in this state.
document.querySelectorAll<HTMLButtonElement>(".fristen-adhoc-chip").forEach((chip) => {
chip.addEventListener("click", () => {
const forum = chip.dataset.adHoc as AdhocForum | undefined;
if (forum) selectAdhoc(forum);
});
});
// Reselect: drop the locked context, return to Step 1.
document.getElementById("fristen-step1-summary-reselect")?.addEventListener("click", () => {
clearStep1Context();
// Bounce back to fork (Step 1 + 2) so the user sees the picker,
// even if they were currently in Pathway A or B.
if (initial !== "fork") {
navigateToPathway("fork");
}
});
// Step 2 cards — outgoing (Pathway A wizard) vs incoming (Pathway B
// cascade). showPathway() owns the actual A/B transition; we just
// drive it from the action choice.
document.getElementById("fristen-step2-file")?.addEventListener("click", () => {
navigateToPathway("a");
});
document.getElementById("fristen-pathway-b-cta")?.addEventListener("click", () => {
// Default to tree mode on first entry to Pathway B.
document.getElementById("fristen-step2-happened")?.addEventListener("click", () => {
navigateToPathway("b", "tree");
});
// Back-to-fork buttons inside each pathway shell.
// Back-from-Pathway buttons return to Step 2 (the new "fork" state).
document.getElementById("fristen-pathway-a-back")?.addEventListener("click", () => {
navigateToPathway("fork");
});
@@ -2415,7 +2646,9 @@ function initPathwayFork() {
});
});
// Quick-pick chips on the fork shortcut row → jump straight to Pathway B + filter mode + prefilled query.
// Quick-pick chips on the Step 2 shortcut row → jump straight to
// Pathway B + filter mode + prefilled query. Same behaviour as the
// legacy fork; only the ID's mounting point changed.
document.querySelectorAll<HTMLButtonElement>("#fristen-fork-chips .fristen-search-chip").forEach((chip) => {
chip.addEventListener("click", () => {
const q = chipQueryFor(chip);
@@ -2425,8 +2658,6 @@ function initPathwayFork() {
if (q) url.searchParams.set("q", q);
window.history.pushState({}, "", url.toString());
showPathway("b", "filter");
// initSearch listens for popstate, but we used pushState; sync the
// search input directly.
const input = document.getElementById("fristen-search-input") as HTMLInputElement | null;
if (input && q) {
input.value = q;
@@ -2435,8 +2666,14 @@ function initPathwayFork() {
});
});
// Browser back/forward should restore pathway state.
// Browser back/forward restores pathway + Step 1 context.
window.addEventListener("popstate", () => {
currentStep1Context = readStep1ContextFromURL();
if (currentStep1Context.kind === "project" && currentStep1Context.projectId) {
currentStep1Context.project = cachedAkten.find((p) => p.id === currentStep1Context.projectId);
}
renderStep1Summary();
if (currentStep1Context.kind !== "none") showStep2Card(); else hideStep2Card();
const path = readPathwayFromURL();
const mode = readBModeFromURL();
showPathway(path, mode);

View File

@@ -247,6 +247,25 @@ const translations: Record<Lang, Record<string, string>> = {
"deadlines.optional.badge": "auf Antrag",
"deadlines.proceeding.selected": "Verfahren:",
"deadlines.proceeding.reselect": "Anderes Verfahren wählen",
"deadlines.step1.heading": "Schritt 1 — Welche Akte?",
"deadlines.step1.search.placeholder": "Akte suchen…",
"deadlines.step1.search.empty": "Keine passende Akte gefunden.",
"deadlines.step1.divider.new": "oder eine neue Akte",
"deadlines.step1.divider.adhoc": "oder ad-hoc, ohne Akte",
"deadlines.step1.new.cta": "+ Neue Akte anlegen",
"deadlines.step1.adhoc.upc": "Custom UPC-Verfahren",
"deadlines.step1.adhoc.de": "Custom DE-Verfahren",
"deadlines.step1.adhoc.epa": "Custom EPA-Verfahren",
"deadlines.step1.adhoc.dpma": "Custom DPMA-Verfahren",
"deadlines.step1.selected": "Akte:",
"deadlines.step1.reselect": "Andere Akte",
"deadlines.step1.summary.adhoc.suffix": "ohne Akte (Erkundung)",
"deadlines.step2.heading": "Schritt 2 — Was möchten Sie tun?",
"deadlines.step2.file.title": "Etwas einreichen",
"deadlines.step2.file.desc": "Outgoing — eine Frist tritt aus eigener Handlung ein.",
"deadlines.step2.happened.title": "Etwas ist passiert",
"deadlines.step2.happened.desc": "Incoming — ein Ereignis hat eine Frist ausgelöst.",
"deadlines.save.cta.adhoc.hint": "Ad-hoc — kein Projekt, kein Speichern",
"deadlines.date.edit.hint": "Datum bearbeiten — Folgefristen werden neu berechnet",
"deadlines.view.label": "Ansicht:",
"deadlines.view.timeline": "Zeitstrahl",
@@ -2324,6 +2343,25 @@ const translations: Record<Lang, Record<string, string>> = {
"deadlines.optional.badge": "on request",
"deadlines.proceeding.selected": "Proceeding:",
"deadlines.proceeding.reselect": "Choose another proceeding",
"deadlines.step1.heading": "Step 1 — Which matter?",
"deadlines.step1.search.placeholder": "Search matters…",
"deadlines.step1.search.empty": "No matching matter.",
"deadlines.step1.divider.new": "or a new matter",
"deadlines.step1.divider.adhoc": "or ad-hoc, without a matter",
"deadlines.step1.new.cta": "+ Create new matter",
"deadlines.step1.adhoc.upc": "Custom UPC proceeding",
"deadlines.step1.adhoc.de": "Custom DE proceeding",
"deadlines.step1.adhoc.epa": "Custom EPA proceeding",
"deadlines.step1.adhoc.dpma": "Custom DPMA proceeding",
"deadlines.step1.selected": "Matter:",
"deadlines.step1.reselect": "Other matter",
"deadlines.step1.summary.adhoc.suffix": "no matter (exploration)",
"deadlines.step2.heading": "Step 2 — What do you want to do?",
"deadlines.step2.file.title": "File something",
"deadlines.step2.file.desc": "Outgoing — your action triggers a deadline.",
"deadlines.step2.happened.title": "Something happened",
"deadlines.step2.happened.desc": "Incoming — an event triggered a deadline.",
"deadlines.save.cta.adhoc.hint": "Ad-hoc — no matter, no save",
"deadlines.date.edit.hint": "Edit date — downstream deadlines will recalculate",
"deadlines.view.label": "View:",
"deadlines.view.timeline": "Timeline",

View File

@@ -112,27 +112,99 @@ export function renderFristenrechner(): string {
</p>
</div>
{/* v3 landing fork (t-paliad-133) — visible by default, hidden once
the user picks a pathway. URL ?path= drives visibility. */}
<div className="fristen-pathway-fork" id="fristen-pathway-fork" role="group" aria-label="Pathway selector">
<h2 className="fristen-pathway-fork-heading" data-i18n="deadlines.pathway.fork.heading">Was m&ouml;chten Sie tun?</h2>
<div className="fristen-pathway-fork-cards">
<button type="button" className="fristen-pathway-card" data-path="a" id="fristen-pathway-a-cta">
<span className="fristen-pathway-card-icon" aria-hidden="true">&#128214;</span>
<span className="fristen-pathway-card-title" data-i18n="deadlines.pathway.a.title">Verfahrensablauf informieren</span>
<span className="fristen-pathway-card-desc" data-i18n="deadlines.pathway.a.desc">
Verfahrenstyp w&auml;hlen und alle dazugeh&ouml;rigen Fristen auf einer Zeitleiste sehen.
{/* m's 2026-05-08 18:08 Determinator redesign — Step 1: pick the
Akte (project) that scopes the rest of the flow. Filtered
list of visible projects + "Neue Akte anlegen" link +
four ad-hoc explore-mode chips for users who just want to
look up a rule without saving anywhere. */}
<div className="fristen-step1" id="fristen-step1" role="group" aria-label="Akte picker">
<h2 className="fristen-step-heading" data-i18n="deadlines.step1.heading">
Schritt 1 &mdash; Welche Akte?
</h2>
<div className="fristen-step1-search-row">
<svg className="fristen-search-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<circle cx="11" cy="11" r="7"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
</svg>
<input type="search" id="fristen-akte-search"
className="fristen-akte-search" autocomplete="off"
data-i18n-placeholder="deadlines.step1.search.placeholder"
placeholder="Akte suchen&hellip;" />
</div>
<ul className="fristen-akte-list" id="fristen-akte-list" role="listbox" aria-label="Akten"></ul>
<div className="fristen-step1-divider">
<span data-i18n="deadlines.step1.divider.new">oder eine neue Akte</span>
</div>
<a href="/projects/new" className="fristen-step1-new" id="fristen-step1-new"
data-i18n="deadlines.step1.new.cta">
+ Neue Akte anlegen
</a>
<div className="fristen-step1-divider">
<span data-i18n="deadlines.step1.divider.adhoc">oder ad-hoc, ohne Akte</span>
</div>
<div className="fristen-adhoc-chips" role="group" aria-label="Ad-hoc proceeding">
<button type="button" className="fristen-adhoc-chip" data-ad-hoc="upc"
data-i18n="deadlines.step1.adhoc.upc">
Custom UPC proceeding
</button>
<button type="button" className="fristen-adhoc-chip" data-ad-hoc="de"
data-i18n="deadlines.step1.adhoc.de">
Custom DE proceeding
</button>
<button type="button" className="fristen-adhoc-chip" data-ad-hoc="epa"
data-i18n="deadlines.step1.adhoc.epa">
Custom EPA proceeding
</button>
<button type="button" className="fristen-adhoc-chip" data-ad-hoc="dpma"
data-i18n="deadlines.step1.adhoc.dpma">
Custom DPMA proceeding
</button>
</div>
</div>
{/* Step 1 collapsed summary, shown after a pick. Mirrors the
proceeding-summary collapse pattern from 097e21c. */}
<div className="fristen-step1-summary" id="fristen-step1-summary" style="display:none" role="group">
<span className="fristen-step1-summary-label" data-i18n="deadlines.step1.selected">Akte:</span>
<strong className="fristen-step1-summary-name" id="fristen-step1-summary-name">&mdash;</strong>
<span className="fristen-step1-summary-meta" id="fristen-step1-summary-meta"></span>
<button type="button" className="fristen-step1-summary-reselect" id="fristen-step1-summary-reselect"
data-i18n="deadlines.step1.reselect">
Andere Akte
</button>
</div>
{/* Step 2 — Do / Happened bifurcation. Hidden until Step 1 is
satisfied. Click on a card routes to the existing Pathway A
(Verfahrensablauf wizard) or Pathway B (cascade) shells —
we keep the routing primitive in showPathway()/showBMode(). */}
<div className="fristen-step2" id="fristen-step2" hidden>
<h2 className="fristen-step-heading" data-i18n="deadlines.step2.heading">
Schritt 2 &mdash; Was m&ouml;chten Sie tun?
</h2>
<div className="fristen-step2-cards">
<button type="button" className="fristen-step2-card" data-action="file" id="fristen-step2-file">
<span className="fristen-step2-card-icon" aria-hidden="true">&#9999;&#65039;</span>
<span className="fristen-step2-card-title" data-i18n="deadlines.step2.file.title">
Etwas einreichen
</span>
<span className="fristen-step2-card-desc" data-i18n="deadlines.step2.file.desc">
Outgoing &mdash; eine Frist tritt aus eigener Handlung ein.
</span>
</button>
<button type="button" className="fristen-pathway-card" data-path="b" id="fristen-pathway-b-cta">
<span className="fristen-pathway-card-icon" aria-hidden="true">&#128197;</span>
<span className="fristen-pathway-card-title" data-i18n="deadlines.pathway.b.title">Frist eintragen aufgrund Ereignis</span>
<span className="fristen-pathway-card-desc" data-i18n="deadlines.pathway.b.desc">
Ein Ereignis ist eingetreten &mdash; ich brauche die richtige Frist f&uuml;r meine Akte.
<button type="button" className="fristen-step2-card" data-action="happened" id="fristen-step2-happened">
<span className="fristen-step2-card-icon" aria-hidden="true">&#128229;</span>
<span className="fristen-step2-card-title" data-i18n="deadlines.step2.happened.title">
Etwas ist passiert
</span>
<span className="fristen-step2-card-desc" data-i18n="deadlines.step2.happened.desc">
Incoming &mdash; ein Ereignis hat eine Frist ausgel&ouml;st.
</span>
</button>
</div>
<div className="fristen-pathway-fork-shortcut">
<div className="fristen-step2-shortcut">
<div className="fristen-pathway-fork-shortcut-label" data-i18n="deadlines.pathway.shortcut.label">
oder direkt zu einer Frist springen:
</div>

View File

@@ -898,6 +898,7 @@ export type I18nKey =
| "deadlines.proceeding.selected"
| "deadlines.reset"
| "deadlines.save.cta"
| "deadlines.save.cta.adhoc.hint"
| "deadlines.save.error"
| "deadlines.save.modal.akte"
| "deadlines.save.modal.akte.choose"
@@ -936,7 +937,25 @@ export type I18nKey =
| "deadlines.status.pending"
| "deadlines.status.waived"
| "deadlines.step1"
| "deadlines.step1.adhoc.de"
| "deadlines.step1.adhoc.dpma"
| "deadlines.step1.adhoc.epa"
| "deadlines.step1.adhoc.upc"
| "deadlines.step1.divider.adhoc"
| "deadlines.step1.divider.new"
| "deadlines.step1.heading"
| "deadlines.step1.new.cta"
| "deadlines.step1.reselect"
| "deadlines.step1.search.empty"
| "deadlines.step1.search.placeholder"
| "deadlines.step1.selected"
| "deadlines.step1.summary.adhoc.suffix"
| "deadlines.step2"
| "deadlines.step2.file.desc"
| "deadlines.step2.file.title"
| "deadlines.step2.happened.desc"
| "deadlines.step2.happened.title"
| "deadlines.step2.heading"
| "deadlines.step3"
| "deadlines.subtitle"
| "deadlines.summary.completed"

View File

@@ -6949,6 +6949,274 @@ input[type="range"]::-moz-range-thumb {
font-variant-numeric: tabular-nums;
}
/* m's 2026-05-08 Determinator redesign — Step 1 (Akte picker) + Step 2
* (Do/Happened bifurcation) sit where the legacy "Was möchten Sie tun?"
* fork used to be. */
.fristen-step-heading {
font-size: 1.05rem;
margin: 0 0 0.75rem;
color: var(--color-text, #222);
}
.fristen-step1 {
margin: 0.5rem 0 1.25rem;
}
.fristen-step1-search-row {
position: relative;
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.4rem 0.75rem;
border: 1px solid var(--color-border, #ddd);
border-radius: 0.5rem;
background: var(--color-bg, #fff);
}
.fristen-step1-search-row .fristen-search-icon {
color: var(--color-muted, #666);
flex-shrink: 0;
}
.fristen-akte-search {
flex: 1;
border: 0;
outline: 0;
background: transparent;
color: var(--color-text, #222);
font-size: 0.95rem;
padding: 0.25rem 0;
}
.fristen-akte-list {
list-style: none;
margin: 0.5rem 0 0;
padding: 0;
max-height: 280px;
overflow-y: auto;
border: 1px solid var(--color-border, #e5e5e5);
border-radius: 0.5rem;
background: var(--color-bg, #fff);
}
.fristen-akte-list li {
border-bottom: 1px solid var(--color-border, #f0f0f0);
}
.fristen-akte-list li:last-child {
border-bottom: 0;
}
.fristen-akte-list-item {
display: block;
width: 100%;
text-align: left;
padding: 0.55rem 0.85rem;
border: 0;
background: transparent;
color: var(--color-text, #222);
font-size: 0.92rem;
cursor: pointer;
}
.fristen-akte-list-item:hover {
background: var(--color-bg-subtle, #f7f7f7);
}
.fristen-akte-list-item:focus-visible {
outline: 2px solid var(--color-accent, #c6f41c);
outline-offset: -2px;
}
.fristen-akte-list-ref {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 0.85rem;
color: var(--color-muted, #666);
}
.fristen-akte-list-title {
color: var(--color-text, #222);
}
.fristen-akte-list-empty {
padding: 0.7rem 0.85rem;
color: var(--color-muted, #666);
font-size: 0.9rem;
font-style: italic;
}
.fristen-step1-divider {
display: flex;
align-items: center;
gap: 0.6rem;
margin: 1rem 0 0.5rem;
color: var(--color-muted, #666);
font-size: 0.85rem;
}
.fristen-step1-divider::before,
.fristen-step1-divider::after {
content: "";
flex: 1;
height: 1px;
background: var(--color-border, #e5e5e5);
}
.fristen-step1-new {
display: inline-block;
padding: 0.4rem 0.85rem;
border: 1px solid var(--color-border, #ddd);
border-radius: 0.5rem;
background: var(--color-bg, #fff);
color: var(--color-text, #222);
font-size: 0.9rem;
text-decoration: none;
transition: background 120ms, border-color 120ms;
}
.fristen-step1-new:hover {
background: var(--color-bg-subtle, #f4f4f4);
border-color: var(--color-text-muted, #aaa);
}
.fristen-adhoc-chips {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.fristen-adhoc-chip {
padding: 0.35rem 0.85rem;
border: 1px dashed var(--color-border, #c5c5c5);
border-radius: 9999px;
background: var(--color-bg, #fff);
color: var(--color-text-muted, #555);
font-size: 0.85rem;
cursor: pointer;
transition: background 120ms, border-color 120ms, color 120ms;
}
.fristen-adhoc-chip:hover {
background: var(--color-bg-subtle, #f4f4f4);
border-style: solid;
color: var(--color-text, #222);
}
.fristen-adhoc-chip:focus-visible {
outline: 2px solid var(--color-accent, #c6f41c);
outline-offset: 1px;
}
.fristen-step1-summary {
display: inline-flex;
align-items: center;
gap: 0.6rem;
margin: 0.5rem 0 1rem;
padding: 0.5rem 0.85rem;
border: 1px solid var(--color-border, #e5e5e5);
border-radius: 0.5rem;
background: var(--color-bg-subtle, #fafafa);
font-size: 0.95rem;
flex-wrap: wrap;
}
.fristen-step1-summary-label {
color: var(--color-muted, #666);
font-size: 0.85rem;
}
.fristen-step1-summary-name {
color: var(--color-text, #222);
}
.fristen-step1-summary-meta {
color: var(--color-muted, #666);
font-size: 0.85rem;
font-style: italic;
}
.fristen-step1-summary-reselect {
margin-left: 0.4rem;
padding: 0.2rem 0.6rem;
border: 1px solid var(--color-border, #ddd);
border-radius: 9999px;
background: var(--color-bg, #fff);
color: var(--color-text-muted, #555);
font-size: 0.8rem;
cursor: pointer;
transition: background 120ms, border-color 120ms;
}
.fristen-step1-summary-reselect:hover {
background: var(--color-bg-subtle, #f4f4f4);
border-color: var(--color-text-muted, #aaa);
}
.fristen-step1-summary-reselect:focus-visible {
outline: 2px solid var(--color-accent, #c6f41c);
outline-offset: 1px;
}
.fristen-step2 {
margin: 0.75rem 0 1.25rem;
}
.fristen-step2-cards {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.75rem;
}
@media (max-width: 600px) {
.fristen-step2-cards { grid-template-columns: 1fr; }
}
.fristen-step2-card {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 0.4rem;
padding: 1rem 1.1rem;
border: 1px solid var(--color-border, #ddd);
border-radius: 0.6rem;
background: var(--color-bg, #fff);
color: var(--color-text, #222);
text-align: left;
cursor: pointer;
transition: background 120ms, border-color 120ms, transform 120ms;
}
.fristen-step2-card:hover {
background: var(--color-bg-subtle, #fafafa);
border-color: var(--color-text-muted, #aaa);
transform: translateY(-1px);
}
.fristen-step2-card:focus-visible {
outline: 2px solid var(--color-accent, #c6f41c);
outline-offset: 2px;
}
.fristen-step2-card-icon {
font-size: 1.4rem;
line-height: 1;
}
.fristen-step2-card-title {
font-weight: 600;
font-size: 1rem;
}
.fristen-step2-card-desc {
color: var(--color-muted, #666);
font-size: 0.85rem;
}
.fristen-step2-shortcut {
margin-top: 1rem;
}
/* Compact one-line summary that replaces the four proceeding-group
* blocks once the user picks a Verfahren. m's 2026-05-08 18:26 ask. */
.proceeding-summary {