<feed xmlns='http://www.w3.org/2005/Atom'>
<title>kukuri.git/modules/orgflow-ui, branch main</title>
<subtitle>kukuri: Kotlin Multiplatform app (desktop / wasm / native / Android) for the orgflow UI</subtitle>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/kukuri.git/'/>
<entry>
<title>UI: the pie labels were a quarter-turn out from their own wedges</title>
<updated>2026-10-05T14:58:26+00:00</updated>
<author>
<name>Charlie Root</name>
<email>root@dangofactory.local</email>
</author>
<published>2026-10-05T14:58:26+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/kukuri.git/commit/?id=e0465ad93dd2d2123a7cd6eb1bf497d0a6b47535'/>
<id>e0465ad93dd2d2123a7cd6eb1bf497d0a6b47535</id>
<content type='text'>
Three attempts at this and the cause was never the offset arithmetic. Measured
on build 86, the label mean angles were 45.9 / 130.3 / 209.1 / 319.9 degrees while
the wedge centres are 0 / 90 / 180 / 270. A constant ~45 degree error in all four
quadrants is not a magnitude problem, it is an origin problem.

The wedges are drawn at angles[i], which distributeAngles() fills starting from 0
and stepping clockwise, so item 0 sits at drawAngle 0 -- to the RIGHT, because
canvas angles run from 3 o'clock. The label loop was computing
`i * (360.0/n) - 90.0`, which assumes the first wedge is at the top. So the labels
were anchored a quarter turn away from the wedges, which is exactly one
separator, and no value of the constant would have fixed it.

The labels now take the wedge angles as a parameter and use angles[i] directly,
so a label and its wedge cannot disagree again -- including for a menu whose item
count is not 4 or which pins an item with an explicit `angle`.

Also worth recording: the two earlier attempts were tuning a constant while the
constant itself was wrong, and the measurements (19 px in the top quadrant, then
"all four on the boundaries") were consistent with an origin bug the whole time.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Three attempts at this and the cause was never the offset arithmetic. Measured
on build 86, the label mean angles were 45.9 / 130.3 / 209.1 / 319.9 degrees while
the wedge centres are 0 / 90 / 180 / 270. A constant ~45 degree error in all four
quadrants is not a magnitude problem, it is an origin problem.

The wedges are drawn at angles[i], which distributeAngles() fills starting from 0
and stepping clockwise, so item 0 sits at drawAngle 0 -- to the RIGHT, because
canvas angles run from 3 o'clock. The label loop was computing
`i * (360.0/n) - 90.0`, which assumes the first wedge is at the top. So the labels
were anchored a quarter turn away from the wedges, which is exactly one
separator, and no value of the constant would have fixed it.

The labels now take the wedge angles as a parameter and use angles[i] directly,
so a label and its wedge cannot disagree again -- including for a menu whose item
count is not 4 or which pins an item with an explicit `angle`.

Also worth recording: the two earlier attempts were tuning a constant while the
constant itself was wrong, and the measurements (19 px in the top quadrant, then
"all four on the boundaries") were consistent with an origin bug the whole time.
</pre>
</div>
</content>
</entry>
<entry>
<title>build: drop the wasm-opt DSL block that detekt cannot parse</title>
<updated>2026-10-05T12:57:29+00:00</updated>
<author>
<name>Charlie Root</name>
<email>root@dangofactory.local</email>
</author>
<published>2026-10-05T12:57:29+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/kukuri.git/commit/?id=4f00e13607ad4137fec4ce54f1ebeca03889e099'/>
<id>4f00e13607ad4137fec4ce54f1ebeca03889e099</id>
<content type='text'>
The -O2 block I added to silence the OOM killer broke the detekt gate instead.
build 82 failed at detekt-gate, and running detekt by hand showed why: it parses
build.gradle.kts as Kotlin source, and the Kotlin DSL's optimizations { wasm-opt
{ ... } } is a lazy accessor with no resolvable type, so detekt reported 9
'Unresolved reference' errors on wasm-opt, optimizationLevel and pass.

