/* ==========================================================================
   HASHPro Suite POS — design tokens

   Every colour is a variable so branding can be changed from Settings without
   touching a component (§55). Tailwind utilities reference these same tokens
   through the config in each page head, so the two never drift apart.

   The palette is taken from the logo: cyan on black. Dark is the primary mode,
   because a POS lives in a dim dining room and a bright kitchen, and a white
   screen at 11pm is the thing staff complain about first.
   ========================================================================== */

:root {
  /* Brand — the cyan is the logo's own value, unmodified. */
  --brand-400: #3FDCEE;
  --brand-500: #12CEE4;
  --brand-600: #0796AC;
  --brand-700: #066F80;

  /* Text placed on a brand-coloured surface. Near-black, not white: that is
     how the wordmark is built, and it measures ~11:1 where white measures ~2.4:1. */
  --on-brand: #04202A;

  /* Ground and surfaces. Pulled toward teal rather than a neutral grey so the
     dark interface reads as part of the brand instead of generic dark mode. */
  --ground: #05161B;
  --surface: #0A2029;
  --surface-raised: #0E2C37;
  --surface-sunken: #031014;
  --line: #143A47;
  --line-strong: #1D5163;

  --text: #E8F4F7;
  --text-muted: #8FAFB9;
  --text-faint: #5E818C;

  --success: #2FD38B;
  --warning: #FFB020;
  --danger: #FF5B5B;
  --info: var(--brand-500);

  --success-soft: rgba(47, 211, 139, 0.14);
  --warning-soft: rgba(255, 176, 32, 0.14);
  --danger-soft: rgba(255, 91, 91, 0.14);
  --brand-soft: rgba(18, 206, 228, 0.12);

  /* Radii step with hierarchy: tiles are softer than inputs, which are softer
     than badges. One radius on everything is the flat SaaS-kit look. */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;
  --radius-xl: 24px;

  --shadow-raised: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px -12px rgba(0, 0, 0, 0.6);
  --shadow-overlay: 0 24px 64px -20px rgba(0, 0, 0, 0.75);

  /* Touch targets. 56px is the smallest a thumb reliably hits on a greasy
     tablet; POS tiles go larger still. */
  --touch: 56px;
  --touch-lg: 72px;

  --font-ui: "Plus Jakarta Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-receipt: ui-monospace, "SF Mono", "Cascadia Mono", "Roboto Mono", monospace;

  --ease: cubic-bezier(0.2, 0, 0, 1);
  color-scheme: dark;
}

[data-theme="light"] {
  --ground: #F2F6F7;
  --surface: #FFFFFF;
  --surface-raised: #FFFFFF;
  --surface-sunken: #E6EEF0;
  --line: #D4E2E6;
  --line-strong: #B4CCD3;

  --text: #04202A;
  --text-muted: #4A6B75;
  --text-faint: #7793A0;

  --brand-500: #0A96AB;
  --brand-600: #077E91;
  --on-brand: #FFFFFF;

  --shadow-raised: 0 1px 2px rgba(4, 32, 42, 0.06), 0 8px 24px -16px rgba(4, 32, 42, 0.25);
  color-scheme: light;
}

/* --------------------------------------------------------------------------
   Base
   -------------------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  /* A POS is a kiosk. Text selection and the iOS callout menu are accidents
     waiting to happen when a cashier long-presses a product tile. */
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  overscroll-behavior: none;
}

.selectable {
  user-select: text;
  -webkit-user-select: text;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.015em;
}

h1 {
  font-size: 1.75rem;
}

h2 {
  font-size: 1.25rem;
}

h3 {
  font-size: 1rem;
}


/**
 * The hidden attribute must always win.
 *
 * `hidden` is only `display: none` in the browser's own stylesheet, so any class
 * rule that sets a display beats it on specificity and the element stays on
 * screen. That had the More menu stuck open, the POS "unsent" badge showing
 * permanently, and empty error lines holding space in forms.
 *
 * One rule rather than a guard per class, so the next element to be toggled this
 * way is right without anybody remembering.
 */
[hidden] { display: none !important; }

/* Money and counters. Without tabular figures a running total visibly jitters
   as digits change width, which reads as the screen glitching. */
