/*
 * Shared UI components.
 *
 * Loaded on every page from village/base.html, immediately after base.css.
 * base.css owns design tokens, the reset, typography and the app shell
 * (header / nav / footer). Anything reusable across pages lives here.
 *
 * Naming: flat kebab-case, prefixed by the block it belongs to
 * (.card, .card-head, .card-title), matching the existing data_table.css.
 * Page-specific styles stay in their own app stylesheet.
 */


/* ---------------------------------------------------------------- buttons */

.btn-prim,
.allauth-main>form>button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  text-transform: capitalize;
  text-align: center;
  min-width: 120px;
  background: var(--gradiant-1);
  border: 1px solid white;
  border-radius: var(--radius);
  color: #fff;
  padding: .5rem .75rem;
  font-size: 1rem;
  transition: 30ms all;
}

a.btn-prim {
  text-decoration: none;
}

.btn-prim:hover,
.allauth-main>form>button:hover {
  cursor: pointer;
  background: var(--gradiant-2);
}

/*
 * Variants. Compound selectors so they only ever modify a .btn-prim, and so
 * they win over the base rule without needing !important.
 */
.btn-prim.btn-secondary,
.btn-prim.btn-secondary:hover {
  background: var(--mana-grey);
}

.btn-prim.btn-danger,
.btn-prim.btn-danger:hover {
  background: var(--mana-brown);
}


/* ----------------------------------------------------------- layout helper */

.row {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 1rem;
}


/* ------------------------------------------------------------ card surface */

.card,
.tile {
  padding: .75rem 1rem .75rem 1rem;
  box-shadow: var(--standard-shadow);
  border-radius: var(--radius-lg);
  background-color: white;
  height: min-content;
}

/*
 * Card header: a group icon beside a heading, with a hairline under it.
 * Used for the homepage section cards.
 */
.card-head {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding-bottom: var(--space-sm);
  margin-bottom: var(--space-sm);
  border-bottom: 1px solid var(--mana-beige);
}

/* Neutralise the global heading padding-bottom from base.css. */
.card-title {
  padding-bottom: 0;
  margin: 0;
  font-size: 1.5rem;
  line-height: 1.2;
  color: var(--mana-brown);
}


/* ------------------------------------------------------------------- icons */

/*
 * Icons are coloured by CSS, not by the fill="" baked into each SVG file, so
 * one file can be orange on the homepage and grey on the directory without
 * keeping a second recoloured copy of it.
 *
 * The SVG is used as an alpha mask: only its shape matters, its own colour is
 * discarded, and background-color shows through. That is why the assorted
 * fill="#f58025" / "#fff" / "#e8eaed" values already in the files are harmless
 * and none of them need editing.
 *
 *   colour -> `color` on the icon or any ancestor (background-color: currentColor)
 *   size   -> width / height
 *   shape  -> an .icon-<name> class from the registry below
 *
 * <span class="icon icon-groups" aria-hidden="true"></span>
 *
 * A masked span carries no alt text. Keep it aria-hidden when adjacent text
 * already names the thing; when the icon is the only label, add
 * role="img" and an aria-label.
 *
 * Seeing a solid coloured square instead of a glyph? Then --icon-url did not
 * resolve: mask-image falls back to `none`, no mask is applied, and the
 * background colour fills the whole box. Either the .icon-<name> class below
 * is missing, or the name in the markup does not match one.
 */
.icon {
  display: inline-block;
  flex: 0 0 auto;
  width: 1.5rem;
  height: 1.5rem;
  background-color: currentColor;
  -webkit-mask-image: var(--icon-url);
          mask-image: var(--icon-url);
  -webkit-mask-position: center;
          mask-position: center;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-size: contain;
          mask-size: contain;
}

/*
 * Browsers too old for mask-image fall back to the file as a plain background
 * image — i.e. the colours baked in today — rather than a solid block.
 */
@supports not ((-webkit-mask-image: url("")) or (mask-image: url(""))) {
  .icon {
    background-color: transparent;
    background-image: var(--icon-url);
    background-position: center;
    background-repeat: no-repeat;
    background-size: contain;
  }
}

/*
 * Icon registry — the one place a glyph's file path is written down.
 * Adding an icon is a single line here plus the class name in the template.
 */