So the file is back to the plain
and detekt passes again (verified: detekt and compileKotlinWasmJs both
BUILD SUCCESSFUL).

The OOM problem is therefore NOT fixed by this commit. wasm-opt still runs at
-Oz and bundleWeb can still be killed by signal 9. The fix has to be expressed in
a way detekt can parse, which means the argument list for the optimizer task
rather than the target DSL. That is the next change, and it needs to be verified
against both detekt and bundleWeb in one go, because each one alone will not tell
you whether it worked.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The -O2 block I added to silence the OOM killer broke the detekt gate instead.
build 82 failed at detekt-gate, and running detekt by hand showed why: it parses
build.gradle.kts as Kotlin source, and the Kotlin DSL's optimizations { wasm-opt
{ ... } } is a lazy accessor with no resolvable type, so detekt reported 9
'Unresolved reference' errors on wasm-opt, optimizationLevel and pass.

So the file is back to the plain
and detekt passes again (verified: detekt and compileKotlinWasmJs both
BUILD SUCCESSFUL).

The OOM problem is therefore NOT fixed by this commit. wasm-opt still runs at
-Oz and bundleWeb can still be killed by signal 9. The fix has to be expressed in
a way detekt can parse, which means the argument list for the optimizer task
rather than the target DSL. That is the next change, and it needs to be verified
against both detekt and bundleWeb in one go, because each one alone will not tell
you whether it worked.
</pre>
</div>
</content>
</entry>
<entry>
<title>build: wasm-opt -Oz -&gt; -O2; the optimizer was OOM-killed</title>
<updated>2026-10-05T12:33:08+00:00</updated>
<author>
<name>Charlie Root</name>
<email>root@dangofactory.local</email>
</author>
<published>2026-10-05T12:33:08+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/kukuri.git/commit/?id=24ab3fc0b9fa9c5079186605f34c71f1dcf11584'/>
<id>24ab3fc0b9fa9c5079186605f34c71f1dcf11584</id>
<content type='text'>
build 81's bundle-web ended with 'process killed by signal 9' during
compileProductionExecutableKotlinWasmJsOptimize, i.e. the OOM killer took
wasm-opt on this 11.9 GB host. wasm-opt exposes no memory cap, so the only lever
is how much work it is asked to do.

At -Oz Kotlin's default pass list runs --gufa plus repeated -O3 --type-merging.
That combination is the memory peak. -O2 keeps most of the size win and does not
pull in gufa. The pass list is now written out explicitly so it cannot silently
drift back to the -Oz defaults.

This trades a little wasm size for the web bundle actually shipping at all, which
is the right way round: an unbuilt bundle helps nobody.

Also fixes the CI fleet-wide daemon pressure by leaving the --max-workers=2
restriction from the previous commit in place.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
build 81's bundle-web ended with 'process killed by signal 9' during
compileProductionExecutableKotlinWasmJsOptimize, i.e. the OOM killer took
wasm-opt on this 11.9 GB host. wasm-opt exposes no memory cap, so the only lever
is how much work it is asked to do.

At -Oz Kotlin's default pass list runs --gufa plus repeated -O3 --type-merging.
That combination is the memory peak. -O2 keeps most of the size win and does not
pull in gufa. The pass list is now written out explicitly so it cannot silently
drift back to the -Oz defaults.

This trades a little wasm size for the web bundle actually shipping at all, which
is the right way round: an unbuilt bundle helps nobody.

Also fixes the CI fleet-wide daemon pressure by leaving the --max-workers=2
restriction from the previous commit in place.
</pre>
</div>
</content>
</entry>
<entry>
<title>UI: place the pie labels by absolute polar coordinates</title>
<updated>2026-10-05T12:04:37+00:00</updated>
<author>
<name>Charlie Root</name>
<email>root@dangofactory.local</email>
</author>
<published>2026-10-05T12:04:37+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/kukuri.git/commit/?id=43bcab0d3af73559c7004e33cc291a95d8522b96'/>
<id>43bcab0d3af73559c7004e33cc291a95d8522b96</id>
<content type='text'>
Third attempt at the label placement, and the previous one did not work. Measured
about the true disc centre (135.0, 725.5, a 200x200 disc) the label means sat at
152 / 201 / 300 degrees: still 15-24 degrees from a separator and 21-62 degrees
from a wedge centre.

