/* =========================================================================
   Shared base styles for every portal (admin, guest, employee, vehicle) and
   the root-level pages.

   This file used to be duplicated as four near-identical copies of
   <portal>/css/common.css, which had already drifted apart: the employee
   portal was missing the label rule and used a different toast z-index.
   Anything that applies app-wide belongs here; each portal's common.css now
   holds only its own layout rules and is loaded AFTER this file so it can
   override.
   ========================================================================= */

:root{
  --teal: #2ec1ac;
  --teal_hover: #279e8c;
}

/* font-size lives on the root element so that it CASCADES.

   It used to sit on the universal selector, as `font-size: 14px` inside the
   `*` rule, which re-set every element independently and therefore broke
   font-size inheritance across the whole app: a child of a larger parent
   still rendered at 14px, so a sizing class on a container had no effect on
   the text inside it.

   14px is deliberately kept as the ROOT value so the rem unit is unchanged
   and every existing layout, control height and Bootstrap spacing stays
   exactly as it is today. */
html{
  font-size: 14px;
}

/* font-family stays on the universal selector because form controls do not
   inherit it by default. */
*{
  font-family: 'Poppins', sans-serif;
}

body{
  background-color: #F7F8FC;
}

input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

input[type=number] {
  -moz-appearance: textfield;
}

label{
  font-size: 14px;
  font-weight: 500;
}

/* Toast container. 2100 keeps it above Bootstrap modals (1055) and above the
   modal backdrop; the employee portal already used this value while the other
   three used 2000. */
.custom-alert{
  position: fixed;
  top: 80px;
  right: 25px;
  z-index: 2100;
}

/* --- Focus visibility ---------------------------------------------------
   Nearly every control in this app carries .shadow-none, and box-shadow is
   Bootstrap 5's only focus signal - so focused fields and buttons were
   visually identical to unfocused ones. outline is unaffected by
   .shadow-none, so it restores a keyboard focus ring without changing any
   existing styling. This file loads after Bootstrap, so the equal-specificity
   `outline: 0` in Bootstrap's own :focus rules is overridden.
   ---------------------------------------------------------------------- */
.form-control:focus,
.form-select:focus,
.form-check-input:focus,
.btn:focus-visible,
.accordion-button:focus-visible,
.dropdown-item:focus-visible,
.nav-link:focus-visible,
a:focus-visible {
  outline: 2px solid #0d6efd;
  outline-offset: 2px;
}

/* --- Shape and elevation tokens -----------------------------------------
   Bootstrap expresses its radii in rem, and this app sets the root to 14px,
   so the stock corners compute to 2.8px - visibly sharper than the 8-12px
   that reads as current. These tokens pin the shape language to pixels so it
   no longer moves with the root font size.

   Deliberately NO !important here: Bootstrap's own utilities (.rounded-pill
   on the account dropdown, .rounded-3, and the input-group corner rules) are
   !important and must keep winning. This file loads after Bootstrap, so for
   equal specificity these still take effect.
   ---------------------------------------------------------------------- */
:root{
  --radius-sm: 6px;
  --radius: 10px;
  --shadow-sm: 0 1px 2px rgba(16,24,40,.06), 0 1px 3px rgba(16,24,40,.10);
  --shadow-md: 0 6px 16px rgba(16,24,40,.10);
  --border-soft: #e6e8ee;
}

.card,
.modal-content,
.accordion,
.accordion-item{
  border-radius: var(--radius);
}

.btn,
.form-control,
.form-select,
.input-group-text,
.alert{
  border-radius: var(--radius-sm);
}

.card{
  border-color: var(--border-soft);
  box-shadow: var(--shadow-sm);
}

.modal-content{
  box-shadow: var(--shadow-md);
  border: 0;
}

/* The app expresses its shape language through Bootstrap's utilities rather
   than through .card directly: .rounded-3 appears 225 times and .shadow-sm
   139 times. Those utilities are !important, so the tokens above cannot reach
   the elements that use them. Retuning the utilities themselves is what
   actually changes the look, and it keeps every existing class name working.

   .rounded-pill is left alone - it expresses a different intent (the account
   dropdown), not a corner-size preference. */
.rounded-3{ border-radius: var(--radius) !important; }
.rounded-2{ border-radius: var(--radius-sm) !important; }
.shadow-sm{ box-shadow: var(--shadow-sm) !important; }
.shadow{ box-shadow: var(--shadow-md) !important; }

/* Round only the header corners rather than clipping the whole table: the
   .table-responsive wrapper must keep overflow-x auto or wide tables stop
   scrolling on small screens. */
