bernardo-de-almeida commited on
Commit
c3a22a8
·
1 Parent(s): 3380a80

feat: improve style

Browse files
Files changed (2) hide show
  1. app.py +178 -163
  2. style.css +1318 -91
app.py CHANGED
@@ -38,8 +38,6 @@ if HF_TOKEN is None:
38
  "Missing Hugging Face token. Set NTV3_HF_TOKEN as a Space Secret."
39
  )
40
 
41
- # asyncio.set_event_loop_policy(asyncio.DefaultEventLoopPolicy())
42
-
43
  PLOT_TARGET_POINTS = int(os.environ.get("PLOT_TARGET_POINTS", "1500"))
44
  SEARCH_MAX_RESULTS = int(os.environ.get("SEARCH_MAX_RESULTS", "50"))
45
 
@@ -122,12 +120,21 @@ def _make_tracks_figure(
122
 
123
  n = len(series)
124
 
 
 
 
 
 
 
 
 
 
125
  # Create subplots with shared x-axis
126
  fig = make_subplots(
127
  rows=n,
128
  cols=1,
129
  shared_xaxes=True,
130
- vertical_spacing=0.02,
131
  subplot_titles=[title for title, _ in series],
132
  )
133
 
@@ -166,13 +173,31 @@ def _make_tracks_figure(
166
  col=1,
167
  )
168
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  # Update layout for better appearance
170
  fig.update_layout(
171
- height=150 * n, # Adjust height based on number of tracks
172
  width=1200,
173
- margin={"l": 80, "r": 20, "t": 40, "b": 60},
174
  hovermode="x unified", # Show all values at same x position
175
  template="plotly_white",
 
 
 
 
 
 
176
  )
177
 
178
  # Update y-axes to remove ticks and improve appearance
@@ -453,12 +478,6 @@ def remove_selected(current_selected: list[str], to_remove: list[str]):
453
  return gr.update(choices=cur, value=cur, visible=show_selected)
454
 
455
 
456
- def update_coords_on_species_change(species: str):
457
- """Update coordinates when species changes."""
458
- coords = DEFAULT_COORDS.get(species, DEFAULT_COORDS["human"])
459
- return coords["chrom"], coords["start"], coords["end"]
460
-
461
-
462
  def reset_on_species_change(species: str):
463
  """Reset search and selected tracks when species changes."""
464
  # Clear results + selected when species changes (avoids mismatched IDs)
@@ -599,18 +618,8 @@ def predict(
599
 
600
  # Defaults if user picked none
601
  if has_bigwigs and not bigwig_selected:
602
- default_bigwig_tracks = [
603
- "ENCSR056HPM", # K562 RNA-seq
604
- "ENCSR921NMD", # K562 DNAse
605
- "ENCSR000DWD", # K562 H3k4me3
606
- "ENCSR000AKO", # K562 CTCF
607
- "ENCSR561FEE_P", # HepG2 RNA-seq
608
- "ENCSR000EJV", # HepG2 DNAse
609
- "ENCSR000AMP", # HepG2 H3k4me3
610
- "ENCSR000BIE", # HepG2 CTCF
611
- ]
612
  # Filter to only include tracks that are available for this species/assembly
613
- bigwig_selected = [tid for tid in default_bigwig_tracks if tid in bw_names]
614
 
615
  if (not bed_elements) and bed_names:
616
  default_bed_elements = ["protein_coding_gene", "exon", "intron"]
@@ -672,9 +681,6 @@ def predict(
672
  fig = _make_tracks_figure(x, series, region=region)
673
  tprint("figure created")
674
 
675
- png_path = _save_fig_png(fig)
676
- tprint("figure png saved")
677
-
678
  meta = {
679
  "model_id": current_model_id,
680
  "species": out.species,
@@ -688,7 +694,16 @@ def predict(
688
  "plot_target_points": PLOT_TARGET_POINTS,
689
  }
690
 
691
- return fig, png_path, meta, out, bigwig_selected, bed_elements
 
 
 
 
 
 
 
 
 
692
 
693
 
694
  # -----------------------------
@@ -699,32 +714,53 @@ CSS_PATH = Path(__file__).parent / "style.css"
699
  CSS = CSS_PATH.read_text() if CSS_PATH.exists() else ""
700
 
701
  JS = """
702
- function addDownloadIcon() {
703
- const plot = document.querySelector("#tracks_plot");
704
- if (!plot) return;
705
- if (document.querySelector("#tracks_plot_download")) return;
706
-
707
- const btn = document.createElement("div");
708
- btn.id = "tracks_plot_download";
709
- btn.title = "Download PNG";
710
- btn.innerHTML = `
711
- <svg viewBox="0 0 24 24" aria-hidden="true">
712
- <path d="M5 20h14v-2H5v2zm7-18v10.17l3.59-3.58L17 10l-5 5-5-5
713
- 1.41-1.41L11 12.17V2h1z"/>
714
- </svg>
715
- `;
716
- btn.onclick = () => {
717
- const link = document.querySelector("#export_png_hidden a");
718
- if (link) link.click();
719
- };
720
- plot.appendChild(btn);
721
  }
722
- function setup() {
723
- addDownloadIcon();
724
- const obs = new MutationObserver(() => addDownloadIcon());
725
- obs.observe(document.body, { childList: true, subtree: true });
 
 
726
  }
727
- setup();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
728
  """
729
 
730
  # BED list is small enough to keep as dropdown
@@ -803,6 +839,14 @@ with gr.Blocks(title="NTv3 Tracks Demo") as demo:
803
  Predict and visualize functional genomics signals directly from DNA using
804
  <strong>Nucleotide Transformer v3</strong>.
805
  </p>
 
 
 
 
 
 
 
 
806
  </div>
807
 
808
  <div class="intro-grid">
@@ -829,8 +873,8 @@ with gr.Blocks(title="NTv3 Tracks Demo") as demo:
829
  <h3>3) Explore</h3>
830
  <ul>
831
  <li>View stacked tracks across the region</li>
832
- <li>Compare multiple signals side-by-side</li>
833
- <li>Download a high-resolution PNG from the plot</li>
834
  </ul>
835
  </div>
836
  </div>
@@ -841,8 +885,7 @@ with gr.Blocks(title="NTv3 Tracks Demo") as demo:
841
  to get started, taking ~ 15 seconds to run for the example on human.</span>
842
  </div>
843
 
844
- <div style="margin-top: 16px; padding: 12px; background: rgba(0,0,0,0.03);
845
- border-radius: 12px; font-size: 0.95rem;">
846
  <strong>Available species:</strong> {_all_species_list}<br>
847
  <br>
848
  <strong>Species with functional tracks:</strong> {_bigwig_species_list}
@@ -853,7 +896,7 @@ with gr.Blocks(title="NTv3 Tracks Demo") as demo:
853
  elem_id="intro_markdown",
854
  )
855
 
856
- gr.Markdown("## Select NTv3 post-trained model")
857
 
858
  # Model display names (without InstaDeepAI/ prefix) and their full IDs
859
  MODEL_OPTIONS = {
@@ -875,7 +918,7 @@ with gr.Blocks(title="NTv3 Tracks Demo") as demo:
875
 
876
  model_status = gr.Markdown("", visible=False)
877
 
878
- gr.Markdown("## Input DNA sequence")
879
 
880
  # Get all available species from the pipeline
881
  all_species = sorted(ASSEMBLY_TO_SPECIES.values())
@@ -910,9 +953,23 @@ with gr.Blocks(title="NTv3 Tracks Demo") as demo:
910
  + ")"
911
  )
912
  with gr.Row():
913
- chrom = gr.Textbox(label="Chromosome", value=_default_coords["chrom"])
914
- start = gr.Number(label="Start", value=_default_coords["start"], precision=0)
915
- end = gr.Number(label="End", value=_default_coords["end"], precision=0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
916
 
917
  # DNA sequence section - visible only when "Enter DNA sequence" is selected
918
  # Using Textbox directly (not wrapped in Group) to avoid visual border/line
@@ -951,7 +1008,7 @@ with gr.Blocks(title="NTv3 Tracks Demo") as demo:
951
  outputs=[model_status, model_status],
952
  )
953
 
954
- gr.Markdown("## Select functional tracks")
955
 
956
  # Button to download tracks metadata
957
  def get_metadata_file_path():
@@ -1013,24 +1070,27 @@ with gr.Blocks(title="NTv3 Tracks Demo") as demo:
1013
  bigwig_clear_btn = gr.Button("Clear search results")
1014
  bigwig_remove_btn = gr.Button("Remove all selected")
1015
 
1016
- gr.Markdown("## Select genome annotation elements")
1017
 
1018
  bed_elements = gr.Dropdown(
1019
  choices=_init_bed,
1020
  value=_init_bed_selected if _init_bed_selected else [],
1021
  multiselect=True,
1022
  label="Genome annotation elements (search + select)",
 
1023
  )
1024
 
1025
  btn = gr.Button("Predict", elem_id="predict_btn")
1026
 
1027
- gr.Markdown("## NTv3 predictions for selected tracks and elements")
1028
- gr.Markdown(
1029
- "Note: NTv3 predictions are for the 37.5% center of the input sequence."
 
 
 
1030
  )
1031
 
1032
- plot = gr.Plot(label="", elem_id="tracks_plot")
1033
- export_png = gr.File(elem_id="export_png_hidden", interactive=False)
1034
 
1035
  # State to store prediction output and selections for BigWig export
1036
  prediction_state = gr.State(value=None)
@@ -1038,13 +1098,12 @@ with gr.Blocks(title="NTv3 Tracks Demo") as demo:
1038
  bed_elements_state = gr.State(value=[])
1039
 
1040
  download_bigwig_btn = gr.Button(
1041
- "📥 Download tracks as BigWig files (ZIP)", variant="secondary"
 
 
1042
  )
1043
  export_bigwig = gr.File(label="Download BigWig files", visible=False)
1044
 
1045
- with gr.Accordion("Meta (click to expand)", open=False):
1046
- meta = gr.JSON(label="Meta")
1047
-
1048
  # --- wiring (live search + auto-add) ---
1049
 
1050
  # Live search on every keystroke and when text changes (including deletion)
@@ -1106,31 +1165,17 @@ with gr.Blocks(title="NTv3 Tracks Demo") as demo:
1106
  current_results: list[str],
1107
  current_species: str,
1108
  ):
1109
- upd = add_selected(selected_now, results_checked) # reuses your function
1110
- # Show selected tracks section if there are selections
1111
  show_selected = bool(upd["value"])
1112
 
1113
- # Get the new search results choices directly (excluding all selected tracks)
1114
  new_choices = _get_search_results_choices(
1115
  current_species, current_query, upd["value"]
1116
  )
1117
 
1118
- # Create a completely fresh update with explicit empty value
1119
- # to prevent any checked state. Force Gradio to clear checked state
1120
- # by explicitly setting value to empty list.
1121
- # Ensure no items from results_checked are in new_choices
1122
- # (they should already be filtered, but double-check)
1123
- checked_track_ids = {_extract_track_id(x) for x in results_checked}
1124
- new_choices_filtered = [
1125
- c for c in new_choices if _extract_track_id(c) not in checked_track_ids
1126
- ]
1127
-
1128
- # Create update with explicit empty value
1129
- # This should force Gradio to clear all checked items
1130
- fresh_update = gr.update(
1131
- choices=new_choices_filtered,
1132
- value=[], # CRITICAL: Explicitly empty list to clear all checked state
1133
- )
1134
 
1135
  return gr.update(**upd, visible=show_selected), fresh_update
1136
 
@@ -1142,8 +1187,8 @@ with gr.Blocks(title="NTv3 Tracks Demo") as demo:
1142
  current_results: list[str],
1143
  current_species: str,
1144
  ):
1145
- # First, get the updates
1146
- selected_update, results_update = _auto_add(
1147
  selected_now,
1148
  results_checked,
1149
  current_query,
@@ -1151,34 +1196,6 @@ with gr.Blocks(title="NTv3 Tracks Demo") as demo:
1151
  current_species,
1152
  )
1153
 
