/* Nip & Claw — Base styles
   Imports tokens. Apply to every page via:
   <link rel="stylesheet" href="assets/css/tokens.css">
   <link rel="stylesheet" href="assets/css/base.css">
   -------------------------------------------------- */

/* Reset */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  font-size: 16px;
  scroll-behavior: smooth;
}

body {
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-family);
  font-size: var(--text-base);
  -webkit-font-smoothing: antialiased;
  line-height: 1.6;
}

/* Focus ring — one shared definition for every focusable element, ported
   from the Accessibility Champion book's own site
   (src/lib/assets/css/champ/utilities/_accessibility.css). outline-color
   defaults to currentColor, so the ring always matches the element's own
   (already contrast-checked) text colour instead of a single fixed colour
   that might not contrast against every background it appears on.
   Per-component overrides (size/colour/offset) should set the custom
   properties below rather than writing a new :focus-visible rule. */
:is(a, button, input, select, textarea, summary) {
  --outline-size: max(2px, 0.08em);
  --outline-style: solid;
  --outline-color: var(--color-gold-hover);
}

:is(a, button, input, select, textarea, summary):focus {
  outline: var(--outline-size) var(--outline-style) var(--outline-color);
  outline-offset: var(--outline-offset, var(--outline-size));
}

:is(a, button, input, select, textarea, summary):focus-visible {
  outline: var(--outline-size) var(--outline-style) var(--outline-color);
  outline-offset: var(--outline-offset, var(--outline-size));
}

:is(a, button, input, select, textarea, summary):focus:not(:focus-visible) {
  outline: none;
}

/* Skip link — always visible (not hidden-until-focus), matching the
   Accessibility Champion book's own site, which keeps its skip links
   permanently on screen rather than revealing them only on focus.
   Horizontal padding matches .site-header .inner's padding at each
   breakpoint (below) so the link text lines up with the logo directly
   underneath it, rather than using its own unrelated spacing value.
   min-height matches --target-min, the same touch-target size every
   other interactive element in the header already uses. */
.skip-link {
  background-color: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  color: var(--color-text);
  display: block;
  padding-block: 0.5rem;
  padding-inline: 1rem;
  text-align: center;
  width: 100%;

  &:focus {
    background-color: var(--color-gold-light);
    color: var(--color-brand);
    text-decoration: none;
  }
}

/* -------------------------------------------------- */

/* Site header / nav */

/* -------------------------------------------------- */

.site-header {
  background: var(--color-brand);
  box-shadow: var(--shadow-md);
  color: var(--color-white);
  height: var(--nav-height);
  position: sticky;
  top: 0;
  z-index: 100;
}

.site-header .inner {
  align-items: center;
  display: flex;
  gap: var(--space-3);
  height: 100%;
  margin: 0 auto;
  max-width: var(--max-width);
  padding: 0 var(--space-4);
}

.site-logo {
  flex-shrink: 0;
  text-decoration: none;
}

.site-logo .wordmark {
  color: var(--color-white);
  font-size: var(--text-xl);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1;
}

.site-logo .tagline {
  color: var(--color-gold-light);
  display: block;
  font-size: var(--text-xs);
  font-style: italic;
  letter-spacing: 0.01em;
  margin-top: 1px;
}

.site-nav ul {
  align-items: center;
  display: flex;
  gap: var(--space-1);
  list-style: none;
}

.site-nav a {
  align-items: center;
  border-radius: var(--radius-md);
  color: var(--color-white);
  display: flex;
  font-size: var(--text-sm);
  font-weight: 500;
  min-height: var(--target-min);
  padding: var(--space-2) var(--space-3);

  /* Underlined by default so links are recognisable without relying on
     colour alone (WCAG 1.4.1) — removed on hover/focus, where the
     background fill already provides that same distinction. */
  text-decoration: underline;
  transition: background var(--transition-fast);
}

.site-nav a:hover {
  background: var(--color-brand-mid);
  text-decoration: none;
}

.site-nav a[aria-current='page'] {
  background: var(--color-brand-mid);
  font-weight: 700;
}