Why 90 dp did not fix it: Modifier.offset is applied AFTER placement, so it adds
to wherever the parent's placement rules already decided. With
Box(Modifier.fillMaxSize(), contentAlignment = Center) the parent was deciding,
and a polar offset added on top of that is not a polar position -- the parent's
rules win and the angle comes out wrong.

This time the parent stops deciding. BoxWithConstraints gives the real
constraint size, and each label box is positioned at
(centre + cos/sin * 67dp - halfBox) with nothing else touching placement. Box
is 84 dp so it fits inside a 45 degree wedge at r=67 (arc length there is about
53 dp), and the box's centre, not its corner, is placed on the bisector.

Verified by measurement on the next build rather than assumed: the label mean
angle per quadrant must come out near 0/90/180/270 rather than 45/135/225/315.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Third attempt at the label placement, and the previous one did not work. Measured
about the true disc centre (135.0, 725.5, a 200x200 disc) the label means sat at
152 / 201 / 300 degrees: still 15-24 degrees from a separator and 21-62 degrees
from a wedge centre.

Why 90 dp did not fix it: Modifier.offset is applied AFTER placement, so it adds
to wherever the parent's placement rules already decided. With
Box(Modifier.fillMaxSize(), contentAlignment = Center) the parent was deciding,
and a polar offset added on top of that is not a polar position -- the parent's
rules win and the angle comes out wrong.

This time the parent stops deciding. BoxWithConstraints gives the real
constraint size, and each label box is positioned at
(centre + cos/sin * 67dp - halfBox) with nothing else touching placement. Box
is 84 dp so it fits inside a 45 degree wedge at r=67 (arc length there is about
53 dp), and the box's centre, not its corner, is placed on the bisector.

Verified by measurement on the next build rather than assumed: the label mean
angle per quadrant must come out near 0/90/180/270 rather than 45/135/225/315.
</pre>
</div>
</content>
</entry>
<entry>
<title>UI: stop the pie labels from riding the quadrant boundaries</title>
<updated>2026-10-05T11:19:36+00:00</updated>
<author>
<name>Charlie Root</name>
<email>root@dangofactory.local</email>
</author>
<published>2026-10-05T11:19:36+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/kukuri.git/commit/?id=fa6352a2e84a17651234fee639d0f560877fd23f'/>
<id>fa6352a2e84a17651234fee639d0f560877fd23f</id>
<content type='text'>
The previous commit fixed the missing top label but left the placement wrong in
a subtler way, and the measurement caught it: taking the circular mean of the
white ink in each quadrant gave 60 / 128 / 207 / 325 degrees. The wedge bisectors
are 0 / 90 / 180 / 270 and the separators are 45 / 135 / 225 / 315, so every
label sat 27-60 degrees off its wedge centre and within 7-18 degrees of a
separator.

Cause: each label lived in a Box sized labelRadius * 2 = 134 dp. That is two
thirds of the whole 200 dp disc, so it does not fit inside a 45 degree wedge.
Compose redistributed the overflow by placing the child about 45 degrees away
from where the offset asked, which is exactly the boundary-hugging result.

Fix: size the measuring box at 90 dp so it fits the wedge arc, and compute the
top-left so the box's CENTRE lands on the bisector at 67 dp rather than letting
the box corner land there. Radial distance is unchanged.

Hub stays at 22% and the separators stay 3 px; the review only complained the
overall structure still read weakly because of this placement.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The previous commit fixed the missing top label but left the placement wrong in
a subtler way, and the measurement caught it: taking the circular mean of the
white ink in each quadrant gave 60 / 128 / 207 / 325 degrees. The wedge bisectors
are 0 / 90 / 180 / 270 and the separators are 45 / 135 / 225 / 315, so every
label sat 27-60 degrees off its wedge centre and within 7-18 degrees of a
separator.

