42b33234bee213325c2b6eede35edbb4fb2e566c
max
  Thu Sep 3 06:40:30 2026 -0700
hgBlat: spinner while a search runs, shorter example, left-justified result columns

Four items from Lou's note-37 on #38086.

The search is a plain form POST, so nothing on screen changed between Submit and
the arrival of the results - on an assembly served by a dynamic BLAT server that
is a ten second wait with no sign that anything is happening.  A busy overlay now
covers the form: a generic .gbBusyBg/.gbSpinner in gbModern.css (CSS-drawn, since
the page is already navigating away when it appears), put up by blatFormBusyWire()
350 ms after submit so a sub-second hg38 search does not flash a scrim, and
swapping its text after 8 s to say that an index is probably being loaded on
demand.  Skipped for Clear and for an empty query; a pageshow handler takes it
down again after a Back navigation.

The example sequence goes from 13.8 kb of the SOD1 locus to 2.5 kb of PTP4A3,
hg38 chr8:141,424,501-141,427,000.  That window is carried by both
chr8_KI270819v1_alt and chr8_MU273363v1_fix, so the example now demonstrates the
alt and fix rows and their FAQ icons instead of returning one plain hit, and it
covers two PTP4A3 exons so the result track is named after the gene.

Every column of the results table is left-justified; the numeric ones keep
tabular figures, and the score value gets a fixed width so its bars stay in a
straight line.  The alt/fix explanation icon is red rather than faint grey, and
is drawn as the browser's own info-icon SVG rather than the U+24D8 glyph, which
some system fonts do not have.

refs #38086

diff --git src/hg/htdocs/style/hgBlat.css src/hg/htdocs/style/hgBlat.css
index 7a5511a2662..0b4dcea89e0 100644
--- src/hg/htdocs/style/hgBlat.css
+++ src/hg/htdocs/style/hgBlat.css
@@ -16,49 +16,60 @@
 #blatTable { font-size:13px; width:100%; border-collapse:collapse; }
 /* Let the long text columns wrap so the table shrinks to fit smaller screens, while the fixed
  * bar columns keep a min-width so they never compress into an overlap; when even that won't fit,
  * #blatTable_wrapper scrolls horizontally. */
 #blatTable td.blatPos, #blatTable td.queryCol { white-space:normal; word-break:break-word; }
 #blatTable td.scoreCol { min-width:118px; }
 #blatTable td.covCol { min-width:120px; }
 #blatTable thead th { background:var(--headrow); border-bottom:1px solid var(--headrowLine);
     font-size:12px; color:var(--navy); font-weight:700; padding:8px 12px; white-space:nowrap; }
 #blatTable tbody td { padding:8px 12px; border-bottom:1px solid var(--lineSoft); white-space:nowrap;
     vertical-align:middle; }
 #blatTable tbody tr { cursor:pointer; }
 #blatTable tbody tr:nth-child(even) { background:var(--stripe); }
 #blatTable tbody tr:hover { background:var(--hover); }
 #blatTable tbody tr.blatSel { background:var(--sel); box-shadow:inset 3px 0 0 var(--navy); }
-#blatTable td.num, #blatTable th.num { text-align:right; font-variant-numeric:tabular-nums; }
+/* Every column reads left-justified (Lou, #38086 note-37): a table that mixes right-aligned
+ * numbers, a centred strand and left-aligned text has no single edge for the eye to follow.  The
+ * numeric columns keep tabular figures so their digits still line up under each other. */
+#blatTable thead th, #blatTable tbody td { text-align:left; }
+#blatTable td.rankCol, #blatTable td.scoreCol, #blatTable td.identCol,
+#blatTable td.spanCol { font-variant-numeric:tabular-nums; }
 #blatTable td.rankCol { color:var(--faint); }