/* Mobile nav — CSS Grid, two rows: logo + connectivity badge share row 1
   (identity cluster, logo left/badge right), nav + cart share row 2
   (actions cluster). Grid areas place elements visually WITHOUT touching
   document order — logo, badge, nav, and cart stay in that exact DOM
   order, matching this row-by-row, left-to-right visual layout exactly,
   so keyboard tab order always matches what's on screen.
   (An earlier version used flexbox `order` to pull the cart up next to
   the logo without changing DOM order — visually tidy, but it meant a
   keyboard user watching the focus ring saw it jump backward: logo, down
   to the nav row, then back up to the cart. Fixed properly this time by
   actually moving the cart earlier in the DOM instead of just repainting
   it earlier — see the desktop `.site-nav` rule above for the other half
   of this. A later version put nav and cart on one shared row, which
   fixed the tab-order jump but squeezed the two against each other and
   clipped nav's three links; a version after that gave all three their
   own full-width row each, correct but wasteful — the cart sat alone on
   a mostly-empty row. That version fixed both at once, with cart sharing
   row 1 with the logo; cart and the connectivity badge later swapped
   rows so cart sits with the other navigation-ish items on row 2 and the
   badge — logically closer to site identity than to navigation — sits
   with the logo instead.)
   Tagline may wrap to two lines here — row 1 is narrower now that it
   shares space with the badge, and that's fine: wrapping is cheaper than
   truncating or forcing the badge down to yet another row. */
@media (width <= 640px) {
  .site-header {
    height: auto; /* grow to fit two rows */
  }

  .site-header .inner {
    align-items: center;
    display: grid;
    gap: var(--space-4) var(--space-3);
    grid-template-areas:
      'logo badge'
      'nav  cart';
    grid-template-columns: 1fr auto;
    padding: var(--space-2) var(--space-4);
  }

  .site-logo {
    grid-area: logo;
  }

  .nav-cart {
    /* nav (sharing this row) can wrap its 3 links to a second line at
       narrow widths — align-self: end keeps cart level with nav's last
       (lowest) line instead of vertically centering across both lines,
       which put cart visually between the wrapped nav lines and broke
       tab order (My Orders sits below cart in DOM but was rendering
       above it). */
    align-self: end;
    grid-area: cart;
  }

  .site-nav {
    grid-area: nav;
  }

  .site-nav ul {
    flex-wrap: wrap; /* nav has the full row to itself, room to wrap if needed */
  }

  .site-nav a {
    font-size: var(--text-xs);
    padding: var(--space-2) var(--space-3);
  }

  .connectivity-badge {
    grid-area: badge;
    margin-inline: 0; /* desktop's centring margin doesn't apply to the grid layout */
  }

  .skip-link {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }
}

.nav-cart {
  align-items: center;
  display: flex;
  gap: var(--space-4);
}

.cart-link {
  align-items: center;
  border: 1.5px solid rgb(255 255 255 / 30%);
  border-radius: var(--radius-pill);
  color: var(--color-white);
  display: flex;
  font-size: var(--text-sm);
  font-weight: 600;
  gap: var(--space-2);
  min-height: var(--target-min);
  padding: var(--space-2) var(--space-3);
  text-decoration: none;
  transition:
    border-color var(--transition-fast),
    background var(--transition-fast);
}

.cart-link:hover {
  background: rgb(255 255 255 / 10%);
  border-color: var(--color-gold-light);
}

.cart-count {
  background: var(--color-gold-light);
  border-radius: var(--radius-pill);
  color: var(--color-brand);
  font-size: var(--text-xs);
  font-weight: 800;
  line-height: 1.5;
  min-width: 1.4rem;
  padding: 0 var(--space-2);
  text-align: center;
}

/* No border/background by default — sitting next to the logo rather
   than sandwiched between the bordered cart pill and nav links, it no
   longer needs a boundary to read as its own element, and a border here
   would visually imply it's clickable like its former neighbours. The
   offline state gets a background fill (below) to draw attention to the
   one state actually worth noticing. */