Cause: each label lived in a Box sized labelRadius * 2 = 134 dp. That is two
thirds of the whole 200 dp disc, so it does not fit inside a 45 degree wedge.
Compose redistributed the overflow by placing the child about 45 degrees away
from where the offset asked, which is exactly the boundary-hugging result.

Fix: size the measuring box at 90 dp so it fits the wedge arc, and compute the
top-left so the box's CENTRE lands on the bisector at 67 dp rather than letting
the box corner land there. Radial distance is unchanged.

Hub stays at 22% and the separators stay 3 px; the review only complained the
overall structure still read weakly because of this placement.
</pre>
</div>
</content>
</entry>
<entry>
<title>UI: fix the pie's top label falling outside the disc</title>
<updated>2026-10-05T09:10:58+00:00</updated>
<author>
<name>Charlie Root</name>
<email>root@dangofactory.local</email>
</author>
<published>2026-10-05T09:10:58+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/kukuri.git/commit/?id=996db6abbfd929d746444409ce77d22d4aa07827'/>
<id>996db6abbfd929d746444409ce77d22d4aa07827</id>
<content type='text'>
Pro reviewed the rebuilt menu and read the image rather than the numbers: three
quadrants had labels, the top one had none. My own pixel count agreed --
19 px of white ink in the top quadrant against 421-519 px in the others.

Cause: the label loop computed a polar offset relative to the CENTRE but applied
it with Modifier.offset inside Box(Modifier.fillMaxSize()), whose origin is the
TOP-LEFT. So every label was displaced by half a radius too little, and the top
one at y = -67 dp landed outside the disc entirely. The three that appeared to
work were only roughly right.

Fix: centre the outer Box (contentAlignment = Center) so the origin is the disc
centre, and pass the polar displacement as a relative offset. Pro's -90 deg
convention was already right -- item 0 at the top, proceeding clockwise -- and is
kept; only the origin was wrong.

Pro's other read on the rebuild: the 3 px separator reads well at this size and
does not flare, and the 22% hub is better balanced than 26%. Both kept.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Pro reviewed the rebuilt menu and read the image rather than the numbers: three
quadrants had labels, the top one had none. My own pixel count agreed --
19 px of white ink in the top quadrant against 421-519 px in the others.

Cause: the label loop computed a polar offset relative to the CENTRE but applied
it with Modifier.offset inside Box(Modifier.fillMaxSize()), whose origin is the
TOP-LEFT. So every label was displaced by half a radius too little, and the top
one at y = -67 dp landed outside the disc entirely. The three that appeared to
work were only roughly right.

Fix: centre the outer Box (contentAlignment = Center) so the origin is the disc
centre, and pass the polar displacement as a relative offset. Pro's -90 deg
convention was already right -- item 0 at the top, proceeding clockwise -- and is
kept; only the origin was wrong.

Pro's other read on the rebuild: the 3 px separator reads well at this size and
does not flare, and the 22% hub is better balanced than 26%. Both kept.
</pre>
</div>
</content>
</entry>
<entry>
<title>UI: place the pie labels on the wedge bisectors, not on a grid</title>
<updated>2026-10-05T07:35:41+00:00</updated>
<author>
<name>Charlie Root</name>
<email>root@dangofactory.local</email>
</author>
<published>2026-10-05T07:35:41+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/kukuri.git/commit/?id=7c90fe2e0923f1e74b4f9d9d212b8709cb7e6249'/>
<id>7c90fe2e0923f1e74b4f9d9d212b8709cb7e6249</id>
<content type='text'>
The menu still looked wrong after the donut revision, so the geometry was
re-measured rather than re-guessed. The numbers matched the previous reviewer's
spec exactly, which is what made the spec itself the suspect.

Measured on the published build: disc 200x200 at (139.5, 725.5), hub 54x54 dead
centred on it, wedge/gap boundaries exactly on 45/135/225/315 degrees. So the
distances were right. But sampling the white label ink at r=40..90 and taking the
circular mean of each cluster gave 35 / 133 / 148 / 212 / 330 degrees. The wedge
bisectors are 0/90/180/270. The labels were sitting on the SEPARATOR axes, not
the wedge centres.

