/*
  Custom Styles for Shiny App
  This file contains styles used across the Shiny app.
  These styles control the app theme, navigation, buttons, query builders,
  loading screens, home page layout, plots, forms, and footer.
  Author: Tim Hackmann
  Date: 6 September 2024
*/

/* Theme variables */
:root {
  /* Font Awesome */
  --fa-style-family-brands: "Font Awesome 6 Brands";
  --fa-font-brands: normal 400 1em/1 "Font Awesome 6 Brands";
  --fa-font-regular: normal 400 1em/1 "Font Awesome 6 Free";
  --fa-style-family-classic: "Font Awesome 6 Free";
  --fa-font-solid: normal 900 1em/1 "Font Awesome 6 Free";

  /* Bootstrap theme */
  --bslib-bootstrap-version: 5;
  --bslib-preset-name: litera;
  --bslib-preset-type: bootswatch;

  /* Colors */
  --primary-color: #337ab7;
  --primary-hover-color: #2e6da4;
  --primary-border-color: #2e6da4;
  --primary-text-color: white;
  --secondary-color: #adb5bd;
  --success-color: #02b875;
  --danger-color: #d9534f;
  --warning-color: #f0ad4e;
  --info-color: #17a2b8;
  --light-color: #f8f9fa;
  --dark-color: #343a40;
  --gray-color: #868e96;
  --white-color: #fff;
  --black-color: #000;

  /* Text colors */
  --text-color-light: var(--white-color);
  --text-color-dark: var(--black-color);
  --text-color-gray: #6c757d;

  /* Buttons */
  --btn-padding: 0.5rem 1rem;
  --btn-small-padding: 0.25rem 0.5rem;
  --btn-border-radius: .375rem;
  --btn-border-width: 1px;
  --btn-font-size: 1rem;
  --btn-small-font-size: 0.85rem;
  --btn-font-family: var(--bs-font-sans-serif);
  --btn-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  --btn-hover-shadow: 0 3px 6px rgba(0, 0, 0, 0.15);
  --btn-active-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);

  /* Background colors */
  --bg-primary-subtle: #dae6fb;
  --bg-secondary-subtle: #eff0f2;
  --bg-success-subtle: #ccf1e3;
  --bg-danger-subtle: #f7dddc;
  --bg-warning-subtle: #fcefdc;
  --bg-info-subtle: #d1ecf1;
  --bg-light-subtle: #fcfcfd;
  --bg-dark-subtle: #ced4da;
  --grey-95: #f2f2f2;

  /* Border colors */
  --border-primary-subtle: #b5cdf7;
  --border-secondary-subtle: #dee1e5;
  --border-success-subtle: #9ae3c8;
  --border-danger-subtle: #f0bab9;
  --border-warning-subtle: #f9deb8;
  --border-info-subtle: #a2dae3;
  --border-light-subtle: #e9ecef;
  --border-dark-subtle: #adb5bd;
  --grey90: #e5e5e5;

  /* Body text and background */
  --body-font-family: var(--bs-font-sans-serif);
  --body-font-size: 1.1rem;
  --body-small-font-size: 1.0rem;
  --body-font-weight: 400;
  --body-line-height: 1.5;
  --body-color: #343a40;
  --body-bg: var(--white-color);

  /* Borders and shadows */
  --border-color: #ddd;
  --border-radius: .375rem;
  --border-radius-pill: 50rem;
  --box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);

  /* Icons */
  --icon-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  --icon-hover-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);

  /* Navigation */
  --navbar-bg-color: var(--white-color);
  --navbar-text-color: var(--black-color);
  --navbar-active-bg: var(--grey90);

  /* Query builder */
  --query-bg-color: var(--white-color);
  --query-border-color: var(--grey90);
  --query-header-bg: var(--white-color); /* was var(--grey-95) #f2f2f2; restored to white (header bg was effectively white before, via an undefined --grey95 reference) */
  --query-header-border: var(--border-color); /* was var(--border-primary-subtle) #b5cdf7 (blue); matched to grey #ddd used by the rule rows below */
  --query-header-text-color: var(--primary-color);
  --query-rule-bg: var(--white-color);
  --query-rule-border: var(--border-color);
  --query-select-bg: var(--bg-light-subtle);
  --query-select-border: var(--border-color);

  /* Lists */
  --list-circle-fill-color: #ffffff;
  --list-circle-border-color: #9ca3af;
  --list-circle-text-color: #374151;

  /* Button states */
  --secondary-hover-color: #929a9e;
  --success-hover-color: #029e65;
  --danger-hover-color: #c9302c;
  --warning-hover-color: #ec971f;
  --info-hover-color: #138496;
  --light-hover-color: #e2e6ea;
  --dark-hover-color: #23272b;
}