.connectivity-badge {
  align-items: center;
  color: var(--color-white);
  display: inline-flex;
  font-size: var(--text-sm);
  font-weight: 600;
  gap: var(--space-2);

  /* Auto margins on both sides split the row's remaining free space
     evenly between "logo↔badge" and "badge↔nav" — centred, equidistant
     from the identity cluster on its left and the actions cluster on
     its right, rather than hugging the logo and leaving one big empty
     gap before nav. Reset to 0 in the mobile grid layout below, where
     the badge is positioned by grid-area instead. */
  margin-inline: auto;
  min-height: var(--target-min);
  padding: var(--space-2) var(--space-3);
  transition:
    background var(--transition-fast),
    color var(--transition-fast);
}

.connectivity-badge--offline {
  background: var(--color-gold-light);
  border-radius: var(--radius-md);
  color: var(--color-brand);
}

/* -------------------------------------------------- */

/* Page layout */

/* -------------------------------------------------- */

.page-wrapper {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.main-content {
  flex: 1;
  margin: 0 auto;
  max-width: var(--max-width);
  padding: var(--space-8) var(--space-6);
  width: 100%;
}

/* -------------------------------------------------- */

/* Typography */

/* -------------------------------------------------- */

h1 {
  font-size: var(--text-3xl);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.2;
}

h2 {
  font-size: var(--text-2xl);
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.25;
}

h3 {
  font-size: var(--text-xl);
  font-weight: 700;
  line-height: 1.3;
}

h4 {
  font-size: var(--text-lg);
  font-weight: 600;
  line-height: 1.35;
}

p + p {
  margin-top: var(--space-4);
}

.page-heading {
  margin-bottom: var(--space-8);
}

.page-heading h1 {
  color: var(--color-brand-text);
}

.page-heading p {
  color: var(--color-muted);
  font-size: var(--text-lg);
  margin-top: var(--space-2);
}

/* Type badge / label */
.type-badge {
  border-radius: var(--radius-pill);
  display: inline-block;
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.07em;
  padding: 0.2rem 0.6rem;
  text-transform: uppercase;
}

.type-naptime {
  background: var(--color-type-naptime-bg);
  color: var(--color-type-naptime-text);
}

.type-zoomies {
  background: var(--color-type-zoomies-bg);
  color: var(--color-type-zoomies-text);
} /* was #e65100 at 3.45:1, failed AA */

.type-existential {
  background: var(--color-type-existential-bg);
  color: var(--color-type-existential-text);
}

/* -------------------------------------------------- */

/* Buttons */

/* -------------------------------------------------- */

.btn {
  align-items: center;
  border: 2px solid transparent;
  border-radius: var(--radius-md);
  cursor: pointer;
  display: inline-flex;
  font-family: var(--font-family);
  font-size: var(--text-base);
  font-weight: 600;
  gap: var(--space-2);
  justify-content: center;
  min-height: var(--target-min);
  padding: var(--space-3) var(--space-6);
  text-decoration: none;
  transition:
    background var(--transition-fast),
    color var(--transition-fast),
    border-color var(--transition-fast);
  white-space: nowrap;
}

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

.btn-primary:hover {
  background: var(--color-brand-mid);
}

.btn-secondary {
  background: transparent;
  border-color: var(--color-brand-text);
  color: var(--color-brand-text);
}

.btn-secondary:hover {
  background: var(--color-brand);
  color: var(--color-white);
}

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

.btn-ghost:hover {
  background: var(--color-bg);
  color: var(--color-text);
}

/* Icon-only button — 44×44px minimum */
.btn-icon {
  align-items: center;
  background: transparent;
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-md);
  color: var(--color-muted);
  cursor: pointer;
  display: inline-flex;
  font-family: inherit;
  height: var(--target-min);
  justify-content: center;
  padding: 0;
  transition:
    background var(--transition-fast),
    color var(--transition-fast),
    border-color var(--transition-fast);
  width: var(--target-min);
}

.btn-icon:hover {
  background: var(--color-bg);
  border-color: var(--color-brand-light);
  color: var(--color-text);
}

.btn-icon.btn-icon--danger {
  border-color: var(--color-error-border);
  color: var(--color-error);
}