1154
- # Force the results update to have an explicit empty value
1155
- # Extract choices from results_update if it's a dict-like object
1156
- if isinstance(results_update, dict):
1157
- results_choices = results_update.get("choices", [])
1158
- else:
1159
- # If it's a gr.update object, we need to access it differently
1160
- # Try to get choices from the update
1161
- try:
1162
- results_choices = (
1163
- results_update.choices if hasattr(results_update, "choices") else []
1164
- )
1165
- except Exception:
1166
- # Fallback: get choices from the search function directly
1167
- results_choices = _get_search_results_choices(
1168
- current_species,
1169
- current_query,
1170
- selected_now + results_checked
1171
- if isinstance(selected_now, list)
1172
- and isinstance(results_checked, list)
1173
- else [],
1174
- )
1175
-
1176
- # Create a completely fresh update with explicit empty value
1177
- # This should force Gradio to clear all checked items
1178
- fresh_results_update = gr.update(choices=results_choices, value=[])
1179
-
1180
- return selected_update, fresh_results_update
1181
-
1182
  bigwig_results.change(
1183
  fn=_auto_add_wrapper,
1184
  inputs=[bigwig_selected, bigwig_results, bigwig_query, bigwig_results, species],
@@ -1247,27 +1264,19 @@ with gr.Blocks(title="NTv3 Tracks Demo") as demo:
1247
  show_seq = not show_coords
1248
 
1249
  # Format available tracks for display if species has bigwigs
 
 
 
 
1250
  if has_bigwigs:
1251
  try:
1252
  track_ids = _get_bigwig_names(species)
1253
  formatted_tracks = [_format_track_for_display(tid) for tid in track_ids]
1254
- # Get default tracks for this species (filter to what's available)
1255
- default_track_ids = [
1256
- tid for tid in DEFAULT_BIGWIG_TRACKS if tid in track_ids
1257
- ]
1258
- default_formatted = [
1259
- _format_track_for_display(tid) for tid in default_track_ids
1260
- ]
1261
- # Show selected tracks section if there are default tracks
1262
  show_selected_tracks = bool(default_formatted)
1263
  except Exception:
1264
- formatted_tracks = []
1265
- default_formatted = []
1266
- show_selected_tracks = False
1267
- else:
1268
- formatted_tracks = []
1269
- default_formatted = []
1270
- show_selected_tracks = False
1271
 
1272
  return (
1273
  gr.update(visible=show_coords, value=coords["chrom"]),
@@ -1307,32 +1316,17 @@ with gr.Blocks(title="NTv3 Tracks Demo") as demo:
1307
  # Update input visibility when radio button changes
1308
  def update_input_visibility(input_type_val: str, species: str):
1309
  """Update input visibility when radio button changes."""
1310
- # Explicitly check the input type value
1311
- if input_type_val == "Enter DNA sequence":
1312
- # Hide coordinates, show sequence
1313
- return (
1314
- gr.update(
1315
- visible=False
1316
- ), # coords_group - always hide when sequence is selected
1317
- gr.update(visible=True), # seq - always show when sequence is selected
1318
- )
1319
- elif input_type_val == "Use genomic coordinates":
1320
- # Show coordinates only if species supports it
1321
- is_supported = species in SPECIES_WITH_COORDINATE_SUPPORT
1322
- return (
1323
- gr.update(
1324
- visible=is_supported
1325
- ), # coords_group - show only if supported
1326
- gr.update(
1327
- visible=not is_supported
1328
- ), # seq - hide when coordinates are shown
1329
- )
1330
- else:
1331
- # Fallback: hide both (shouldn't happen)
1332
- return (
1333
- gr.update(visible=False),
1334
- gr.update(visible=False),
1335
- )
1336
 
1337
  species.change(
1338
  fn=update_input_type_on_species_change,
@@ -1361,10 +1355,29 @@ with gr.Blocks(title="NTv3 Tracks Demo") as demo:
1361
  input_type.change(
1362
  fn=update_input_visibility,
1363
  inputs=[input_type, species],
1364
- outputs=[coords_group, seq],
1365
  )
1366
 
 
 
 
 
 
 
 
 
 
 
1367
  btn.click(
 
 
 
 
 
 
 
 
 
1368
  fn=predict,
1369
  inputs=[
1370
  seq,
@@ -1377,9 +1390,11 @@ with gr.Blocks(title="NTv3 Tracks Demo") as demo:
1377
  bed_elements,
1378
  ],
1379
  outputs=[
 
 
1380
  plot,
1381
- export_png,
1382
- meta,
1383
  prediction_state,
1384
  bigwig_selected_state,
1385
  bed_elements_state,
 
38
  "Missing Hugging Face token. Set NTV3_HF_TOKEN as a Space Secret."
39
  )
40
 
 
 
41
  PLOT_TARGET_POINTS = int(os.environ.get("PLOT_TARGET_POINTS", "1500"))
42
  SEARCH_MAX_RESULTS = int(os.environ.get("SEARCH_MAX_RESULTS", "50"))
43
 
 
120
 
121
  n = len(series)
122
 
123
+ # Adjust vertical spacing based on number of tracks
124
+ # More spacing when fewer tracks to prevent title overlap
125
+ if n <= 2:
126
+ vertical_spacing = 0.15 # More space for 1-2 tracks
127
+ elif n <= 4:
128
+ vertical_spacing = 0.08 # Moderate space for 3-4 tracks
129
+ else:
130
+ vertical_spacing = 0.04 # Tighter spacing for many tracks
131
+
132
  # Create subplots with shared x-axis
133
  fig = make_subplots(
134
  rows=n,
135
  cols=1,
136
  shared_xaxes=True,
137
+ vertical_spacing=vertical_spacing,
138
  subplot_titles=[title for title, _ in series],
139
  )
140
 
 
173
  col=1,
174
  )
175
 
176
+ # Adjust height and margins based on number of tracks
177
+ # More height per track when fewer tracks to accommodate titles
178
+ if n <= 2:
179
+ height_per_track = 200 # More height for 1-2 tracks
180
+ top_margin = 60 # More top margin for titles
181
+ elif n <= 4:
182
+ height_per_track = 170 # Moderate height for 3-4 tracks
183
+ top_margin = 50
184
+ else:
185
+ height_per_track = 150 # Standard height for many tracks
186
+ top_margin = 40
187
+
188
  # Update layout for better appearance
189
  fig.update_layout(
190
+ height=height_per_track * n, # Adjust height based on number of tracks
191
  width=1200,
192
+ margin={"l": 80, "r": 20, "t": top_margin, "b": 60},
193
  hovermode="x unified", # Show all values at same x position
194
  template="plotly_white",
195
+ modebar={
196
+ "activecolor": "#7dd3fc", # Blue color for active/hovered buttons
197
+ "bgcolor": "rgba(255, 255, 255, 0.9)",
198
+ "color": "#7dd3fc", # Blue color for buttons
199
+ "orientation": "v",
200
+ },
201
  )
202
 
203
  # Update y-axes to remove ticks and improve appearance
 
478
  return gr.update(choices=cur, value=cur, visible=show_selected)
479
 
480
 
 
 
 
 
 
 
481
  def reset_on_species_change(species: str):
482
  """Reset search and selected tracks when species changes."""
483
  # Clear results + selected when species changes (avoids mismatched IDs)
 
618
 
619
  # Defaults if user picked none
620
  if has_bigwigs and not bigwig_selected:
 
 
 
 
 
 
 
 
 
 
621
  # Filter to only include tracks that are available for this species/assembly
622
+ bigwig_selected = [tid for tid in DEFAULT_BIGWIG_TRACKS if tid in bw_names]
623
 
624
  if (not bed_elements) and bed_names:
625
  default_bed_elements = ["protein_coding_gene", "exon", "intron"]
 
681
  fig = _make_tracks_figure(x, series, region=region)
682
  tprint("figure created")
683
 
 
 
 
684
  meta = {
685
  "model_id": current_model_id,
686
  "species": out.species,
 
694
  "plot_target_points": PLOT_TARGET_POINTS,
695
  }
696
 
697
+ return (
698
+ gr.update(visible=True), # predictions_heading
699
+ gr.update(visible=True), # predictions_note
700
+ gr.update(value=fig, visible=True), # plot
701
+ gr.update(visible=True), # download_bigwig_btn
702
+ # meta,
703
+ out,
704
+ bigwig_selected,
705
+ bed_elements,
706
+ )
707
 
708
 
709
  # -----------------------------
 
714
  CSS = CSS_PATH.read_text() if CSS_PATH.exists() else ""
715
 
716
  JS = """
717
+ // Remove blue backgrounds from footer buttons after page loads
718
+ function removeFooterButtonBackgrounds() {
719
+ // Target all buttons and links in footer
720
+ const footer = document.querySelector('footer');
721
+ if (footer) {
722
+ const buttons = footer.querySelectorAll('button, a[role="button"], a[class*="button"]');
723
+ buttons.forEach(btn => {
724
+ btn.style.setProperty('background', 'transparent', 'important');
725
+ btn.style.setProperty('background-color', 'transparent', 'important');
726
+ btn.style.setProperty('border', '1px solid rgba(125, 211, 252, 0.2)', 'important');
727
+ });
728
+ }
 
 
 
 
 
 
 
729
  }
730
+
731
+ // Run on page load
732
+ if (document.readyState === 'loading') {
733
+ document.addEventListener('DOMContentLoaded', removeFooterButtonBackgrounds);
734
+ } else {
735
+ removeFooterButtonBackgrounds();
736
  }
737
+
738
+ // Also run after a delay to catch dynamically loaded content
739
+ setTimeout(removeFooterButtonBackgrounds, 100);
740
+ setTimeout(removeFooterButtonBackgrounds, 500);
741
+ setTimeout(removeFooterButtonBackgrounds, 1000);
742
+
743
+ // Use MutationObserver to watch for dynamically added footer buttons
744
+ const observer = new MutationObserver(() => {
745
+ removeFooterButtonBackgrounds();
746
+ });
747
+
748
+ // Observe changes to the footer
749
+ const footer = document.querySelector('footer');
750
+ if (footer) {
751
+ observer.observe(footer, {
752
+ childList: true,
753
+ subtree: true,
754
+ attributes: true,
755
+ attributeFilter: ['style', 'class']
756
+ });
757
+ }
758
+
759
+ // Also observe the entire document for footer additions
760
+ observer.observe(document.body, {
761
+ childList: true,
762
+ subtree: true
763
+ });
764
  """
765
 
766
  # BED list is small enough to keep as dropdown
 
839
  Predict and visualize functional genomics signals directly from DNA using
840
  <strong>Nucleotide Transformer v3</strong>.
841
  </p>
842
+
843
+ <div class="intro-pillrow">
844
+ <span class="intro-pill">🧬 Functional genomics</span>
845
+ <span class="intro-pill">📊 BigWig tracks</span>
846
+ <span class="intro-pill">🎯 Genome annotation</span>
847
+ <span class="intro-pill">🌍 Multi-species</span>
848
+ <span class="intro-pill">⚡ Interactive visualization</span>
849
+ </div>
850
  </div>
851
 
852
  <div class="intro-grid">
 
873
  <h3>3) Explore</h3>
874
  <ul>
875
  <li>View stacked tracks across the region</li>
876
+ <li>Compare multiple tracks side-by-side</li>
877
+ <li>Download plot and BigWig files</li>
878
  </ul>
879
  </div>
880
  </div>
 
885
  to get started, taking ~ 15 seconds to run for the example on human.</span>
886
  </div>
887
 
888
+ <div class="intro-species-info">
 
889
  <strong>Available species:</strong> {_all_species_list}<br>
890
  <br>
891
  <strong>Species with functional tracks:</strong> {_bigwig_species_list}
 
896
  elem_id="intro_markdown",
897
  )
898
 
899
+ gr.Markdown("# Select NTv3 post-trained model")
900
 
901
  # Model display names (without InstaDeepAI/ prefix) and their full IDs
902
  MODEL_OPTIONS = {
 
918
 
919
  model_status = gr.Markdown("", visible=False)
920
 
921
+ gr.Markdown("# Input DNA sequence")
922
 
923
  # Get all available species from the pipeline
924
  all_species = sorted(ASSEMBLY_TO_SPECIES.values())
 
953
  + ")"
954
  )
955
  with gr.Row():
956
+ # chrom = gr.Textbox(
957
+ # label="Chromosome", value=_default_coords["chrom"], elem_id="chromosome_input"
958
+ # )
959
+ chrom = gr.Dropdown(
960
+ label="Chromosome",
961
+ choices=[], # no predefined list
962
+ value=_default_coords["chrom"],
963
+ allow_custom_value=True, # user can type anything (e.g. chr19, scaffold_123)
964
+ filterable=True, # enables typing/search UI
965
+ elem_id="chromosome_input",
966
+ )
967
+ start = gr.Number(
968
+ label="Start", value=_default_coords["start"], precision=0, elem_id="start_input"
969
+ )
970
+ end = gr.Number(
971
+ label="End", value=_default_coords["end"], precision=0, elem_id="end_input"
972
+ )
973
 
974
  # DNA sequence section - visible only when "Enter DNA sequence" is selected
975
  # Using Textbox directly (not wrapped in Group) to avoid visual border/line
 
1008
  outputs=[model_status, model_status],
1009
  )