Cause: the labels were placed with a 3x3 Row/Column grid. That grid happens to put
cell centres on the diagonals, so a polar control was being laid out with
Cartesian logic and the 61 dp radius -- correct as the midpoint of the 26..96 band
-- landed the glyphs on the boundaries.

Labels are now placed in polar coordinates: angle from the wedge bisector (top,
then clockwise), radius 67 dp, centred on their own measured glyph box rather than
a grid slot. Horizontal text is kept; rotating the left/right labels would read as
an instrument dial rather than school navigation, so the radial relationship comes
from position only.

Also, per the same review, the separators stop being angular gaps. A 2 degree gap
is 0.94 px wide at the hub and the wedge/gap contrast was 1.34:1, so it read as
four notches in one disc. They are now a constant 3 px stroke in #24272D, which
does not flare with radius, and pieWedge moves #5C6068 -&gt; #626873 to reach about
3:1 against it. The hub drops from 26% to 22% of the radius so the centre is less
dominant. Labels go to 15sp semibold, which also helps the longest (3 chars) sit
level with the 2-char ones.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The menu still looked wrong after the donut revision, so the geometry was
re-measured rather than re-guessed. The numbers matched the previous reviewer's
spec exactly, which is what made the spec itself the suspect.

Measured on the published build: disc 200x200 at (139.5, 725.5), hub 54x54 dead
centred on it, wedge/gap boundaries exactly on 45/135/225/315 degrees. So the
distances were right. But sampling the white label ink at r=40..90 and taking the
circular mean of each cluster gave 35 / 133 / 148 / 212 / 330 degrees. The wedge
bisectors are 0/90/180/270. The labels were sitting on the SEPARATOR axes, not
the wedge centres.

Cause: the labels were placed with a 3x3 Row/Column grid. That grid happens to put
cell centres on the diagonals, so a polar control was being laid out with
Cartesian logic and the 61 dp radius -- correct as the midpoint of the 26..96 band
-- landed the glyphs on the boundaries.

Labels are now placed in polar coordinates: angle from the wedge bisector (top,
then clockwise), radius 67 dp, centred on their own measured glyph box rather than
a grid slot. Horizontal text is kept; rotating the left/right labels would read as
an instrument dial rather than school navigation, so the radial relationship comes
from position only.

Also, per the same review, the separators stop being angular gaps. A 2 degree gap
is 0.94 px wide at the hub and the wedge/gap contrast was 1.34:1, so it read as
four notches in one disc. They are now a constant 3 px stroke in #24272D, which
does not flare with radius, and pieWedge moves #5C6068 -&gt; #626873 to reach about
3:1 against it. The hub drops from 26% to 22% of the radius so the centre is less
dominant. Labels go to 15sp semibold, which also helps the longest (3 chars) sit
level with the 2-char ones.
</pre>
</div>
</content>
</entry>
<entry>
<title>Pie: gaps instead of dividers, and drop the second outer ring</title>
<updated>2026-10-05T01:25:21+00:00</updated>
<author>
<name>Charlie Root</name>
<email>root@dangofactory.local</email>
</author>
<published>2026-10-05T01:25:21+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/kukuri.git/commit/?id=8872807293a6e6352c2b3c8c0451e706a5d8d954'/>
<id>8872807293a6e6352c2b3c8c0451e706a5d8d954</id>
<content type='text'>
Reviewed with GPT 5.5 Think Deeper over the M365 relay. It confirmed the donut
was the right call and rejected one part of it.

Keep the donut. The hub is 6.76% of the disc area (radius 26dp of 100dp)
against ~23.3% per wedge, so it is usable without crowding the items, and
removing the cross from behind the "W" fixes a real defect. It also supplies the
missing semantic rule: the centre is a meta-action, not a fifth command, and
must not be styled like a wedge -- recorded at the glyph, since the tree is
currently one level deep and "W" is correct only at the root.

Dividers: replace the radial strokes with a 2dp negative-space gap in the disc
colour. Contrasting strokes read as construction lines and emphasise the pie's
geometry rather than four selectable objects. The gap is paint only -- hit
testing keeps the exact 90-degree boundaries, so a pointer in a gap still
belongs deterministically to one adjacent sector.