.btn-icon.btn-icon--danger:hover {
  background: var(--color-error-bg);
  border-color: var(--color-error);
}

/* -------------------------------------------------- */

/* Cards */

/* -------------------------------------------------- */

.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  transition:
    box-shadow var(--transition-base),
    transform var(--transition-base);
}

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

.card-body {
  padding: var(--space-5);
}

/* -------------------------------------------------- */

/* Forms */

/* -------------------------------------------------- */

.form-group {
  margin-bottom: var(--space-5);
}

label {
  color: var(--color-text);
  display: block;
  font-size: var(--text-sm);
  font-weight: 600;
  margin-bottom: var(--space-2);
}

.field-hint {
  color: var(--color-muted);
  font-size: var(--text-xs);
  margin-top: var(--space-1);
}

input[type='text'],
input[type='email'],
input[type='tel'],
input[type='number'],
select,
textarea {
  background: var(--color-surface);
  border: 1.5px solid var(--color-input-border);
  border-radius: var(--radius-md);
  color: var(--color-text);
  font-family: var(--font-family);
  font-size: var(--text-base);
  min-height: var(--target-min);
  padding: var(--space-3) var(--space-4);
  transition:
    border-color var(--transition-fast),
    box-shadow var(--transition-fast);
  width: 100%;
}

input:focus,
select:focus,
textarea:focus {
  border-color: var(--color-brand-text);
  box-shadow: 0 0 0 3px
    color-mix(in srgb, var(--color-brand-text) 15%, transparent);
}

input[aria-invalid='true'],
input.has-error {
  border-color: var(--color-error);
}

input[aria-invalid='true']:focus,
input.has-error:focus {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-error) 15%, transparent);
}

.field-error {
  align-items: center;
  color: var(--color-error);
  display: flex;
  font-size: var(--text-sm);
  gap: var(--space-2);
  margin-top: var(--space-2);
}

.field-error::before {
  content: '⚠';
  flex-shrink: 0;
}

/* -------------------------------------------------- */

/* Tables */

/* -------------------------------------------------- */

.table-wrapper {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  -webkit-overflow-scrolling: touch;
  overflow-x: auto;
  width: 100%;
}

table {
  background: var(--color-surface);
  border-collapse: collapse;
  font-size: var(--text-sm);
  width: 100%;
}

thead {
  background: var(--color-brand);
  color: var(--color-white);
}

thead th {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.07em;
  padding: var(--space-4) var(--space-5);
  text-align: left;
  text-transform: uppercase;
  white-space: nowrap;
}

tbody tr {
  border-bottom: 1px solid var(--color-border);
  transition: background var(--transition-fast);
}

tbody tr:last-child {
  border-bottom: none;
}

tbody tr:hover {
  background: var(--color-table-row-hover);
}

tbody td,
tbody th[scope='row'] {
  padding: var(--space-4) var(--space-5);
  vertical-align: middle;
}

tbody th[scope='row'] {
  color: var(--color-text);
  font-weight: 600;
  text-align: left;
}

.table-actions {
  align-items: center;
  display: flex;
  gap: var(--space-2);
}

/* -------------------------------------------------- */

/* Filter bar — shared by index.html (strain type) and admin.html (order status) */

/* -------------------------------------------------- */

.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-bottom: var(--space-8);
}

.filter-btn {
  background: var(--color-surface);
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-pill);
  color: var(--color-muted);
  cursor: pointer;
  font-family: var(--font-family);
  font-size: var(--text-sm);
  font-weight: 600;
  min-height: var(--target-min);
  padding: var(--space-2) var(--space-5);
  transition: all var(--transition-fast);
}

.filter-btn:hover,
.filter-btn:focus-visible {
  border-color: var(--color-brand-text);
  color: var(--color-brand-text);
}

.filter-btn[aria-pressed='true'] {
  background: var(--color-brand);
  border-color: var(--color-brand);
  color: var(--color-white);
}

/* -------------------------------------------------- */

/* Badges / status chips */

/* -------------------------------------------------- */