.icon-account-circle   { --icon-url: url("/static/village/ui/account_circle.8b043fecf10c.svg"); }
.icon-add-location     { --icon-url: url("/static/village/ui/add_location.343774af4cb2.svg"); }
.icon-bolt             { --icon-url: url("/static/village/ui/bolt.490f24c8d597.svg"); }
.icon-data-table       { --icon-url: url("/static/village/ui/data_table.b7acd9eee6d6.svg"); }
.icon-groups           { --icon-url: url("/static/village/ui/groups.d7e1682eb8be.svg"); }
.icon-lab-panel        { --icon-url: url("/static/village/ui/lab_panel.321fad8e2de9.svg"); }
.icon-pallet           { --icon-url: url("/static/village/ui/pallet.871c1ef89f3a.svg"); }
.icon-quiz             { --icon-url: url("/static/village/ui/quiz.9f3719ff2c2f.svg"); }
.icon-shuffle          { --icon-url: url("/static/village/ui/shuffle.c3ebb5f01798.svg"); }
.icon-task             { --icon-url: url("/static/village/ui/task.0a3dd94a9569.svg"); }
.icon-print            { --icon-url: url("/static/labels/assets/print.8ba43ec2900c.svg"); }
.icon-qr-code          { --icon-url: url("/static/labels/assets/qr_code.788807a76b8c.svg"); }
.icon-qr-code-scanner  { --icon-url: url("/static/labels/assets/qr_code_scanner.b0d1f6a99305.svg"); }
.icon-link             { --icon-url: url("/static/shortlinks/assets/link.4e8104566091.svg"); }
.icon-widgets             { --icon-url: url("/static/village/ui/widgets.ceddeaa4ef46.svg"); }

/*
 * Circular chip behind an icon. Sets the colour its .icon child inherits.
 */
.icon-circle {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius-pill);
  background-color: var(--mana-orange-soft);
  color: var(--mana-orange);
}

.icon-circle-lg {
  width: 3rem;
  height: 3rem;
}

.icon-circle-lg > .icon {
  width: 1.75rem;
  height: 1.75rem;
}

.ui-icon-small {
  height: 32px;
}


/* -------------------------------------------------------------------- hero */

/*
 * Page-opening statement. Sits directly on the page background rather than in
 * a card, so it reads as part of the page rather than as another tile.
 * clamp() scales the headline with the viewport without needing breakpoints.
 */
.hero {
  margin-bottom: var(--space-xl);
}

.hero-eyebrow {
  padding-bottom: var(--space-xxs);
  font-size: 0.9375rem;
  color: var(--mana-grey);
}

.hero-title {
  padding-bottom: var(--space-xs);
  font-size: clamp(1.875rem, 5vw, 3rem);
  line-height: 1.1;
  color: var(--mana-brown);
}

.hero-lead {
  padding-bottom: 0;
  max-width: 60ch;
  font-size: clamp(1rem, 2.2vw, 1.15rem);
  line-height: 1.5;
  color: var(--mana-grey);
}


/* --------------------------------------------------------- card + link grid */

/*
 * Responsive card grid. min() keeps a card from forcing horizontal scroll on
 * a narrow phone: below 320px of available width it simply goes full width.
 *
 * Cards stretch to share a row height (the grid default) rather than each
 * keeping its natural height. Which groups a person can see depends on their
 * permissions, so any mix of one- and two-item cards has to look composed —
 * not just the full set an admin sees. Letting them keep natural heights
 * leaves dead space under the short ones and reads as ragged.
 */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr));
  gap: var(--space-md);
  margin-bottom: var(--space-md);
}

/* .card sets height: min-content for standalone use, which would defeat the
   stretch above. Inside the grid the row decides. */
.card-grid > .card {
  height: auto;
}

/*
 * Small status pill — a state on a card, not a control. --radius-pill has
 * existed for this shape since the tokens were written; this is the first
 * component to use it.
 *
 *   .badge         neutral fact (a count, a category)
 *   .badge-accent  a finished or ready state
 *   .badge-warn    something worth a second look, not an error
 */
.badge {
  display: inline-block;
  padding: 0 var(--space-xs);
  border-radius: var(--radius-pill);
  font-size: 0.8rem;
  line-height: 1.6;
  white-space: nowrap;
  background-color: var(--mana-beige);
  color: var(--mana-brown);
}

