diff --git a/src/ui/routes/MonthRoute.tsx b/src/ui/routes/MonthRoute.tsx
index 7c9fd4c..9d04644 100644
--- a/src/ui/routes/MonthRoute.tsx
+++ b/src/ui/routes/MonthRoute.tsx
@@ -3,6 +3,7 @@ import { Link, useParams } from "react-router";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
+import { NativeSelect } from "@/components/ui/native-select";
import { useDataset } from "../hooks/useDataset.ts";
import { useMutate } from "../hooks/useMutate.ts";
import { monthView, type MonthViewModel } from "../../domain/views.ts";
@@ -42,9 +43,9 @@ export function MonthRoute() {
className="flex items-center justify-between gap-3 rounded-lg border border-destructive/40 bg-destructive/5 p-3 text-sm"
>
Could not save: {error}
-
)}
@@ -190,41 +191,63 @@ function PurchaseRow({
}) {
const slice = sliceAmountForMonth(purchase, monthId)!;
return (
-
-
+ // `-mx-2 px-2` rather than `px-1`: the row's text now starts exactly where
+ // its own date heading does — `px-1` indented it 4px past the heading —
+ // and the hover wash bleeds 8px outward, so the highlight has an inset
+ // instead of stopping flush against the first character.
+ //
+ // One line from `sm:` up, two below it. At 390px this row's fixed parts —
+ // a mono amount, "edit", "delete" — take about 215px of a 350px card,
+ // which left the description roughly 110px: it truncated to "Weeken…",
+ // then "Bik…", and on the financed row to nothing but its badge. The
+ // description is the only part that says what the purchase WAS, so at that
+ // width it gets a line to itself and everything else gets the next one.
+ // The same call PostTable already makes, for the same reason.
+
+
{purchase.description}
{purchase.note && (
{purchase.note}
)}
- {purchase.schedule && (
-
- financed
+
+ {/* `sm:contents` dissolves this wrapper from `sm:` up, so the desktop row
+ is exactly the flat flex line it has always been. Below `sm:` it is
+ the second line, and its `w-full` is what forces the wrap. */}
+
+ {purchase.schedule && (
+
+ financed
+
+ )}
+
+ {formatMoney(slice.amount, slice.currency)}
+
+
+ {/* From `sm:` up: revealed on hover, and held at a fixed width so
+ revealing it cannot shift the amounts, which are the column being
+ read down. Below `sm:`: always visible. A phone has no hover, so
+ `opacity-0` had made these two the hardest controls in the app to
+ reach, while still reserving 120px of the row to hide them in. */}
+
+
+ edit
+
+ }
+ />
+
+ delete
+
- )}
-
- {formatMoney(slice.amount, slice.currency)}
-
- {/* Held at a fixed width so revealing the actions on hover cannot shift
- the amounts, which are the column being read down. */}
-
-
- edit
-
- }
- />
-
- delete
-
);
@@ -260,7 +283,7 @@ function MonthStep({ to, label, back = false }: { to: string; label: string; bac
return (
{back ? `\u2190 ${label}` : `${label} \u2192`}
@@ -307,12 +330,12 @@ function RuleFromMonth({
}
return (
-