/* ==========================================================================
   Avanzo Calendar — Components
   --------------------------------------------------------------------------
   Every class name here that existed in the old inline <style> block is kept
   verbatim. Ten templates still reference these names; they are re-implemented
   on the token layer but the contract is unchanged, so this file can land
   without touching any screen template.
   ========================================================================== */

/* ==========================================================================
   Buttons
   Every button clears the 44px minimum touch target. Icon-only buttons keep a
   small visual footprint but get a full-size hit area via .nav-btn's padding
   box, not by shrinking the target.
   ========================================================================== */

.btn-blue, .btn-outlined, .btn-red, .btn-green, .btn-orange {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  padding: var(--sp-2) var(--sp-5);
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
  text-decoration: none;
  white-space: nowrap;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}

.btn-blue    { background: var(--brand);  color: var(--text-inverse); }
.btn-blue:hover  { background: var(--brand-hover); box-shadow: var(--shadow-sm); }
.btn-blue:active { background: var(--brand-active); }

.btn-outlined {
  background: var(--surface);
  color: var(--brand-text);
  border-color: var(--border);
}
.btn-outlined:hover  { background: var(--brand-subtle); border-color: var(--brand); }
.btn-outlined:active { background: var(--brand-subtle-hover); }

.btn-red     { background: var(--status-rejected-fg);  color: var(--text-inverse); }
.btn-red:hover   { background: var(--status-rejected-fg-hover); }

.btn-green   { background: var(--status-approved-fg);  color: var(--text-inverse); }
.btn-green:hover { background: var(--status-approved-fg-hover); }

.btn-orange  { background: var(--status-pending-fg);   color: var(--text-inverse); }
.btn-orange:hover { background: var(--status-pending-fg-hover); }

:is(.btn-blue, .btn-outlined, .btn-red, .btn-green, .btn-orange):disabled,
:is(.btn-blue, .btn-outlined, .btn-red, .btn-green, .btn-orange)[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

/* Icon-only circular control (header nav arrows, drawer toggle). */
.nav-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: var(--tap-min);
  height: var(--tap-min);
  color: var(--text-secondary);
  background: none;
  border: none;
  border-radius: var(--r-full);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease);
}
.nav-btn:hover  { background: var(--surface-hover); }
.nav-btn:active { background: var(--surface-active); }

/* ==========================================================================
   Status chips
   Status is never signalled by colour alone: the chip carries an icon slot
   AND its text label. Colour is a third, redundant cue.
   ========================================================================== */

.event-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-3);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
  white-space: nowrap;
  border: 1px solid transparent;
  border-radius: var(--r-full);
}
.event-chip::before {
  font-family: 'bootstrap-icons';
  font-size: 1em;
  line-height: 1;
}

.chip-PENDING   { color: var(--status-pending-fg);   background: var(--status-pending-bg);   border-color: var(--status-pending-accent); }
.chip-APPROVED  { color: var(--status-approved-fg);  background: var(--status-approved-bg);  border-color: var(--status-approved-accent); }
.chip-REJECTED  { color: var(--status-rejected-fg);  background: var(--status-rejected-bg);  border-color: var(--status-rejected-accent); }
.chip-CANCELLED { color: var(--status-cancelled-fg); background: var(--status-cancelled-bg); border-color: var(--status-cancelled-accent); }

/* Bootstrap Icons codepoints — the redundant non-colour cue. */
.chip-PENDING::before   { content: "\F4A0"; }  /* hourglass-split */
.chip-APPROVED::before  { content: "\F26B"; }  /* check-circle    */
.chip-REJECTED::before  { content: "\F62A"; }  /* x-circle        */
.chip-CANCELLED::before { content: "\F4F6"; }  /* slash-circle    */

/* Role badge */
.role-chip {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--sp-2);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  letter-spacing: 0.03em;
  border-radius: var(--r-full);
  white-space: nowrap;
}
.role-ADMIN       { color: var(--status-rejected-fg);  background: var(--status-rejected-bg); }
.role-FACULTY     { color: var(--brand-text);          background: var(--brand-subtle); }
.role-COORDINATOR { color: var(--status-approved-fg);  background: var(--status-approved-bg); }

/* Header count pills */
.stat-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-3);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  border-radius: var(--r-full);
  white-space: nowrap;
}
.pill-pending  { color: var(--status-pending-fg);  background: var(--status-pending-bg); }
.pill-approved { color: var(--status-approved-fg); background: var(--status-approved-bg); }

/* ==========================================================================
   Cards & page headers
   ========================================================================== */

.gcal-card {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
}

.gcal-card-hd {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding: var(--sp-4);
  font-family: var(--font-display);
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  border-bottom: 1px solid var(--border);
}

.gcal-card-bd { padding: var(--sp-4); }

.page-hd {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-bottom: var(--sp-4);
}

.page-title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-weight: var(--fw-medium);
  color: var(--text-primary);
}

/* ==========================================================================
   Forms
   Inputs are --fs-base (16px) and must stay there: anything smaller makes iOS
   Safari zoom the viewport on focus, which reads to users as the page breaking.
   ========================================================================== */