.tnum,
.amount {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.amount {
  font-weight: 700;
  letter-spacing: -0.02em;
}

:focus-visible {
  outline: 2px solid var(--brand-500);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

@media (prefers-reduced-motion: reduce) {

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: var(--touch);
  padding: 0 1.25rem;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: var(--surface-raised);
  color: var(--text);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  transition: background 120ms var(--ease), transform 80ms var(--ease), opacity 120ms var(--ease);
}

.btn:active:not(:disabled) {
  transform: scale(0.985);
}

.btn:disabled,
.btn[aria-busy="true"] {
  opacity: 0.55;
  cursor: not-allowed;
}

.btn-primary {
  background: var(--brand-500);
  color: var(--on-brand);
}

.btn-primary:hover:not(:disabled) {
  background: var(--brand-400);
}

.btn-ghost {
  background: transparent;
  border-color: var(--line);
  color: var(--text-muted);
}

.btn-ghost:hover:not(:disabled) {
  border-color: var(--line-strong);
  color: var(--text);
}

.btn-danger {
  background: var(--danger);
  color: #200505;
}

.btn-block {
  width: 100%;
}

/* --------------------------------------------------------------------------
   Fields
   -------------------------------------------------------------------------- */

.field {
  display: block;
  margin-bottom: 1rem;
}

.field-label {
  display: block;
  margin-bottom: 0.375rem;
  color: var(--text-muted);
  font-size: 0.8125rem;
  font-weight: 600;
}

.input,
.select {
  width: 100%;
  min-height: var(--touch);
  padding: 0 1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
  color: var(--text);
  font: inherit;
  transition: border-color 120ms var(--ease), box-shadow 120ms var(--ease);
}

.input::placeholder {
  color: var(--text-faint);
}

.input:focus,
.select:focus {
  outline: none;
  border-color: var(--brand-500);
  box-shadow: 0 0 0 3px var(--brand-soft);
}

.input[aria-invalid="true"] {
  border-color: var(--danger);
}

.field-error {
  display: block;
  margin-top: 0.375rem;
  color: var(--danger);
  font-size: 0.8125rem;
}

/* --------------------------------------------------------------------------
   Surfaces, badges, connection state
   -------------------------------------------------------------------------- */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.25rem 0.625rem;
  border-radius: var(--radius-sm);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.01em;
}

.badge-success {
  background: var(--success-soft);
  color: var(--success);
}

.badge-warning {
  background: var(--warning-soft);
  color: var(--warning);
}

.badge-danger {
  background: var(--danger-soft);
  color: var(--danger);
}

.badge-brand {
  background: var(--brand-soft);
  color: var(--brand-500);
}

/* The connection indicator (§6). Its dot pulses only while syncing, so movement
   on screen always means work is actually happening. */
.conn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8125rem;
  font-weight: 600;
}

.conn-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text-faint);
  flex: none;
}

.conn[data-state="online"] .conn-dot {
  background: var(--success);
}

.conn[data-state="offline"] .conn-dot {
  background: var(--warning);
}

.conn[data-state="error"] .conn-dot {
  background: var(--danger);
}

.conn[data-state="syncing"] .conn-dot {
  background: var(--brand-500);
  animation: conn-pulse 1.1s var(--ease) infinite;
}

@keyframes conn-pulse {

  0%,
  100% {
    opacity: 1;
    transform: scale(1);
  }

  50% {
    opacity: 0.45;
    transform: scale(0.75);
  }
}

/* --------------------------------------------------------------------------
   Toasts
   -------------------------------------------------------------------------- */

.toast-stack {
  position: fixed;
  inset-inline: 0;
  bottom: max(1rem, env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  padding: 0 1rem;
  z-index: 80;
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  max-width: 32rem;
  padding: 0.875rem 1.125rem;
  border-radius: var(--radius-md);
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
  box-shadow: var(--shadow-overlay);
  font-size: 0.9375rem;
  pointer-events: auto;
  animation: toast-in 200ms var(--ease);
}

.toast-danger {
  border-color: var(--danger);
}

.toast-success {
  border-color: var(--success);
}

@keyframes toast-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* --------------------------------------------------------------------------
   Sign-in
   -------------------------------------------------------------------------- */

.auth {
  display: grid;
  grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);
  min-height: 100dvh;
}

/* The left panel is the device telling you what it is. A cashier on a floor
   with four terminals needs to know they are at Counter 1 before typing.

   Grouped rather than spread: an earlier version used space-between over the
   full height, which on a desktop monitor left two feet of empty panel between
   the logo and the device details and made the screen look broken. The brand
   sits at the top, everything else sits together at the bottom. */
.auth-aside {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  padding: 2.25rem 2rem;
  background: var(--surface-sunken);
  border-right: 1px solid var(--line);
}

.auth-aside-top {
  margin-bottom: 0.5rem;
}

.auth-aside-stack {
  margin-top: auto;
}

.auth-main {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem 1.5rem;
}

/* A visible card, not text floating on the background. On a wide monitor the
   form was previously a small island of unframed text in the middle of an empty
   page, which reads as an unfinished screen rather than a sign-in. */