1010
 
1011
+ gr.Markdown("# Select functional tracks")
1012
 
1013
  # Button to download tracks metadata
1014
  def get_metadata_file_path():
 
1070
  bigwig_clear_btn = gr.Button("Clear search results")
1071
  bigwig_remove_btn = gr.Button("Remove all selected")
1072
 
1073
+ gr.Markdown("# Select genome annotation elements")
1074
 
1075
  bed_elements = gr.Dropdown(
1076
  choices=_init_bed,
1077
  value=_init_bed_selected if _init_bed_selected else [],
1078
  multiselect=True,
1079
  label="Genome annotation elements (search + select)",
1080
+ elem_id="bed_elements_dropdown",
1081
  )
1082
 
1083
  btn = gr.Button("Predict", elem_id="predict_btn")
1084
 
1085
+ predictions_heading = gr.Markdown(
1086
+ "## NTv3 predictions for selected tracks and elements", visible=False
1087
+ )
1088
+ predictions_note = gr.Markdown(
1089
+ "Note: NTv3 predictions are for the 37.5% center of the input sequence.",
1090
+ visible=False,
1091
  )
1092
 
1093
+ plot = gr.Plot(label="", elem_id="tracks_plot", visible=False)
 
1094
 
1095
  # State to store prediction output and selections for BigWig export
1096
  prediction_state = gr.State(value=None)
 
1098
  bed_elements_state = gr.State(value=[])
1099
 
1100
  download_bigwig_btn = gr.Button(
1101
+ "📥 Download tracks as BigWig files (ZIP)",
1102
+ variant="secondary",
1103
+ visible=False,
1104
  )
1105
  export_bigwig = gr.File(label="Download BigWig files", visible=False)
1106
 
 
 
 
1107
  # --- wiring (live search + auto-add) ---
1108
 
1109
  # Live search on every keystroke and when text changes (including deletion)
 
1165
  current_results: list[str],
1166
  current_species: str,
1167
  ):
1168
+ """Add selected tracks and refresh search results."""
1169
+ upd = add_selected(selected_now, results_checked)
1170
  show_selected = bool(upd["value"])
1171
 
1172
+ # Get updated search results (excluding newly selected tracks)
1173
  new_choices = _get_search_results_choices(
1174
  current_species, current_query, upd["value"]
1175
  )
1176
 
1177
+ # Clear checked state by setting empty value
1178
+ fresh_update = gr.update(choices=new_choices, value=[])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1179
 
1180
  return gr.update(**upd, visible=show_selected), fresh_update
1181
 
 
1187
  current_results: list[str],
1188
  current_species: str,
1189
  ):
1190
+ """Wrapper to ensure results are cleared after adding tracks."""
1191
+ return _auto_add(
1192
  selected_now,
1193
  results_checked,
1194
  current_query,
 
1196
  current_species,
1197
  )
1198
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1199
  bigwig_results.change(
1200
  fn=_auto_add_wrapper,
1201
  inputs=[bigwig_selected, bigwig_results, bigwig_query, bigwig_results, species],
 
1264
  show_seq = not show_coords
1265
 
1266
  # Format available tracks for display if species has bigwigs
1267
+ formatted_tracks = []
1268
+ default_formatted = []
1269
+ show_selected_tracks = False
1270
+
1271
  if has_bigwigs:
1272
  try:
1273
  track_ids = _get_bigwig_names(species)
1274
  formatted_tracks = [_format_track_for_display(tid) for tid in track_ids]
1275
+ default_track_ids = [tid for tid in DEFAULT_BIGWIG_TRACKS if tid in track_ids]
1276
+ default_formatted = [_format_track_for_display(tid) for tid in default_track_ids]
 
 
 
 
 
 
1277
  show_selected_tracks = bool(default_formatted)
1278
  except Exception:
1279
+ pass
 
 
 
 
 
 
1280
 
1281
  return (
1282
  gr.update(visible=show_coords, value=coords["chrom"]),
 
1316
  # Update input visibility when radio button changes
1317
  def update_input_visibility(input_type_val: str, species: str):
1318
  """Update input visibility when radio button changes."""
1319
+ is_supported = species in SPECIES_WITH_COORDINATE_SUPPORT
1320
+ use_coords = input_type_val == "Use genomic coordinates"
1321
+ show_coords = is_supported and use_coords
1322
+
1323
+ return (
1324
+ gr.update(visible=show_coords), # coords_group
1325
+ gr.update(visible=not show_coords), # seq
1326
+ gr.update(visible=show_coords), # chrom
1327
+ gr.update(visible=show_coords), # start
1328
+ gr.update(visible=show_coords), # end
1329
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1330
 
1331
  species.change(
1332
  fn=update_input_type_on_species_change,
 
1355
  input_type.change(
1356
  fn=update_input_visibility,
1357
  inputs=[input_type, species],
1358
+ outputs=[coords_group, seq, chrom, start, end],
1359
  )
1360
 
1361
+ def show_prediction_ui():
1362
+ """Show prediction UI elements immediately when Predict is clicked."""
1363
+ return (
1364
+ gr.update(visible=True), # predictions_heading
1365
+ gr.update(visible=True), # predictions_note
1366
+ gr.update(visible=True), # plot (shows progress bar)
1367
+ gr.update(visible=False), # download_bigwig_btn (will be shown after prediction)
1368
+ )
1369
+
1370
+ # Show UI elements immediately when button is clicked
1371
  btn.click(
1372
+ fn=show_prediction_ui,
1373
+ inputs=[],
1374
+ outputs=[
1375
+ predictions_heading,
1376
+ predictions_note,
1377
+ plot,
1378
+ download_bigwig_btn,
1379
+ ],
1380
+ ).then(
1381
  fn=predict,
1382
  inputs=[
1383
  seq,
 
1390
  bed_elements,
1391
  ],
1392
  outputs=[
1393
+ predictions_heading,
1394
+ predictions_note,
1395
  plot,
1396
+ download_bigwig_btn,
1397
+ # meta,
1398
  prediction_state,
1399
  bigwig_selected_state,
1400
  bed_elements_state,
style.css CHANGED
@@ -1,55 +1,135 @@
1
- #tracks_plot { position: relative; width: 100% !important; max-width: 100% !important; }
2
- #tracks_plot .wrap, #tracks_plot .plot-container {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  width: 100% !important;
4
  max-width: 100% !important;
5
  }
6
 
7
- #tracks_plot_download {
8
- position: absolute;
9
- top: 10px;
10
- right: 12px;
11
- z-index: 50;
12
- background: rgba(0,0,0,0.55);
13
- border: 1px solid rgba(255,255,255,0.15);
14
- border-radius: 10px;
15
- padding: 6px 8px;
16
- cursor: pointer;
17
- user-select: none;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  }
19
- #tracks_plot_download:hover { background: rgba(0,0,0,0.7); }
20
- #tracks_plot_download svg { width: 18px; height: 18px; display: block; fill: white; }
21
- #export_png_hidden { display: none !important; }
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  #predict_btn {
24
- background-color: #FF6B35 !important;
25
  color: white !important;
26
  border: none !important;
 
 
 
 
27
  }
28
  #predict_btn:hover {
29
- background-color: #E55A2B !important;
 
 
30
  }
31
 
 
32
  #intro_markdown {
33
- max-width: 1200px;
 
34
  margin: 0 auto;
35
- padding: 14px 8px 6px 8px;
36
  }
37
 
38
- /* overall hero container */
39
  #intro_markdown .intro-hero {
40
- border: 1px solid rgba(0,0,0,0.08);
41
- border-radius: 18px;
42
- padding: 18px 18px 14px 18px;
43
- background: linear-gradient(
44
- 180deg,
45
- rgba(0, 128, 255, 0.06),
46
- rgba(0, 0, 0, 0.00)
47
- );
48
  }
49
 
50
- /* badge + title row */
51
  #intro_markdown .intro-title {
52
- margin-bottom: 14px;
 
 
 
 
53
  }
54
 
55
  #intro_markdown .intro-badge {
@@ -59,95 +139,109 @@
59
  letter-spacing: 0.02em;
60
  padding: 6px 10px;
61
  border-radius: 999px;
62
- background: rgba(0,0,0,0.06);
 
63
  margin-bottom: 10px;
 
64
  }
65
 
66
  #intro_markdown h1 {
67
- font-size: 2.25rem !important;
68
  line-height: 1.1 !important;
69
  margin: 0 0 8px 0 !important;
 
 
70
  }
71
 
72
  #intro_markdown .intro-subtitle {
73
  font-size: 1.05rem !important;
74
- line-height: 1.6 !important;
75
  margin: 0 !important;
76
- opacity: 0.9;
77
  }
78
 
79
- /* grid of cards */
80
  #intro_markdown .intro-grid {
81
  display: grid;
82
  grid-template-columns: repeat(3, minmax(0, 1fr));
83
- gap: 12px;
84
- margin-top: 14px;
85
  }
86
 
87
- /* cards */
88
  #intro_markdown .intro-card {
89
- border: 1px solid rgba(56, 189, 248, 0.18); /* sky accent */
90
- border-radius: 16px;
91
- padding: 14px 14px 12px 14px;
92
-
93
- /* dark glass */
94
- background: linear-gradient(
95
- 180deg,
96
- rgba(15, 23, 42, 0.72),
97
- rgba(15, 23, 42, 0.55)
98
- );
99
-
100
- box-shadow:
101
- 0 10px 30px rgba(0, 0, 0, 0.35),
102
- inset 0 1px 0 rgba(255, 255, 255, 0.06);
103
-
104
- backdrop-filter: blur(10px);
105
- -webkit-backdrop-filter: blur(10px);
106
-
107
  transition: transform 120ms ease, border-color 120ms ease, box-shadow 120ms ease;
108
  }
109
 
110
  #intro_markdown .intro-card:hover {
111
  transform: translateY(-2px);
112
- border-color: rgba(56, 189, 248, 0.38);
113
- box-shadow:
114
- 0 14px 36px rgba(0, 0, 0, 0.42),
115
- inset 0 1px 0 rgba(255, 255, 255, 0.08);
116
  }
117
 
118
  #intro_markdown .intro-card h3 {
119
- font-size: 1.05rem !important;
120
- margin: 0 0 8px 0 !important;
121
- color: rgba(255, 255, 255, 0.95);
122
  letter-spacing: 0.01em;
 
 
 
 
 
 
 
123
  }
124
 
125
  #intro_markdown .intro-card li {
126
- font-size: 0.98rem !important;
127
- line-height: 1.55 !important;
128
- margin: 6px 0;
129
- color: rgba(255, 255, 255, 0.82);
130
  }
131
 
132
  #intro_markdown .intro-card li::marker {
133
- color: rgba(56, 189, 248, 0.75);
134
  }
135
 
136
  #intro_markdown .intro-card em,
137
  #intro_markdown .intro-card strong {
138
- color: rgba(255, 255, 255, 0.92);
139
  }
140
 
141
- /* tip callout */
142
  #intro_markdown .intro-tip {
143
- margin-top: 14px;
144
  display: flex;
145
  gap: 10px;
146
  align-items: flex-start;
147
- padding: 10px 12px;
148
  border-radius: 14px;