.fgroup { margin-bottom: var(--sp-5); }

.gcal-label {
  display: block;
  margin-bottom: var(--sp-2);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--text-secondary);
}

.gcal-input {
  display: block;
  width: 100%;
  min-height: var(--tap-min);
  padding: var(--sp-3);
  font-size: var(--fs-base);
  color: var(--text-primary);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  transition: border-color var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease);
}
.gcal-input::placeholder { color: var(--text-muted); }
.gcal-input:hover { border-color: var(--text-secondary); }
.gcal-input:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 1px var(--brand);
  outline: none;
}
.gcal-input:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: var(--focus-ring-offset);
}
.gcal-input.err,
.gcal-input[aria-invalid="true"] { border-color: var(--status-rejected-fg); }

select.gcal-input {
  appearance: none;
  padding-right: var(--sp-8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%235f6368'%3E%3Cpath d='M4.5 6.5 8 10l3.5-3.5z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--sp-3) center;
  background-size: 20px;
}

/* Error text carries an icon so the message is not colour-dependent. */
.field-error {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-1);
  margin-top: var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--status-rejected-fg);
}
.field-error::before {
  content: "\F33A";           /* exclamation-circle */
  font-family: 'bootstrap-icons';
  line-height: var(--lh-normal);
  flex-shrink: 0;
}

/* ==========================================================================
   Tables
   The table itself is only used from 768px up (below that, screens render
   cards). It still scrolls inside its own box as a safety net so a long value
   can never make the page body scroll sideways.
   ========================================================================== */

.gcal-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}

.gcal-table th {
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  text-align: left;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  background: var(--surface-sunken);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

.gcal-table td {
  padding: var(--sp-3) var(--sp-4);
  color: var(--text-secondary);
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

.gcal-table tbody tr:last-child td { border-bottom: none; }
.gcal-table tbody tr:hover { background: var(--surface-sunken); }

/* ==========================================================================
   Toasts
   Bottom-anchored on mobile so they sit in the thumb zone and clear the
   bottom navigation; top-right on desktop.
   ========================================================================== */

.toast-tray {
  position: fixed;
  inset: auto var(--sp-3) calc(var(--bottomnav-h) + var(--sp-3)) var(--sp-3);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  pointer-events: none;
}

.gcal-toast {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--text-inverse);
  background: var(--text-primary);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  pointer-events: auto;
  animation: toast-in var(--dur-normal) var(--ease);
}

.gcal-toast.t-error   { background: var(--status-rejected-fg); }
.gcal-toast.t-warning { background: var(--status-pending-fg); }

.toast-x {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  margin: calc(var(--sp-3) * -1) calc(var(--sp-2) * -1) calc(var(--sp-3) * -1) auto;
  color: inherit;
  background: none;
  border: none;
  border-radius: var(--r-full);
  cursor: pointer;
  opacity: 0.8;
}
.toast-x:hover { opacity: 1; background: rgb(255 255 255 / 15%); }

@keyframes toast-in {
  from { opacity: 0; translate: 0 var(--sp-4); }
  to   { opacity: 1; translate: 0 0; }
}

@media (min-width: 768px) {
  .toast-tray {
    inset: calc(var(--header-h) + var(--sp-4)) var(--sp-4) auto auto;
    max-width: var(--toast-max-w);
  }
  @keyframes toast-in {
    from { opacity: 0; translate: var(--sp-4) 0; }
    to   { opacity: 1; translate: 0 0; }
  }
}

/* ==========================================================================
   Event card
   Shared component behind apps/web/templates/web/events/_event_card.html.
   Renders identically wherever that partial is included (events list below
   768px today; other screens may reuse it later). The whole card is a single
   link to the event detail page; a real, separate Edit control can sit in
   the corner without being nested inside that link — it is a plain sibling
   positioned on top, not a link-in-a-link.
   ========================================================================== */

.event-card {
  position: relative;
  padding: var(--sp-4);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  transition: box-shadow var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.event-card:hover { box-shadow: var(--shadow-sm); border-color: var(--border-strong); }
.event-card + .event-card { margin-top: var(--sp-3); }

/* Reserve room so the corner Edit control never sits over the last text row. */
.event-card:has(.event-card-edit) { padding-bottom: calc(var(--sp-4) + var(--tap-min)); }

.event-card-link {
  display: block;
  color: inherit;
  text-decoration: none;
}
.event-card-link:hover .event-card-name { color: var(--brand-text); }

.event-card-hd {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-bottom: var(--sp-2);
}

.event-card-name {
  font-family: var(--font-display);
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  color: var(--text-primary);
}

.event-card-row {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-top: var(--sp-1);
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}
.event-card-row i { color: var(--text-muted); flex-shrink: 0; }

.event-card-edit {
  position: absolute;
  z-index: 1;
  right: var(--sp-2);
  bottom: var(--sp-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  color: var(--brand-text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  text-decoration: none;
  transition: background var(--dur-fast) var(--ease);
}
.event-card-edit:hover { background: var(--brand-subtle); border-color: var(--brand); }