.status-badge {
  align-items: center;
  border-radius: var(--radius-pill);
  display: inline-flex;
  font-size: var(--text-xs);
  font-weight: 700;
  gap: var(--space-1);
  padding: 0.2rem 0.65rem;
  white-space: nowrap;
}

.status-delivered {
  background: var(--color-success-bg);
  color: var(--color-success);
}

.status-processing {
  background: var(--color-warning-bg);
  color: var(--color-warning);
}

.status-shipped {
  background: var(--color-status-shipped-bg);
  color: var(--color-status-shipped-text);
}

.status-cancelled {
  background: var(--color-status-cancelled-bg);
  color: var(--color-status-cancelled-text);
}

/* -------------------------------------------------- */

/* Footer */

/* -------------------------------------------------- */

.site-footer {
  background: var(--color-brand);
  color: rgb(255 255 255 / 70%);
  margin-top: auto;
  padding: var(--space-8) var(--space-6);
}

.site-footer .inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin: 0 auto;
  max-width: var(--max-width);
}

.site-footer p {
  font-size: var(--text-sm);
  line-height: 1.5;
}

.site-footer a {
  color: var(--color-gold-light);
  text-decoration: underline;
}

.footer-brand {
  color: var(--color-white);
}

/* Brand line + theme toggle, side by side with the toggle pinned right —
   wraps to stack vertically once the row no longer has room for both,
   rather than a fixed-width breakpoint. The theme toggle lives here
   (moved from the header) rather than in the header's single-row flex
   layout, which only has a fixed budget of horizontal space; the footer
   has no such constraint. */
.footer-top {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  justify-content: space-between;
}

/* -------------------------------------------------- */

/* Visually hidden — available to screen readers, hidden from sighted users.
   Use for supplementary text that screen reader users need but sighted users
   do not, e.g. product names appended to generic "Add to cart" buttons.
   Discussed in Chapter 06025 — Keyboard navigation and focus.
   -------------------------------------------------- */

.sr-only {
  border: 0;
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}

/* -------------------------------------------------- */

/* SVG icons (inline) */

/* -------------------------------------------------- */

.icon {
  fill: none;
  flex-shrink: 0;
  height: 1.25em;
  stroke: currentcolor;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 2;
  vertical-align: -0.15em;
  width: 1.25em;
}

/* The HTML UA stylesheet's [hidden] { display: none } rule doesn't
   reliably apply to inline <svg> elements (SVG's own UA stylesheet
   defaults interact oddly with it) — without this, an svg.icon carrying
   the hidden attribute still renders. */
svg.icon[hidden] {
  display: none;
}

/* -------------------------------------------------- */

/* Theme toggle */

/* -------------------------------------------------- */

.theme-toggle {
  border: none;
  display: flex;
  gap: var(--space-1);
  margin: 0;
  padding: 0;
}

.theme-option {
  align-items: center;
  border-radius: var(--radius-md);
  color: rgb(255 255 255 / 70%);
  cursor: pointer;
  display: flex;
  height: var(--target-min);
  justify-content: center;
  position: relative;
  transition:
    background var(--transition-fast),
    color var(--transition-fast);
  width: var(--target-min);
}

.theme-option:hover {
  background: var(--color-brand-mid);
  color: var(--color-white);
}

.theme-option .icon {
  height: 20px;
  width: 20px;
}

/* Both the icon and the sr-only label text sit in normal flow, stacked
   on top of the clipped radio input below — without this, they intercept
   clicks and taps meant for the input, since they paint above the
   input's static-position fallback location. The label's native
   input association still handles the click either way; this just
   keeps a direct click/tap on the input itself (e.g. Playwright's
   getByRole('radio').check()) from timing out. */
.theme-option > *:not(input) {
  pointer-events: none;
}

.theme-toggle input {
  border: 0;
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}

.theme-toggle .theme-option:has(input:checked) {
  background: var(--color-gold-light);
  color: var(--color-brand);
}

.theme-toggle .theme-option:has(input:focus-visible) {
  outline: 3px solid var(--color-gold-light);
  outline-offset: 2px;
}