149
- background: rgba(0, 128, 255, 0.08);
150
- border: 1px solid rgba(0, 128, 255, 0.18);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  }
152
 
153
  #intro_markdown .intro-tip-icon {
@@ -157,59 +251,807 @@
157
  }
158
 
159
  #intro_markdown .intro-tip span {
160
- font-size: 0.98rem !important;
161
- line-height: 1.55 !important;
 
162
  }
163
 
164
- /* responsive */
165
- @media (max-width: 960px) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  #intro_markdown .intro-grid {
167
  grid-template-columns: 1fr;
168
  }
169
  #intro_markdown h1 {
170
- font-size: 2.0rem !important;
171
  }
172
  }
173
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  /* Remove borders/lines from input sections */
175
- .gr-group {
 
 
 
 
176
  border: none !important;
177
  box-shadow: none !important;
178
  margin-bottom: 0 !important;
179
  padding-bottom: 0 !important;
 
 
180
  }
181
 
182
- /* Remove any borders or separators from textbox components in input sections */
183
- .gr-textbox {
184
- border-top: none !important;
185
- margin-top: 0 !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  }
187
 
188
- /* Remove borders from form sections */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  .form {
190
  border: none !important;
191
  }
192
 
193
- /* Remove any hr or separator lines */
194
  hr {
195
  display: none !important;
196
  }
197
 
198
- /* Remove line above DNA sequence input */
199
  #dna_sequence_input {
200
  border-top: none !important;
201
  margin-top: 0 !important;
202
  padding-top: 0 !important;
203
  }
204
 
205
- /* Remove any border or separator before the DNA sequence input */
206
  #dna_sequence_input::before,
207
  #dna_sequence_input .wrap::before {
208
  display: none !important;
209
  content: none !important;
210
  }
211
 
212
- /* Ensure coordinates group doesn't leave a border when hidden */
213
  #coords_group[style*="display: none"],
214
  #coords_group:not(:visible) {
215
  display: none !important;
@@ -218,10 +1060,395 @@ hr {
218
  padding: 0 !important;
219
  }
220
 
221
- /* Remove any separator between input sections */
222
  #coords_group + *,
223
  #coords_group ~ #dna_sequence_input {
224
  border-top: none !important;
225
  margin-top: 0 !important;
226
  padding-top: 0 !important;
227
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* CSS Variables matching NTv3 hub design */
2
+ :root {
3
+ --bg: #0b1020;
4
+ --card: rgba(255, 255, 255, 0.06);
5
+ --text: rgba(255, 255, 255, 0.92);
6
+ --muted: rgba(255, 255, 255, 0.65);
7
+ --link: #7dd3fc;
8
+ --border: rgba(255, 255, 255, 0.12);
9
+ --shadow: 0 10px 30px rgba(0,0,0,0.35);
10
+ --radius: 18px;
11
+ }
12
+
13
+ /* Overall page background matching hub */
14
+ body, .gradio-container {
15
+ background:
16
+ radial-gradient(1200px 800px at 10% 10%, rgba(125, 211, 252, 0.12), transparent 60%),
17
+ radial-gradient(1200px 800px at 90% 30%, rgba(167, 139, 250, 0.12), transparent 55%),
18
+ var(--bg) !important;
19
+ min-height: 100vh;
20
+ }
21
+
22
+ /* Plot container */
23
+ #tracks_plot {
24
+ position: relative;
25
+ width: 100% !important;
26
+ max-width: 100% !important;
27
+ }
28
+ #tracks_plot .wrap,
29
+ #tracks_plot .plot-container {
30
  width: 100% !important;
31
  max-width: 100% !important;
32
  }
33
 
34
+
35
+ /* Plotly modebar buttons - make them blue for visibility on white background */
36
+ /* Target all possible Plotly modebar selectors */
37
+ .modebar-btn,
38
+ .modebar-btn svg,
39
+ .modebar-btn path,
40
+ .modebar-group .modebar-btn,
41
+ .modebar-group .modebar-btn svg,
42
+ .modebar-group .modebar-btn path,
43
+ #tracks_plot .modebar-btn,
44
+ #tracks_plot .modebar-btn svg,
45
+ #tracks_plot .modebar-btn path,
46
+ #tracks_plot .modebar-group .modebar-btn,
47
+ #tracks_plot .modebar-group .modebar-btn svg,
48
+ #tracks_plot .modebar-group .modebar-btn path,
49
+ .js-plotly-plot .modebar-btn,
50
+ .js-plotly-plot .modebar-btn svg,
51
+ .js-plotly-plot .modebar-btn path,
52
+ .plotly .modebar-btn,
53
+ .plotly .modebar-btn svg,
54
+ .plotly .modebar-btn path {
55
+ color: #7dd3fc !important;
56
+ fill: #7dd3fc !important;
57
+ stroke: #7dd3fc !important;
58
+ }
59
+
60
+ .modebar-btn:hover,
61
+ .modebar-btn:focus,
62
+ #tracks_plot .modebar-btn:hover,
63
+ #tracks_plot .modebar-btn:focus {
64
+ background-color: rgba(125, 211, 252, 0.1) !important;
65
+ color: #3B82F6 !important;
66
  }
 
 
 
67
 
68
+ .modebar-btn:hover svg,
69
+ .modebar-btn:hover path,
70
+ .modebar-btn:focus svg,
71
+ .modebar-btn:focus path,
72
+ #tracks_plot .modebar-btn:hover svg,
73
+ #tracks_plot .modebar-btn:hover path,
74
+ #tracks_plot .modebar-btn:focus svg,
75
+ #tracks_plot .modebar-btn:focus path {
76
+ fill: #3B82F6 !important;
77
+ stroke: #3B82F6 !important;
78
+ }
79
+
80
+ /* Plotly modebar container */
81
+ .modebar,
82
+ #tracks_plot .modebar,
83
+ .js-plotly-plot .modebar,
84
+ .plotly .modebar {
85
+ background-color: rgba(255, 255, 255, 0.9) !important;
86
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
87
+ border-radius: 8px !important;
88
+ }
89
+
90
+ /* Predict button matching hub button style */
91
  #predict_btn {
92
+ background: rgba(41,91,234,1) !important;
93
  color: white !important;
94
  border: none !important;
95
+ border-radius: 12px !important;
96
+ font-weight: 600 !important;
97
+ transition: all 0.2s ease !important;
98
+ box-shadow: 0 4px 12px rgba(125, 211, 252, 0.3) !important;
99
  }
100
  #predict_btn:hover {
101
+ background: rgb(5, 36, 121) !important;
102
+ transform: translateY(-2px) !important;
103
+ box-shadow: 0 6px 16px rgba(125, 211, 252, 0.4) !important;
104
  }
105
 
106
+ /* Intro markdown container */
107
  #intro_markdown {
108
+ max-width: 100% !important;
109
+ width: 100% !important;
110
  margin: 0 auto;
111
+ padding: 44px 18px 6px 18px;
112
  }
113
 
114
+ /* Hero container matching hub */
115
  #intro_markdown .intro-hero {
116
+ border: 1px solid var(--border);
117
+ border-radius: var(--radius);
118
+ padding: 26px 24px;
119
+ background: var(--card);
120
+ box-shadow: var(--shadow);
121
+ width: 100% !important;
122
+ max-width: 100% !important;
123
+ box-sizing: border-box !important;
124
  }
125
 
126
+ /* Badge + title row */
127
  #intro_markdown .intro-title {
128
+ margin-bottom: 0;
129
+ }
130
+
131
+ #intro_markdown .intro-title h1 {
132
+ margin-bottom: 8px;
133
  }
134
 
135
  #intro_markdown .intro-badge {
 
139
  letter-spacing: 0.02em;
140
  padding: 6px 10px;
141
  border-radius: 999px;
142
+ background: rgba(255,255,255,0.04);
143
+ border: 1px solid var(--border);
144
  margin-bottom: 10px;
145
+ color: var(--muted);
146
  }
147
 
148
  #intro_markdown h1 {
149
+ font-size: 34px !important;
150
  line-height: 1.1 !important;
151
  margin: 0 0 8px 0 !important;
152
+ letter-spacing: -0.02em;
153
+ color: var(--text) !important;
154
  }
155
 
156
  #intro_markdown .intro-subtitle {
157
  font-size: 1.05rem !important;
158
+ line-height: 1.5 !important;
159
  margin: 0 !important;
160
+ color: var(--muted) !important;
161
  }
162
 
163
+ /* Grid of cards */
164
  #intro_markdown .intro-grid {
165
  display: grid;
166
  grid-template-columns: repeat(3, minmax(0, 1fr));
167
+ gap: 14px;
168
+ margin-top: 18px;
169
  }
170
 
171
+ /* Cards matching hub card style */
172
  #intro_markdown .intro-card {
173
+ border: 1px solid var(--border);
174
+ border-radius: var(--radius);
175
+ padding: 18px 18px;
176
+ background: var(--card);
177
+ box-shadow: 0 6px 18px rgba(0,0,0,0.22);
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  transition: transform 120ms ease, border-color 120ms ease, box-shadow 120ms ease;
179
  }
180
 
181
  #intro_markdown .intro-card:hover {
182
  transform: translateY(-2px);
183
+ border-color: rgba(255, 255, 255, 0.2);
184
+ box-shadow: 0 10px 30px rgba(0,0,0,0.35);
 
 
185
  }
186
 
187
  #intro_markdown .intro-card h3 {
188
+ font-size: 16px !important;
189
+ margin: 0 0 10px 0 !important;
190
+ color: var(--text) !important;
191
  letter-spacing: 0.01em;
192
+ font-weight: 600;
193
+ }
194
+
195
+ #intro_markdown .intro-card ul {
196
+ margin: 0;
197
+ padding-left: 18px;
198
+ color: var(--muted);
199
  }
200
 
201
  #intro_markdown .intro-card li {
202
+ font-size: 0.95rem !important;
203
+ line-height: 1.5 !important;
204
+ margin: 8px 0;
205
+ color: var(--muted) !important;
206
  }
207
 
208
  #intro_markdown .intro-card li::marker {
209
+ color: var(--link);
210
  }
211
 
212
  #intro_markdown .intro-card em,
213
  #intro_markdown .intro-card strong {
214
+ color: var(--text) !important;
215
  }
216
 
217
+ /* Tip callout */
218
  #intro_markdown .intro-tip {
219
+ margin-top: 18px;
220
  display: flex;
221
  gap: 10px;
222
  align-items: flex-start;
223
+ padding: 12px 16px;
224
  border-radius: 14px;
225
+ background: var(--card);
226
+ border: 1px solid var(--border);
227
+ }
228
+
229
+ /* Pill badges matching hub style */
230
+ #intro_markdown .intro-pillrow {
231
+ display: flex;
232
+ gap: 8px;
233
+ flex-wrap: wrap;
234
+ margin-top: 14px;
235
+ }
236
+
237
+ #intro_markdown .intro-pill {
238
+ font-size: 12px;
239
+ padding: 6px 10px;
240
+ border-radius: 999px;
241
+ border: 1px solid var(--border);
242
+ background: rgba(255, 255, 255, 0.04);
243
+ color: var(--muted);
244
+ font-weight: 500;
245
  }
246
 
247
  #intro_markdown .intro-tip-icon {
 
251
  }
252
 
253
  #intro_markdown .intro-tip span {
254
+ font-size: 0.95rem !important;
255
+ line-height: 1.5 !important;
256
+ color: var(--muted) !important;
257
  }
258
 
259
+ #intro_markdown .intro-tip strong {
260
+ color: var(--text) !important;
261
+ }
262
+
263
+ /* Species info box */
264
+ #intro_markdown .intro-species-info {
265
+ margin-top: 18px !important;
266
+ padding: 12px 16px !important;
267
+ background: var(--card) !important;
268
+ border-radius: 12px !important;
269
+ border: 1px solid var(--border) !important;
270
+ font-size: 0.95rem !important;
271
+ color: var(--muted) !important;
272
+ }
273
+
274
+ #intro_markdown .intro-species-info strong {
275
+ color: var(--text) !important;
276
+ }
277
+
278
+ /* Responsive */
279
+ @media (max-width: 860px) {
280
  #intro_markdown .intro-grid {
281
  grid-template-columns: 1fr;
282
  }