The near-coincident ring was the actual mistake: a selection ring at r-1.5/3px
sat 3px outside the frame ring at r-1.2/2.4px and read as two parallel lines.
Selection is now the corresponding arc of the single existing frame, drawn at
5px in the accent colour.

Label band unchanged at 39dp: the hub turns out to validate it rather than
invalidate it -- 61dp is exactly the midpoint of the now-visible 26..96dp
annulus, so moving labels either way would make the hub look wrong.

Pro also confirmed the arithmetic behind the 200dp diameter is sound (Blender
and Kando both use 100px radius; Gnome-Pie's formula gives 46px only as the
geometric minimum).
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Reviewed with GPT 5.5 Think Deeper over the M365 relay. It confirmed the donut
was the right call and rejected one part of it.

Keep the donut. The hub is 6.76% of the disc area (radius 26dp of 100dp)
against ~23.3% per wedge, so it is usable without crowding the items, and
removing the cross from behind the "W" fixes a real defect. It also supplies the
missing semantic rule: the centre is a meta-action, not a fifth command, and
must not be styled like a wedge -- recorded at the glyph, since the tree is
currently one level deep and "W" is correct only at the root.

Dividers: replace the radial strokes with a 2dp negative-space gap in the disc
colour. Contrasting strokes read as construction lines and emphasise the pie's
geometry rather than four selectable objects. The gap is paint only -- hit
testing keeps the exact 90-degree boundaries, so a pointer in a gap still
belongs deterministically to one adjacent sector.

The near-coincident ring was the actual mistake: a selection ring at r-1.5/3px
sat 3px outside the frame ring at r-1.2/2.4px and read as two parallel lines.
Selection is now the corresponding arc of the single existing frame, drawn at
5px in the accent colour.

Label band unchanged at 39dp: the hub turns out to validate it rather than
invalidate it -- 61dp is exactly the midpoint of the now-visible 26..96dp
annulus, so moving labels either way would make the hub look wrong.

Pro also confirmed the arithmetic behind the 200dp diameter is sound (Blender
and Kando both use 100px radius; Gnome-Pie's formula gives 46px only as the
geometric minimum).
</pre>
</div>
</content>
</entry>
<entry>
<title>UI: fix the Note row title, the white-on-ground text, and reshape the pie</title>
<updated>2026-10-04T23:50:34+00:00</updated>
<author>
<name>Charlie Root</name>
<email>root@dangofactory.local</email>
</author>
<published>2026-10-04T23:50:34+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/kukuri.git/commit/?id=3b650fe13b5fcc628114c258e00d2615c109a335'/>
<id>3b650fe13b5fcc628114c258e00d2615c109a335</id>
<content type='text'>
Three separate defects, all found by measuring captures rather than reading
the code.

1. Note row title stayed black. NoteButton's title Text omitted color=, so it
   inherited LocalContentColor and got Compose Material's default black --
   identical to the KUKURI/card bugs, but my earlier sweep MISSED it. That
   sweep's parenthesis matching over-ran past a single-line call into the
   next statement, absorbed that statement's color=, and reported zero. The
   detector now tracks depth per character across the file; it reports 0
   genuinely uncoloured Text() calls across all 13 files, so this class is
   closed by construction rather than by spot fixes.

2. Light mode left white-on-ground text. Five sites had a hard-coded
   Color.White with nothing filled behind them, so they vanished on the light
   ground: the Home "今日" heading, the CountChip number, the pie hub ring,
   the pie child dots, and the pie "W". Each now takes the theme's paired
   colour (onSurface / pieInk / pieLine).

   The other Color.White uses are left alone deliberately -- they sit on a
   filled accent (wine primary, personal-kind chip, FAB, active nav item,
   filled filter/action buttons), where white is correct in both themes.
   Verified each by reading its background rather than by blanket replace.