/* Navigation */
.navbar {
  background-color: var(--navbar-bg-color);
  min-height: 25px !important;
}

.navbar-default .navbar-nav > li > a {
  color: var(--navbar-text-color);
}

.navbar-default .navbar-nav > .active > a,
.navbar-default .navbar-nav > .active > a:focus,
.navbar-default .navbar-nav > .active > a:hover {
  color: var(--navbar-text-color);
  background-color: var(--navbar-active-bg);
}

.navbar-nav > li > a {
  padding-top: 15px !important;
  padding-bottom: 15px !important;
  height: 50px;
}

.dropdown-toggle::after {
  display: none;
}

/* Card navigation */
.card-header.bslib-navs-card-title {
  display: block !important;
}

.card-header.bslib-navs-card-title > .nav {
  justify-content: flex-start !important;
}

.nav-title {
  font-weight: 600;
  white-space: nowrap;
  margin-right: 1rem;
}

/* Sidebars */
/* bslib sets the top padding of .sidebar-content to --_padding-icon (3rem by
   default) to leave room for the collapse toggle, which pushes the first
   sidebar element well below the first element in the main panel. Reducing the
   variable tightens the top gap without touching the side padding. */
.bslib-sidebar-layout {
  --_padding-icon: 1.75rem;
}

/* Accordions */
/* bslib pulls a sidebar accordion edge to edge with a negative margin equal to
   the sidebar padding, which makes the item borders overhang the inputs above.
   Cancelling the margin brings the borders in to the content width, and
   zeroing the button padding keeps the header text aligned with it. */
.advanced-accordion {
  margin-left: 0 !important;
  margin-right: 0 !important;
}

.advanced-accordion .accordion-button,
.advanced-accordion .accordion-body {
  padding-left: 0;
  padding-right: 0;
}

/* Buttons */
.btn {
  padding: var(--btn-padding);
  border-radius: var(--btn-border-radius);
  border-width: var(--btn-border-width);
  font-size: var(--btn-font-size);
  font-family: var(--btn-font-family);
  box-shadow: var(--btn-shadow);
}

.btn-primary {
  background-color: var(--primary-color);
  border-color: var(--primary-color);
  color: var(--text-color-light);
}

.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active {
  background-color: var(--primary-hover-color);
  border-color: var(--primary-hover-color);
  box-shadow: var(--btn-shadow);
}

.btn-secondary {
  background-color: var(--secondary-color);
  border-color: var(--secondary-color);
  color: var(--text-color-light);
}

.btn-secondary:hover,
.btn-secondary:focus,
.btn-secondary:active {
  background-color: var(--secondary-hover-color);
  border-color: var(--secondary-hover-color);
  box-shadow: var(--btn-shadow);
}

.btn-success {
  background-color: var(--success-color);
  border-color: var(--success-color);
  color: var(--text-color-light);
}

.btn-success:hover,
.btn-success:focus,
.btn-success:active {
  background-color: var(--success-hover-color);
  border-color: var(--success-hover-color);
  box-shadow: var(--btn-shadow);
}

.btn-danger {
  background-color: var(--danger-color);
  border-color: var(--danger-color);
  color: var(--text-color-light);
}

.btn-danger:hover,
.btn-danger:focus,
.btn-danger:active {
  background-color: var(--danger-hover-color);
  border-color: var(--danger-hover-color);
  box-shadow: var(--btn-active-shadow);
}

.btn-warning {
  background-color: var(--warning-color);
  border-color: var(--warning-color);
  color: var(--text-color-light);
}

.btn-warning:hover,
.btn-warning:focus,
.btn-warning:active {
  background-color: var(--warning-hover-color);
  border-color: var(--warning-hover-color);
  box-shadow: var(--btn-active-shadow);
}