.badge-accent {
  background-color: var(--mana-orange-soft);
  color: var(--mana-brown);
}

/* Amber has no token yet — the palette carries no warning colour. */
.badge-warn {
  background-color: #fdf0d5;
  color: #8a6d3b;
}

/* A wrapping run of badges, e.g. the SARFs requested on one lot. */
.badge-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xxs);
}

.link-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
  gap: var(--space-xxs);
  list-style: none;
}

/* An icon chip, a name and a line of supporting detail, as one tap target. */
.link-item {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  min-height: var(--tap-target);
  padding: var(--space-xs);
  border-radius: var(--radius);
  color: inherit;
  text-decoration: none;
  transition: background-color 120ms ease;
}

.link-item:hover {
  background-color: var(--mana-orange-soft);
}

.link-item:focus-visible {
  outline: 2px solid var(--secondary);
  outline-offset: 2px;
}

.link-item-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.link-item-title {
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--mana-brown);
}

.link-item-detail {
  font-size: 0.875rem;
  line-height: 1.35;
  color: var(--mana-grey);
}


@media only screen and (max-width: 480px) {
  .card-title {
    font-size: 1.3rem;
  }

  .link-item-title {
    font-size: 1rem;
  }
}

/* ------------------------------------------------------------ page heading */

/*
 * Interior-page title and supporting line. The homepage uses .hero instead —
 * this is the quieter version for a working page.
 */
.page-title {
  padding-bottom: var(--space-xs);
  font-size: clamp(1.5rem, 3.5vw, 1.875rem);
  line-height: 1.2;
  color: var(--mana-brown);
}

.page-lead {
  padding-bottom: var(--space-md);
  max-width: 65ch;
  line-height: 1.5;
  color: var(--mana-grey);
}


/* ------------------------------------------------------------------- forms */

/*
 * Shared form styling, used by the shipping gate-out captures, driver
 * check-in, lab report upload and the short-link forms. Previously this lived
 * in shipping/style/shipping.css keyed to #form-container — an id, so it could
 * not be reused twice on a page or composed with anything else.
 *
 *   .form-page   centres the column
 *   .form-card   the white panel around the form itself
 *   .form-field  one label + control + errors, stacked
 *   .help-text   the grey note under a control
 */
.form-page {
  max-width: 640px;
  margin-left: auto;
  margin-right: auto;
}

/*
 * Wide variant, for form pages built around a table or a list of options rather
 * than a stacked column of fields — the SARF panel picker and sample grid. Takes
 * the same width as the nav and the page header so it lines up with them
 * instead of sitting in a narrow well.
 */
.form-page.form-page-wide {
  max-width: var(--container-width);
}

.form-card {
  background-color: white;
  padding: var(--space-xl);
  border-radius: var(--radius-lg);
  box-shadow: var(--standard-shadow);
  margin-bottom: var(--space-lg);
}

.form-field {
  margin-bottom: var(--space-lg);
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.form-field:last-of-type {
  margin-bottom: var(--space-md);
}

.form-card label {
  font-weight: 600;
  color: var(--mana-brown);
  display: flex;
  align-items: center;
  gap: var(--space-xs);
}

.form-card input[type="text"],
.form-card input[type="url"],
.form-card input[type="email"],
.form-card input[type="number"],
.form-card input[type="date"],
.form-card select,
.form-card textarea {
  padding: var(--space-sm) var(--space-md);
  border: 1px solid var(--mana-grey);
  border-radius: var(--radius);
  background-color: white;
  /* 16px minimum — anything smaller makes iOS Safari zoom on focus. */
  font-size: 1rem;
  transition: border-color 0.3s ease;
}

.form-card input:focus,
.form-card select:focus,
.form-card textarea:focus {
  outline: none;
  border-color: var(--mana-orange);
  box-shadow: 0 0 0 3px var(--mana-orange-soft);
}

/* File inputs read as a drop target rather than as a bare browse button. */
.form-card input[type="file"] {
  padding: var(--space-sm);
  border: 2px dashed var(--mana-orange);
  border-radius: var(--radius);
  background-color: #fef9f5;
  cursor: pointer;
  transition: all 0.3s ease;
}

.form-card input[type="file"]:hover {
  border-color: var(--mana-brown);
  background-color: white;
}

/*
 * Every form's buttons live here: their own line, right-aligned, sized to
 * their label rather than stretched. Right-aligned because the eye finishes a
 * form at the bottom-right of the field column, so that is where the action
 * belongs — and it keeps the button in the same place on every page.
 */
.form-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-items: center;
  gap: var(--space-sm);
  margin-top: var(--space-md);
}