283
  #intro_markdown h1 {
284
+ font-size: 28px !important;
285
  }
286
  }
287
 
288
+ /* ============================================================================
289
+ GRADIO COMPONENT STYLING
290
+ ============================================================================ */
291
+
292
+ /* Remove grey backgrounds from Gradio containers */
293
+ .gr-form,
294
+ .gr-block,
295
+ .gr-panel,
296
+ .gr-box,
297
+ [class*="panel"],
298
+ [class*="block"],
299
+ [class*="form"],
300
+ /* Remove grey backgrounds from Gradio containers and wrappers */
301
+ .gradio-container > div,
302
+ .gradio-container .wrap,
303
+ .gradio-container [class*="panel"],
304
+ .gradio-container [class*="block"],
305
+ .gradio-container [class*="form"],
306
+ [class*="gradio"] [class*="panel"],
307
+ [class*="gradio"] [class*="block"],
308
+ div[class*="panel"],
309
+ div[class*="block"] {
310
+ background: transparent !important;
311
+ background-color: transparent !important;
312
+ }
313
+
314
+ /* Ensure form containers don't constrain textbox width */
315
+ .gr-form .gr-textbox,
316
+ .gr-block .gr-textbox,
317
+ .gradio-container .gr-textbox {
318
+ width: 100% !important;
319
+ max-width: 100% !important;
320
+ }
321
+
322
+ /* Remove grey backgrounds from section containers */
323
+ section,
324
+ .gr-section,
325
+ [role="region"] {
326
+ background: transparent !important;
327
+ background-color: transparent !important;
328
+ border: none !important;
329
+ }
330
+
331
+ /* Markdown headings */
332
+ h2 {
333
+ color: var(--text) !important;
334
+ font-size: 18px !important;
335
+ letter-spacing: 0.01em !important;
336
+ margin-top: 24px !important;
337
+ margin-bottom: 16px !important;
338
+ }
339
+
340
+ /* Input labels */
341
+ label {
342
+ color: var(--text) !important;
343
+ font-weight: 500 !important;
344
+ background: transparent !important;
345
+ background-color: transparent !important;
346
+ }
347
+
348
+ /* ============================================================================
349
+ INPUT FIELDS - Base styling for all input types
350
+ ============================================================================ */
351
+
352
+ /* Base input styling - applies to all input types EXCEPT number inputs in coords_group */
353
+ input[type="text"],
354
+ input[type="search"],
355
+ input[type="email"],
356
+ input[type="password"],
357
+ input[type="tel"],
358
+ input[type="url"],
359
+ textarea {
360
+ background: rgba(125, 211, 252, 0.08) !important;
361
+ background-color: rgba(125, 211, 252, 0.08) !important;
362
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
363
+ border-radius: 12px !important;
364
+ color: var(--text) !important;
365
+ padding: 10px 12px !important;
366
+ }
367
+
368
+ /* Number inputs - default blue background */
369
+ /* Note: Coordinates group inputs are overridden at the end of the file */
370
+ input[type="number"],
371
+ .gr-number input {
372
+ background: rgba(125, 211, 252, 0.08) !important;
373
+ background-color: rgba(125, 211, 252, 0.08) !important;
374
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
375
+ border-radius: 12px !important;
376
+ color: var(--text) !important;
377
+ padding: 10px 12px !important;
378
+ }
379
+
380
+ input[type="text"]:focus,
381
+ input[type="search"]:focus,
382
+ input[type="email"]:focus,
383
+ input[type="password"]:focus,
384
+ input[type="tel"]:focus,
385
+ input[type="url"]:focus,
386
+ textarea:focus {
387
+ background: rgba(125, 211, 252, 0.12) !important;
388
+ background-color: rgba(125, 211, 252, 0.12) !important;
389
+ border-color: rgba(125, 211, 252, 0.35) !important;
390
+ box-shadow: 0 0 0 3px rgba(125, 211, 252, 0.1) !important;
391
+ outline: none !important;
392
+ }
393
+
394
+ /* Number inputs focus - default blue background */
395
+ input[type="number"]:focus {
396
+ background: rgba(125, 211, 252, 0.12) !important;
397
+ background-color: rgba(125, 211, 252, 0.12) !important;
398
+ border-color: rgba(125, 211, 252, 0.35) !important;
399
+ box-shadow: 0 0 0 3px rgba(125, 211, 252, 0.1) !important;
400
+ outline: none !important;
401
+ }
402
+
403
+ /* Coordinates group number inputs focus - transparent background */
404
+ #coords_group input[type="number"]:focus,
405
+ #coords_group .gr-number input:focus,
406
+ #coords_group .gr-row input[type="number"]:focus,
407
+ #coords_group .gr-row .gr-number input:focus {
408
+ background: transparent !important;
409
+ background-color: transparent !important;
410
+ border-color: rgba(125, 211, 252, 0.35) !important;
411
+ box-shadow: 0 0 0 3px rgba(125, 211, 252, 0.1) !important;
412
+ outline: none !important;
413
+ }
414
+
415
+ input[type="text"]:hover,
416
+ input[type="search"]:hover,
417
+ textarea:hover {
418
+ background: rgba(125, 211, 252, 0.1) !important;
419
+ border-color: rgba(125, 211, 252, 0.25) !important;
420
+ }
421
+
422
+ /* Number inputs hover - default blue background */
423
+ input[type="number"]:hover {
424
+ background: rgba(125, 211, 252, 0.1) !important;
425
+ border-color: rgba(125, 211, 252, 0.25) !important;
426
+ }
427
+
428
+ /* Coordinates group number inputs hover - transparent background */
429
+ #coords_group input[type="number"]:hover,
430
+ #coords_group .gr-number input:hover,
431
+ #coords_group .gr-row input[type="number"]:hover,
432
+ #coords_group .gr-row .gr-number input:hover {
433
+ background: transparent !important;
434
+ background-color: transparent !important;
435
+ border-color: rgba(125, 211, 252, 0.35) !important;
436
+ }
437
+
438
+ /* Placeholder text */
439
+ input::placeholder,
440
+ textarea::placeholder {
441
+ color: rgba(255, 255, 255, 0.5) !important;
442
+ opacity: 0.7 !important;
443
+ }
444
+
445
+ /* Override inline grey backgrounds */
446
+ input[style*="background"],
447
+ textarea[style*="background"] {
448
+ background: rgba(125, 211, 252, 0.08) !important;
449
+ background-color: rgba(125, 211, 252, 0.08) !important;
450
+ }
451
+
452
+ /* ============================================================================
453
+ GRADIO COMPONENT WRAPPERS - Make transparent
454
+ ============================================================================ */
455
+
456
+ /* Make textbox and number input wrappers transparent (only input is styled) */
457
+ /* NOTE: Dropdowns are EXCLUDED - they keep blue backgrounds */
458
+ .gr-textbox .wrap,
459
+ .gr-textbox .wrap > div,
460
+ .gr-textbox .wrap > div > div,
461
+ .gr-number .wrap,
462
+ .gr-number .wrap > div,
463
+ .gr-number .wrap > div > div,
464
+ .gr-radio .wrap,
465
+ .gr-radio .wrap > div,
466
+ .gr-radio .wrap > div > div {
467
+ background: transparent !important;
468
+ background-color: transparent !important;
469
+ }
470
+
471
+ /* Explicitly ensure dropdown wrappers are NOT transparent */
472
+ .gr-dropdown .wrap,
473
+ .gr-dropdown .wrap > div,
474
+ .gr-dropdown .wrap > div > div,
475
+ .gr-dropdown .wrap > div > div > div {
476
+ background: rgba(125, 211, 252, 0.08) !important;
477
+ background-color: rgba(125, 211, 252, 0.08) !important;
478
+ }
479
+
480
+ /* ============================================================================
481
+ TEXTBOX COMPONENTS
482
+ ============================================================================ */
483
+
484
+ /* Textbox component - transparent wrapper, only input is styled */
485
+ .gr-textbox {
486
+ background: transparent !important;
487
+ border: none !important;
488
+ box-shadow: none !important;
489
+ padding: 0 !important;
490
+ border-top: none !important;
491
+ margin-top: 0 !important;
492
+ width: 100% !important;
493
+ max-width: 100% !important;
494
+ }
495
+
496
+ /* Make textbox wrappers full width */
497
+ .gr-textbox .wrap,
498
+ .gr-textbox .wrap > div,
499
+ .gr-textbox .wrap > div > div {
500
+ width: 100% !important;
501
+ max-width: 100% !important;
502
+ }
503
+
504
+ /* Make textbox inputs full width */
505
+ .gr-textbox input,
506
+ .gr-textbox textarea {
507
+ width: 100% !important;
508
+ max-width: 100% !important;
509
+ box-sizing: border-box !important;
510
+ }
511
+
512
+ /* Textbox input inherits base input styling above */
513
+
514
+ /* ============================================================================
515
+ NUMBER INPUT COMPONENTS
516
+ ============================================================================ */
517
+
518
+ /* Number input component - transparent wrapper, only input is styled */
519
+ .gr-number {
520
+ background: transparent !important;
521
+ }
522
+
523
+ /* Number input inherits base input styling above */
524
+
525
+ /* ============================================================================
526
+ DROPDOWN COMPONENTS
527
+ ============================================================================ */
528
+
529
+ /* Dropdowns */
530
+ .gr-dropdown,
531
+ .gr-dropdown input,
532
+ .gr-dropdown select,
533
+ .gr-dropdown .wrap,
534
+ .gr-dropdown .wrap > div,
535
+ select {
536
+ background: rgba(125, 211, 252, 0.08) !important;
537
+ background-color: rgba(125, 211, 252, 0.08) !important;
538
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
539
+ border-radius: 12px !important;
540
+ color: var(--text) !important;
541
+ outline: none !important;
542
+ box-shadow: none !important;
543
+ }
544
+
545
+ /* Override any inline grey backgrounds on dropdowns */
546
+ .gr-dropdown[style*="background"],
547
+ select[style*="background"] {
548
+ background: rgba(125, 211, 252, 0.08) !important;
549
+ background-color: rgba(125, 211, 252, 0.08) !important;
550
+ }
551
+
552
+ .gr-dropdown:hover,
553
+ .gr-dropdown:focus,
554
+ .gr-dropdown input:hover,
555
+ .gr-dropdown input:focus,
556
+ .gr-dropdown select:hover,
557
+ .gr-dropdown select:focus,
558
+ select:hover,
559
+ select:focus {
560
+ background: rgba(125, 211, 252, 0.12) !important;
561
+ background-color: rgba(125, 211, 252, 0.12) !important;
562
+ border-color: rgba(125, 211, 252, 0.35) !important;
563
+ outline: none !important;
564
+ box-shadow: 0 0 0 3px rgba(125, 211, 252, 0.1) !important;
565
+ }
566
+
567
+ /* Ensure dropdown option container is blue */
568
+ .gr-dropdown .wrap select,
569
+ .gr-dropdown select option {
570
+ background: rgba(125, 211, 252, 0.08) !important;
571
+ background-color: rgba(125, 211, 252, 0.08) !important;
572
+ color: var(--text) !important;
573
+ }
574
+
575
+ /* Selected tags/chips in multiselect dropdown */
576
+ #bed_elements_dropdown .wrap > div > span:not(:empty),
577
+ #bed_elements_dropdown .wrap > div > div:not(.wrap):not(input):not(select):not(:empty),
578
+ #bed_elements_dropdown .wrap > div > button:not([type="submit"]),
579
+ #bed_elements_dropdown [class*="tag"],
580
+ #bed_elements_dropdown [class*="chip"],
581
+ #bed_elements_dropdown [class*="badge"],
582
+ #bed_elements_dropdown [class*="pill"] {
583
+ background: rgba(125, 211, 252, 0.15) !important;
584
+ background-color: rgba(125, 211, 252, 0.15) !important;
585
+ border: 1px solid rgba(125, 211, 252, 0.35) !important;
586
+ border-radius: 6px !important;
587
+ color: var(--text) !important;
588
+ padding: 5px 10px !important;
589
+ margin: 2px 4px 2px 0 !important;
590
+ font-size: 0.875rem !important;
591
+ font-weight: 500 !important;
592
+ display: inline-flex !important;
593
+ align-items: center !important;
594
+ gap: 6px !important;
595
+ transition: all 0.2s ease !important;
596
+ }
597
+
598
+ #bed_elements_dropdown .wrap > div > span:hover:not(input),
599
+ #bed_elements_dropdown .wrap > div > div:hover:not(input):not(select):not(.wrap),
600
+ #bed_elements_dropdown .wrap > div > button:hover:not([type="submit"]) {
601
+ background: rgba(125, 211, 252, 0.25) !important;
602
+ border-color: var(--link) !important;
603
+ }
604
+
605
+ /* X button inside tags */
606
+ #bed_elements_dropdown button[aria-label*="Remove"],
607
+ #bed_elements_dropdown button[aria-label*="remove"],
608
+ #bed_elements_dropdown span button,
609
+ #bed_elements_dropdown div button {
610
+ background: transparent !important;
611
+ border: none !important;
612
+ color: var(--text) !important;
613
+ opacity: 0.7 !important;
614
+ padding: 2px 4px !important;
615
+ margin-left: 4px !important;
616
+ border-radius: 4px !important;
617
+ cursor: pointer !important;
618
+ }
619
+
620
+ #bed_elements_dropdown button[aria-label*="Remove"]:hover,
621
+ #bed_elements_dropdown button[aria-label*="remove"]:hover,
622
+ #bed_elements_dropdown span button:hover,
623
+ #bed_elements_dropdown div button:hover {
624
+ background: rgba(255, 255, 255, 0.1) !important;
625
+ opacity: 1 !important;
626
+ }
627
+
628
+ /* ============================================================================
629
+ RADIO BUTTONS
630
+ ============================================================================ */
631
+
632
+ .gr-radio {
633
+ background: rgba(125, 211, 252, 0.08) !important;
634
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
635
+ border-radius: 12px !important;
636
+ padding: 12px !important;
637
+ }
638
+
639
+ .gr-radio label,
640
+ input[type="radio"] + label {
641
+ color: var(--text) !important;
642
+ background: rgba(125, 211, 252, 0.08) !important;
643
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
644
+ border-radius: 8px !important;
645
+ padding: 8px 12px !important;
646
+ margin: 4px !important;
647
+ display: inline-block !important;
648
+ transition: all 0.2s ease !important;
649
+ }
650
+
651
+ .gr-radio label:hover,
652
+ input[type="radio"] + label:hover {
653
+ background: rgba(125, 211, 252, 0.12) !important;
654
+ border-color: rgba(125, 211, 252, 0.3) !important;
655
+ }
656
+
657
+ .gr-radio input[type="radio"]:checked + label,
658
+ input[type="radio"]:checked + label {
659
+ background: rgba(125, 211, 252, 0.18) !important;
660
+ border-color: rgba(125, 211, 252, 0.4) !important;
661
+ }
662
+
663
+ /* Change radio button selected indicator from orange to blue */
664
+ input[type="radio"] {
665
+ accent-color: #7dd3fc !important;
666
+ color: #7dd3fc !important;
667
+ }
668
+
669
+ /* Override Gradio's default orange radio button styling */
670
+ input[type="radio"]:checked {
671
+ accent-color: #7dd3fc !important;
672
+ background-color: #7dd3fc !important;
673
+ border-color: #7dd3fc !important;
674
+ }
675
+
676
+ /* Radio button circle/dot when checked - change from orange to blue */
677
+ input[type="radio"]:checked::before,
678
+ input[type="radio"]:checked::after,
679
+ .gr-radio input[type="radio"]:checked::before,
680
+ .gr-radio input[type="radio"]:checked::after,
681
+ label:has(input[type="radio"]:checked) input[type="radio"]::before,
682
+ label:has(input[type="radio"]:checked) input[type="radio"]::after {
683
+ color: #7dd3fc !important;
684
+ background-color: #7dd3fc !important;
685
+ border-color: #7dd3fc !important;
686
+ }
687
+
688
+ /* SVG radio button icons */
689
+ input[type="radio"]:checked + svg,
690
+ .gr-radio input[type="radio"]:checked + svg,
691
+ label:has(input[type="radio"]:checked) svg {
692
+ fill: #7dd3fc !important;
693
+ color: #7dd3fc !important;
694
+ }
695
+
696
+ /* Radio button circle background when checked */
697
+ input[type="radio"]:checked {
698
+ background-color: #7dd3fc !important;
699
+ background: #7dd3fc !important;
700
+ border-color: #7dd3fc !important;
701
+ }
702
+
703
+ /* Override any orange colors in radio button styling */
704
+ input[type="radio"][style*="orange"],
705
+ input[type="radio"][style*="#ff"],
706
+ input[type="radio"][style*="rgb(255"],
707
+ .gr-radio input[type="radio"][style*="orange"],
708
+ .gr-radio input[type="radio"][style*="#ff"],
709
+ .gr-radio input[type="radio"][style*="rgb(255"] {
710
+ accent-color: #7dd3fc !important;
711
+ background-color: #7dd3fc !important;
712
+ border-color: #7dd3fc !important;
713
+ }
714
+
715
+ /* Target radio button wrapper elements */
716
+ .gr-radio .wrap input[type="radio"]:checked,
717
+ .gr-radio label .wrap input[type="radio"]:checked,
718
+ .gr-radio [class*="radio"] input[type="radio"]:checked {
719
+ accent-color: #7dd3fc !important;
720
+ background-color: #7dd3fc !important;
721
+ border-color: #7dd3fc !important;
722
+ }
723
+
724
+ /* Override Gradio's default radio button checked state colors */
725
+ .gradio-container input[type="radio"]:checked {
726
+ accent-color: #7dd3fc !important;
727
+ background-color: #7dd3fc !important;
728
+ background: #7dd3fc !important;
729
+ border-color: #7dd3fc !important;
730
+ }
731
+
732
+ /* ============================================================================
733
+ CHECKBOX GROUPS
734
+ ============================================================================ */
735
+
736
+ .gr-checkboxgroup {
737
+ background: rgba(125, 211, 252, 0.08) !important;
738
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
739
+ border-radius: 12px !important;
740
+ padding: 12px !important;
741
+ }
742
+
743
+ .gr-checkboxgroup label {
744
+ color: var(--text) !important;
745
+ background: rgba(125, 211, 252, 0.08) !important;
746
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
747
+ border-radius: 8px !important;
748
+ padding: 8px 12px !important;
749
+ margin: 4px 0 !important;
750
+ display: block !important;
751
+ transition: all 0.2s ease !important;
752
+ }
753
+
754
+ .gr-checkboxgroup label:hover {
755
+ background: rgba(125, 211, 252, 0.12) !important;
756
+ border-color: rgba(125, 211, 252, 0.3) !important;
757
+ }
758
+
759
+ .gr-checkboxgroup input[type="checkbox"]:checked + label,
760
+ .gr-checkboxgroup label:has(input[type="checkbox"]:checked) {
761
+ background: rgba(125, 211, 252, 0.18) !important;
762
+ border: 1px solid rgba(125, 211, 252, 0.4) !important;
763
+ }
764
+
765
+ /* Change checkbox icon color from orange to blue */
766
+ input[type="checkbox"] {
767
+ accent-color: #7dd3fc !important;
768
+ color: #7dd3fc !important;
769
+ }
770
+
771
+ /* Override Gradio's default orange checkbox styling */
772
+ input[type="checkbox"]:checked {
773
+ accent-color: #7dd3fc !important;
774
+ background-color: #7dd3fc !important;
775
+ border-color: #7dd3fc !important;
776
+ }
777
+
778
+ /* Checkbox checkmark icon - change from orange to blue */
779
+ input[type="checkbox"]:checked::before,
780
+ input[type="checkbox"]:checked::after,
781
+ .gr-checkboxgroup input[type="checkbox"]:checked::before,
782
+ .gr-checkboxgroup input[type="checkbox"]:checked::after,
783
+ label:has(input[type="checkbox"]:checked) input[type="checkbox"]::before,
784
+ label:has(input[type="checkbox"]:checked) input[type="checkbox"]::after {
785
+ color: #7dd3fc !important;
786
+ background-color: #7dd3fc !important;
787
+ border-color: #7dd3fc !important;
788
+ }
789
+
790
+ /* SVG checkmark icons */
791
+ input[type="checkbox"]:checked + svg,
792
+ .gr-checkboxgroup input[type="checkbox"]:checked + svg,
793
+ label:has(input[type="checkbox"]:checked) svg {
794
+ fill: #7dd3fc !important;
795
+ color: #7dd3fc !important;
796
+ }
797
+
798
+ /* Checkbox square/box background when checked */
799
+ input[type="checkbox"]:checked {
800
+ background-color: #7dd3fc !important;
801
+ background: #7dd3fc !important;
802
+ border-color: #7dd3fc !important;
803
+ }
804
+
805
+ /* Override any orange colors in checkbox styling */
806
+ input[type="checkbox"][style*="orange"],
807
+ input[type="checkbox"][style*="#ff"],
808
+ input[type="checkbox"][style*="rgb(255"],
809
+ .gr-checkboxgroup input[type="checkbox"][style*="orange"],
810
+ .gr-checkboxgroup input[type="checkbox"][style*="#ff"],
811
+ .gr-checkboxgroup input[type="checkbox"][style*="rgb(255"] {
812
+ accent-color: #7dd3fc !important;
813
+ background-color: #7dd3fc !important;
814
+ border-color: #7dd3fc !important;
815
+ }
816
+
817
+ /* Target checkbox wrapper elements that might contain the icon */
818
+ .gr-checkboxgroup .wrap input[type="checkbox"]:checked,
819
+ .gr-checkboxgroup label .wrap input[type="checkbox"]:checked,
820
+ .gr-checkboxgroup [class*="checkbox"] input[type="checkbox"]:checked {
821
+ accent-color: #7dd3fc !important;
822
+ background-color: #7dd3fc !important;
823
+ border-color: #7dd3fc !important;
824
+ }
825
+
826
+ /* Checkbox icon/checkmark in various possible locations */
827
+ .gr-checkboxgroup [class*="icon"]:has(input[type="checkbox"]:checked),
828
+ .gr-checkboxgroup [class*="check"]:has(input[type="checkbox"]:checked),
829
+ .gr-checkboxgroup span:has(input[type="checkbox"]:checked),
830
+ .gr-checkboxgroup div:has(input[type="checkbox"]:checked) {
831
+ color: #7dd3fc !important;
832
+ background-color: #7dd3fc !important;
833
+ }
834
+
835
+ /* Override Gradio's default checkbox checked state colors */
836
+ .gradio-container input[type="checkbox"]:checked {
837
+ accent-color: #7dd3fc !important;
838
+ background-color: #7dd3fc !important;
839
+ background: #7dd3fc !important;
840
+ border-color: #7dd3fc !important;
841
+ }
842
+
843
+ /* ============================================================================
844
+ BUTTONS
845
+ ============================================================================ */
846
+
847
+ button {
848
+ border-radius: 12px !important;
849
+ font-weight: 500 !important;
850
+ transition: all 0.2s ease !important;
851
+ }
852
+
853
+ /* All buttons except predict button */
854
+ button:not(#predict_btn):not([id*="predict"]),
855
+ .gr-button:not(#predict_btn),
856
+ button.gr-button:not(#predict_btn),
857
+ [class*="button"]:not(#predict_btn) {
858
+ background: rgba(125, 211, 252, 0.1) !important;
859
+ background-color: rgba(125, 211, 252, 0.1) !important;
860
+ border: 1px solid rgba(125, 211, 252, 0.3) !important;
861
+ color: var(--text) !important;
862
+ }
863
+
864
+ button:not(#predict_btn):not([id*="predict"]):hover,
865
+ .gr-button:not(#predict_btn):hover,
866
+ button.gr-button:not(#predict_btn):hover,
867
+ [class*="button"]:not(#predict_btn):hover {
868
+ background: rgba(125, 211, 252, 0.15) !important;
869
+ background-color: rgba(125, 211, 252, 0.15) !important;
870
+ border-color: var(--link) !important;
871
+ box-shadow: 0 4px 12px rgba(125, 211, 252, 0.2) !important;
872
+ }
873
+
874
+ /* ============================================================================
875
+ COORDINATES GROUP - Special handling
876
+ ============================================================================ */
877
+
878
  /* Remove borders/lines from input sections */
879
+ .gr-group,
880
+ .gr-group *,
881
+ .gr-group .wrap,
882
+ .gr-group .wrap > div,
883
+ .gr-group .wrap > div > div {
884
  border: none !important;
885
  box-shadow: none !important;
886
  margin-bottom: 0 !important;
887
  padding-bottom: 0 !important;
888
+ background: transparent !important;
889
+ background-color: transparent !important;
890
  }
891
 
892
+ .gr-row,
893
+ .gr-row *,
894
+ .gr-row .wrap,
895
+ .gr-row .wrap > div,
896
+ .gr-row .wrap > div > div {
897
+ background: transparent !important;
898
+ background-color: transparent !important;
899
+ }
900
+
901
+ /* Coordinates group: make wrappers transparent, keep inputs styled */
902
+ #coords_group .wrap,
903
+ #coords_group .wrap > div,
904
+ #coords_group .wrap > div > div,
905
+ #coords_group .gr-row,
906
+ #coords_group .gr-row *:not(input):not(textarea):not(select) {
907
+ background: transparent !important;
908
+ background-color: transparent !important;
909
+ }
910
+
911
+ /* Override inline grey backgrounds in coordinates group */
912
+ #coords_group [style*="rgb(40"],
913
+ #coords_group [style*="rgba(40"],
914
+ #coords_group [style*="rgb(50"],
915
+ #coords_group [style*="rgba(50"],
916
+ #coords_group [style*="#282"],
917
+ #coords_group [style*="#3a4"],
918
+ #coords_group [style*="#444"],
919
+ #coords_group [style*="#555"] {
920
+ background: transparent !important;
921
+ background-color: transparent !important;
922
+ }
923
+
924
+ /* Inputs in coordinates group - match dropdown style with transparent background and border */
925
+ /* These rules must override base input styling, so they come after */
926
+ #coords_group .gr-number input,
927
+ #coords_group .gr-number .wrap input,
928
+ #coords_group .gr-number .wrap > div input,
929
+ #coords_group input[type="number"],
930
+ #coords_group .gr-row .gr-number input,
931
+ #coords_group .gr-row input[type="number"] {
932
+ background: transparent !important;
933
+ background-color: transparent !important;
934
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
935
+ border-radius: 12px !important;
936
+ color: var(--text) !important;
937
+ height: 44px !important;
938
+ min-height: 44px !important;
939
+ padding: 0 12px !important;
940
+ line-height: 44px !important;
941
+ }
942
+
943
+ #coords_group .gr-number input:hover,
944
+ #coords_group .gr-number .wrap input:hover,
945
+ #coords_group input[type="number"]:hover,
946
+ #coords_group .gr-row .gr-number input:hover,
947
+ #coords_group .gr-row input[type="number"]:hover {
948
+ background: transparent !important;
949
+ background-color: transparent !important;
950
+ border-color: rgba(125, 211, 252, 0.35) !important;
951
+ }
952
+
953
+ #coords_group .gr-number input:focus,
954
+ #coords_group .gr-number .wrap input:focus,
955
+ #coords_group input[type="number"]:focus,
956
+ #coords_group .gr-row .gr-number input:focus,
957
+ #coords_group .gr-row input[type="number"]:focus {
958
+ background: transparent !important;
959
+ background-color: transparent !important;
960
+ border-color: rgba(125, 211, 252, 0.35) !important;
961
+ box-shadow: 0 0 0 3px rgba(125, 211, 252, 0.1) !important;
962
+ outline: none !important;
963
  }
964
 
965
+ /* ============================================================================
966
+ CHROMOSOME INPUT - Special case
967
+ ============================================================================ */
968
+
969
+ /* Chromosome component: transparent wrapper, remove all borders from wrappers */
970
+ #chromosome_input,
971
+ #chromosome_input label,
972
+ #chromosome_input > label,
973
+ #chromosome_input .wrap label {
974
+ background: transparent !important;
975
+ background-color: transparent !important;
976
+ border: none !important;
977
+ box-shadow: none !important;
978
+ padding: 0 !important;
979
+ }
980
+
981
+ /* Remove borders from all wrapper elements */
982
+ #chromosome_input .wrap,
983
+ #chromosome_input .wrap > div,
984
+ #chromosome_input .wrap > div > div,
985
+ #chromosome_input .wrap > div > div > div,
986
+ #chromosome_input.gr-dropdown,
987
+ #chromosome_input.gr-dropdown .wrap,
988
+ #chromosome_input.gr-dropdown .wrap > div,
989
+ #chromosome_input.gr-dropdown .wrap > div > div {
990
+ background: transparent !important;
991
+ background-color: transparent !important;
992
+ border: none !important;
993
+ box-shadow: none !important;
994
+ outline: none !important;
995
+ }
996
+
997
+ /* Chromosome input: match dropdown style with transparent background and border */
998
+ /* Only the actual input field should have a border */
999
+ #chromosome_input input,
1000
+ #chromosome_input input[type="text"],
1001
+ #chromosome_input .wrap input,
1002
+ #chromosome_input .wrap > div input,
1003
+ #chromosome_input .wrap > div > div input,
1004
+ #chromosome_input [role="combobox"],
1005
+ #chromosome_input button[aria-haspopup] {
1006
+ background: transparent !important;
1007
+ background-color: transparent !important;
1008
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
1009
+ border-radius: 12px !important;
1010
+ color: var(--text) !important;
1011
+ height: 44px !important;
1012
+ min-height: 44px !important;
1013
+ padding: 0 12px !important;
1014
+ line-height: 44px !important;
1015
+ }
1016
+
1017
+ #chromosome_input input:hover,
1018
+ #chromosome_input .wrap input:hover,
1019
+ #chromosome_input [role="combobox"]:hover {
1020
+ border-color: rgba(125, 211, 252, 0.35) !important;
1021
+ }
1022
+
1023
+ #chromosome_input input:focus,
1024
+ #chromosome_input .wrap input:focus,
1025
+ #chromosome_input [role="combobox"]:focus {
1026
+ border-color: rgba(125, 211, 252, 0.35) !important;
1027
+ box-shadow: 0 0 0 3px rgba(125, 211, 252, 0.1) !important;
1028
+ outline: none !important;
1029
+ }
1030
+
1031
+ /* ============================================================================
1032
+ FORM SECTIONS & SEPARATORS
1033
+ ============================================================================ */
1034
+
1035
  .form {
1036
  border: none !important;
1037
  }