.btn-info {
  background-color: var(--info-color);
  border-color: var(--info-color);
  color: var(--text-color-light);
}

.btn-info:hover,
.btn-info:focus,
.btn-info:active {
  background-color: var(--info-hover-color);
  border-color: var(--info-hover-color);
  box-shadow: var(--btn-active-shadow);
}

.btn-light {
  background-color: var(--light-color);
  border-color: var(--light-color);
  color: var(--dark-color);
}

.btn-light:hover,
.btn-light:focus,
.btn-light:active {
  background-color: var(--light-hover-color);
  border-color: var(--light-hover-color);
}

.btn-dark {
  background-color: var(--dark-color);
  border-color: var(--dark-color);
  color: var(--text-color-light);
}

.btn-dark:hover,
.btn-dark:focus,
.btn-dark:active {
  background-color: var(--dark-hover-color);
  border-color: var(--dark-hover-color);
  box-shadow: var(--btn-active-shadow);
}

.btn.disabled,
.btn:disabled {
  background-color: var(--secondary-color);
  border-color: var(--secondary-color);
  color: var(--text-color-gray);
  opacity: 0.65;
  cursor: not-allowed;
}

.btn-primary {
  background-color: var(--primary-color) !important;
  border-color: var(--primary-border-color) !important;
  color: var(--primary-text-color) !important;
}

.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active {
  background-color: var(--primary-hover-color) !important;
  border-color: var(--primary-hover-color) !important;
}

/* Query builder */
#databaseSearch-query_builder_group_0,
#databaseSearch-query_builder_group_1,
#databaseSearch-query_builder_group_2,
#databaseSearch-query_builder_group_3,
#predictionsTaxonomy-query_builder_group_0,
#predictionsTaxonomy-query_builder_group_1,
#predictionsTaxonomy-query_builder_group_2,
#predictionsTaxonomy-query_builder_group_3,
#predictionsMachineLearning-query_builder_group_0,
#predictionsMachineLearning-query_builder_group_1,
#predictionsMachineLearning-query_builder_group_2,
#predictionsMachineLearning-query_builder_group_3 {
  background-color: var(--query-bg-color);
  border: 1px solid var(--query-border-color);
}

.rules-group-header {
  background-color: var(--query-header-bg);
  border-bottom: 2px solid var(--query-header-border);
  padding: 10px;
  font-weight: bold;
  color: var(--query-header-text-color);
}

.rules-group-header .group-conditions .btn-primary {
  background-color: var(--primary-color) !important;
  border-color: var(--primary-color) !important;
  color: var(--text-color-light) !important;
  opacity: 1 !important;
  cursor: pointer !important;
  font-size: var(--btn-small-font-size);
  padding: var(--btn-small-padding);
}

.rules-group-header .group-conditions .btn-primary.disabled,
.rules-group-header .group-conditions .btn-primary:disabled {
  background-color: var(--primary-color) !important;
  border-color: var(--primary-color) !important;
  color: var(--text-color-light) !important;
  opacity: 1 !important;
  cursor: pointer !important;
  font-size: var(--btn-small-font-size);
  padding: var(--btn-small-padding);
}

.rules-group-header .group-actions .btn,
.rule-actions .btn {
  font-size: var(--btn-small-font-size);
  padding: var(--btn-small-padding);
}

.rule-container {
  background-color: var(--query-rule-bg);
  border: 1px solid var(--query-rule-border);
  margin-bottom: 10px;
  padding: 10px;
  border-radius: var(--border-radius);
}

.rule-filter-container select,
.rule-operator-container select,
.rule-value-container select {
  background-color: var(--query-select-bg);
  border: 1px solid var(--query-select-border);
  padding: 5px;
  border-radius: var(--border-radius);
  width: 100%;
}

.rule-actions .btn-danger {
  background-color: var(--danger-color);
  border-color: var(--danger-color);
  color: var(--text-color-light);
  font-size: var(--btn-small-font-size);
  padding: var(--btn-small-padding);
}

/* Modals */
.modal-dialog {
  top: 50% !important;
  left: 50% !important;
  transform: translate(-50%, -50%) !important;
  margin: 0 !important;
  max-height: 95vh;
}

.modal-content {
  max-height: 95vh;
  overflow-y: auto;
}

body.modal-open {
  overflow: hidden !important;
}

