zephyrie Claude Opus 4.7 commited on
Commit
e7c2ab6
Β·
1 Parent(s): 2f5e4d9

Flat-matte Generate button, fix hover, FOV-based MR presets

Browse files

1. Generate button β€” was a green gradient (#7fc003 -> var(--green)) with
glossy inset highlights + a green glow shadow; in light mode var(--green)
is the deeper #5d9400 so the gradient was pronounced. Now a flat solid
#76b900 with no gradient and no shadow β€” matte, and pixel-identical in
light and dark (fixed hex, not the theme token).

2. Hover was unreadable in dark. Root cause: every .primary-cta state rule
used the descendant selector `.primary-cta button`, but Gradio puts the
class on the <button> itself β€” so :hover/:active/:disabled never matched.
On hover, `.controls button:hover` took over and set the background to
var(--pill-hover-bg) = transparent in dark, revealing the navy panel
behind the black text. Rewrote every state to `button.primary-cta`, and
excluded .primary-cta from the `.controls button:hover` chip rule. Hover
is now a flat brighter green (#84cc00) with readable dark text.

3. MR quick presets β€” replaced with the three highest-volume regions in the
rflow-mr training set, with voxel dims + spacing derived from the median
FOV data (FOV mm = voxels x spacing):
T1 brain 256x256x256 spacing 0.65/1.0/1.0 (FOV ~166x256x256)
T1 breast 256x256x256 spacing 0.70/0.80/0.80 (FOV ~179x205x205)
T2 prostate 256x256x128 spacing 0.65/0.65/0.70 (FOV ~166x166x90)

Verified with Playwright: button is flat/matte/identical in both themes,
hover is green with readable text, and the T1 brain preset populates
256/256 voxels + [0.65,1.0,1.0] spacing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

Files changed (2) hide show
  1. app.py +37 -67
  2. ui/presets.py +8 -3
app.py CHANGED
@@ -1033,7 +1033,7 @@ body [role="option"][aria-selected="true"] {
1033
  do NOT change text color here, because this rule blanket-matches every
1034
  button inside .controls β€” including the primary Generate CTA β€” and tinting
1035
  text green there would make it invisible against the green button bg. */
1036
- .controls button:hover { border-color: var(--green) !important; background: var(--pill-hover-bg) !important; }
1037
 
1038
  /* ─────────────── UNIFIED SELECTED STATE ─────────────── */
1039
  /* Pattern: active = filled accent bg + accent border + accent text.
@@ -1116,11 +1116,14 @@ body [role="option"][aria-selected="true"] {
1116
  color: var(--green) !important;
1117
  }
1118
 
1119
- /* Primary CTA: Generate β€” same NVIDIA green as section headers, single-tone */
1120
- .primary-cta button, button.primary-cta {
 
 
 
1121
  margin: 18px 0 6px !important;
1122
  padding: 14px 20px !important;
1123
- background: linear-gradient(180deg, #7fc003 0%, var(--green) 100%) !important;
1124
  color: #0b1a00 !important;
1125
  border: 1px solid #5d9100 !important;
1126
  border-radius: var(--radius) !important;
@@ -1132,83 +1135,50 @@ body [role="option"][aria-selected="true"] {
1132
  position: relative;
1133
  width: 100% !important;
1134
  cursor: pointer !important;
1135
- box-shadow:
1136
- 0 1px 0 rgba(255,255,255,0.25) inset,
1137
- 0 -1px 0 rgba(0,0,0,0.20) inset,
1138
- 0 10px 28px -10px rgba(118, 185, 0, 0.40) !important;
1139
- transition: transform 140ms ease, box-shadow 220ms ease, background 180ms ease !important;
1140
- }
1141
- .primary-cta button:hover {
1142
- background: linear-gradient(180deg, #8acc00 0%, #74b400 100%) !important;
1143
- transform: translateY(-1px) !important;
1144
- box-shadow:
1145
- 0 1px 0 rgba(255,255,255,0.35) inset,
1146
- 0 -1px 0 rgba(0,0,0,0.20) inset,
1147
- 0 0 0 1px rgba(118,185,0,0.30),
1148
- 0 18px 44px -10px rgba(118, 185, 0, 0.60) !important;
1149
- }
1150
- .primary-cta button:active {
1151
- transform: translateY(0) !important;
1152
- box-shadow:
1153
- 0 1px 0 rgba(255,255,255,0.15) inset,
1154
- 0 -1px 0 rgba(0,0,0,0.30) inset,
1155
- 0 6px 16px -8px rgba(118, 185, 0, 0.50) !important;
1156
- }
1157
-
1158
- /* Lock the Generate button text color across ALL states + descendants. Going
1159
- aggressive because Gradio injects Svelte-hashed classes on the button that
1160
- can bump up rule specificity unpredictably. */
1161
- .controls .primary-cta button,
1162
- .controls .primary-cta button:hover,
1163
- .controls .primary-cta button:focus,
1164
- .controls .primary-cta button:active,
1165
- .controls .primary-cta button:focus-visible,
1166
- .controls .primary-cta button *,
1167
- .controls .primary-cta button:hover *,
1168
- .controls .primary-cta button:focus *,
1169
- .controls .primary-cta button:active *,
1170
- .primary-cta button,
1171
- .primary-cta button:hover,
1172
- .primary-cta button:focus,
1173
- .primary-cta button:active,
1174
- .primary-cta button *,
1175
- .primary-cta button:hover *,
1176
- .gradio-container .primary-cta button,
1177
- .gradio-container .primary-cta button:hover {
1178
  color: #0b1a00 !important;
1179
  -webkit-text-fill-color: #0b1a00 !important;
1180
  }
1181
 
1182
- /* Disabled / generating state β€” must beat the hover rules above. The combined
1183
- pseudo-class `:disabled:hover` adds extra specificity (0,3,2 with .controls)
1184
- so the disabled style wins even while the user is hovering. */
1185
- .primary-cta button:disabled,
1186
- .primary-cta button:disabled:hover,
1187
- .primary-cta button:disabled:focus,
1188
- .primary-cta button:disabled:active,
1189
- .primary-cta button:disabled:focus-visible,
1190
- .controls .primary-cta button:disabled,
1191
- .controls .primary-cta button:disabled:hover,
1192
- .controls .primary-cta button:disabled:focus,
1193
- .controls .primary-cta button:disabled:active,
1194
- .gradio-container .primary-cta button:disabled,
1195
- .gradio-container .primary-cta button:disabled:hover {
1196
- background: linear-gradient(180deg, var(--cta-off-a) 0%, var(--cta-off-b) 100%) !important;
1197
  color: var(--cta-off-text) !important;
1198
  -webkit-text-fill-color: var(--cta-off-text) !important;
1199
  cursor: wait !important;
1200
  opacity: 1 !important;
1201
- transform: none !important;
1202
  box-shadow: none !important;
1203
  border-color: var(--cta-off-border) !important;
1204
  }
1205
- /* Make sure nested spans inside the disabled button inherit the dim text color */
1206
- .primary-cta button:disabled *,
1207
- .primary-cta button:disabled:hover * {
1208
  color: var(--cta-off-text) !important;
1209
  -webkit-text-fill-color: var(--cta-off-text) !important;
1210
  }
1211
- .primary-cta button:disabled::after {
1212
  content: "";
1213
  display: inline-block;
1214
  width: 10px; height: 10px;
 
1033
  do NOT change text color here, because this rule blanket-matches every
1034
  button inside .controls β€” including the primary Generate CTA β€” and tinting
1035
  text green there would make it invisible against the green button bg. */
1036
+ .controls button:not(.primary-cta):hover { border-color: var(--green) !important; background: var(--pill-hover-bg) !important; }
1037
 
1038
  /* ─────────────── UNIFIED SELECTED STATE ─────────────── */
1039
  /* Pattern: active = filled accent bg + accent border + accent text.
 
1116
  color: var(--green) !important;
1117
  }
1118
 
1119
+ /* Primary CTA: Generate β€” flat matte NVIDIA green, identical in light + dark.
1120
+ Gradio puts elem_classes on the <button>, so every state targets
1121
+ `button.primary-cta` directly; the old descendant form `.primary-cta button`
1122
+ matched nothing, which is why the hover/active states silently failed. */
1123
+ button.primary-cta {
1124
  margin: 18px 0 6px !important;
1125
  padding: 14px 20px !important;
1126
+ background: #76b900 !important;
1127
  color: #0b1a00 !important;
1128
  border: 1px solid #5d9100 !important;
1129
  border-radius: var(--radius) !important;
 
1135
  position: relative;
1136
  width: 100% !important;
1137
  cursor: pointer !important;
1138
+ box-shadow: none !important;
1139
+ transition: background 140ms ease !important;
1140
+ }
1141
+ .controls button.primary-cta:hover,
1142
+ button.primary-cta:hover {
1143
+ background: #84cc00 !important;
1144
+ border-color: #5d9100 !important;
1145
+ }
1146
+ button.primary-cta:active {
1147
+ background: #6aa600 !important;
1148
+ }
1149
+
1150
+ /* Lock the Generate button text colour across normal/hover/active states and
1151
+ any Svelte-hashed descendant spans. (Disabled overrides this below.) */
1152
+ button.primary-cta,
1153
+ button.primary-cta:hover,
1154
+ button.primary-cta:focus,
1155
+ button.primary-cta:active,
1156
+ button.primary-cta *,
1157
+ button.primary-cta:hover *,
1158
+ button.primary-cta:active * {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1159
  color: #0b1a00 !important;
1160
  -webkit-text-fill-color: #0b1a00 !important;
1161
  }
1162
 
1163
+ /* Disabled / generating state β€” the :disabled:hover pseudo adds specificity so
1164
+ it beats the plain :hover rule even while the pointer is over the button. */
1165
+ .controls button.primary-cta:disabled,
1166
+ button.primary-cta:disabled,
1167
+ button.primary-cta:disabled:hover {
1168
+ background: var(--cta-off-a) !important;
 
 
 
 
 
 
 
 
 
1169
  color: var(--cta-off-text) !important;
1170
  -webkit-text-fill-color: var(--cta-off-text) !important;
1171
  cursor: wait !important;
1172
  opacity: 1 !important;
 
1173
  box-shadow: none !important;
1174
  border-color: var(--cta-off-border) !important;
1175
  }
1176
+ button.primary-cta:disabled *,
1177
+ button.primary-cta:disabled:hover * {
 
1178
  color: var(--cta-off-text) !important;
1179
  -webkit-text-fill-color: var(--cta-off-text) !important;
1180
  }
1181
+ button.primary-cta:disabled::after {
1182
  content: "";
1183
  display: inline-block;
1184
  width: 10px; height: 10px;
ui/presets.py CHANGED
@@ -82,10 +82,15 @@ CT_SAMPLES = [
82
  },
83
  ]
84
 
 
 
 
 
 
85
  MR_SAMPLES = [
86
- {"label": "T2 prostate", "modality_label": "T2 prostate", "xy": 256, "z": 128, "spacing": [1.0, 1.0, 1.5]},
87
- {"label": "T1 abdomen", "modality_label": "T1 abdomen", "xy": 256, "z": 128, "spacing": [1.25, 1.0, 1.0]},
88
- {"label": "T2 brain", "modality_label": "T2 brain", "xy": 256, "z": 128, "spacing": [1.0, 1.0, 1.0]},
89
  ]
90
 
91
  MR_BRAIN_SAMPLES = [
 
82
  },
83
  ]
84
 
85
+ # FOV-derived from rflow-mr training-data medians (FOV mm = voxels Γ— spacing);
86
+ # the three highest-volume body regions in the training set:
87
+ # T1 brain 160 Γ— 256 Γ— 256 mm (n=4,659)
88
+ # T1 breast 174 Γ— 200 Γ— 200 mm (n=2,162)
89
+ # T2 prostate 170 Γ— 170 Γ— 90 mm (n=898)
90
  MR_SAMPLES = [
91
+ {"label": "T1 brain", "modality_label": "T1 brain", "xy": 256, "z": 256, "spacing": [0.65, 1.0, 1.0]},
92
+ {"label": "T1 breast", "modality_label": "T1 breast", "xy": 256, "z": 256, "spacing": [0.70, 0.80, 0.80]},
93
+ {"label": "T2 prostate", "modality_label": "T2 prostate", "xy": 256, "z": 128, "spacing": [0.65, 0.65, 0.70]},
94
  ]
95
 
96
  MR_BRAIN_SAMPLES = [