-#blatTable td.strandCol { text-align:center; color:var(--muted); }
+#blatTable td.strandCol { color:var(--muted); }
 #blatTable td.actionsCol a { color:var(--accent); font-weight:700; }
 #blatTable td.actionsCol .blatActSep { color:var(--line); margin:0 10px; }
 /* "New tab" shown as the usual box-with-arrow icon (via a CSS background so it isn't repeated in
  * every row's markup), sitting right after the position link with just a space between them. */
 #blatTable a.blatNewTab { display:inline-block; width:11px; height:11px;
     margin-left:4px; vertical-align:-1px; background-repeat:no-repeat; background-position:center;
     background-size:contain; background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%23003a72' d='M320 0c-17.7 0-32 14.3-32 32s14.3 32 32 32h82.7L201.4 265.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L448 109.3V192c0 17.7 14.3 32 32 32s32-14.3 32-32V32c0-17.7-14.3-32-32-32H320zM80 32C35.8 32 0 67.8 0 112V432c0 44.2 35.8 80 80 80H400c44.2 0 80-35.8 80-80V320c0-17.7-14.3-32-32-32s-32 14.3-32 32V432c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V112c0-8.8 7.2-16 16-16H192c17.7 0 32-14.3 32-32s-14.3-32-32-32H80z'/%3E%3C/svg%3E"); }
 #blatTable a.blatNewTab:hover { opacity:.65; }
 #blatTable a { color:var(--accent); text-decoration:none; }
 #blatTable a:hover { color:var(--accentHover); text-decoration:underline; }
 .blatRowHint { padding:11px 18px 2px; font-size:13px; color:var(--muted); }
 .blatLocus { max-width:280px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
-.chrNote { color:var(--faint); text-decoration:none; margin-left:4px; }
-.chrNote:hover { color:var(--accent); }
-.blatScoreWrap { display:flex; align-items:center; gap:9px; justify-content:flex-end; }
-.blatScoreVal { font-size:13px; font-weight:700; text-align:right; font-variant-numeric:tabular-nums; }
+/* The alt/fix explanation icon is the one thing on the row a user really should notice, so it is
+ * red rather than the faint grey it started as (Lou, #38086 note-37).  The selector carries
+ * #blatTable so it outranks the table's generic "#blatTable a" link colour, which would otherwise
+ * repaint the icon navy through currentColor. */
+#blatTable a.chrNote { color:#b1301f; text-decoration:none; margin-left:5px; }
+#blatTable a.chrNote:hover { color:var(--accentHover); }
+/* Score is a number followed by a bar.  The number gets a fixed width so that left-justifying the
+ * column does not leave the bars in a ragged column of their own. */
+.blatScoreWrap { display:flex; align-items:center; gap:9px; }
+.blatScoreVal { font-size:13px; font-weight:700; min-width:42px; font-variant-numeric:tabular-nums; }
 .blatScoreBar { flex:0 0 54px; height:8px; background:var(--headrow); border:1px solid var(--headrowLine); overflow:hidden; }
 .blatScoreBar > i { display:block; height:100%; background:var(--accent); }
 .blatIdPct { font-size:13px; font-weight:700; font-variant-numeric:tabular-nums; }
 .blatCov { position:relative; display:block; width:150px; max-width:100%; height:10px; background:var(--headrow); border:1px solid var(--headrowLine); }
 .blatCov > i { position:absolute; top:0; bottom:0; background:var(--accent); }
 #blatTable_filter { float:left; margin:0 0 10px; }
 #blatTable_filter input { width:300px; max-width:55vw; border:1px solid var(--btnLine);
     border-radius:0; padding:5px 9px; font-size:14px; }
 #blatTable_wrapper { padding:6px 0 4px; overflow-x:auto; }
 .blatDetail { border-bottom:1px solid var(--line); background:var(--panel); padding:14px 18px 16px; }
 .blatDetail .dhead { display:flex; align-items:baseline; gap:10px; margin-bottom:12px; flex-wrap:wrap; }
 .blatDetail .dhead .lab { font-size:13px; color:var(--muted); }
 .blatSelectHint { font-size:14px; color:var(--ink); }
 .blatSelectHint a { color:var(--accent); }
 .blatSelectHint a:hover { color:var(--accentHover); }