/* General layout */
.flex-container {
  display: flex;
  gap: 1rem;
}

.flex-item {
  flex: 1;
  min-width: 150px;
}

.hidden {
  display: none !important;
}

.tight-heading {
  margin-bottom: -16px !important;
}

.form-group {
  margin-bottom: 0px !important;
}

.vertical-container > * {
  display: block;
}

.vertical-container > *:first-child {
  margin-bottom: 5px;
}

.bslib-gap-spacing {
  margin-top: 5px;
  margin-bottom: 5px;
  padding-top: 5px;
  padding-bottom: 5px;
}

/* Plot messages */
/* Shown in place of a plot when there is nothing to draw, in the same style as
   the missing-file modals: a bold first line naming the problem, then a line
   telling the user what to do about it. */
.plot-message {
  padding: 2rem 1rem;
  text-align: center;
  font-size: var(--body-small-font-size);
  color: var(--text-color-gray);
}

.plot-message-title {
  font-weight: 600;
  margin-bottom: 0.25rem;
  color: var(--body-color);
}

/* Messages from validate(), which take the place of a plot inside its
   container.  Given room to sit on their own line so they are not clipped. */
.shiny-output-error-validation {
  display: block;
  padding: 2rem 1rem;
  text-align: center;
  font-size: var(--body-small-font-size);
  color: var(--text-color-gray);
}

/* Plot containers */
.treemap-container-style {
  margin-right: auto;
  margin-left: auto;
}

.network-container-style {
  height: 50vh;
}

/* Spinners */
/* The spinner shows the first time an output renders and is held back after
   that, so redraws change the plot or table in place.  The mark that holds it
   back is set in custom.js and is cleared when a new job is loaded. */
.shiny-spinner-output-container[data-spin-once].spinner-rendered .load-container {
  visibility: hidden;
}

/* Keep room for the spinner until the output has rendered.  Containers that
   size to their content have nothing in them at that point, so the spinner
   would otherwise spill out of the card and be clipped. */
.shiny-spinner-output-container[data-spin-once]:not(.spinner-rendered) {
  min-height: 200px;
}

/* Numbered lists */
.circled-number-list {
  counter-reset: h5-circle;
}

.circled-number-list h5 {
  counter-increment: h5-circle;
  position: relative;
  padding-left: 42px;
  margin-top: 1.2rem;
  margin-bottom: 0.6rem;
}

.circled-number-list h5::before {
  content: counter(h5-circle);
  position: absolute;
  left: 0;
  top: 0.15em;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 14px;
  background-color: var(--list-circle-fill-color);
  border: 2px solid var(--list-circle-border-color);
  color: var(--list-circle-text-color);
}

ol.circled-letter-list {
  list-style: none;
  counter-reset: circled-letter;
  padding-left: 0;
  margin-left: 0;
}

ol.circled-letter-list li {
  counter-increment: circled-letter;
  position: relative;
  margin-bottom: 15px;
  padding-left: 36px;
}

ol.circled-letter-list li::before {
  content: counter(circled-letter, lower-alpha);
  position: absolute;
  left: 0;
  top: 0.15em;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 13px;
  background-color: var(--list-circle-border-color);
  border: 2px solid var(--list-circle-border-color);
  color: white;
}

/* Home page */
.home-grid {
  --home-grid-columns: 3; /* max number of columns of buttons */
  --home-button-width: 295px; /* width of each button */
  --home-grid-column-gap: 14px; /* space between buttons */

  display: grid;
  grid-template-columns: repeat(auto-fit, var(--home-button-width));
  gap: 6px var(--home-grid-column-gap);
  max-width: calc(
    var(--home-button-width) * var(--home-grid-columns) +
    var(--home-grid-column-gap) * (var(--home-grid-columns) - 1)
  );
  margin: 0 auto;
  justify-content: center;
  align-items: stretch;
}

.home-section-label {
  grid-column: 1 / -1;      
  justify-self: start;      
  margin: 10px 0 2px;
  padding: 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--gray-color);
  text-align: left;
}

.home-button-grid {
  display: grid;
  grid-template-columns: 75px 1fr;
  width: 100%;
  height: 100%;
  align-items: center;
  padding-left: 0px;
  padding-right: 0px;
  padding-top: 3px;
  padding-bottom: 3px;
}