.help-text {
  padding-bottom: 0;
  font-size: 0.85em;
  line-height: 1.4;
  color: var(--mana-grey);
}

.form-card .errorlist {
  margin-top: var(--space-xs);
  margin-bottom: 10px;
  padding: var(--space-sm);
  background-color: #f2dede;
  border-left: 4px solid #a94442;
  border-radius: var(--radius);
}

/* An already-uploaded photo shown above the file input that would replace it. */
.media-preview {
  margin-bottom: var(--space-sm);
}

.media-preview img {
  max-width: 100%;
  max-height: 300px;
  border-radius: var(--radius);
  box-shadow: var(--standard-shadow);
}


/* ----------------------------------------------------------------- toolbar */

/*
 * The orange strip under the header on pages that carry page-level controls
 * (pallet labels, repackage boxes, the village square). Not every page needs
 * one — pages whose inputs belong in the body keep them there.
 */
.banner {
  padding: var(--space-xs) var(--space-sm);
  background-color: var(--mana-orange);
  color: white;
  border-radius: var(--radius);
  overflow-x: auto;
}

/* Icon buttons sitting on the orange strip. */
.banner button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap-target);
  min-height: var(--tap-target);
  padding: var(--space-xxs);
  border: none;
  border-radius: var(--radius);
  background-color: transparent;
  color: white;
  cursor: pointer;
  transition: background-color 120ms ease;
}

.banner button:hover {
  background-color: rgba(255, 255, 255, 0.22);
}

.banner button:focus-visible {
  outline: 2px solid white;
  outline-offset: -2px;
}


/* ------------------------------------------------------ responsive: forms */

@media only screen and (max-width: 768px) {
  .form-card {
    padding: var(--space-lg);
  }
}

@media only screen and (max-width: 480px) {
  .form-card {
    padding: var(--space-md);
  }

  .form-field {
    margin-bottom: var(--space-md);
  }
}


/* ---------------------------------------------------------------- utilities */

/*
 * Present for screen readers and the document outline, invisible on screen.
 * Lets a page whose title is carried by a toolbar still have a real <h1>.
 */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}


/* --------------------------------------------------------------- scan page */

/*
 * The shared column for the scan-then-act pages (find bin space, repackage
 * boxes). Narrower than the full container: these are read one-handed on a
 * phone, and a short measure keeps the lead text and the results scannable.
 */
.scan-page {
  max-width: 640px;
  margin: 0 auto;
  padding-bottom: var(--space-xxl);
}


/* ----------------------------------------------------------------- scanner */

/*
 * Camera surface for the pages that scan a code (find bin space, repackage
 * boxes). Both mount the html5-qrcode library, which builds its own controls
 * inside the container with ids derived from that container's id — so they are
 * styled here by descendant selector, which works for either page.
 */
.scanner {
  margin-bottom: var(--space-md);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.scanner video,
.scanner img {
  max-width: 100%;
  height: auto;
}

/* The library's own "Request Camera Permission" / "Stop Scanning" buttons. */
.scanner button {
  min-width: 120px;
  padding: .5rem .75rem;
  border: 1px solid white;
  border-radius: var(--radius);
  background: var(--gradiant-1);
  color: #fff;
  font-size: 1rem;
  cursor: pointer;
}

.scanner button:hover {
  background: var(--gradiant-2);
}

.scanner a {
  color: var(--secondary);
}

.scanner select {
  padding: var(--space-xs) var(--space-sm);
  border: 1px solid var(--mana-grey);
  border-radius: var(--radius);
  font-size: 1rem;
}

/* Line under the scanner reporting what was read, or why it failed. */
.scan-status {
  min-height: 1.5rem;
  margin-bottom: var(--space-md);
  color: var(--mana-brown);
  font-size: 1rem;
}

.scan-status-error {
  color: #a12b2b;
}