1038
 
 
1039
  hr {
1040
  display: none !important;
1041
  }
1042
 
 
1043
  #dna_sequence_input {
1044
  border-top: none !important;
1045
  margin-top: 0 !important;
1046
  padding-top: 0 !important;
1047
  }
1048
 
 
1049
  #dna_sequence_input::before,
1050
  #dna_sequence_input .wrap::before {
1051
  display: none !important;
1052
  content: none !important;
1053
  }
1054
 
 
1055
  #coords_group[style*="display: none"],
1056
  #coords_group:not(:visible) {
1057
  display: none !important;
 
1060
  padding: 0 !important;
1061
  }
1062
 
 
1063
  #coords_group + *,
1064
  #coords_group ~ #dna_sequence_input {
1065
  border-top: none !important;
1066
  margin-top: 0 !important;
1067
  padding-top: 0 !important;
1068
  }
1069
+
1070
+ /* ============================================================================
1071
+ ACCORDION
1072
+ ============================================================================ */
1073
+
1074
+ .gr-accordion {
1075
+ background: rgba(125, 211, 252, 0.08) !important;
1076
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
1077
+ border-radius: 12px !important;
1078
+ }
1079
+
1080
+ .gr-accordion summary {
1081
+ color: var(--text) !important;
1082
+ }
1083
+
1084
+ .gr-accordion .gr-json {
1085
+ color: var(--muted) !important;
1086
+ }
1087
+
1088
+ /* ============================================================================
1089
+ FINAL OVERRIDES - Ensure dropdowns have blue backgrounds
1090
+ ============================================================================ */
1091
+
1092
+ /* Force dropdowns to have blue background - override any grey */
1093
+ .gradio-container .gr-dropdown,
1094
+ .gradio-container .gr-dropdown .wrap,
1095
+ .gradio-container .gr-dropdown .wrap > div,
1096
+ .gradio-container .gr-dropdown .wrap > div > div,
1097
+ .gradio-container .gr-dropdown input,
1098
+ .gradio-container .gr-dropdown select {
1099
+ background: rgba(125, 211, 252, 0.08) !important;
1100
+ background-color: rgba(125, 211, 252, 0.08) !important;
1101
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
1102
+ }
1103
+
1104
+ /* Override any grey color values in inline styles for dropdowns */
1105
+ .gradio-container .gr-dropdown[style*="rgb(40"],
1106
+ .gradio-container .gr-dropdown[style*="rgba(40"],
1107
+ .gradio-container .gr-dropdown[style*="#282"],
1108
+ .gradio-container .gr-dropdown[style*="#3a4"],
1109
+ .gradio-container .gr-dropdown[style*="#444"],
1110
+ .gradio-container .gr-dropdown .wrap[style*="rgb(40"],
1111
+ .gradio-container .gr-dropdown .wrap[style*="rgba(40"],
1112
+ .gradio-container .gr-dropdown .wrap[style*="#282"],
1113
+ .gradio-container .gr-dropdown .wrap[style*="#3a4"],
1114
+ .gradio-container .gr-dropdown .wrap[style*="#444"],
1115
+ .gradio-container .gr-dropdown .wrap > div[style*="rgb(40"],
1116
+ .gradio-container .gr-dropdown .wrap > div[style*="rgba(40"],
1117
+ .gradio-container .gr-dropdown .wrap > div[style*="#282"],
1118
+ .gradio-container .gr-dropdown .wrap > div[style*="#3a4"],
1119
+ .gradio-container .gr-dropdown .wrap > div[style*="#444"] {
1120
+ background: rgba(125, 211, 252, 0.08) !important;
1121
+ background-color: rgba(125, 211, 252, 0.08) !important;
1122
+ }
1123
+
1124
+ /* Ultimate catch-all: Force blue background on ALL dropdown elements */
1125
+ /* This ensures no grey backgrounds slip through - applies to Model, Species, Chromosome, etc. */
1126
+ .gradio-container .gr-dropdown,
1127
+ .gradio-container .gr-dropdown > *,
1128
+ .gradio-container .gr-dropdown .wrap,
1129
+ .gradio-container .gr-dropdown .wrap > *,
1130
+ .gradio-container .gr-dropdown .wrap > div,
1131
+ .gradio-container .gr-dropdown .wrap > div > *,
1132
+ .gradio-container .gr-dropdown .wrap > div > div,
1133
+ .gradio-container .gr-dropdown .wrap > div > div > *,
1134
+ .gradio-container .gr-dropdown .wrap > div > div > div,
1135
+ .gradio-container .gr-dropdown input,
1136
+ .gradio-container .gr-dropdown select,
1137
+ .gradio-container select {
1138
+ background: rgba(125, 211, 252, 0.08) !important;
1139
+ background-color: rgba(125, 211, 252, 0.08) !important;
1140
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
1141
+ }
1142
+
1143
+ /* Override any element with grey background that's inside a dropdown */
1144
+ .gradio-container .gr-dropdown [style*="rgb(40"],
1145
+ .gradio-container .gr-dropdown [style*="rgba(40"],
1146
+ .gradio-container .gr-dropdown [style*="#282"],
1147
+ .gradio-container .gr-dropdown [style*="#3a4"],
1148
+ .gradio-container .gr-dropdown [style*="#444"],
1149
+ .gradio-container .gr-dropdown [style*="background: rgb(40"],
1150
+ .gradio-container .gr-dropdown [style*="background: rgba(40"] {
1151
+ background: rgba(125, 211, 252, 0.08) !important;
1152
+ background-color: rgba(125, 211, 252, 0.08) !important;
1153
+ }
1154
+
1155
+ /* ============================================================================
1156
+ FINAL OVERRIDE - Number inputs in coordinates group: transparent background
1157
+ ============================================================================ */
1158
+ /* This comes at the very end to override ALL other rules - maximum specificity */
1159
+ /* Normal state */
1160
+ #coords_group input[type="number"],
1161
+ #coords_group .gr-number input,
1162
+ #coords_group .gr-number .wrap input,
1163
+ #coords_group .gr-number .wrap > div input,
1164
+ #coords_group .gr-number .wrap > div > div input,
1165
+ #coords_group .gr-row input[type="number"],
1166
+ #coords_group .gr-row .gr-number input,
1167
+ #coords_group .gr-row .gr-number .wrap input,
1168
+ #coords_group .gr-row .gr-number .wrap > div input,
1169
+ .gradio-container #coords_group input[type="number"],
1170
+ .gradio-container #coords_group .gr-number input,
1171
+ .gradio-container #coords_group .gr-row input[type="number"],
1172
+ .gradio-container #coords_group .gr-row .gr-number input,
1173
+ #coords_group input[type="number"][style*="background"],
1174
+ #coords_group input[type="number"][style*="rgba(125"],
1175
+ #coords_group input[type="number"][style*="rgb(125"],
1176
+ #coords_group .gr-number input[style*="background"],
1177
+ #coords_group .gr-number input[style*="rgba(125"],
1178
+ #coords_group .gr-number input[style*="rgb(125"] {
1179
+ background: transparent !important;
1180
+ background-color: transparent !important;
1181
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
1182
+ border-radius: 12px !important;
1183
+ color: var(--text) !important;
1184
+ }
1185
+
1186
+ /* Hover state */
1187
+ #coords_group input[type="number"]:hover,
1188
+ #coords_group .gr-number input:hover,
1189
+ #coords_group .gr-number .wrap input:hover,
1190
+ #coords_group .gr-row input[type="number"]:hover,
1191
+ #coords_group .gr-row .gr-number input:hover,
1192
+ .gradio-container #coords_group input[type="number"]:hover,
1193
+ .gradio-container #coords_group .gr-number input:hover {
1194
+ background: transparent !important;
1195
+ background-color: transparent !important;
1196
+ border-color: rgba(125, 211, 252, 0.35) !important;
1197
+ }
1198
+
1199
+ /* Focus state */
1200
+ #coords_group input[type="number"]:focus,
1201
+ #coords_group .gr-number input:focus,
1202
+ #coords_group .gr-number .wrap input:focus,
1203
+ #coords_group .gr-row input[type="number"]:focus,
1204
+ #coords_group .gr-row .gr-number input:focus,
1205
+ .gradio-container #coords_group input[type="number"]:focus,
1206
+ .gradio-container #coords_group .gr-number input:focus {
1207
+ background: transparent !important;
1208
+ background-color: transparent !important;
1209
+ border-color: rgba(125, 211, 252, 0.35) !important;
1210
+ box-shadow: 0 0 0 3px rgba(125, 211, 252, 0.1) !important;
1211
+ outline: none !important;
1212
+ }
1213
+
1214
+ /* ============================================================================
1215
+ START AND END INPUTS - Direct ID targeting for maximum specificity
1216
+ ============================================================================ */
1217
+ /* Target Start and End inputs directly by their IDs - override everything */
1218
+ #start_input input,
1219
+ #start_input input[type="number"],
1220
+ #start_input .wrap input,
1221
+ #start_input .wrap > div input,
1222
+ #start_input .wrap > div > div input,
1223
+ #end_input input,
1224
+ #end_input input[type="number"],
1225
+ #end_input .wrap input,
1226
+ #end_input .wrap > div input,
1227
+ #end_input .wrap > div > div input,
1228
+ #coords_group #start_input input,
1229
+ #coords_group #start_input input[type="number"],
1230
+ #coords_group #end_input input,
1231
+ #coords_group #end_input input[type="number"],
1232
+ .gradio-container #start_input input,
1233
+ .gradio-container #start_input input[type="number"],
1234
+ .gradio-container #end_input input,
1235
+ .gradio-container #end_input input[type="number"] {
1236
+ background: transparent !important;
1237
+ background-color: transparent !important;
1238
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
1239
+ border-radius: 12px !important;
1240
+ color: var(--text) !important;
1241
+ }
1242
+
1243
+ #start_input input:hover,
1244
+ #start_input .wrap input:hover,
1245
+ #end_input input:hover,
1246
+ #end_input .wrap input:hover,
1247
+ #coords_group #start_input input:hover,
1248
+ #coords_group #end_input input:hover {
1249
+ background: transparent !important;
1250
+ background-color: transparent !important;
1251
+ border-color: rgba(125, 211, 252, 0.35) !important;
1252
+ }
1253
+
1254
+ #start_input input:focus,
1255
+ #start_input .wrap input:focus,
1256
+ #end_input input:focus,
1257
+ #end_input .wrap input:focus,
1258
+ #coords_group #start_input input:focus,
1259
+ #coords_group #end_input input:focus {
1260
+ background: transparent !important;
1261
+ background-color: transparent !important;
1262
+ border-color: rgba(125, 211, 252, 0.35) !important;
1263
+ box-shadow: 0 0 0 3px rgba(125, 211, 252, 0.1) !important;
1264
+ outline: none !important;
1265
+ }
1266
+
1267
+ /* Override any inline styles on Start and End inputs */
1268
+ #start_input input[style*="background"],
1269
+ #start_input input[style*="rgba(125"],
1270
+ #start_input input[style*="rgb(125"],
1271
+ #end_input input[style*="background"],
1272
+ #end_input input[style*="rgba(125"],
1273
+ #end_input input[style*="rgb(125"] {
1274
+ background: transparent !important;
1275
+ background-color: transparent !important;
1276
+ }
1277
+
1278
+ /* ============================================================================
1279
+ GRADIO FOOTER BUTTONS - Remove blue backgrounds
1280
+ ============================================================================ */
1281
+
1282
+ /* Target footer buttons: "Use via API" and "Settings" */
1283
+ footer button,
1284
+ footer .gr-button,
1285
+ footer a[role="button"],
1286
+ footer a[class*="button"],
1287
+ .gradio-footer button,
1288
+ .gradio-footer .gr-button,
1289
+ .gradio-footer a[role="button"],
1290
+ [class*="footer"] button,
1291
+ [class*="footer"] .gr-button,
1292
+ [class*="footer"] a[role="button"],
1293
+ footer span button,
1294
+ footer div button {
1295
+ background: transparent !important;
1296
+ background-color: transparent !important;
1297
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
1298
+ color: var(--text) !important;
1299
+ }
1300
+
1301
+ footer button:hover,
1302
+ footer .gr-button:hover,
1303
+ footer a[role="button"]:hover,
1304
+ footer a[class*="button"]:hover,
1305
+ .gradio-footer button:hover,
1306
+ .gradio-footer .gr-button:hover,
1307
+ .gradio-footer a[role="button"]:hover,
1308
+ [class*="footer"] button:hover,
1309
+ [class*="footer"] .gr-button:hover,
1310
+ [class*="footer"] a[role="button"]:hover,
1311
+ footer span button:hover,
1312
+ footer div button:hover {
1313
+ background: rgba(125, 211, 252, 0.08) !important;
1314
+ background-color: rgba(125, 211, 252, 0.08) !important;
1315
+ border-color: rgba(125, 211, 252, 0.3) !important;
1316
+ }
1317
+
1318
+ /* More specific targeting for footer area buttons */
1319
+ footer > div button,
1320
+ footer > div a[role="button"],
1321
+ footer > div .gr-button,
1322
+ footer > div > div button,
1323
+ footer > div > div a[role="button"] {
1324
+ background: transparent !important;
1325
+ background-color: transparent !important;
1326
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
1327
+ }
1328
+
1329
+ /* Target all buttons in footer container */
1330
+ footer * button,
1331
+ footer * a[role="button"],
1332
+ footer * .gr-button {
1333
+ background: transparent !important;
1334
+ background-color: transparent !important;
1335
+ }
1336
+
1337
+ /* Override any inline blue/grey backgrounds on footer buttons */
1338
+ footer button[style*="background"],
1339
+ footer a[style*="background"],
1340
+ footer .gr-button[style*="background"],
1341
+ footer button[style*="rgba(125"],
1342
+ footer button[style*="rgb(125"],
1343
+ footer a[style*="rgba(125"],
1344
+ footer a[style*="rgb(125"] {
1345
+ background: transparent !important;
1346
+ background-color: transparent !important;
1347
+ }
1348
+
1349
+ /* Target buttons with specific Gradio footer classes */
1350
+ [class*="api"] button,
1351
+ [class*="API"] button,
1352
+ [class*="settings"] button,
1353
+ [class*="Settings"] button,
1354
+ button[class*="api"],
1355
+ button[class*="API"],
1356
+ button[class*="settings"],
1357
+ button[class*="Settings"] {
1358
+ background: transparent !important;
1359
+ background-color: transparent !important;
1360
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
1361
+ }
1362
+
1363
+ /* Specifically target buttons and links in footer - more specific */
1364
+ footer a,
1365
+ footer button,
1366
+ footer [role="button"],
1367
+ footer [class*="button"],
1368
+ footer span button,
1369
+ footer div button,
1370
+ footer div a,
1371
+ footer span a {
1372
+ background: transparent !important;
1373
+ background-color: transparent !important;
1374
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
1375
+ color: var(--text) !important;
1376
+ }
1377
+
1378
+ footer a:hover,
1379
+ footer button:hover,
1380
+ footer [role="button"]:hover,
1381
+ footer [class*="button"]:hover,
1382
+ footer span button:hover,
1383
+ footer div button:hover,
1384
+ footer div a:hover,
1385
+ footer span a:hover {
1386
+ background: rgba(125, 211, 252, 0.08) !important;
1387
+ background-color: rgba(125, 211, 252, 0.08) !important;
1388
+ }
1389
+
1390
+ /* Override any blue color values in inline styles - very specific */
1391
+ footer button[style*="background"],
1392
+ footer a[style*="background"],
1393
+ footer [role="button"][style*="background"],
1394
+ footer [class*="button"][style*="background"],
1395
+ footer button[style*="background-color"],
1396
+ footer a[style*="background-color"] {
1397
+ background: transparent !important;
1398
+ background-color: transparent !important;
1399
+ }
1400
+
1401
+ /* Target Gradio's specific footer structure with maximum specificity */
1402
+ .gradio-container footer button,
1403
+ .gradio-container footer a,
1404
+ .gradio-container > footer button,
1405
+ .gradio-container > footer a,
1406
+ body footer button,
1407
+ body footer a,
1408
+ html body footer button,
1409
+ html body footer a {
1410
+ background: transparent !important;
1411
+ background-color: transparent !important;
1412
+ }
1413
+
1414
+ /* Target by data attributes or specific Gradio classes */
1415
+ footer [data-testid],
1416
+ footer [aria-label],
1417
+ footer button[type="button"],
1418
+ footer a[href] {
1419
+ background: transparent !important;
1420
+ background-color: transparent !important;
1421
+ }
1422
+
1423
+ /* Nuclear option - target ALL elements in footer that might be buttons */
1424
+ footer > * > * > button,
1425
+ footer > * > * > a,
1426
+ footer > * > button,
1427
+ footer > * > a,
1428
+ footer button,
1429
+ footer a,
1430
+ footer [class*="btn"],
1431
+ footer [class*="button"],
1432
+ footer [role="button"] {
1433
+ background: transparent !important;
1434
+ background-color: transparent !important;
1435
+ border: 1px solid rgba(125, 211, 252, 0.2) !important;
1436
+ }
1437
+
1438
+ /* Override ALL possible background color formats */
1439
+ footer button,
1440
+ footer a,
1441
+ footer [role="button"],
1442
+ footer [class*="button"] {
1443
+ background: transparent !important;
1444
+ background-color: transparent !important;
1445
+ background-image: none !important;
1446
+ }
1447
+
1448
+ /* Force override even with inline styles using attribute selectors */
1449
+ footer button[style],
1450
+ footer a[style],
1451
+ footer [role="button"][style] {
1452
+ background: transparent !important;
1453
+ background-color: transparent !important;
1454
+ }