.home-button-box {
  width: var(--home-button-width, 295px);
  height: 100%;
  min-height: 74px;
  background-color: transparent;
  transition: 0.5s ease;
  position: relative;
  object-fit: scale-down;
}

.home-button-box:hover {
  -webkit-transform: scale(1.05);
  -ms-transform: scale(1.05);
  transform: scale(1.05);
}

.home-button-icon {
  border-radius: 5px;
  width: 100%;
  height: 100%;
  background-color: var(--white-color);
  border: 0;
  padding-top: 0px;
  object-fit: scale-down;
  box-shadow: var(--icon-shadow);
}

.home-button-icon:hover {
  box-shadow: var(--icon-hover-shadow);
}

.home-button-title,
.home-button-subtitle {
  text-align: left;
  padding-left: 10px;
  padding-right: 10px;
  padding-top: 0px;
  padding-bottom: 0px;
}

.home-button-title {
  font-weight: bold;
  color: var(--black-color);
}

.home-button-subtitle {
  color: var(--gray-color);
}

.home-action-button-right,
.home-action-button-left {
  position: absolute;
  top: 0px;
  left: 0px;
  right: 0px;
  width: 100%;
  height: 100%;
  opacity: 0;
}

/* Form inputs */
.selectize-control.multi .selectize-input {
  max-height: 75px !important;
  overflow-y: auto !important;
  white-space: normal !important;
}

.trait-not-predicted {
  color: var(--text-color-gray);
  font-style: italic;
}

.plot-options-container {
  padding: 0; /* was 0 1rem; toolbar now sits inside padded card-body header, so no extra horizontal padding (keeps it flush with card title) */
}

/* Sliders in the plot options toolbar */
/* The min and max labels and the bottom margin are dropped so the slider sits at
   about the same height as the pickers and switches beside it. */
.compact-slider .form-group {
  margin-bottom: 0 !important;
}

.compact-slider label.control-label {
  font-family: var(--body-font-family);
  font-size: var(--body-small-font-size);
  margin-bottom: 5px;
}

.compact-slider .irs {
  font-family: var(--body-font-family);
  font-size: var(--body-small-font-size);
}

.compact-slider .irs-min,
.compact-slider .irs-max {
  display: none;
}

/* A slider gets cramped at the 150px the other toolbar items use, and it does
   not need to stretch the way a picker does, so give it a fixed width. */
.flex-item-slider {
  flex: 0 0 220px;
  min-width: 220px;
}

/* Plot options toolbar */
/* The toolbar wraps so the accordion body, which asks for the full width, can
   drop onto its own line. Aligning to the bottom keeps the accordion button and
   the switches level with the pickers, whose labels sit above them. */
.plot-options-container {
  flex-wrap: wrap;
  align-items: flex-end;
}

/* Options accordion, sharing the toolbar above it */
/* display: contents drops the accordion and its item from the box tree, so the
   button and the collapsing body become items of the toolbar. The button takes
   a quarter of the toolbar; the body takes all of it and so wraps to the next
   line, which is what makes the L.

   The conditional panel wrapping the accordion has to go the same way, or it,
   rather than the toolbar, becomes the parent of those items. Shiny hides a
   conditional panel with an inline display: none and shows it by clearing that
   style, so display: contents is what it falls back to when shown.

   This depends on bslib emitting .accordion > .accordion-item > .accordion-header
   and .accordion-collapse. A bslib upgrade that changes that markup is what
   would break the layout. */
.options-accordion-wrapper,
.options-accordion-inline,
.options-accordion-inline .accordion-item {
  display: contents;
}

.options-accordion-inline .accordion-header {
  flex: 0 0 calc(25% - 1rem);
  min-width: 160px;
  margin: 0;
  /* Push the button to the right end of the toolbar when there is space left
     over.  The pickers grow to fill the toolbar, so this only takes effect when
     none of them is showing and the button is on its own. */
  margin-left: auto;
  align-self: flex-end;
}

.options-accordion-inline .accordion-collapse {
  flex: 0 0 100%;
}

.options-accordion-inline .accordion-button {
  background-color: var(--white-color);
  border: 1px solid var(--border-dark-subtle);
  border-radius: var(--btn-border-radius);
  box-shadow: none;
  color: var(--body-color);
  font-family: var(--body-font-family);
  font-size: var(--body-small-font-size);
  padding: var(--btn-small-padding);
}