.auth-panel {
  width: 100%;
  max-width: 23rem;
  padding: 2rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
  background: var(--surface);
  box-shadow: var(--shadow-raised);
}

.auth-panel h1 {
  font-size: 1.375rem;
  font-weight: 800;
  letter-spacing: -0.01em;
}

.identity-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  padding: 0.625rem 0;
  border-bottom: 1px solid var(--line);
}

.identity-row:last-child {
  border-bottom: 0;
}

.identity-key {
  color: var(--text-faint);
  font-size: 0.8125rem;
}

.identity-value {
  font-weight: 600;
}

/* PIN entry */
.pin-dots {
  display: flex;
  justify-content: center;
  gap: 0.875rem;
  margin: 1.75rem 0 2rem;
}

.pin-dot {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid var(--line-strong);
  transition: background 140ms var(--ease), border-color 140ms var(--ease), transform 140ms var(--ease);
}

.pin-dot[data-filled="true"] {
  background: var(--brand-500);
  border-color: var(--brand-500);
  transform: scale(1.15);
}

.keypad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.75rem;
}

.key {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--touch-lg);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface-raised);
  color: var(--text);
  font: inherit;
  font-size: 1.375rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: background 100ms var(--ease), transform 60ms var(--ease);
}

.key:hover:not(:disabled) {
  background: var(--surface);
}

.key:active:not(:disabled) {
  transform: scale(0.96);
  background: var(--brand-soft);
}

.key-enter {
  background: var(--brand-500);
  color: var(--on-brand);
  border-color: transparent;
}

.key-enter:hover:not(:disabled) {
  background: var(--brand-400);
}

.key-muted {
  background: transparent;
  color: var(--text-muted);
}

.shake {
  animation: shake 380ms var(--ease);
}

@keyframes shake {

  0%,
  100% {
    transform: translateX(0);
  }

  20%,
  60% {
    transform: translateX(-7px);
  }

  40%,
  80% {
    transform: translateX(7px);
  }
}

.link-button {
  background: none;
  border: 0;
  padding: 0.5rem;
  color: var(--text-muted);
  font: inherit;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.link-button:hover {
  color: var(--brand-500);
}

.divider-text {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1.5rem 0;
  color: var(--text-faint);
  font-size: 0.8125rem;
}

.divider-text::before,
.divider-text::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}

/* On a tablet held in portrait the identity panel moves above the keypad
   rather than disappearing — it is information, not decoration. */
@media (max-width: 860px) {
  .auth {
    grid-template-columns: 1fr;
  }

  .auth-aside {
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    gap: 1rem 2rem;
    padding: 1.25rem 1.5rem;
    border-right: 0;
    border-bottom: 1px solid var(--line);
  }

  .auth-aside .identity-row {
    border: 0;
    padding: 0;
  }

  .auth-aside-top {
    margin-bottom: 0;
  }

  /* margin-top:auto pushes this to the bottom of a column; in a row it would
     just push it off the end, so it is cleared here. */
  .auth-aside-stack {
    display: flex;
    gap: 1.5rem;
    flex-wrap: wrap;
    margin-top: 0;
  }

  .auth-main {
    padding: 1.5rem 1rem 2.5rem;
  }

  .auth-panel {
    padding: 1.5rem;
    border: 0;
    background: transparent;
    box-shadow: none;
  }
}

.spinner {
  width: 1.125rem;
  height: 1.125rem;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 620ms linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ==========================================================================
   Dialogs

   Shared rather than living in pos.css, because the back office uses the same
   dialog for every add-and-edit screen and does not load the POS stylesheet.
   Keeping a second copy there would guarantee the two drift apart.
   ========================================================================== */

/* --- modal --------------------------------------------------------------- */

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(2, 10, 13, 0.72);
  display: grid;
  place-items: center;
  padding: 1rem;
  z-index: 60;
}

.modal {
  width: min(34rem, 100%);
  max-height: 88vh;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-overlay);
  padding: 1.25rem;
}

.modal-wide {
  width: min(48rem, 100%);
}

.modal h2 {
  font-size: 1.125rem;
  font-weight: 700;
}

.modal-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
}

.modal-foot {
  display: flex;
  gap: 0.5rem;
  margin-top: 1.25rem;
}

.modal-foot .btn {
  flex: 1;
}


/* Small square button used for quantity steppers and for removing a row. */
.qty-btn {
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface-sunken);
  color: var(--text);
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
  display: grid;
  place-items: center;
}

.qty-btn:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

.qty-value {
  min-width: 2rem;
  text-align: center;
  font-weight: 700;
  font-size: 0.875rem;
}