.table thead th:first-child{ border-top-left-radius: var(--radius-sm); }
.table thead th:last-child{ border-top-right-radius: var(--radius-sm); }

/* Wide data tables keep a usable minimum width on small screens and scroll
   horizontally inside their .table-responsive wrapper, rather than crushing
   every column. This was previously pasted into a <style> block on 56
   separate pages. */
@media screen and (max-width: 530px) {
  .table-responsive table{
    min-width: 850px !important;
  }
}

/* --- Motion --------------------------------------------------------------
   Deliberately restrained: this is a dense operational tool, not a marketing
   site, and the whole block is wrapped in prefers-reduced-motion so anyone
   who has asked their OS for less movement gets none of it.

   Durations are short (60-200ms) so nothing delays an operator mid-task.
   ---------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference){

  /* Tables are replaced wholesale via innerHTML after each XHR, so rows
     animate in naturally as they enter the DOM. DataTables only puts the
     current page in the DOM, so this is ~10 rows, not the whole set. */
  @keyframes row-in{
    from{ opacity: 0; transform: translateY(3px); }
    to{ opacity: 1; transform: none; }
  }

  tbody tr{
    animation: row-in .18s ease-out both;
  }

  /* Bootstrap already slides the dialog down; adding a slight scale makes it
     read as opening rather than dropping. Extending its existing transform
     rather than replacing it keeps the .show handoff intact. */
  .modal.fade .modal-dialog{
    transform: translate(0, -24px) scale(.98);
    transition: transform .2s ease-out, opacity .2s ease-out;
  }

  .modal.show .modal-dialog{
    transform: none;
  }

  /* Tactile feedback on press, and a gentle lift on cards. */
  .btn{
    transition: transform .06s ease, background-color .15s ease, border-color .15s ease, color .15s ease;
  }

  .btn:active{
    transform: translateY(1px);
  }

  .card{
    transition: box-shadow .18s ease;
  }

  .card:hover{
    box-shadow: var(--shadow-md);
  }
}

/* Indeterminate top progress bar, driven by the XHR interceptor in
   inc/scripts.php. Sits above the toast layer. */
#xhr-progress{
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  z-index: 3000;
  pointer-events: none;
  opacity: 0;
  transition: opacity .2s ease;
  background-image: linear-gradient(90deg, rgba(13,110,253,0), #0d6efd, rgba(13,110,253,0));
  background-size: 40% 100%;
  background-repeat: no-repeat;
}

#xhr-progress.active{
  opacity: 1;
  animation: xhr-progress-slide 1s linear infinite;
}

@keyframes xhr-progress-slide{
  from{ background-position: -40% 0; }
  to{ background-position: 140% 0; }
}

@media (prefers-reduced-motion: reduce){
  #xhr-progress.active{ animation: none; background-position: 0 0; background-size: 100% 100%; }
}



/* --- KPI tiles ------------------------------------------------------------
   The dashboards show their headline numbers as plain white cards with a
   coloured heading. These give each tile a colour accent matching the metric
   it reports, and - where the tile links somewhere - a clear affordance that
   it can be clicked.

   The modifier class is applied from the existing text-* class on the tile's
   heading, so the accent always matches the number's own colour.
   ---------------------------------------------------------------------- */
.kpi{
  border-left: 4px solid #adb5bd;
  min-width: 148px;
  transition: transform .15s ease, box-shadow .15s ease;
}

.kpi .card-body{ padding: 14px 16px; }

.kpi-primary{ border-left-color: #0d6efd; background-color: rgba(13,110,253,.045); }
.kpi-success{ border-left-color: #198754; background-color: rgba(25,135,84,.045); }
.kpi-warning{ border-left-color: #ffc107; background-color: rgba(255,193,7,.07);  }
.kpi-danger { border-left-color: #dc3545; background-color: rgba(220,53,69,.045); }
.kpi-info   { border-left-color: #0dcaf0; background-color: rgba(13,202,240,.055); }

/* Clickable tiles: the whole card is the target, and it lifts on hover so the
   difference from a static tile is visible rather than implied. */
.kpi-link{
  display: block;
  text-decoration: none;
  color: inherit;
  padding: 0;
  border: 0;
  background: none;
}

.kpi-link:hover .kpi,
.kpi-link:focus-visible .kpi{
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.kpi-link:focus-visible{
  outline: 2px solid #0d6efd;
  outline-offset: 3px;
  border-radius: var(--radius);
}

@media (prefers-reduced-motion: reduce){
  .kpi{ transition: none; }
  .kpi-link:hover .kpi{ transform: none; }
}
