Deploy AIOS web (React glide grid + FastAPI slice)
Browse files- RELEASES.json +7 -1
- VERSION +1 -1
- web/src/customer-grid/MapView.tsx +146 -119
- web/src/index.css +26 -0
RELEASES.json
CHANGED
|
@@ -1,6 +1,12 @@
|
|
| 1 |
{
|
| 2 |
-
"current": "
|
| 3 |
"releases": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
{
|
| 5 |
"version": "v47",
|
| 6 |
"sha": "917f9a0",
|
|
|
|
| 1 |
{
|
| 2 |
+
"current": "v48 (3c69fd9)",
|
| 3 |
"releases": [
|
| 4 |
+
{
|
| 5 |
+
"version": "v48",
|
| 6 |
+
"sha": "3c69fd9",
|
| 7 |
+
"date": "2026-08-23",
|
| 8 |
+
"subject": "release v48"
|
| 9 |
+
},
|
| 10 |
{
|
| 11 |
"version": "v47",
|
| 12 |
"sha": "917f9a0",
|
VERSION
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
|
|
|
|
| 1 |
+
v48 (3c69fd9)
|
web/src/customer-grid/MapView.tsx
CHANGED
|
@@ -2039,114 +2039,15 @@ export function MapView({
|
|
| 2039 |
))}
|
| 2040 |
</select>
|
| 2041 |
</label>
|
| 2042 |
-
{/*
|
| 2043 |
-
|
| 2044 |
-
|
| 2045 |
-
|
| 2046 |
-
as what it is: leg 1, then leg 2.
|
| 2047 |
-
β POSITION IS PART OF THE INSTRUCTION, not a detail. They sit between the
|
| 2048 |
-
select and its Save button rather than after the whole block, because the
|
| 2049 |
-
block's tail can carry a stale marker, a shared-orders note and two message
|
| 2050 |
-
rows, and "under the Visit order column" stops being true the moment three
|
| 2051 |
-
of those render between the two. */}
|
| 2052 |
-
{plan.links.length > 0 && (
|
| 2053 |
-
<div className="cg-map-google-links" aria-label="Google Maps route links">
|
| 2054 |
-
{plan.links.map((link) => (
|
| 2055 |
-
<a
|
| 2056 |
-
key={link.index}
|
| 2057 |
-
href={link.url}
|
| 2058 |
-
target="_blank"
|
| 2059 |
-
rel="noopener noreferrer"
|
| 2060 |
-
title={`Open Google Maps route ${link.index} in a new tab`}
|
| 2061 |
-
>
|
| 2062 |
-
Google Maps route {link.index}
|
| 2063 |
-
</a>
|
| 2064 |
-
))}
|
| 2065 |
-
</div>
|
| 2066 |
-
)}
|
| 2067 |
-
{/* ββ ITEMS 4 AND 5: "Save route", and it ASKS FOR THE NAME βββββββββββββββββ
|
| 2068 |
-
β ITEM 4 β the button read "Save visit order". Owner: *"Change the button
|
| 2069 |
-
called 'Save visit order' to 'Save route'."* The FIELD is still the visit
|
| 2070 |
-
order (that is what the numbers in it are); the ACT is saving a route.
|
| 2071 |
-
β ITEM 5 β a NEW field now opens a name box first, pre-filled with the
|
| 2072 |
-
server's next free "Route N". Updating a field that already exists does not
|
| 2073 |
-
prompt: it already has a name, and asking again would invite a rename
|
| 2074 |
-
through a door that re-solves numbers rather than through Edit field.
|
| 2075 |
-
β AN INLINE STEP, NOT A BROWSER `prompt()`. A modal dialog blocks the page
|
| 2076 |
-
and cannot be styled, read by the design system, or dismissed with Escape
|
| 2077 |
-
the way every other overlay here is. */}
|
| 2078 |
-
{naming && !saveTarget ? (
|
| 2079 |
-
<div className="cg-route-name" role="group" aria-label="Name this route">
|
| 2080 |
-
<input
|
| 2081 |
-
className="cg-input"
|
| 2082 |
-
autoFocus
|
| 2083 |
-
value={nameDraft}
|
| 2084 |
-
aria-label="Route name"
|
| 2085 |
-
placeholder={nextLabel || "Name this route"}
|
| 2086 |
-
maxLength={120}
|
| 2087 |
-
onChange={(e) => setNameDraft(e.target.value)}
|
| 2088 |
-
onKeyDown={(e) => {
|
| 2089 |
-
if (e.key === "Enter") { e.preventDefault(); void saveRouteOrder(nameDraft); }
|
| 2090 |
-
if (e.key === "Escape") { e.preventDefault(); setNaming(false); }
|
| 2091 |
-
}}
|
| 2092 |
-
/>
|
| 2093 |
-
<span className="cg-route-name-actions">
|
| 2094 |
-
<button
|
| 2095 |
-
type="button"
|
| 2096 |
-
className="cg-btn cg-btn--primary"
|
| 2097 |
-
disabled={saveBusy || !nameDraft.trim()}
|
| 2098 |
-
onClick={() => void saveRouteOrder(nameDraft)}
|
| 2099 |
-
title="Save these visit numbers into a new field with this name"
|
| 2100 |
-
>
|
| 2101 |
-
{saveBusy ? "Saving" : "Save route"}
|
| 2102 |
-
</button>
|
| 2103 |
-
<button
|
| 2104 |
-
type="button"
|
| 2105 |
-
className="cg-btn"
|
| 2106 |
-
onClick={() => setNaming(false)}
|
| 2107 |
-
title="Do not save this route yet"
|
| 2108 |
-
>
|
| 2109 |
-
Cancel
|
| 2110 |
-
</button>
|
| 2111 |
-
</span>
|
| 2112 |
-
</div>
|
| 2113 |
-
) : (
|
| 2114 |
-
<button
|
| 2115 |
-
type="button"
|
| 2116 |
-
className="cg-btn cg-btn--primary cg-route-cta"
|
| 2117 |
-
disabled={saveBusy}
|
| 2118 |
-
onClick={() => {
|
| 2119 |
-
if (saveTarget) { void saveRouteOrder(); return; }
|
| 2120 |
-
setNameDraft(nextLabel);
|
| 2121 |
-
setSaveErr(null);
|
| 2122 |
-
setSaveMsg(null);
|
| 2123 |
-
setNaming(true);
|
| 2124 |
-
}}
|
| 2125 |
-
title={
|
| 2126 |
-
saveTarget
|
| 2127 |
-
? "Write these visit numbers into the saved field, for everyone it is shared with"
|
| 2128 |
-
: "Name this route and save these visit numbers as a new field"
|
| 2129 |
-
}
|
| 2130 |
-
>
|
| 2131 |
-
{saveBusy ? "Saving" : saveTarget ? "Update route" : "Save route"}
|
| 2132 |
-
</button>
|
| 2133 |
-
)}
|
| 2134 |
-
{/* β DERIVED, NEVER STORED. The saved field carries the fingerprint of the
|
| 2135 |
-
inputs it was solved from; this compares it against the cohort ON SCREEN
|
| 2136 |
-
NOW, so the marker cannot itself go out of date. */}
|
| 2137 |
-
{orderStale && (
|
| 2138 |
-
<span className="cg-map-route-note">
|
| 2139 |
-
Stale. The saved numbers were solved from different stops, so re-solving
|
| 2140 |
-
would change them.
|
| 2141 |
-
</span>
|
| 2142 |
-
)}
|
| 2143 |
{(routeCols || []).some((f) => !f.mine) && (
|
| 2144 |
<span className="cg-map-route-note">
|
| 2145 |
Shared orders you can read but not re-solve are not listed above.
|
| 2146 |
</span>
|
| 2147 |
)}
|
| 2148 |
-
{saveMsg && <span className="cg-map-route-note">{saveMsg}</span>}
|
| 2149 |
-
{saveErr && <span className="cg-cal-nodate">{saveErr}</span>}
|
| 2150 |
</>
|
| 2151 |
)}
|
| 2152 |
|
|
@@ -2273,23 +2174,149 @@ export function MapView({
|
|
| 2273 |
</span>
|
| 2274 |
)}
|
| 2275 |
|
| 2276 |
-
{
|
| 2277 |
-
|
| 2278 |
-
|
| 2279 |
-
|
| 2280 |
-
|
| 2281 |
-
|
| 2282 |
-
|
| 2283 |
-
|
| 2284 |
-
|
| 2285 |
-
|
| 2286 |
-
|
| 2287 |
-
|
| 2288 |
-
|
| 2289 |
-
|
| 2290 |
-
|
| 2291 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2292 |
)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2293 |
</div>
|
| 2294 |
</aside>
|
| 2295 |
)}
|
|
|
|
| 2039 |
))}
|
| 2040 |
</select>
|
| 2041 |
</label>
|
| 2042 |
+
{/* β THIS NOTE STAYS WITH THE SELECT, while items 8 and 9 send the Save
|
| 2043 |
+
button and the Google links to the foot. It is a statement about what
|
| 2044 |
+
the LIST ABOVE does not contain ("not listed above"), so it is the one
|
| 2045 |
+
line in the old block that would become false the moment it travelled. */}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2046 |
{(routeCols || []).some((f) => !f.mine) && (
|
| 2047 |
<span className="cg-map-route-note">
|
| 2048 |
Shared orders you can read but not re-solve are not listed above.
|
| 2049 |
</span>
|
| 2050 |
)}
|
|
|
|
|
|
|
| 2051 |
</>
|
| 2052 |
)}
|
| 2053 |
|
|
|
|
| 2174 |
</span>
|
| 2175 |
)}
|
| 2176 |
|
| 2177 |
+
{/* ββ OWNER ITEMS 8 AND 9 (2026-08-23) β THE COMMITTING CONTROLS LIVE AT THE FOOT ββ
|
| 2178 |
+
Owner: *"the 'Google Map Route 1' etc. should still be located at the bottom
|
| 2179 |
+
just above clear route button. And the save route button should still be at
|
| 2180 |
+
the bottom too beside clear route button."*
|
| 2181 |
+
ββ THIS OVERRULES THE OLDER "POSITION IS PART OF THE INSTRUCTION" NOTE, WHICH
|
| 2182 |
+
IS KEPT NOWHERE ELSE, SO IT IS RESTATED HERE RATHER THAN DELETED. Item 4 of the
|
| 2183 |
+
earlier pass put the Google links BETWEEN the visit-order select and its Save
|
| 2184 |
+
button, so that "under the Visit order column" stayed true; item 3b then moved
|
| 2185 |
+
that whole block above Start. The owner has now separated the two jobs: the
|
| 2186 |
+
select is SETUP and belongs at the top with Add a record, while saving and
|
| 2187 |
+
clearing are the two ways to FINISH and belong together at the bottom. The old
|
| 2188 |
+
argument was about keeping the links adjacent to something; they are now
|
| 2189 |
+
adjacent to the button that commits them, which serves it.
|
| 2190 |
+
β The Save button and Clear route share one row (item 9's "beside"), so
|
| 2191 |
+
`.cg-route-cta`'s full-width override is deliberately NOT applied to them β
|
| 2192 |
+
two full-width buttons cannot sit beside each other. */}
|
| 2193 |
+
{plan && (
|
| 2194 |
+
<>
|
| 2195 |
+
{/* ββ ITEM 4: the hand-off links, ONE PER LINE βββββββββββββββββββββββββ
|
| 2196 |
+
They were a `flex-wrap` cluster of chips, unreadable the moment a route
|
| 2197 |
+
needs more than one Google leg. Stacked, each on its own row, the list
|
| 2198 |
+
reads as what it is: leg 1, then leg 2. Owner item 8 moved the stack down
|
| 2199 |
+
here, directly above the two buttons that finish the job. */}
|
| 2200 |
+
{plan.links.length > 0 && (
|
| 2201 |
+
<div className="cg-map-google-links" aria-label="Google Maps route links">
|
| 2202 |
+
{plan.links.map((link) => (
|
| 2203 |
+
<a
|
| 2204 |
+
key={link.index}
|
| 2205 |
+
href={link.url}
|
| 2206 |
+
target="_blank"
|
| 2207 |
+
rel="noopener noreferrer"
|
| 2208 |
+
title={`Open Google Maps route ${link.index} in a new tab`}
|
| 2209 |
+
>
|
| 2210 |
+
Google Maps route {link.index}
|
| 2211 |
+
</a>
|
| 2212 |
+
))}
|
| 2213 |
+
</div>
|
| 2214 |
+
)}
|
| 2215 |
+
{/* ββ ITEMS 4 AND 5: "Save route", and it ASKS FOR THE NAME βββββββββββββββββ
|
| 2216 |
+
β ITEM 4 β the button read "Save visit order". Owner: *"Change the button
|
| 2217 |
+
called 'Save visit order' to 'Save route'."* The FIELD is still the visit
|
| 2218 |
+
order (that is what the numbers in it are); the ACT is saving a route.
|
| 2219 |
+
β ITEM 5 β a NEW field now opens a name box first, pre-filled with the
|
| 2220 |
+
server's next free "Route N". Updating a field that already exists does not
|
| 2221 |
+
prompt: it already has a name, and asking again would invite a rename
|
| 2222 |
+
through a door that re-solves numbers rather than through Edit field.
|
| 2223 |
+
β AN INLINE STEP, NOT A BROWSER `prompt()`. A modal dialog blocks the page
|
| 2224 |
+
and cannot be styled, read by the design system, or dismissed with Escape
|
| 2225 |
+
the way every other overlay here is. */}
|
| 2226 |
+
{naming && !saveTarget && (
|
| 2227 |
+
<div className="cg-route-name" role="group" aria-label="Name this route">
|
| 2228 |
+
<input
|
| 2229 |
+
className="cg-input"
|
| 2230 |
+
autoFocus
|
| 2231 |
+
value={nameDraft}
|
| 2232 |
+
aria-label="Route name"
|
| 2233 |
+
placeholder={nextLabel || "Name this route"}
|
| 2234 |
+
maxLength={120}
|
| 2235 |
+
onChange={(e) => setNameDraft(e.target.value)}
|
| 2236 |
+
onKeyDown={(e) => {
|
| 2237 |
+
if (e.key === "Enter") { e.preventDefault(); void saveRouteOrder(nameDraft); }
|
| 2238 |
+
if (e.key === "Escape") { e.preventDefault(); setNaming(false); }
|
| 2239 |
+
}}
|
| 2240 |
+
/>
|
| 2241 |
+
<span className="cg-route-name-actions">
|
| 2242 |
+
<button
|
| 2243 |
+
type="button"
|
| 2244 |
+
className="cg-btn cg-btn--primary"
|
| 2245 |
+
disabled={saveBusy || !nameDraft.trim()}
|
| 2246 |
+
onClick={() => void saveRouteOrder(nameDraft)}
|
| 2247 |
+
title="Save these visit numbers into a new field with this name"
|
| 2248 |
+
>
|
| 2249 |
+
{saveBusy ? "Saving" : "Save route"}
|
| 2250 |
+
</button>
|
| 2251 |
+
<button
|
| 2252 |
+
type="button"
|
| 2253 |
+
className="cg-btn"
|
| 2254 |
+
onClick={() => setNaming(false)}
|
| 2255 |
+
title="Do not save this route yet"
|
| 2256 |
+
>
|
| 2257 |
+
Cancel
|
| 2258 |
+
</button>
|
| 2259 |
+
</span>
|
| 2260 |
+
</div>
|
| 2261 |
+
)}
|
| 2262 |
+
{/* β DERIVED, NEVER STORED. The saved field carries the fingerprint of the
|
| 2263 |
+
inputs it was solved from; this compares it against the cohort ON SCREEN
|
| 2264 |
+
NOW, so the marker cannot itself go out of date. */}
|
| 2265 |
+
{orderStale && (
|
| 2266 |
+
<span className="cg-map-route-note">
|
| 2267 |
+
Stale. The saved numbers were solved from different stops, so re-solving
|
| 2268 |
+
would change them.
|
| 2269 |
+
</span>
|
| 2270 |
+
)}
|
| 2271 |
+
{saveMsg && <span className="cg-map-route-note">{saveMsg}</span>}
|
| 2272 |
+
{saveErr && <span className="cg-cal-nodate">{saveErr}</span>}
|
| 2273 |
+
</>
|
| 2274 |
)}
|
| 2275 |
+
|
| 2276 |
+
<div className="cg-route-foot">
|
| 2277 |
+
{/* β THE NAME BOX IS FULL WIDTH ABOVE THE ROW, NOT INSIDE IT. A text input, a
|
| 2278 |
+
Save and a Cancel cannot share a 338px row with Clear route without every
|
| 2279 |
+
one of them shrinking past reading width, so while it is open the row shows
|
| 2280 |
+
Clear route alone and the prompt owns the line above it. */}
|
| 2281 |
+
{plan && !(naming && !saveTarget) && (
|
| 2282 |
+
<button
|
| 2283 |
+
type="button"
|
| 2284 |
+
className="cg-btn cg-btn--primary cg-route-foot-btn"
|
| 2285 |
+
disabled={saveBusy}
|
| 2286 |
+
onClick={() => {
|
| 2287 |
+
if (saveTarget) { void saveRouteOrder(); return; }
|
| 2288 |
+
setNameDraft(nextLabel);
|
| 2289 |
+
setSaveErr(null);
|
| 2290 |
+
setSaveMsg(null);
|
| 2291 |
+
setNaming(true);
|
| 2292 |
+
}}
|
| 2293 |
+
title={
|
| 2294 |
+
saveTarget
|
| 2295 |
+
? "Write these visit numbers into the saved field, for everyone it is shared with"
|
| 2296 |
+
: "Name this route and save these visit numbers as a new field"
|
| 2297 |
+
}
|
| 2298 |
+
>
|
| 2299 |
+
{saveBusy ? "Saving" : saveTarget ? "Update route" : "Save route"}
|
| 2300 |
+
</button>
|
| 2301 |
+
)}
|
| 2302 |
+
{routeOn && (
|
| 2303 |
+
<button
|
| 2304 |
+
type="button"
|
| 2305 |
+
className="cg-btn cg-btn--danger cg-route-cta"
|
| 2306 |
+
onClick={() => {
|
| 2307 |
+
setRouteOn(false);
|
| 2308 |
+
setRouteStartPid(null);
|
| 2309 |
+
setRouteOrder(null);
|
| 2310 |
+
setRoad(null);
|
| 2311 |
+
setRoadErr(null);
|
| 2312 |
+
setDepot(null);
|
| 2313 |
+
}}
|
| 2314 |
+
title="Drop this route and start again. The records stay selected."
|
| 2315 |
+
>
|
| 2316 |
+
Clear route
|
| 2317 |
+
</button>
|
| 2318 |
+
)}
|
| 2319 |
+
</div>
|
| 2320 |
</div>
|
| 2321 |
</aside>
|
| 2322 |
)}
|
web/src/index.css
CHANGED
|
@@ -5086,6 +5086,20 @@ a.cg-map-ctl-b { text-decoration: none; }
|
|
| 5086 |
gap: 6px;
|
| 5087 |
}
|
| 5088 |
.cg-route-name-actions .cg-btn { flex: 1 1 0; justify-content: center; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5089 |
.cg-route-popover .cg-map-route-sum { white-space: normal; line-height: 1.45; }
|
| 5090 |
.cg-route-popover .cg-map-route-opt {
|
| 5091 |
align-items: stretch;
|
|
@@ -5195,6 +5209,18 @@ a.cg-map-ctl-b { text-decoration: none; }
|
|
| 5195 |
scrollbar-width: thin;
|
| 5196 |
}
|
| 5197 |
.cg-route-picker-opt {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5198 |
padding: 5px 6px;
|
| 5199 |
border: 0;
|
| 5200 |
border-radius: 4px;
|
|
|
|
| 5086 |
gap: 6px;
|
| 5087 |
}
|
| 5088 |
.cg-route-name-actions .cg-btn { flex: 1 1 0; justify-content: center; }
|
| 5089 |
+
/* β OWNER ITEMS 8 AND 9 (2026-08-23) β SAVE AND CLEAR SHARE THE LAST ROW. Owner: *"the save
|
| 5090 |
+
route button should still be at the bottom too beside clear route button."* The Google links sit
|
| 5091 |
+
directly above it (item 8), so the panel ends: how to hand this route to Google, then the two
|
| 5092 |
+
ways to finish with it.
|
| 5093 |
+
β `.cg-route-cta`'s `width: 100%` is OVERRIDDEN here rather than simply not applied, because
|
| 5094 |
+
`Clear route` still carries that class from every other position it has ever had. Two full-width
|
| 5095 |
+
buttons cannot sit beside each other, which is the whole of item 9. */
|
| 5096 |
+
.cg-route-foot {
|
| 5097 |
+
display: flex;
|
| 5098 |
+
gap: 6px;
|
| 5099 |
+
width: 100%;
|
| 5100 |
+
margin-top: 2px;
|
| 5101 |
+
}
|
| 5102 |
+
.cg-route-foot .cg-btn { flex: 1 1 0; width: auto; justify-content: center; text-align: center; }
|
| 5103 |
.cg-route-popover .cg-map-route-sum { white-space: normal; line-height: 1.45; }
|
| 5104 |
.cg-route-popover .cg-map-route-opt {
|
| 5105 |
align-items: stretch;
|
|
|
|
| 5209 |
scrollbar-width: thin;
|
| 5210 |
}
|
| 5211 |
.cg-route-picker-opt {
|
| 5212 |
+
/* ββ OWNER ITEM 10 (2026-08-23) β `flex: 0 0 auto` IS THE WHOLE FIX, AND ITS ABSENCE IS WHY
|
| 5213 |
+
THE RESULTS PILED ON TOP OF EACH OTHER. Owner: *"when i type search records for the route, the
|
| 5214 |
+
dropdown overlays for both start and search database."* The list is a flex COLUMN with
|
| 5215 |
+
`max-height: 168px`, and a flex item's default `flex-shrink: 1` lets the browser squash it
|
| 5216 |
+
below its content height to fit β so 40 results in a 168px box became 40 four-pixel rows,
|
| 5217 |
+
each one's text spilling over its neighbour's. REPRODUCED before it was fixed: 662 matches
|
| 5218 |
+
for "flow", the panel painting an unreadable stack of half-overlapping names.
|
| 5219 |
+
β The `overflow-y: auto` on the list was never the problem and is not the fix: a scroller
|
| 5220 |
+
only scrolls what it is allowed to leave at full height. It could not, so it never scrolled.
|
| 5221 |
+
β Applies to BOTH pickers by construction (Start and Add a record are one component), which
|
| 5222 |
+
is what the owner's "for both" describes. */
|
| 5223 |
+
flex: 0 0 auto;
|
| 5224 |
padding: 5px 6px;
|
| 5225 |
border: 0;
|
| 5226 |
border-radius: 4px;
|