.options-accordion-inline .accordion-button:not(.collapsed) {
  background-color: var(--white-color);
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  box-shadow: none;
  color: var(--body-color);
}

.options-accordion-inline .accordion-body {
  border-top: 1px solid var(--border-dark-subtle);
  padding: 0.75rem 0 0 0;
}

/* Options accordion, on a row of its own */
.options-accordion-row {
  margin-left: 0 !important;
  margin-right: 0 !important;
}

.options-accordion-row .accordion-button,
.options-accordion-row .accordion-body {
  padding-left: 0;
  padding-right: 0;
}

/* Notes sitting in the plot options area, which are captions rather than
   controls */
.plot-options-note {
  color: var(--gray-color);
  font-family: var(--body-font-family);
  font-size: var(--body-small-font-size);
}

.bootstrap-select .btn,
.selectize-input {
  background-color: var(--white-color) !important;
  border: 1px solid var(--border-dark-subtle) !important;
  color: var(--body-color) !important;
  font-family: var(--body-font-family) !important;
  font-size: var(--body-small-font-size) !important;
  font-weight: 400 !important;
  padding: var(--btn-small-padding);
  border-radius: var(--btn-border-radius);
}

.bootstrap-select .dropdown-menu,
.selectize-dropdown {
  background-color: var(--white-color) !important;
  border: 1px solid var(--border-dark-subtle) !important;
}

.bootstrap-select .dropdown-menu .dropdown-item,
.selectize-dropdown .selectize-dropdown-content .option {
  color: var(--body-color) !important;
  font-family: var(--body-font-family) !important;
  font-size: var(--body-small-font-size) !important;
  font-weight: 400 !important;
}

.bootstrap-select .dropdown-menu .dropdown-item:hover,
.selectize-dropdown .selectize-dropdown-content .option:hover {
  background-color: var(--bg-primary-subtle) !important;
  color: var(--primary-hover-color) !important;
}

.bootstrap-select .btn::after {
  border-top-color: var(--border-dark-subtle) !important;
}

/* Loading screen */
.loading-screen {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  width: 100%;
  text-align: center;
  margin-top: 0;
}

.loading-text {
  color: grey;
  font-size: 30px;
}

.fade-svg {
  opacity: 0;
  animation-name: fadeInOut;
  animation-duration: 2s;
  animation-delay: 0.2s;
  animation-iteration-count: infinite;
  animation-timing-function: ease-in-out;
  animation-fill-mode: forwards;
}

@keyframes fadeInOut {
  0% { opacity: 0.2; }
  50% { opacity: 1; }
  100% { opacity: 0.2; }
}

/* Home page logo */
.logo-text {
  font-family: 'Roboto Flex', sans-serif;
  font-size: 40px;
  font-variation-settings: 'wght' 1000, 'wdth' 100;
  text-align: center;
  margin: 0;
  padding: 0;
  letter-spacing: 1px;
  text-shadow: 0.5px 0.5px 1px rgba(0, 0, 0, 0.1);
}

.home-header {
  text-align: center;
  margin: 0;
  padding: 0;
}

.home-logo {
  margin-bottom: -5px;
  padding: 0;
}

.logo-subtitle {
  font-family: 'Roboto Flex', sans-serif;
  font-size: 20px;
  color: #6c757d;
  text-align: center;
  margin-top: -10px;
}

.blinking-cursor {
  animation: blink 3s step-start infinite;
}

@keyframes blink {
  0%, 50%, 100% { opacity: 1; }
  25%, 75% { opacity: 0; }
}

/* Footer */
.page-wrapper {
  min-height: 100vh;
  padding-bottom: 40px;
}

.app-footer {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: 34px;
  padding: 6px 14px;
  background: rgba(240, 240, 240, 0.85);
  border-top: 1px solid #ddd;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  z-index: 2000;
  font-size: 13px;
}

.cc-icon {
  height: 18px;
  width: auto;
  margin-left: 2px;
  opacity: 0.7;
  filter: grayscale(30%);
  transition: 0.2s;
}

.cc-icon:hover {
  opacity: 1;
  filter: grayscale(0%);
}