3. Pie menu reshape, asked for as "もっといい形に". The wedges ran to the
   centre and the divider lines crossed the hub, so the "W" had a line
   through it and the four items read as one pie. It is now a donut: a hub
   disc drawn over the wedges, dividers starting at the hub radius instead of
   the centre, and a ring on the touched wedge's outer edge so the current
   selection is shown by position as well as colour.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Three separate defects, all found by measuring captures rather than reading
the code.

1. Note row title stayed black. NoteButton's title Text omitted color=, so it
   inherited LocalContentColor and got Compose Material's default black --
   identical to the KUKURI/card bugs, but my earlier sweep MISSED it. That
   sweep's parenthesis matching over-ran past a single-line call into the
   next statement, absorbed that statement's color=, and reported zero. The
   detector now tracks depth per character across the file; it reports 0
   genuinely uncoloured Text() calls across all 13 files, so this class is
   closed by construction rather than by spot fixes.

2. Light mode left white-on-ground text. Five sites had a hard-coded
   Color.White with nothing filled behind them, so they vanished on the light
   ground: the Home "今日" heading, the CountChip number, the pie hub ring,
   the pie child dots, and the pie "W". Each now takes the theme's paired
   colour (onSurface / pieInk / pieLine).

   The other Color.White uses are left alone deliberately -- they sit on a
   filled accent (wine primary, personal-kind chip, FAB, active nav item,
   filled filter/action buttons), where white is correct in both themes.
   Verified each by reading its background rather than by blanket replace.

3. Pie menu reshape, asked for as "もっといい形に". The wedges ran to the
   centre and the divider lines crossed the hub, so the "W" had a line
   through it and the four items read as one pie. It is now a donut: a hub
   disc drawn over the wedges, dividers starting at the hub radius instead of
   the centre, and a ring on the touched wedge's outer edge so the current
   selection is shown by position as well as colour.
</pre>
</div>
</content>
</entry>
<entry>
<title>UI: fix the card body text that stayed black in dark mode</title>
<updated>2026-10-04T22:47:16+00:00</updated>
<author>
<name>Charlie Root</name>
<email>root@dangofactory.local</email>
</author>
<published>2026-10-04T22:47:16+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/kukuri.git/commit/?id=361ba36662c9a778ae57baae54078a691011b92b'/>
<id>361ba36662c9a778ae57baae54078a691011b92b</id>
<content type='text'>
Follow-up to the KUKURI title fix -- same defect, same cause, six more sites.
The card content on Home / Note / Timeline rendered black on the dark ground:

  HomeSection label        (TODO section heading)
  Today's section label    (今日 section heading)
  NoteRow body             (note text, the unread/bold variant)
  timeline row body        (the line text)
  timeline row `from`      (the author column)
  second timeline body     (the line with an attachment/badge)

All omitted color, so they inherited LocalContentColor; no Surface in those
columns sets it, so they took Compose Material's default black. Adjacent
elements in the same rows -- the note caption, the badge, the right-aligned
due labels -- already passed an explicit color, which is why only part of each
row looked wrong.

Every Text in modules/orgflow-ui now names a color: a sweep of the whole module
for Text(...) calls with no color= argument returns zero, so this class of bug
is closed rather than patched at six sites.

onSurface rather than White, so light mode stays correct.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Follow-up to the KUKURI title fix -- same defect, same cause, six more sites.
The card content on Home / Note / Timeline rendered black on the dark ground:

  HomeSection label        (TODO section heading)
  Today's section label    (今日 section heading)
  NoteRow body             (note text, the unread/bold variant)
  timeline row body        (the line text)
  timeline row `from`      (the author column)
  second timeline body     (the line with an attachment/badge)

All omitted color, so they inherited LocalContentColor; no Surface in those
columns sets it, so they took Compose Material's default black. Adjacent
elements in the same rows -- the note caption, the badge, the right-aligned
due labels -- already passed an explicit color, which is why only part of each
row looked wrong.

Every Text in modules/orgflow-ui now names a color: a sweep of the whole module
for Text(...) calls with no color= argument returns zero, so this class of bug
is closed rather than patched at six sites.

onSurface rather than White, so light mode stays correct.
</pre>
</div>
</content>
</entry>
</feed>
