/*
 * Tailor Pro — design tokens and base UI.
 *
 * The palette and typography come from the project's visual identity. Everything is defined as
 * a custom property on :root so the same stylesheet serves the web app, the MAUI Blazor Hybrid
 * app and the in-shop kiosk without a fork.
 *
 * Written RTL-first: use logical properties (inline-start/end, margin-inline) rather than
 * left/right, so an LTR locale needs no second stylesheet.
 */

:root {
  /* Brand */
  --brand-gold: #D9A96C;
  --brand-bronze: #B07D46;
  --brand-deep: #8A5C2C;
  --brand-cream: #F6F0E4;
  --brand-cream-alt: #EDE4D3;
  --brand-ink: #221E18;
  --brand-ink-deep: #1B1813;
  --brand-olive: #6F7A4E;
  --brand-olive-light: #95A06B;
  --brand-stone: #8A8276;
  --brand-stone-deep: #6B6459;

  /* The same brand hues as channels, for the tints the report pages wash over their surfaces.
   * Written this way rather than with color-mix(): the tablet's web view is whatever Android
   * shipped with it, and a tint that silently resolves to nothing takes the whole panel's
   * character with it. */
  --brand-gold-rgb: 217, 169, 108;
  --brand-bronze-rgb: 176, 125, 70;
  --brand-olive-rgb: 111, 122, 78;

  /* What the report pages wash their header with. Named by the job rather than by the colour, so
   * a second palette retints those pages by setting two values instead of restating the rules. */
  --skin-tint-rgb: var(--brand-gold-rgb);
  --skin-thread-rgb: var(--brand-bronze-rgb);

  /* Headings and figures can differ from body text in a palette that wants them to. Both default
   * to what this file already used, so nothing changes until a theme says otherwise. */
  --font-display: var(--font-sans);
  --font-figure: var(--font-mono);

  /* The sidebar, by role rather than by colour.
   *
   * It used to be painted straight from the brand hues, which meant it was the one surface a
   * palette could not reach: every theme changed the whole product and left the navigation
   * bronze-on-ink, so the app looked half-converted. These defaults are exactly what it was. */
  --nav-surface: var(--brand-ink);
  --nav-border: var(--brand-ink-deep);
  --nav-divider: rgba(246, 240, 228, .1);
  --nav-text: var(--brand-cream-alt);
  --nav-text-strong: var(--brand-cream);
  --nav-muted: var(--brand-stone);
  --nav-hover: rgba(246, 240, 228, .07);
  --nav-active: var(--accent-strong);
  --nav-active-text: #FFFFFF;
  --nav-mark: linear-gradient(135deg, var(--brand-gold), var(--brand-bronze));
  --nav-mark-text: var(--brand-ink);

  /* Semantic surfaces */
  --surface: #FFFFFF;
  --surface-sunken: var(--brand-cream);
  --surface-raised: #FFFFFF;
  --border: #E2D8C6;
  --border-strong: #CDBFA6;

  /* Text */
  --text: var(--brand-ink);
  --text-muted: var(--brand-stone-deep);
  --text-subtle: var(--brand-stone);
  --text-on-brand: #FFFFFF;

  /* Intent */
  --accent: var(--brand-bronze);
  --accent-hover: var(--brand-deep);
  --accent-soft: #F3E4CE;

  /* Two accents, because a hairline and a filled button are different jobs. The bronze that reads
   * well as a 1px edge gives white text 3.58:1 - under the 4.5 a label needs - so anything that
   * fills a shape and writes on itself uses the deeper step instead. Measured, not judged:
   * tools/contrast/check-contrast.mjs. */
  --accent-strong: var(--brand-deep);
  --success: var(--brand-olive);
  --success-soft: #E8EDDC;
  --warning: #B7791F;
  --warning-soft: #FBEFD5;
  --danger: #A4342B;
  --danger-soft: #F8E2DF;

  /* The ink a badge writes in. Separate from the status colour itself, which stays the hue used
   * for edges and marks: olive on its own tint is 3.85:1, and badge text is small. */
  --success-ink: #626C45;
  --warning-ink: #956319;
  --danger-ink: var(--danger);

  /* Chart series.
   *
   * NOT the brand palette, and that is deliberate. Bronze and olive sit 4.4 apart under
   * protanopia and 10.5 apart under normal vision - measured, not guessed - so the two lines
   * would be one line for a colour-blind reader and nearly one for everyone else. A chart's
   * first job is telling series apart; decoration comes second and loses.
   *
   * These two are 24.7 apart under protanopia and clear the chroma, lightness and contrast
   * floors against both surfaces. Re-check before changing either. */
  --chart-series-1: #2A78D6;
  --chart-series-2: #EB6834;

  /* Shape and depth */
  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 16px;
  --shadow-sm: 0 1px 2px rgba(34, 30, 24, .06);
  --shadow: 0 2px 8px rgba(34, 30, 24, .08);
  --shadow-lg: 0 12px 32px rgba(34, 30, 24, .12);

  /* Rhythm */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;

  --font-sans: "IBM Plex Sans Arabic", "IBM Plex Sans", "Segoe UI", system-ui, sans-serif;
  /* The Arabic font second, not a system monospace. IBM Plex Mono has no Arabic letters, so every
     Arabic word written in a figure's font - "ر.س" beside an amount, a category name as a stat, a
     sentence carrying a date - fell through to the system's monospace and came out as spaced,
     broken letters on every screen that shows money. The browser picks per character: digits
     still come from the mono, and the letters from a face that has them. */
  --font-mono: "IBM Plex Mono", "IBM Plex Sans Arabic", ui-monospace, "Cascadia Mono", monospace;

  --sidebar-width: 264px;
  --header-height: 64px;

  color-scheme: light;
}

[data-theme="dark"] {
  --surface: #2A251E;
  --surface-sunken: var(--brand-ink-deep);
  --surface-raised: #332C24;
  --border: #443C31;
  --border-strong: #5A5043;

  --text: var(--brand-cream);
  --text-muted: #B5AB9B;
  --text-subtle: var(--brand-stone);

  --accent: var(--brand-gold);
  --accent-hover: #E8BE85;
  --accent-soft: #3C3225;
  --accent-strong: var(--brand-gold);

  /* Dark ink on gold. White on it is 2.13:1 - a primary button nobody could read, which is what
   * this palette shipped with until it was measured. */
  --text-on-brand: #1B1813;

  /* Lifted rather than darkened: on a dark tint the ink has to be the lighter of the two. */
  --success-ink: #9CA385;
  --warning-ink: #C39045;
  --danger-ink: #C8837E;
  --success-soft: #2E3524;

  /* A step darker than the page's own ground, so the navigation still reads as its own plane
     rather than as the page continuing off the edge. */
  --nav-surface: #15120E;
  --nav-border: #2E2820;
  --nav-active: var(--brand-deep);
  --warning-soft: #3A3020;
  --danger-soft: #3A2523;

  /* Stepped for the dark surface rather than reused from light - the same two hues, moved so
   * they still clear contrast against #2A251E. */
  --chart-series-1: #3987E5;
  --chart-series-2: #D95926;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .3);
  --shadow: 0 2px 8px rgba(0, 0, 0, .35);
  --shadow-lg: 0 12px 32px rgba(0, 0, 0, .45);

  color-scheme: dark;
}

/* ---------- Base ---------- */

*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
}

body {
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.65;
  color: var(--text);
  background: var(--surface-sunken);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  margin: 0 0 var(--space-3);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

h1 { font-size: 1.75rem; }
h2 { font-size: 1.35rem; }
h3 { font-size: 1.1rem; }

p { margin: 0 0 var(--space-3); }

a {
  color: var(--accent);
  text-decoration: none;
}

a:hover { color: var(--accent-hover); text-decoration: underline; }

code, .num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* ---------- App shell ---------- */

.app-shell {
  display: grid;
  grid-template-columns: var(--sidebar-width) 1fr;
  min-height: 100vh;
}

/*
 * Pinned to the window on a desk, with a scroll of its own. It used to scroll away with the page,
 * so on a long report the entries below the fold could not be reached without first scrolling the
 * whole report back up. The drawer below 900px overrides the position and keeps its own behaviour.
 */
.app-sidebar {
  background: var(--nav-surface);
  color: var(--nav-text-strong);
  display: flex;
  flex-direction: column;
  border-inline-end: 1px solid var(--nav-border);
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--nav-divider) transparent;
}

.app-brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex: none;
  height: var(--header-height);
  padding-inline: var(--space-5);
  border-block-end: 1px solid var(--nav-divider);
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--nav-surface);
}

.app-brand-mark {
  width: 34px;
  height: 34px;
  border-radius: var(--radius-sm);
  display: grid;
  place-items: center;
  background: var(--nav-mark);
  color: var(--nav-mark-text);
  font-weight: 700;
  flex: none;
}

.app-brand-text { display: flex; flex-direction: column; line-height: 1.2; }
.app-brand-name { font-weight: 600; font-size: 1rem; }
.app-brand-sub { font-size: .75rem; color: var(--nav-muted); }

.app-nav {
  padding: var(--space-3) var(--space-3) var(--space-6);
  display: flex;
  flex-direction: column;
  gap: 1px;
}

/*
 * The group headings. Quiet, but a real heading rather than a caption: at .7rem and the muted
 * colour they read as noise, and the list read as one run of thirty entries. A hairline above each
 * one does the separating, so the heading itself does not have to shout.
 */
.app-nav-section {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-block-start: var(--space-3);
  padding: var(--space-3) var(--space-3) var(--space-1);
  border-block-start: 1px solid var(--nav-divider);
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--nav-muted);
}

.app-nav a {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 38px;
  padding: 6px var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--nav-text);
  font-size: .9rem;
  line-height: 1.3;
  transition: background .12s ease, color .12s ease;
}

.app-nav a:hover { background: var(--nav-hover); text-decoration: none; }

.app-nav a.active {
  background: var(--nav-active);
  color: var(--nav-active-text);
  font-weight: 600;
}

/* A bar on the leading edge as well as the fill, so where you are survives a glance. */
.app-nav a.active::before {
  content: "";
  position: absolute;
  inset-block: 8px;
  inset-inline-start: -12px;
  inline-size: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--nav-mark);
}

.nav-icon { flex: none; opacity: .7; transition: opacity .12s ease; }

.app-nav a:hover .nav-icon,
.app-nav a.active .nav-icon { opacity: 1; }

/* The settings group, folded until it is wanted. */
/* A column like the nav itself - not display: contents, which a details element does not survive:
   Chromium stops folding it. */
.app-nav-group { display: flex; flex-direction: column; gap: 1px; }

.app-nav-group > summary {
  cursor: pointer;
  list-style: none;
  user-select: none;
  border-radius: var(--radius-sm);
}

.app-nav-group > summary::-webkit-details-marker { display: none; }

.app-nav-group > summary::after {
  content: "";
  margin-inline-start: auto;
  inline-size: 7px;
  block-size: 7px;
  border-inline-end: 1.8px solid currentColor;
  border-block-end: 1.8px solid currentColor;
  /* Open: pointing up, to fold it away. Closed: pointing down, to open it. */
  transform: rotate(-135deg);
  transition: transform .15s ease;
}

.app-nav-group:not([open]) > summary::after { transform: rotate(45deg); }

.app-nav-group > summary:hover { color: var(--nav-text); }

.app-nav-group > summary .nav-icon { inline-size: 14px; block-size: 14px; }

/* The person signed in, and the way out, in the header. */
.app-user {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: .88rem;
  color: var(--text-muted);
}

.app-user-avatar {
  display: inline-grid;
  place-items: center;
  inline-size: 30px;
  block-size: 30px;
  border-radius: 50%;
  font-size: .78rem;
  font-weight: 700;
  color: var(--text-on-brand);
  background: var(--accent);
}

.app-logout { gap: 6px; }

@media (max-width: 540px) {
  .app-user-name { display: none; }
}

.app-main { display: flex; flex-direction: column; min-width: 0; }

.app-header {
  height: var(--header-height);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-inline: var(--space-6);
  background: var(--surface);
  border-block-end: 1px solid var(--border);
}

.app-content { padding: var(--space-6); flex: 1; }

/* Hamburger and scrim exist only in drawer mode. */
.app-nav-toggle { display: none; }
.app-nav-scrim { display: none; }

@media (max-width: 900px) {
  .app-shell { grid-template-columns: 1fr; }
  .app-content { padding: var(--space-4); }

  .app-nav-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    padding: 0;
    background: transparent;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    cursor: pointer;
    flex: none;
  }

  /* Three bars drawn from one element: the middle is the box, the outer two are shadows. */
  .app-nav-toggle-bars,
  .app-nav-toggle-bars::before,
  .app-nav-toggle-bars::after {
    display: block;
    width: 18px;
    height: 2px;
    background: var(--text);
    border-radius: 2px;
  }

  .app-nav-toggle-bars { position: relative; }

  .app-nav-toggle-bars::before,
  .app-nav-toggle-bars::after {
    content: "";
    position: absolute;
    inset-inline-start: 0;
  }

  .app-nav-toggle-bars::before { top: -6px; }
  .app-nav-toggle-bars::after  { top: 6px; }

  .app-sidebar {
    position: fixed;
    top: auto;
    height: auto;
    inset-block: 0;
    /* Logical inset, so the drawer slides in from the correct edge in both RTL and LTR
       without a direction-specific transform. */
    inset-inline-start: calc(-1 * (min(280px, 82vw) + 12px));
    width: min(280px, 82vw);
    z-index: 60;
    box-shadow: var(--shadow-lg);
    transition: inset-inline-start .22s ease;
  }

  .nav-open .app-sidebar { inset-inline-start: 0; }

  .app-nav-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 50;
    padding: 0;
    border: 0;
    background: rgba(34, 30, 24, .45);
    opacity: 0;
    pointer-events: none;
    transition: opacity .22s ease;
    cursor: default;
  }

  .nav-open .app-nav-scrim { opacity: 1; pointer-events: auto; }
}

@media (prefers-reduced-motion: reduce) {
  .app-sidebar, .app-nav-scrim { transition: none; }
}

/* ---------- Page furniture ---------- */

.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-block-end: var(--space-5);
  flex-wrap: wrap;
}

/* The tape controls grew a transport selector, which is one control more than a phone header
   holds in a line. Wrapping beats a page that scrolls sideways. */
.page-header .row { justify-content: flex-end; }
.page-header .row .input { max-width: 15rem; }

.page-title { margin: 0; font-family: var(--font-display); }
.page-subtitle { margin: var(--space-1) 0 0; color: var(--text-muted); font-size: .92rem; }

/* ---------- Card ---------- */

.card {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.card-header {
  padding: var(--space-4) var(--space-5);
  border-block-end: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.card-title { margin: 0; font-size: 1rem; font-weight: 600; font-family: var(--font-display); }
.card-body { padding: var(--space-5); }

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-4);
}

/* ---------- Stat ---------- */

.stat { padding: var(--space-5); }
.stat-label { font-size: .8rem; color: var(--text-muted); margin-block-end: var(--space-2); }
.stat-value { font-family: var(--font-figure); font-size: 1.9rem; font-weight: 600; line-height: 1; }
.stat-hint { font-size: .78rem; color: var(--text-subtle); margin-block-start: var(--space-2); }

/* A stat whose value is a name, not a figure - the biggest expense heading. The figure font's
   monospaced space opened a gap in the middle of "رواتب وأجور". */
.stat-value.is-text { font-family: var(--font-display); font-size: 1.5rem; line-height: 1.2; }

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  min-height: 38px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  transition: background .12s ease, border-color .12s ease, color .12s ease;
}

.btn:disabled { opacity: .55; cursor: not-allowed; }

.btn-primary { background: var(--accent-strong); color: var(--text-on-brand); }
.btn-primary:hover:not(:disabled) { background: var(--accent-hover); }

.btn-ghost { background: transparent; color: var(--text); border-color: var(--border-strong); }
.btn-ghost:hover:not(:disabled) { background: var(--surface-sunken); }

.btn-quiet { background: transparent; color: var(--text-muted); }
.btn-quiet:hover:not(:disabled) { color: var(--text); background: var(--surface-sunken); }

/*
 * A button that undoes something. Tinted rather than solid: withdrawing a purchase invoice is a
 * deliberate act a manager takes once a month, not a primary action, and a solid red button beside
 * "record a payment" would pull the eye to the wrong one all day.
 *
 * --danger-ink on --danger-soft is the pair the contrast test already measures in all four
 * palettes as "a bad badge", so this cannot be the thing that makes a theme fail.
 */
.btn-danger { background: var(--danger-soft); color: var(--danger-ink); border-color: var(--danger); }
.btn-danger:hover:not(:disabled) { background: var(--danger); color: var(--text-on-brand); }

/* ---------- Forms ---------- */

.field { display: flex; flex-direction: column; gap: var(--space-2); margin-block-end: var(--space-4); }
.field-label { font-size: .85rem; font-weight: 500; }
.field-hint { font-size: .78rem; color: var(--text-subtle); }

.input, .select, .textarea {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  min-height: 38px;
  font: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
}

.input:focus-visible, .select:focus-visible, .textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}

.input.is-invalid { border-color: var(--danger); }
.input.is-warning { border-color: var(--warning); }

/* Measurement inputs are read at arm's length across a counter: keep the digits large. */
.input-measure {
  font-family: var(--font-mono);
  font-size: 1.15rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.field-row {
  display: grid;
  grid-template-columns: 1fr 132px;
  align-items: center;
  gap: var(--space-4);
  padding-block: var(--space-2);
}

/* Measuring screen: fields beside the live validation panel on a desktop, stacked on a tablet
   held in one hand. Collapses at 1000px rather than the usual 900px, because two columns of
   measurement fields become unusable well before the sidebar does. */
.measure-layout {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr);
  gap: var(--space-4);
  align-items: start;
}

@media (max-width: 1000px) {
  .measure-layout { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 420px) {
  .field-row { grid-template-columns: 1fr 104px; gap: var(--space-3); }
}

/* ---------- Table ---------- */

.table { width: 100%; border-collapse: collapse; font-size: .92rem; }
.table th, .table td { padding: var(--space-3) var(--space-4); text-align: start; }
.table thead th {
  font-size: .78rem;
  font-weight: 600;
  color: var(--text-muted);
  border-block-end: 1px solid var(--border);
}
.table tbody tr { border-block-end: 1px solid var(--border); }
.table tbody tr:last-child { border-block-end: none; }
.table td.num { font-variant-numeric: tabular-nums; }

/*
 * A row that needs doing something about, and one that has been retired.
 *
 * Four screens had been marking rows .row-danger since phase 5 - an overdue order, an absent
 * tailor, a fabric the shop has run out of, an unpaid subscription - and the class had no rule
 * behind it, so every one of those rows looked exactly like the rest. The tint is --danger-soft,
 * which the contrast test already measures against body text in all four palettes.
 *
 * Never colour alone: each of those screens also carries the reason in words in the row.
 */
/*
 * A figure that is bad news, and one that is good.
 *
 * Twenty-five places across the product write class="danger" on a cell or a stat value - an
 * overdue balance, a negative stock figure, an unpaid invoice - and the class had no rule behind
 * it, so every one of them read exactly like the figure beside it. The .success half is its pair,
 * for the one figure that is better below zero: a VAT refund position.
 *
 * Ink colours, not backgrounds, and never the only signal: every screen that uses these also says
 * what is wrong in words.
 */
.danger  { color: var(--danger-ink); }
.success { color: var(--success-ink); }

.table tbody tr.row-danger { background: var(--danger-soft); }
.table tbody tr.row-muted td { color: var(--text-muted); }

/*
 * A table inside a form rather than inside a report.
 *
 * The class already meant something before it meant anything here: table-cards.js reads it as the
 * opt-out from the phone card treatment, which is right for these - the invoice-entry lines and the
 * expense headings are rows of controls, not records to scan, and a card per control row is chrome
 * around one input.
 *
 * What it had no rule for was how they look on a wide screen. The hover tint follows a pointer on
 * its way to an input rather than marking a row worth reading, and a rule under every row competes
 * with the inputs' own borders.
 */
.table-plain tbody tr { border-block-end: none; }
.table-plain tbody tr:hover { background: transparent; }
.table-plain th, .table-plain td { padding-block: var(--space-2); }

.table-scroll { overflow-x: auto; }

/*
 * Tables, the most-read thing in this product.
 *
 * Middle-aligned, because a row whose name wraps to three lines otherwise leaves its amount and
 * its actions at the top and the row reads as three rows. Headings on one line and on a tinted
 * band, so the columns read as columns. Figures never break across lines - "1,357.00" split at the
 * comma is two numbers.
 */
.table th, .table td { vertical-align: middle; }

.table thead th {
  white-space: nowrap;
  background: var(--surface-sunken);
}

.table thead th:first-child { border-start-start-radius: var(--radius-sm); }
.table thead th:last-child  { border-start-end-radius: var(--radius-sm); }

.table td.num, .table th.num, .table td .num { white-space: nowrap; }

/*
 * A figure cell is left-to-right inside a right-to-left table, so a negative amount keeps its sign
 * in front: laid out in the row's own direction, "-300.00" was drawn as "300.00-" - a credit that
 * reads as a debt with a stray dash. Still aligned to the right, like its heading, so the column
 * does not jump. The four figure cells that can hold a word hold one word, which is safe either way.
 */
.table td.num {
  direction: ltr;
  unicode-bidi: isolate;
  text-align: right;
}

/*
 * The link-shaped actions at the end of a row - "تعديل", "حذف", "كشف الحساب" - were grey text a
 * reader had to find. They read as actions now, and the destructive one reads as destructive.
 */
.table .item-actions a,
.table .item-actions .btn-quiet {
  font-weight: 600;
  color: var(--accent);
}

.table .item-actions .danger,
.table .item-actions .btn-quiet.danger { color: var(--danger-ink); }

/* A cell stays a cell. ".item-actions" is a flex row, and on a <td> that stopped it being a table
   cell at all - so it ignored vertical-align and every row's actions sat at the top of the row. */
.table td.item-actions { display: table-cell; white-space: nowrap; }
.table td.item-actions > * + * { margin-inline-start: var(--space-1); }

/*
 * Narrower gutters: the widest registers carry nine columns, and at the desk's width the text ones
 * were folding onto three lines - "فرع / العليا" - to leave room for padding.
 */
.table th, .table td { padding-inline: var(--space-3); }

/*
 * Blocks laid straight into a page, outside a .stack, touched: a row of figures sat flush against
 * the card under it on the expenses, payroll and receivables screens. Vertical margins between
 * siblings collapse, so a page that already spaces its cards keeps its own spacing and gains
 * nothing twice.
 */
:where(.app-content, .preview-shell) > :where(.card, .card-grid, .alert, .stack, .detail-layout,
  .today-layout, .filter-bar)
  + :where(.card, .card-grid, .alert, .stack, .detail-layout, .today-layout, .filter-bar) {
  margin-block-start: var(--space-4);
}

/* A telephone number is a left-to-right thing wherever it sits, so its "+" stays at its start. */
.phone {
  direction: ltr;
  unicode-bidi: isolate;
  font-family: var(--font-mono);
  font-size: .9em;
  white-space: nowrap;
}

/* ---------- Badges and alerts ---------- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: 999px;
  font-size: .75rem;
  font-weight: 500;
  white-space: nowrap;
}

.badge-neutral { background: var(--surface-sunken); color: var(--text-muted); }
.badge-accent  { background: var(--accent-soft);  color: var(--accent-hover); }
.badge-success { background: var(--success-soft); color: var(--success-ink); }
.badge-warning { background: var(--warning-soft); color: var(--warning-ink); }
.badge-danger  { background: var(--danger-soft);  color: var(--danger-ink); }

.alert {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  border-inline-start: 3px solid transparent;
  font-size: .9rem;
  margin-block-end: var(--space-3);
}

.alert-info    { background: var(--surface-sunken); border-inline-start-color: var(--text-subtle); }
.alert-success { background: var(--success-soft);   border-inline-start-color: var(--success); }
.alert-warning { background: var(--warning-soft);   border-inline-start-color: var(--warning); }
.alert-danger  { background: var(--danger-soft);    border-inline-start-color: var(--danger); }

/* Confidence signalling for measurement values. */
.confidence-high   { color: var(--success); }
.confidence-medium { color: var(--warning); }
.confidence-low    { color: var(--danger); }

.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; background: currentColor; }

/* ---------- Workshop board ---------- */

/*
 * Columns scroll horizontally as one strip rather than wrapping: a board that reflows puts the
 * same piece in a different place every visit, and the people using it navigate by muscle memory.
 */
/*
 * The workshop board.
 *
 * Flex rather than a grid of equal columns, because the columns are not equal: eight stages do not
 * fit across a tablet at a readable width, and an empty stage keeps its heading while handing its
 * width to the stages that have work in them. Before this the late piece in "ironing" was in the
 * column pushed off the edge.
 */
/* Every stage at a glance, above the board, and a way to reach the columns off the edge. */
.board-strip {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-block-end: var(--space-3);
}

.board-strip-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 5px 12px;
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--stage);
  border-radius: var(--radius-sm);
  background: var(--surface-raised);
  color: var(--text);
  font-size: .82rem;
  font-weight: 600;
  text-decoration: none;
}

.board-strip-item .num {
  color: var(--text-muted);
  font-weight: 500;
}

.board-strip-item:hover { background: var(--surface); border-color: var(--stage); }
.board-strip-item.is-empty { opacity: .6; }
.board-strip-item.is-alert { background: var(--danger-soft); }
.board-strip-item.is-alert .num { color: var(--danger-ink); font-weight: 700; }

/*
 * One colour per production stage, for anything that says which stage it belongs to - the board's
 * columns and strip, the day's pipeline, a stage badge. Declared once so a stage is the same colour
 * on every screen; a component sets its own default and these win by specificity.
 */
/*
 * The stages have colours of their own rather than the palette's, and that was learned the hard
 * way: drawn from the palette, "cutting" was brand-bronze and "sewing" was the accent - which in the
 * classic palette IS brand-bronze - and "ironing" and "finishing" were both the olive. Four stages
 * wore two colours. These are categories, like the status colours, so they stay the same in every
 * palette; mid-tones, so a stripe or a dot reads on a light surface and a dark one alike.
 */
:root {
  --stage-pending:    #9A9185;
  --stage-cutting:    #C07A1E;
  --stage-sewing:     #3D7BB0;
  --stage-embroidery: #8D5BB4;
  --stage-ironing:    #2C978A;
  --stage-finishing:  #6E9140;
  --stage-rework:     #C0392B;
  --stage-done:       #857B70;
}

[data-stage="pending"]    { --stage: var(--stage-pending); }
[data-stage="cutting"]    { --stage: var(--stage-cutting); }
[data-stage="sewing"]     { --stage: var(--stage-sewing); }
[data-stage="embroidery"] { --stage: var(--stage-embroidery); }
[data-stage="ironing"]    { --stage: var(--stage-ironing); }
[data-stage="finishing"]  { --stage: var(--stage-finishing); }
[data-stage="rework"]     { --stage: var(--stage-rework); }
[data-stage="done"]       { --stage: var(--stage-done); }

.board {
  display: flex;
  gap: var(--space-3);
  overflow-x: auto;
  padding-block-end: var(--space-3);
  align-items: flex-start;
  scroll-snap-type: x proximity;
}

.board-column {
  /* Each stage has a colour of its own (see [data-stage]), carried on the heading and nowhere
     loud. No default here: this rule and [data-stage] weigh the same, and a default declared after
     them would paint every column grey. */
  flex: 1 0 236px;
  max-inline-size: 320px;
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-block-start: 3px solid var(--stage);
  border-radius: var(--radius);
  scroll-snap-align: start;
  scroll-margin-inline: var(--space-3);
}

.board-column.is-empty { flex: 0 0 132px; }

.board-column-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-3);
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--surface-sunken);
  border-start-start-radius: var(--radius);
  border-start-end-radius: var(--radius);
}

.board-column-title { font-weight: 700; font-size: .92rem; }

.board-column-counts { display: inline-flex; align-items: center; gap: var(--space-1); }

.board-count {
  min-inline-size: 1.7rem;
  padding: 1px 8px;
  border-radius: 999px;
  text-align: center;
  font-size: .78rem;
  font-weight: 600;
  color: var(--text-muted);
  background: var(--surface);
  border: 1px solid var(--border);
}

.board-column-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: 0 var(--space-2) var(--space-2);
}

.board-empty {
  margin: 0;
  padding: var(--space-4) var(--space-2);
  text-align: center;
  font-size: .8rem;
  color: var(--text-subtle);
  border: 1px dashed var(--border);
  border-radius: var(--radius-sm);
}

.board-card {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: 6px;
  box-shadow: var(--shadow-sm);
  transition: box-shadow .15s ease, transform .15s ease;
}

.board-card:hover { box-shadow: var(--shadow); }

/* Lateness is carried on the card edge and a tint, so it survives being scanned at arm's length. */
.board-card.is-due-soon { border-inline-start: 4px solid var(--warning); }

.board-card.is-overdue {
  border-inline-start: 4px solid var(--danger);
  background: color-mix(in srgb, var(--danger-soft) 45%, var(--surface-raised));
}

.board-card-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-2);
}

.board-card-title { font-weight: 700; font-size: 1rem; line-height: 1.3; }

.board-card-customer { font-size: .88rem; color: var(--text-muted); }

/* Order number and tracking code as one left-to-right strip, never broken at the hyphen. */
.board-card-ids {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 2px var(--space-2);
  font-size: .76rem;
  color: var(--text-subtle);
  white-space: nowrap;
}

.board-card-code { letter-spacing: .04em; opacity: .85; }

.board-card-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-1) var(--space-2);
  margin-block-start: 2px;
}

.board-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: .76rem;
  font-weight: 600;
  white-space: nowrap;
  line-height: 1.5;
}

.board-pill.is-danger  { background: var(--danger-soft);  color: var(--danger-ink); }
.board-pill.is-warning { background: var(--warning-soft); color: var(--warning-ink); }
.board-pill.is-muted   { background: var(--surface-sunken); color: var(--text-muted); }

.board-who {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: .8rem;
  color: var(--text-muted);
}

.board-avatar {
  display: inline-grid;
  place-items: center;
  inline-size: 22px;
  block-size: 22px;
  border-radius: 50%;
  font-size: .72rem;
  font-weight: 700;
  color: var(--text-on-brand);
  background: var(--accent);
}

.board-who.is-unassigned {
  padding: 1px 8px;
  border: 1px dashed var(--border-strong);
  border-radius: 999px;
  color: var(--text-subtle);
}

.board-card-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
  margin-block-start: var(--space-1);
  padding-block-start: var(--space-2);
  border-block-start: 1px solid var(--border);
}

/* The way forward: the stage's own colour, so the tap target says where the piece is going. */
:is(.board-card-actions, .piece-actions) .board-forward {
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 600;
}

:is(.board-card-actions, .piece-actions) .board-forward:hover {
  background: var(--accent);
  color: var(--text-on-brand);
}

/* Sending back is there and quieter - a mis-tap on it costs a remake. */
:is(.board-card-actions, .piece-actions) .board-back { color: var(--danger); }

.board-card-actions .board-open { margin-inline-start: auto; color: var(--text-subtle); }

/*
 * The day's first screen.
 *
 * Built from the board's own pieces - its badges, its circles, its stage colours - so a piece reads
 * the same here as it does on the bench, and a change to one is a change to both.
 */

.today-date { font-weight: 600; color: var(--text); }

/* A figure that can be followed to its pieces: the whole card is the link. */
a.stat-link {
  color: inherit;
  text-decoration: none;
  transition: box-shadow .15s ease, transform .15s ease;
}

a.stat-link:hover {
  text-decoration: none;
  box-shadow: var(--shadow);
  transform: translateY(-1px);
}

@media (prefers-reduced-motion: reduce) {
  a.stat-link:hover { transform: none; }
}

.today-alert {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

/* The next deliveries beside where the work is piling up; one column below a desk's width. */
.today-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.7fr) minmax(260px, 1fr);
  gap: var(--space-4);
  align-items: start;
}

@media (max-width: 1000px) {
  .today-layout { grid-template-columns: minmax(0, 1fr); }
}

.due-list, .pipeline-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.due-list { display: flex; flex-direction: column; gap: var(--space-2); }

/* Fixed tracks for everything but the title, so the stages, the people and the dates line up down
   the list - each row is its own grid, and auto tracks sized every row to its own content. */
.due-row {
  display: grid;
  grid-template-columns: 6.5rem minmax(0, 1fr) 7.5rem 8.5rem;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-raised);
  color: inherit;
  text-decoration: none;
  transition: background .12s ease, border-color .12s ease;
}

.due-row:hover { text-decoration: none; border-color: var(--border-strong); background: var(--surface); }

.due-row.is-overdue {
  border-inline-start: 4px solid var(--danger);
  background: color-mix(in srgb, var(--danger-soft) 45%, var(--surface-raised));
}

.due-stage {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: .8rem;
  font-weight: 600;
  color: var(--text-muted);
}

.due-stage::before {
  content: "";
  inline-size: 8px;
  block-size: 8px;
  border-radius: 50%;
  background: var(--stage, var(--text-subtle));
  flex: none;
}

.due-main { display: flex; flex-direction: column; min-inline-size: 0; }

.due-row > .board-pill { justify-self: end; }

.due-row > .due-who { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.due-title { font-weight: 700; }

.due-sub {
  display: flex;
  flex-wrap: wrap;
  gap: 2px var(--space-2);
  font-size: .82rem;
  color: var(--text-muted);
}

.due-sub .num { color: var(--text-subtle); font-size: .76rem; }

/* On a phone the row folds to two lines: what and when above, where and who below. */
@media (max-width: 640px) {
  .due-row {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "main due" "stage who";
    row-gap: var(--space-2);
  }

  .due-row > .due-main  { grid-area: main; }
  .due-row > .board-pill { grid-area: due; }
  .due-row > .due-stage { grid-area: stage; }
  .due-row > .due-who   { grid-area: who; justify-self: end; }
}

/* Where the work is along the line: one bar, one segment per stage that holds anything. */
.pipeline-bar {
  display: flex;
  gap: 2px;
  block-size: 12px;
  margin-block-end: var(--space-4);
  border-radius: 999px;
  overflow: hidden;
  background: var(--surface-sunken);
}

.pipeline-segment {
  flex-basis: 0;
  min-inline-size: 6px;
  background: var(--stage, var(--text-subtle));
}

.pipeline-list { display: flex; flex-direction: column; gap: 2px; }

.pipeline-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 7px var(--space-2);
  border-radius: var(--radius-sm);
  color: inherit;
  text-decoration: none;
  font-size: .9rem;
}

.pipeline-item:hover { background: var(--surface-sunken); text-decoration: none; }

.pipeline-item.is-empty { color: var(--text-subtle); }

.pipeline-dot {
  inline-size: 10px;
  block-size: 10px;
  border-radius: 3px;
  background: var(--stage, var(--text-subtle));
  flex: none;
}

.pipeline-item.is-empty .pipeline-dot { opacity: .35; }

.pipeline-name { flex: 1; }

.pipeline-count {
  min-inline-size: 1.6rem;
  text-align: center;
  font-weight: 700;
}

.pipeline-item.is-empty .pipeline-count { font-weight: 400; }

/*
 * A row of choices, one of them on. Used where a drop-down would hide which one is chosen: the
 * order statuses first. Buttons, so they take focus and a keyboard, and wrap on a phone.
 */
.chip-row { display: flex; flex-wrap: wrap; gap: var(--space-2); }

.chip {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 4px 14px;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-muted);
  font: inherit;
  font-size: .85rem;
  cursor: pointer;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}

.chip:hover { border-color: var(--accent); color: var(--text); }

.chip.is-on {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--text-on-brand);
  font-weight: 600;
}

.chip:disabled { opacity: .6; cursor: default; }

/* The search box and its button, side by side and full width. */
.orders-search { display: flex; gap: var(--space-2); }
.orders-search .input { flex: 1; }

.order-number { font-weight: 700; color: var(--text); }
.order-customer { font-weight: 600; }
.order-owed { color: var(--warning-ink); font-weight: 600; }

.board-pill.is-success { background: var(--success-soft); color: var(--success-ink); }

/* On a row already tinted as late, the late badge would be the same soft red as its ground and
   vanish into it; it takes the card's own surface and a red edge instead. */
.row-danger .board-pill.is-danger,
.is-overdue .board-pill.is-danger {
  background: var(--surface-raised);
  box-shadow: inset 0 0 0 1px var(--danger);
}

/* "Opens" at the end of a clickable row, pointing the way the page reads. */
.table td.row-go { color: var(--text-subtle); font-size: 1.2rem; inline-size: 1.5rem; }
.table tr.row-clickable:hover td.row-go { color: var(--accent); }

/* A person in a table: the circle the board uses, then the name and anything said about them. */
.person-cell { display: flex; align-items: center; gap: var(--space-3); }
.person-cell .board-avatar { inline-size: 32px; block-size: 32px; font-size: .8rem; flex: none; }
.person-name { font-weight: 600; margin-block-end: 2px; }

/* The measuring screen's header: the tape on one side, the measurement's actions on the other. */
.measure-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  inline-size: 100%;
}

.tool-group { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }

.tool-device .select, .tool-device select.input { inline-size: auto; min-inline-size: 11rem; }

/* The tape's state, with a light that is green only when it is actually connected. */
.tape-status { display: inline-flex; align-items: center; gap: 6px; }

.status-light {
  inline-size: 8px;
  block-size: 8px;
  border-radius: 50%;
  background: var(--text-subtle);
}

.tape-status.is-live .status-light {
  background: var(--success);
  box-shadow: 0 0 0 3px var(--success-soft);
}

/*
 * The design catalogue's tiles: the chosen one unmistakable. A thin ring in the accent's pale tint
 * was all that marked it, which from a step away is every tile.
 */
.option-tile { position: relative; transition: border-color .12s ease, box-shadow .12s ease, transform .12s ease; }

.option-tile:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); }

.option-tile.is-picked {
  border: 2px solid var(--accent);
  background: var(--accent-soft);
  box-shadow: none;
  padding: calc(var(--space-2) - 1px);
}

.option-tile.is-picked::after {
  content: "";
  position: absolute;
  inset-block-start: 8px;
  inset-inline-start: 8px;
  inline-size: 22px;
  block-size: 22px;
  border-radius: 50%;
  background: var(--accent) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E") center / 14px no-repeat;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .2);
}

@media (prefers-reduced-motion: reduce) {
  .option-tile:hover { transform: none; }
}

/* The order page's heading: the number, and its status as a badge big enough to read first. */
.order-title { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-3); }
/* A border in its own colour, because the neutral badge - a draft - is pale enough to read as
   disabled text beside a heading this size. */
.status-badge {
  font-size: .85rem;
  font-weight: 700;
  padding: 4px 12px;
  border: 1px solid currentColor;
}

.order-cancel { color: var(--danger-ink); }

/* One piece: what it is on one side, what to do with it on the other. */
.piece-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  padding-block-end: var(--space-2);
  margin-block-end: var(--space-2);
  border-block-end: 1px dashed var(--border);
}

.piece-title strong { font-size: 1.05rem; }

.piece-actions { gap: var(--space-2); }

.item-row + .item-row { padding-block-start: var(--space-4); }

/*
 * The customer's statement: a sheet of paper in every palette, like the invoice. It sets the
 * theme's tokens back to paper values inside itself, because the table, the figures and the muted
 * text it is built from all read them - and a statement printed from the dark palette came out in
 * near-white on white.
 *
 * No heavy black rules anywhere on it: separation comes from light lines, tint and weight.
 */
.stmt-sheet {
  --text: #1C1C1C;
  --text-muted: #5A5A5A;
  --text-subtle: #767676;
  --border: #E2E2E2;
  --border-strong: #C8C8C8;
  --surface: #FFFFFF;
  --surface-raised: #FFFFFF;
  --surface-sunken: #F5F5F3;
  --danger-ink: #A4342B;
  --danger-soft: #FBECEA;
  --success-ink: #4F6B2F;
  --success-soft: #EEF3E6;
  --info-soft: #EEF3F8;

  background: #FFFFFF;
  color: var(--text);
}

.stmt-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block-end: var(--space-4);
  margin-block-end: var(--space-4);
  border-block-end: 1px solid var(--border);
}

.stmt-kicker {
  font-size: .78rem;
  font-weight: 700;
  color: var(--accent);
  margin-block-end: 2px;
}

.stmt-title { margin: 0 0 2px; font-size: 1.5rem; font-family: var(--font-display); }

.stmt-meta {
  display: grid;
  grid-template-columns: auto auto;
  gap: 2px var(--space-3);
  margin: 0;
  font-size: .85rem;
}

.stmt-meta dt { color: var(--text-muted); }
.stmt-meta dd { margin: 0; font-weight: 600; }

/* The figures: as many boxes as there are things to say, the closing balance widest and loudest. */
/* A wrapping row rather than a grid: the closing box is wider by growing more, not by spanning two
   columns - which, where only three fitted, sent it onto a row of its own beside an empty gap. */
.stmt-summary {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-block-end: var(--space-4);
}

.stmt-figure { flex: 1 1 130px; }

.stmt-figure {
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
}

.stmt-figure-label { font-size: .78rem; color: var(--text-muted); margin-block-end: 4px; }
.stmt-figure-value { font-size: 1.15rem; font-weight: 700; }

.stmt-figure.is-closing { flex: 1.8 1 200px; background: var(--surface); border-color: var(--border-strong); }
.stmt-figure.is-closing .stmt-figure-value { font-size: 1.6rem; }
.stmt-figure.is-owed { background: var(--danger-soft); border-color: var(--danger-ink); }
.stmt-figure.is-owed .stmt-figure-value { color: var(--danger-ink); }
.stmt-figure.is-credit { background: var(--success-soft); border-color: var(--success-ink); }
.stmt-figure.is-credit .stmt-figure-value { color: var(--success-ink); }

.stmt-currency { font-size: .75em; font-weight: 600; font-family: var(--font-sans); }

.stmt-table .stmt-balance { font-weight: 700; }
.stmt-table .stmt-credit { color: var(--success-ink); }

/* The first and last rows are the account's edges: tinted, and the closing one weighted. */
.stmt-table tr.stmt-edge td { background: var(--surface-sunken); color: var(--text-muted); font-weight: 600; }
.stmt-table tr.stmt-edge.is-closing td { color: var(--text); border-block-start: 1px solid var(--border-strong); }
.stmt-table tfoot td { border-block-end: none; }

@media print {
  .stmt-figure { break-inside: avoid; }
}

/* Bench targets stay finger-sized even in the compact variant. */
.btn-small {
  min-height: 32px;
  padding: var(--space-1) var(--space-3);
  font-size: .82rem;
}

.select-small { min-height: 32px; font-size: .82rem; padding-block: var(--space-1); }

/*
 * A fabric's colour beside its name.
 *
 * Three screens have been drawing one of these since phase 7 - the stock ledger, the cloth margin
 * report, and now a purchase invoice - and the class had no rule behind it, so the span had no
 * size and the colour never appeared at all. It is a hint, never the only way to tell two cloths
 * apart: the name is always next to it.
 */
.swatch-dot {
  display: inline-block;
  inline-size: 12px;
  block-size: 12px;
  border-radius: 50%;
  margin-inline-end: var(--space-2);
  vertical-align: -1px;
  border: 1px solid var(--border-strong);
}

/*
 * The two blocks at the top of a supplier statement: who it is for, and what window it covers.
 *
 * Side by side on a desk and stacked on a phone, because this is the part a merchant checks first
 * and a name wrapped under a date reads as two separate facts.
 */
.statement-head {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
  justify-content: space-between;
  padding-block-end: var(--space-4);
  margin-block-end: var(--space-4);
  border-block-end: 1px solid var(--border);
}

/* The sentence under a figure that says what the figure does not cover. */
.stat-note { margin-block-start: var(--space-1); font-size: .76rem; color: var(--text-subtle); }

/*
 * The three figures under a list of priced lines: before tax, tax, total.
 *
 * Wraps to a column on a narrow screen rather than scrolling, because these are the numbers
 * somebody checks against the paper in their hand.
 */
.totals {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  align-items: baseline;
  padding-block-start: var(--space-3);
  border-block-start: 1px solid var(--border);
}
.totals .num { font-variant-numeric: tabular-nums; margin-inline-start: var(--space-2); }

/* ---------- Order screens ---------- */

.detail-layout {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr);
  gap: var(--space-4);
  align-items: start;
}

@media (max-width: 1000px) {
  .detail-layout { grid-template-columns: minmax(0, 1fr); }
}

.filter-bar {
  display: grid;
  grid-template-columns: 1fr 180px auto;
  gap: var(--space-3);
}

@media (max-width: 700px) {
  .filter-bar { grid-template-columns: 1fr; }
}

.row-clickable { cursor: pointer; }
.row-clickable:hover { background: var(--surface-sunken); }

.progress {
  height: 6px;
  border-radius: 999px;
  background: var(--border);
  overflow: hidden;
}

.progress-fill { height: 100%; background: var(--success); }

.item-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  padding-block: var(--space-3);
  border-block-end: 1px solid var(--border);
  flex-wrap: wrap;
}

.item-row:last-child { border-block-end: none; }

.item-actions { display: flex; flex-wrap: wrap; gap: var(--space-1); align-items: center; }

.line-editor {
  display: grid;
  grid-template-columns: 1.4fr .7fr .9fr 1.2fr auto;
  gap: var(--space-3);
  align-items: end;
  padding-block: var(--space-3);
  border-block-end: 1px solid var(--border);
}

.line-editor .field { margin-block-end: 0; }

@media (max-width: 800px) {
  .line-editor { grid-template-columns: 1fr 1fr; }
}

.choice-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-1);
  border-block-end: 1px solid var(--border);
  cursor: pointer;
}

.choice-row:last-child { border-block-end: none; }
.choice-row:hover { background: var(--surface-sunken); }

/* No gap between the two columns - the space is padding on the figure instead - so a rule drawn
   across a total runs unbroken under the label and the amount, rather than as two dashes. */
.money-list {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--space-2) 0;
  margin: 0;
}

.money-list dd { padding-inline-start: var(--space-4); }

.money-list dt { color: var(--text-muted); font-size: .88rem; }
.money-list dd { margin: 0; text-align: end; font-variant-numeric: tabular-nums; }
.money-list .money-total { font-weight: 600; color: var(--text); font-size: 1rem; }

/*
 * The two lines that matter, set apart from the arithmetic that leads to them: a rule above each,
 * and what is still owed the largest figure on the card - it is the number the counter is asked.
 */
.money-list .money-total { padding-block-start: var(--space-2); border-block-start: 1px solid var(--border); }
.money-list dd.money-total:last-of-type,
.money-list dt.money-total:last-of-type { font-size: 1.15rem; }

/* ---------- Utilities ---------- */

.stack { display: flex; flex-direction: column; gap: var(--space-4); }
.row { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
.muted { color: var(--text-muted); }
/* The measurements a piece is cut to: a drawing of the garment beside the numbers.

   Side by side where there is room, stacked on a narrow screen. The table carries tabular figures
   so the digits line up down the column - the whole point of showing them as a table rather than
   a sentence. */
.garment-measures {
  display: grid;
  grid-template-columns: minmax(180px, 260px) 1fr;
  gap: 1rem;
  align-items: start;
  margin-block-start: .6rem;
}

.garment-measures.is-compact { grid-template-columns: 1fr; gap: 0; }

@media (max-width: 640px) {
  .garment-measures { grid-template-columns: 1fr; }
}

.garment-figure { width: 100%; height: auto; display: block; }

.gm-body {
  fill: var(--surface-sunken);
  stroke: var(--border-strong);
  stroke-width: 2;
  stroke-linejoin: round;
}

.gm-collar { fill: none; stroke: var(--border-strong); stroke-width: 2; }

/* Dashed, so a measuring line is never mistaken for a seam. */
.gm-line {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.5;
  stroke-dasharray: 5 3;
}

.gm-dot { fill: var(--accent); }

.gm-num {
  fill: var(--text-on-brand);
  font-size: 12px;
  font-weight: 700;

  /* Latin digits inside an Arabic page: the marker must match the number in the table. */
  direction: ltr;
}

.measure-table { width: 100%; font-size: .85rem; }
.measure-table td, .measure-table th { padding: .25rem .4rem; }

/* A measurement's name on one line: "محيط / الرقبة" split in two read as two measurements. */
.measure-table td, .measure-table th { white-space: nowrap; }

.measure-table .gm-col-num {
  width: 1%;
  white-space: nowrap;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.gm-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 1.35rem;
  block-size: 1.35rem;
  border-radius: 50%;
  background: var(--accent);
  color: var(--text-on-brand);
  font-size: .72rem;
  font-weight: 700;
  direction: ltr;
}

/* On a board card the drawing is dropped and the table is all that is left. */
.board-card-measures { margin-block-start: .4rem; }
.board-card-measures > summary { cursor: pointer; color: var(--text-subtle); }
.board-card-measures .measure-table { font-size: .78rem; }

/* A figure that is a problem should not look like a figure that is fine. Only two states, so a
   glance still sorts them: something is late, or something is waiting for a decision. */
.card.stat.is-alarm { border-color: #D97A6C; }
.card.stat.is-alarm .stat-value { color: #C4553F; }
.card.stat.is-warn .stat-value { color: var(--brand-bronze); }

.subtle { color: var(--text-subtle); }
.small { font-size: .85rem; }
.grow { flex: 1; }
.empty-state { padding: var(--space-7) var(--space-4); text-align: center; color: var(--text-muted); }

/* ---------- Sign-in ---------- */

.auth-shell {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: var(--space-5);
  background: var(--surface-sunken);
}

.auth-card {
  width: min(420px, 100%);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--space-6);
}

.auth-brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-block-end: var(--space-6);
}

/* ---------- Printing ---------- */

.print-page { padding: var(--space-5); background: var(--surface-sunken); min-height: 100vh; }

.print-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-block-end: var(--space-5);
  padding: var(--space-3) var(--space-4);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

/* Label sheet: a grid on screen, the same grid on paper. */
.label-sheet {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: var(--space-3);
}

.label {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  padding: var(--space-3);
  background: #FFFFFF;
  color: #000000;
  /* Dashed on purpose: on paper it is the line the scissors follow. */
  border: 1px dashed #999999;
  border-radius: var(--radius-sm);
  /* A sticker must not split across a page. */
  break-inside: avoid;
  page-break-inside: avoid;
}

.label-qr { flex: none; width: 88px; height: 88px; }
.label-qr svg { width: 100%; height: 100%; display: block; }

.label-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; line-height: 1.35; }

.label-garment { font-size: .95rem; font-weight: 700; }
.label-customer { font-size: .82rem; font-weight: 600; color: #222222; }

/* One line that never folds: "قطعة 1 من 1" wrapped onto a line of its own on paper. */
.label-meta { font-size: .72rem; color: #444444; white-space: nowrap; }

.label-tags { display: flex; flex-wrap: wrap; gap: 3px; margin-block-start: 2px; }

.label-tag {
  padding: 0 6px;
  border: 1px solid #BBBBBB;
  border-radius: 999px;
  font-size: .66rem;
  color: #333333;
  white-space: nowrap;
}

/* The code somebody types, boxed so it reads as one thing and cannot be misread as the order. */
.label-code {
  align-self: flex-start;
  margin-block-start: 4px;
  padding: 1px 6px;
  border: 1px solid #D0D0D0;
  border-radius: 4px;
  font-size: .86rem;
  font-weight: 700;
  letter-spacing: .06em;
  white-space: nowrap;
}

/*
 * Invoice.
 *
 * Paper, whatever the screen is wearing. The invoice is white with black ink in every palette, and
 * it sets the theme's colour tokens back to paper values inside itself - because the text, tables
 * and money lists it is built from read those tokens. Under the dark palette they did: the total
 * and the balance were drawn in the dark theme's near-white on this white sheet and all but
 * vanished, and the table heading turned into a black band. A tax invoice whose total cannot be
 * read is the one thing this page must not produce.
 */
.invoice {
  --text: #111111;
  --text-muted: #555555;
  --text-subtle: #6B6B6B;
  --border: #DDDDDD;
  --border-strong: #BBBBBB;
  --surface: #FFFFFF;
  --surface-raised: #FFFFFF;
  --surface-sunken: #F3F3F3;
  --danger-ink: #A4342B;
  --success-ink: #4F5A2F;

  background: #FFFFFF;
  color: var(--text);
  padding: var(--space-6);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  max-width: 800px;
  margin-inline: auto;
}

.invoice-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--space-5);
  padding-block-end: var(--space-4);
  border-block-end: 2px solid #111111;
  flex-wrap: wrap;
}

.invoice-seller { font-size: 1.5rem; margin: 0 0 var(--space-1); }
.invoice-vat { font-size: .88rem; }

.invoice-title { display: flex; flex-direction: column; align-items: stretch; gap: var(--space-2); min-inline-size: 240px; }

.invoice-title-box {
  padding: var(--space-2) var(--space-3);
  border: 1px solid #D0D0D0;
  border-radius: var(--radius-sm);
  text-align: center;
}

.invoice-title-ar { font-weight: 700; font-size: 1.1rem; }
.invoice-title-en { font-size: .75rem; color: var(--text-muted); letter-spacing: .04em; }

.invoice-meta {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px var(--space-3);
  margin: 0;
  font-size: .85rem;
}

.invoice-meta dt { color: var(--text-muted); }
.invoice-meta dd { margin: 0; text-align: end; font-weight: 600; }

.invoice-party {
  display: flex;
  align-items: stretch;
  margin-block: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.invoice-party-label {
  display: grid;
  place-items: center;
  padding: var(--space-2) var(--space-3);
  background: var(--surface-sunken);
  border-inline-end: 1px solid var(--border);
  font-size: .8rem;
  font-weight: 700;
  color: var(--text-muted);
}

.invoice-party-body {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-6);
  padding: var(--space-2) var(--space-3);
}

.invoice-lines th, .invoice-lines td { border-block-end: 1px solid var(--border); }
.invoice-lines thead th { background: var(--surface-sunken); color: var(--text); }
.invoice-lines tbody tr:hover { background: transparent; }
.invoice-lines .invoice-line-no { inline-size: 2.5rem; color: var(--text-muted); text-align: center; }
.invoice-line-name { font-weight: 600; }

.invoice-footer {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--space-6);
  padding-block-start: var(--space-5);
  flex-wrap: wrap;
}

.invoice-qr { width: 140px; text-align: center; }
.invoice-qr svg { width: 120px; height: 120px; display: block; margin-inline: auto; }

.invoice-totals {
  min-width: 300px;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

/* The amount due: a heavy rule and the largest figure on the sheet. */
.invoice-totals .invoice-grand {
  font-size: 1.15rem;
  font-weight: 700;
  border-block-start: 2px solid #111111;
}

.invoice-note {
  margin-block-start: var(--space-5);
  padding-block-start: var(--space-3);
  border-block-start: 1px dashed var(--border-strong);
  font-size: .8rem;
  color: var(--text-muted);
  text-align: center;
}

@media print {
  /* Paper is white and ink is expensive: drop the theme's surfaces entirely. */
  .no-print { display: none !important; }

  /* The page itself too. Printed from the dark palette with "background graphics" on, the sheet
     came out dark around a white invoice - the document was paper, the page it sat on was not. */
  html, body { background: #FFFFFF !important; }

  .print-page { padding: 0; background: #FFFFFF; min-height: auto; }

  .invoice { border: none; box-shadow: none; padding: 0; max-width: none; }

  /* A card is a screen device: it groups things against a page of other things. On paper there is
     nothing else on the sheet, so its border and shadow are ink laid down for no reader. The
     supplier statement is the first document built out of cards rather than out of .invoice. */
  .card { border: none; box-shadow: none; background: #FFFFFF; }
  .card-body { padding: 0; }

  /*
   * minmax(0, 1fr), not 1fr: a plain fraction will not shrink below its widest unbreakable line, so
   * the tracking code - which must not wrap - pushed the columns wider than the paper and the first
   * column printed with its code cut to "34TCGA2L7U". The labels fit the sheet; what is inside them
   * is sized to fit the label.
   */
  .label-sheet { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4mm; }

  .label { gap: 2.5mm; padding: 2.5mm; }
  .label-qr { width: 22mm; height: 22mm; }
  .label-body { overflow: hidden; }
  .label-garment { font-size: 10pt; }
  .label-customer { font-size: 8.5pt; }
  .label-meta { font-size: 7pt; white-space: normal; }
  .label-code { font-size: 8.5pt; letter-spacing: .02em; padding: 0 1.5mm; }

  @page { margin: 10mm; }

  body { background: #FFFFFF; }

  /* The dressed header is ink a printer would lay down for nothing. On paper the page's name is
     enough. */
  .page-header {
    background: none;
    box-shadow: none;
    border: none;
    padding: 0;
  }

  .page-header::after { display: none; }
}

/* The field the Bluetooth tape will fill next. Must be obvious from across a fitting room, so
   it uses a filled edge rather than a subtle tint. */
.field-row.is-tape-target {
  background: var(--accent-soft);
  border-inline-start: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  padding-inline: var(--space-3);
}

/* The keystroke pad for a HID tape.

   It looks like a control that holds attention because that is exactly its job: while it has
   focus the tape's keystrokes go here and nowhere else, and the moment it loses focus they would
   land in whatever the tailor clicked instead. The armed state has to be readable at a glance
   from arm's length, so it changes colour and border rather than showing a small label. */
.hid-pad {
  display: block;
  margin-block-start: var(--space-4);
  padding: var(--space-4);
  border: 2px dashed var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
  cursor: pointer;
  outline: none;
}

.hid-pad.is-armed {
  border-style: solid;
  border-color: var(--accent);
  background: var(--accent-soft);
}

.hid-pad:focus-visible {
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* ---------- Body mapping (the measuring screen) ----------

   A dark instrument panel set into the light application, exactly as the brand deck draws it. The
   darkness is not decoration: the figure is read across a fitting room while the tailor has both
   hands on the tape and the customer, and a lit limb on a dark ground is legible at a glance in a
   way a tinted row in a form never is. */

.bodymap {
  background: var(--brand-ink, #221E18);
  border-radius: 26px;
  padding: 12px;
  box-shadow: 0 40px 90px -40px rgba(34, 30, 24, 0.55);
  color: #F6F0E4;
}

.bodymap-chrome {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px 14px;
}

.bodymap-chrome .dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: rgba(246, 240, 228, 0.22);
}

.bodymap-label {
  /* Arabic now, so no letter-spacing: spacing pulls Arabic letters apart at their joins, and the
     label read as a row of disconnected shapes. The sans face, for the same reason. */
  font-family: var(--font-sans);
  font-size: 11px;
  letter-spacing: 0;
  color: rgba(246, 240, 228, 0.4);
  margin-inline-start: auto;
}

.bodymap-grid {
  background: #1B1813;
  border-radius: 18px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 380px;
  overflow: hidden;
}

/* ---- the stage ---- */

.bodymap-stage {
  position: relative;
  padding: 40px 30px 64px;
  min-height: 700px;
  display: grid;
  place-items: center;
  overflow: hidden;
}

/* Woven grain, at the thread angle used across the identity. */
.bodymap-stage::before {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.45;
  background-image: repeating-linear-gradient(115deg, rgba(246, 240, 228, 0.05) 0 1px, transparent 1px 11px);
  pointer-events: none;
}

.bodymap-drape {
  position: absolute;
  inset: -10%;
  filter: blur(34px);
  opacity: 0.4;
  pointer-events: none;
  contain: paint;
}

.bodymap-drape span {
  position: absolute;
  border-radius: 50% 40% 60% 45%;
}

.bodymap-drape .drape-a {
  width: 60%;
  height: 60%;
  top: 16%;
  left: 12%;
  background: radial-gradient(circle, var(--brand-olive, #6F7A4E), transparent 68%);
  animation: drapeB 21s ease-in-out infinite;
}

.bodymap-drape .drape-b {
  width: 56%;
  height: 56%;
  bottom: 8%;
  right: 8%;
  background: radial-gradient(circle, var(--brand-bronze, #B07D46), transparent 66%);
  animation: drapeA 26s ease-in-out infinite;
}

@keyframes drapeA {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(-4%, 5%, 0) scale(1.08); }
}

@keyframes drapeB {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(5%, -4%, 0) scale(1.06); }
}

@keyframes breathe {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.45; transform: scale(0.82); }
}

@keyframes pulseRing {
  0%   { transform: scale(0.7); opacity: 0.9; }
  100% { transform: scale(1.6); opacity: 0; }
}

/* ---- the figure ----

   Laid out left/top in a fixed 300x560 box, so the coordinates stay the ones the identity was
   drawn against. The box is forced LTR because those coordinates are geometry, not text. */

.bodymap-figure {
  position: relative;
  width: 300px;
  height: 560px;
  direction: ltr;
}

.bm-part {
  position: absolute;
  background: rgba(246, 240, 228, 0.075);
  border: 1px solid rgba(246, 240, 228, 0.12);
  transition: background .5s cubic-bezier(.4, 0, .2, 1),
              border-color .5s cubic-bezier(.4, 0, .2, 1),
              box-shadow .5s cubic-bezier(.4, 0, .2, 1);
}

.bm-part.is-lit {
  background: linear-gradient(150deg, #D9A96C, var(--brand-bronze, #B07D46));
  border-color: rgba(246, 240, 228, 0.35);
  box-shadow: 0 0 34px rgba(217, 169, 108, 0.45);
}

.bm-head     { left: 124px; top: 8px;   width: 52px;  height: 52px;  border-radius: 50%; }
.bm-neck     { left: 140px; top: 56px;  width: 20px;  height: 20px;  border-radius: 6px; }
.bm-shoulder { left: 60px;  top: 72px;  width: 180px; height: 26px;  border-radius: 13px; }
.bm-arm-l    { left: 46px;  top: 86px;  width: 26px;  height: 176px; border-radius: 13px; transform: rotate(4deg); }
.bm-arm-r    { left: 228px; top: 86px;  width: 26px;  height: 176px; border-radius: 13px; transform: rotate(-4deg); }
.bm-chest    { left: 80px;  top: 96px;  width: 140px; height: 94px;  border-radius: 26px 26px 10px 10px; }
.bm-waist    { left: 94px;  top: 192px; width: 112px; height: 62px;  border-radius: 10px 10px 16px 16px; }
.bm-hip      { left: 75px;  top: 256px; width: 150px; height: 62px;  border-radius: 18px 18px 30px 30px; }
.bm-leg-l    { left: 92px;  top: 314px; width: 52px;  height: 226px; border-radius: 16px 16px 22px 22px; }
.bm-leg-r    { left: 156px; top: 314px; width: 52px;  height: 226px; border-radius: 16px 16px 22px 22px; }

/* ---- the measuring line ---- */

.bm-band {
  position: absolute;
  transition: all .5s cubic-bezier(.4, 0, .2, 1);
}

.bm-band.bm-h { border-top: 1.5px dashed #D9A96C; }
.bm-band.bm-v { border-left: 1.5px dashed #D9A96C; }

.bm-chip {
  position: absolute;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: 10.5px;
  padding: 4px 9px;
  border-radius: 20px;
  background: rgba(217, 169, 108, 0.16);
  border: 1px solid rgba(217, 169, 108, 0.4);
  color: #F6F0E4;
  direction: rtl;
}

.bm-band.bm-h > .bm-chip { left: calc(100% + 8px); top: -13px; }
.bm-band.bm-v > .bm-chip { top: calc(100% + 6px); left: -16px; }

.bm-b-neck     { left: 118px; top: 66px;  width: 64px; }
.bm-b-shoulder { left: 56px;  top: 86px;  width: 188px; }
.bm-b-back     { left: 62px;  top: 108px; width: 176px; }
.bm-b-chest    { left: 72px;  top: 134px; width: 156px; }
.bm-b-waist    { left: 86px;  top: 216px; width: 128px; }
.bm-b-hip      { left: 67px;  top: 288px; width: 166px; }
.bm-b-bicep    { left: 36px;  top: 124px; width: 44px; }
.bm-b-forearm  { left: 38px;  top: 198px; width: 42px; }
.bm-b-wrist    { left: 40px;  top: 248px; width: 38px; }
.bm-b-thigh    { left: 82px;  top: 352px; width: 72px; }
.bm-b-knee     { left: 86px;  top: 440px; width: 62px; }
.bm-b-ankle    { left: 90px;  top: 520px; width: 48px; }

.bm-b-sleeve   { left: 34px;  top: 90px;  height: 180px; }
.bm-b-length   { left: 284px; top: 74px;  height: 462px; }
.bm-b-front    { left: 150px; top: 96px;  height: 220px; }
.bm-b-armhole  { left: 74px;  top: 78px;  height: 44px; }
.bm-b-inseam   { left: 144px; top: 320px; height: 218px; }
.bm-b-outseam  { left: 66px;  top: 258px; height: 280px; }

.bm-b-length > .bm-chip,
.bm-b-front > .bm-chip { left: auto; right: -6px; }

.bodymap-stage-footer {
  position: absolute;
  bottom: 22px;
  inset-inline: 30px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.bodymap-stage-footer .mono {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  color: rgba(246, 240, 228, 0.35);
}

.bodymap-pill {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 6px 12px;
  border-radius: 20px;
  background: rgba(246, 240, 228, 0.06);
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: #D9A96C;
}

.bodymap-pill .live-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #D9A96C;
  animation: breathe 2.4s ease-in-out infinite;
}

.bodymap-pill.is-idle { color: rgba(246, 240, 228, 0.45); }
.bodymap-pill.is-idle .live-dot { background: rgba(246, 240, 228, 0.35); animation: none; }

/* ---- the side panel ---- */

.bodymap-side {
  background: var(--brand-ink, #221E18);
  border-inline-start: 1px solid rgba(246, 240, 228, 0.08);
  padding: 26px 22px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
  /* Deliberately unbounded: the list below sets its own limit, so the panel is as tall as the
     garment needs and no taller. A bisht's six measurements make a short panel; a jacket's
     sixteen make a tall one. Capping the panel instead squeezed the list to two visible rows once
     the garment picker and the NOW MEASURING card had taken their share. */
}

.bodymap-side h2 {
  margin: 0;
  font-size: 19px;
  font-weight: 500;
  color: #F6F0E4;
}

.bodymap-side .side-sub {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: rgba(246, 240, 228, 0.45);
  margin-top: 6px;
}

.bodymap-progress {
  display: flex;
  align-items: center;
  gap: 12px;
}

.bodymap-progress .track {
  flex: 1;
  height: 3px;
  border-radius: 3px;
  background: rgba(246, 240, 228, 0.12);
  overflow: hidden;
}

.bodymap-progress .fill {
  height: 100%;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--brand-olive, #6F7A4E), #D9A96C);
  transition: width .5s ease;
}

.bodymap-progress .count {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: #D9A96C;
}

/* Grows into whatever the figure leaves, rather than a fixed window: 21 measurements in a
   320px box is a list you scroll blind, and the panel is already as tall as the figure. */
.bodymap-rows {
  display: flex;
  flex-direction: column;
  gap: 6px;
  overflow-y: auto;
  flex: 0 1 auto;
  max-height: 620px;
  padding-inline-end: 4px;
}

.bodymap-group {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  color: rgba(246, 240, 228, 0.3);
  margin-top: 8px;
}

.bodymap-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-radius: 13px;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background .4s ease, border-color .4s ease;
}

.bodymap-row:hover { background: rgba(246, 240, 228, 0.05); }

.bodymap-row.is-active {
  background: rgba(217, 169, 108, 0.14);
  border-color: rgba(217, 169, 108, 0.35);
}

.bodymap-row .row-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
  background: rgba(246, 240, 228, 0.2);
  transition: background .4s ease;
}

.bodymap-row.is-filled .row-dot { background: var(--brand-olive-light, #95A06B); }
.bodymap-row.is-active .row-dot { background: #D9A96C; animation: breathe 2.4s ease-in-out infinite; }
.bodymap-row.is-error  .row-dot { background: #D97A6C; }

/* Required and not measured yet.
   Distinct from an error on purpose: opening a thobe puts six of thirteen rows in this state, and
   painting them all red would say "wrong" about a screen where nothing has happened yet. Red is
   reserved for a value that is actually implausible. */
.bodymap-row.is-needed .row-dot {
  background: none;
  box-shadow: inset 0 0 0 1.5px rgba(217, 169, 108, 0.75);
}

.bodymap-row .row-name {
  flex: 1;
  min-width: 0;
  font-size: 13.5px;
  color: rgba(246, 240, 228, 0.75);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bodymap-row.is-active .row-name { color: #F6F0E4; }

/* The dark panel's own input. Standalone rather than nested under a row, because the same control
   is used outside one. */
.bodymap-input {
  background: rgba(246, 240, 228, 0.06);
  border: 1px solid rgba(246, 240, 228, 0.12);
  border-radius: 8px;
  padding: 5px 6px;
  color: #F6F0E4;
  font-family: var(--font-mono);
  font-size: 15px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  -moz-appearance: textfield;
  appearance: textfield;
}

.bodymap-row .row-value { width: 70px; flex: none; }

/* Marks a measurement the garment cannot be cut without. A quiet asterisk rather than a badge:
   on a thobe most of the list is required, and a badge on every second row is noise. */
.bodymap-row .row-required {
  color: #D9A96C;
  font-family: var(--font-mono);
  font-size: 13px;
  flex: none;
}

/* The garment picker, in the dark panel's language. */
.bodymap-select {
  width: 100%;
  background: rgba(246, 240, 228, 0.06);
  border: 1px solid rgba(246, 240, 228, 0.16);
  border-radius: 10px;
  padding: 9px 11px;
  color: #F6F0E4;
  font-family: inherit;
  font-size: 14px;
}

.bodymap-select:focus { outline: none; border-color: rgba(217, 169, 108, 0.6); }

/* The list is drawn on a dark ground; the popup is drawn by the operating system, which does not
   inherit it. Naming the option colours keeps the text readable when it opens. */
.bodymap-select option { background: #221E18; color: #F6F0E4; }

/* A focus ring that survives the row's own colours.

   The border alone was the whole indicator, and on a row already tinted for "filled", "needed" or
   "in error" it changed almost nothing - so tabbing looked like it had done nothing, and the field
   only appeared to take focus once a click also lit the row. An outline sits outside the border
   and cannot be swallowed by it. */
.bodymap-input:focus {
  outline: 2px solid var(--brand-gold);
  outline-offset: 1px;
  border-color: rgba(217, 169, 108, 0.9);
}

.bodymap-input.is-invalid { border-color: #D97A6C; color: #F0B3A8; }
.bodymap-input.is-warning { border-color: #D9A96C; }

/* A measurement is never stepped one unit at a time, so the spinner is only a mis-click. */
.bodymap-input::-webkit-outer-spin-button,
.bodymap-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.bodymap-row .row-unit {
  font-family: var(--font-mono);
  font-size: 10px;
  color: rgba(246, 240, 228, 0.3);
  flex: none;
}

.bodymap-now {
  padding: 16px;
  border-radius: 15px;
  background: rgba(111, 122, 78, 0.16);
  border: 1px solid rgba(217, 169, 108, 0.16);
}

.bodymap-now .now-head {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 10px;
}

.bodymap-now .ring {
  position: relative;
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  flex: none;
}

.bodymap-now .ring::before {
  content: "";
  position: absolute;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 1px solid rgba(217, 169, 108, 0.6);
  animation: pulseRing 2.6s ease-out infinite;
}

.bodymap-now .ring::after {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #D9A96C;
  animation: breathe 2.6s ease-in-out infinite;
}

.bodymap-now .now-label {
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0;
  color: #D9A96C;
}

.bodymap-now .now-name { font-size: 15px; font-weight: 500; color: #F6F0E4; }

.bodymap-now .now-hint {
  font-size: 13px;
  line-height: 1.75;
  color: rgba(246, 240, 228, 0.6);
  margin-top: 5px;
}

.bodymap-note {
  font-size: 12.5px;
  line-height: 1.7;
  border-radius: 10px;
  padding: 9px 11px;
  margin-top: 9px;
}

.bodymap-note.is-error   { background: rgba(217, 122, 108, 0.16); border: 1px solid rgba(217, 122, 108, 0.4); color: #F0C0B8; }
.bodymap-note.is-warning { background: rgba(217, 169, 108, 0.14); border: 1px solid rgba(217, 169, 108, 0.35); color: #EAD3B4; }
.bodymap-note.is-info    { background: rgba(246, 240, 228, 0.06); color: rgba(246, 240, 228, 0.7); }

.bodymap-actions {
  display: flex;
  gap: 9px;
  margin-top: auto;
}

.btn-map {
  flex: 1;
  padding: 13px;
  border-radius: 12px;
  border: none;
  background: #D9A96C;
  color: #221E18;
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: background .2s ease;
}

.btn-map:hover:not(:disabled) { background: #F6F0E4; }
.btn-map:disabled { opacity: .45; cursor: not-allowed; }

.btn-map-ghost {
  flex: none;
  padding: 13px 18px;
  border-radius: 12px;
  border: 1px solid rgba(246, 240, 228, 0.2);
  background: transparent;
  color: rgba(246, 240, 228, 0.7);
  font-family: inherit;
  font-size: 14px;
  cursor: pointer;
  transition: border-color .2s ease;
}

.btn-map-ghost:hover:not(:disabled) { border-color: rgba(246, 240, 228, 0.5); }
.btn-map-ghost:disabled { opacity: .45; cursor: not-allowed; }

/* The HID keystroke pad, restated in the dark panel's language. */
.bodymap-side .hid-pad {
  margin-block-start: 0;
  padding: 12px 14px;
  background: rgba(246, 240, 228, 0.05);
  border-color: rgba(246, 240, 228, 0.2);
  color: rgba(246, 240, 228, 0.75);
}

.bodymap-side .hid-pad.is-armed {
  background: rgba(217, 169, 108, 0.14);
  border-color: #D9A96C;
  color: #F6F0E4;
}

.bodymap-side .hid-pad .subtle { color: rgba(246, 240, 228, 0.45); }

@media (max-width: 1080px) {
  .bodymap-grid { grid-template-columns: minmax(0, 1fr); }
  .bodymap-side { border-inline-start: none; border-top: 1px solid rgba(246, 240, 228, 0.08); }
  .bodymap-stage { min-height: 620px; }
  .bodymap-side { max-height: none; }
  .bodymap-rows { flex: 0 0 auto; }
}

@media (max-width: 640px) {
  .bodymap { padding: 8px; border-radius: 20px; }
  .bodymap-stage { padding: 24px 12px 60px; }
  .bodymap-figure { transform: scale(0.82); }
}

/* All of this motion is ambience. None of it carries anything the lit limb and the written state
   do not already carry, so switching it off costs nothing. */
@media (prefers-reduced-motion: reduce) {
  .bodymap-drape .drape-a,
  .bodymap-drape .drape-b,
  .bodymap-pill .live-dot,
  .bodymap-row.is-active .row-dot,
  .bodymap-now .ring::before,
  .bodymap-now .ring::after {
    animation: none;
  }

  .bm-part, .bm-band, .bodymap-progress .fill { transition: none; }
}

/* ---------- Garment template editor ---------- */

.template-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: var(--space-4);
  padding-block: var(--space-3);
  border-block-end: 1px solid var(--border);
}

.template-row:last-child { border-block-end: none; }

/* Three states shown as three buttons rather than a dropdown: the whole point of the screen is
   comparing rows at a glance, and twenty-one closed dropdowns show nothing. */
.segmented {
  display: inline-flex;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  overflow: hidden;
  flex: none;
}

.segment {
  border: none;
  background: var(--surface);
  color: var(--text-muted);
  font-family: inherit;
  font-size: .85rem;
  padding: var(--space-2) var(--space-4);
  cursor: pointer;
  white-space: nowrap;
  transition: background .15s ease, color .15s ease;
}

.segment + .segment { border-inline-start: 1px solid var(--border); }

.segment:hover { background: var(--surface-sunken); }

.segment.is-on {
  background: var(--accent);
  color: var(--text-on-brand);
}

@media (max-width: 640px) {
  .template-row { grid-template-columns: 1fr; }
  .segment { flex: 1; padding-inline: var(--space-3); }
  .segmented { width: 100%; }
}

/* ---------- Settings forms ---------- */

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-4);
}

.form-grid .field-wide { grid-column: 1 / -1; }

.table tr.is-muted td { opacity: .55; }

/* ---------- Ease rows ---------- */

.ease-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: var(--space-4);
  padding-block: var(--space-2);
  border-block-end: 1px solid var(--border);
}

.ease-row:last-child { border-block-end: none; }

/* A row with no rule is not an error, just undecided - dimmed rather than marked. */
.ease-row:not(.is-on) .ease-inputs { opacity: .45; }

.ease-name {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  cursor: pointer;
}

.ease-inputs {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.ease-field {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.ease-field .input-measure { width: 84px; }

.ease-preview {
  min-width: 8.5rem;
  text-align: end;
  color: var(--text-muted);
  font-size: .9rem;
}

@media (max-width: 720px) {
  .ease-row { grid-template-columns: 1fr; }
  .ease-inputs { justify-content: space-between; }
  .ease-preview { min-width: 0; }
}

/* ---- Flat garment marking ---------------------------------------------------------------- */

/*
   The image and its marks have to share one coordinate space, or a line drawn over a seam lands
   somewhere else on a different screen. The stage is sized by the image alone - width 100%,
   height auto - so the box always has exactly the photograph's aspect ratio, and an overlay
   stretched across the box lines up with it at any size. That is also why the marking maths in
   flat-mark.js is a single ratio instead of a letterbox calculation.
*/
.flat-stage {
    position: relative;
    display: block;
    width: 100%;
    margin-bottom: 16px;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--surface-sunken);
    cursor: crosshair;
    touch-action: manipulation;   /* No double-tap zoom stealing the second tap of a span. */
}

.flat-stage img {
    display: block;
    width: 100%;
    height: auto;
}

.flat-overlay {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;         /* Every tap belongs to the stage underneath. */
}

.flat-line {
    stroke: var(--accent);
    stroke-width: 6;
    stroke-linecap: round;
    vector-effect: non-scaling-stroke;   /* Same weight on a 600 px photo and a 6000 px one. */
}

.flat-line-ref {
    stroke: var(--success);
    stroke-dasharray: 10 8;
}

.flat-dot {
    fill: var(--accent);
    fill-opacity: 0.85;
}

.flat-targets {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 12px;
}

/*
   Before a picture is chosen the stage still has to be in the page - it holds the <img> the file
   is loaded into - so it gets a height of its own rather than collapsing to nothing.
*/
.flat-stage-empty {
    min-height: 120px;
    border: 1px dashed var(--border);
    cursor: default;
}

/* ---- Working hours ------------------------------------------------------------------------ */

.hours-day {
    display: flex;
    gap: 16px;
    align-items: flex-start;
    padding: 12px 0;
    border-block-end: 1px solid var(--border);
}

.hours-day:last-of-type { border-block-end: none; }

.hours-day-name {
    flex: 0 0 120px;
    padding-block-start: 6px;
}

.hours-periods {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
}

.hours-period {
    display: flex;
    gap: 6px;
    align-items: center;
}

/* A time input sizes itself to a full date otherwise, and six of them wrap the row. */
.hours-period .input { width: 120px; }

@media (max-width: 700px) {
    .hours-day { flex-direction: column; gap: 8px; }
    .hours-day-name { flex: none; padding-block-start: 0; }
}

/* ---------- The design screen ---------- */

/*
   Preview beside the choices, not below them. Below, a clerk changes a collar and sees nothing
   happen, because the thing that changed is off the bottom of a tablet.
*/
.design-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: var(--space-5);
    align-items: start;
}

.design-main { min-width: 0; }

.design-aside {
    position: sticky;
    top: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.design-steps {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-block-end: var(--space-4);
}

.design-step {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--text-muted);
    font: inherit;
    font-size: .85rem;
    cursor: pointer;
}

.design-step:hover { border-color: var(--border-strong); }

.design-step.is-current {
    border-color: var(--accent);
    background: var(--accent-soft);
    color: var(--text);
    font-weight: 600;
}

/* A step still owing a required answer, marked on the tab so it is visible from any other step. */
.design-step.is-pending .design-step-num {
    background: var(--warning);
    color: #fff;
}

.design-step-num {
    display: inline-grid;
    place-items: center;
    inline-size: 22px;
    block-size: 22px;
    border-radius: 50%;
    background: var(--surface-sunken);
    font-family: var(--font-mono);
    font-size: .72rem;
}

.option-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
    gap: var(--space-3);
}

.option-tile {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-1);
    padding: var(--space-2);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    font: inherit;
    text-align: start;
    cursor: pointer;
}

.option-tile:hover { border-color: var(--border-strong); }

.option-tile.is-picked {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--accent-soft);
}

.option-thumb {
    display: grid;
    place-items: center;
    aspect-ratio: 4 / 3;
    overflow: hidden;
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
}

.option-thumb img { inline-size: 100%; block-size: 100%; object-fit: cover; }

.option-swatch { inline-size: 100%; block-size: 100%; }

.option-initial { font-size: 1.4rem; color: var(--text-subtle); }

.option-name { font-size: .85rem; font-weight: 600; }

.option-price { font-size: .78rem; color: var(--accent); }

.option-details { font-size: .72rem; color: var(--text-subtle); }

.thobe-preview svg {
    inline-size: 100%;
    block-size: auto;
    background: var(--surface-sunken);
    border-radius: var(--radius);
}

/* Said plainly rather than in red: an option with no drawing is usually a shop's own addition. */
.thobe-preview-note {
    margin-block-start: var(--space-2);
    font-size: .75rem;
    color: var(--warning);
}

.price-total {
    margin-block-start: var(--space-2);
    padding-block-start: var(--space-2);
    border-top: 1px solid var(--border);
}

@media (max-width: 1000px) {
    .design-layout { grid-template-columns: minmax(0, 1fr); }

    /* Unpinned when it is above the choices rather than beside them: a sticky block at the top of
       a narrow screen would cover the thing being chosen. */
    .design-aside { position: static; order: -1; }
}

/*
   Money needs more room than a measurement does. Sharing .input-measure, a price of 250.00 was
   clipped to "50" in a narrow column - a wrong number, shown confidently, on the screen where the
   shop decides what to charge.
*/
.input-money {
    inline-size: 7.5rem;
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    text-align: end;
}

/* ---------- What a piece is to look like ---------- */

/*
 * A design, as a sheet of answers: each question above its answer, in cells that line up, the cloth
 * first and marked, the tailor's note set apart. On the board it stays a short list.
 */
.design-brief {
    margin-block-end: var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-raised);
    overflow: hidden;
}

.design-brief-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    background: var(--surface-sunken);
    border-block-end: 1px solid var(--border);
    font-size: .85rem;
}

.design-brief-icon { color: var(--accent); flex: none; }

.design-brief-title { font-weight: 700; }

.design-brief-name {
    color: var(--text-muted);
    font-weight: 600;
}

.design-brief-head .design-brief-name::before { content: "· "; color: var(--text-subtle); }

/* On the board the name is the list's own heading. */
.is-compact .design-brief-name { color: var(--text); font-size: .82rem; margin-block-end: 2px; }

.design-brief-count {
    margin-inline-start: auto;
    font-size: .75rem;
    color: var(--text-subtle);
}

/*
 * A hairline grid, drawn by each cell's own end and bottom borders - not by gaps over a coloured
 * ground, which painted the unfilled slot at the end of a short last row as a solid block. The grid
 * reaches one pixel past the card on those two sides, so the outermost lines fall under the card's
 * clipped edge instead of doubling its border. Wide enough for "فتحة الصدر" and its answer; as many
 * across as the card holds.
 */
.design-brief-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    margin: 0 0 -1px;
    margin-inline-end: -1px;
}

.design-brief-cell {
    padding: var(--space-2) var(--space-3);
    background: var(--surface-raised);
    border-inline-end: 1px solid var(--border);
    border-block-end: 1px solid var(--border);
}

.design-brief-cell dt {
    font-size: .72rem;
    color: var(--text-muted);
    margin-block-end: 2px;
}

.design-brief-cell dd {
    margin: 0;
    font-size: .92rem;
    font-weight: 600;
    color: var(--text);
}

.design-brief-cell.is-fabric { background: var(--accent-soft); }
.design-brief-cell.is-fabric dt { color: var(--accent); font-weight: 600; }

.design-brief-note {
    margin: 0;
    padding: var(--space-3);
    border-block-start: 1px solid var(--border);
    border-inline-start: 3px solid var(--accent);
    background: var(--surface-sunken);
    font-size: .88rem;
    line-height: 1.6;
}

.design-brief-note-label {
    display: block;
    font-size: .72rem;
    font-weight: 700;
    color: var(--accent);
    margin-block-end: 2px;
}

/* The board's short list: the answers in one column beside their questions, not flung to the far
   edge of the card. */
.design-brief.is-compact {
    display: grid;
    gap: 2px;
    margin: 0;
    padding: var(--space-2) 0 0;
    background: none;
    border: none;
    border-radius: 0;
    overflow: visible;
}

.design-brief-line {
    display: grid;
    grid-template-columns: minmax(4.5rem, auto) 1fr;
    gap: var(--space-2);
    font-size: .8rem;
}

.design-brief-line span { color: var(--text-muted); }
.design-brief-line strong { font-weight: 600; }

/* ---------- The customer portal ---------- */

/*
   Its own shell, not the shop's. A customer sees one narrow column and no navigation: the workshop,
   the order book and the settings are not theirs to know about, let alone to be offered.
*/
.portal-shell {
    max-inline-size: 640px;
    margin-inline: auto;
    padding: var(--space-4);
}

.portal-header {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding-block-end: var(--space-4);
    border-bottom: 1px solid var(--border);
    margin-block-end: var(--space-5);
}

.portal-main { display: grid; gap: var(--space-4); }

.portal-dates {
    display: flex;
    gap: var(--space-6);
    margin-block-end: var(--space-4);
}

.portal-dates > div { display: grid; gap: 2px; }

.portal-piece {
    padding: var(--space-3) 0;
    border-top: 1px solid var(--border);
    display: grid;
    gap: 2px;
}

.portal-balance {
    margin-block-start: var(--space-3);
    padding-block-start: var(--space-3);
    border-top: 1px solid var(--border);
}

/* ---------- Chart ----------
 *
 * The plot and its axis band share one box, so the card never grows a nested scrollbar to reach
 * the dates. Marks are thin and the grid is a hairline one step off the surface: the data is the
 * only thing on a chart allowed to be loud. */

.chart { margin: 0; }

/* Height from the ratio, never fixed: a fixed height with a 720x260 viewBox squashes the marks
 * horizontally, which reads as a rendering fault rather than as the chart being wrong. */
.chart-svg {
  width: 100%;
  height: auto;
  overflow: visible;
}

.chart-grid, .chart-axis {
  stroke: var(--border);
  stroke-width: 1;
}

.chart-axis { stroke: var(--border-strong); }

.chart-line {
  fill: none;
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}

/* The ring is the surface colour so a marker stays legible where the lines cross. A stroke in
 * any other colour would be ink that is not data. */
.chart-dot {
  stroke: var(--surface);
  stroke-width: 2;
}

/* Axis text never wears a series colour: a mid-tone hue is illegible as small text, and identity
 * is carried by the swatch beside the label instead. */
.chart-tick {
  fill: var(--text-muted);
  font-size: 11px;
  text-anchor: start;
}

.chart-tick-x { text-anchor: middle; }

.chart-value {
  fill: var(--text);
  font-size: 12px;
  font-weight: 600;
  text-anchor: middle;
}

.chart-legend {
  display: flex;
  gap: var(--space-4);
  flex-wrap: wrap;
  margin-block-end: var(--space-3);
  color: var(--text-muted);
  font-size: .85rem;
}

.chart-key { display: inline-flex; align-items: center; gap: var(--space-2); }

.chart-swatch {
  inline-size: 14px;
  block-size: 3px;
  border-radius: 2px;
}

/* ---------- Page furniture, dressed ----------
 *
 * Every colour here is a brand token already in this file, washed over the same cards the rest of
 * the file defines. It began on the two report pages and now dresses every screen: a shop should
 * not be able to tell which pages were worked on last.
 *
 * Nothing here is interactive, so nothing here lifts, glows or moves on hover: a card that
 * responds to the pointer promises a click that does not exist. */

.page-header {
  position: relative;
  overflow: hidden;
  padding: var(--space-5) var(--space-6);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background:
    radial-gradient(120% 150% at 100% 0%, rgba(var(--skin-tint-rgb), .30), transparent 64%),
    linear-gradient(180deg, var(--surface-raised), var(--surface-sunken));
}

/* A bolt of cloth seen close up: diagonal threads, faded out before they reach the text so they
 * stay texture and never become pattern. */
.page-header::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(
    135deg,
    rgba(var(--skin-thread-rgb), .11) 0 1px,
    transparent 1px 10px);
  -webkit-mask-image: linear-gradient(to left, #000, transparent 60%);
  mask-image: linear-gradient(to left, #000, transparent 60%);
}

.page-header > * { position: relative; z-index: 1; }

.page-header .page-title { font-size: 1.55rem; letter-spacing: -.01em; }

.page-header .page-subtitle { color: var(--text-muted); }

/* A hairline of the brand before every section name. Cheap, quiet, and it turns a page of cards
 * into a page with a spine. */
.card-title::before {
  content: "";
  display: inline-block;
  inline-size: 3px;
  block-size: 1em;
  border-radius: 2px;
  margin-inline-end: var(--space-3);
  vertical-align: -.15em;
  background: var(--accent);
}

/* ---------- Figure cards ---------- */

/* Opted into by a card that wants the treatment, rather than applied to every .stat in the
 * product: a figure card inside a dense panel is a different thing from one at the top of a page,
 * and giving both a coloured edge makes neither mean anything. */
.stat-tone {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* The tone is the card's identity, carried on an edge and in one small glyph rather than by
 * colouring the number - a figure in a mid-tone hue is harder to read and says nothing extra. */
.stat-tone::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  block-size: 3px;
  background: var(--stat-tone, var(--accent));
}

.stat-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.stat-icon {
  flex: none;
  inline-size: 34px;
  block-size: 34px;
  border-radius: 11px;
  display: grid;
  place-items: center;
  color: var(--stat-tone, var(--accent));
  background: var(--stat-tone-soft, var(--accent-soft));
}

.stat-icon-glyph { inline-size: 19px; block-size: 19px; }

.stat-head .stat-label { margin: 0; }

/* Lining figures of one width, so a column of money lines up on the decimal instead of shuffling
 * as the digits change. */
.stat-value { font-variant-numeric: tabular-nums; }

.stat-gold   { --stat-tone: var(--brand-bronze); --stat-tone-soft: var(--accent-soft); }
.stat-olive  { --stat-tone: var(--success);      --stat-tone-soft: var(--success-soft); }
.stat-clay   { --stat-tone: var(--danger);       --stat-tone-soft: var(--danger-soft); }
.stat-stone  { --stat-tone: var(--brand-stone-deep); --stat-tone-soft: var(--surface-sunken); }

/* A card that is already shouting keeps its own colour on the edge too, rather than wearing the
 * default bronze above a red border. */
.stat.is-alarm { --stat-tone: var(--danger); }

/* Four figures across at a desk, two on a tablet, one on a phone - stepped rather than auto-fit,
 * because auto-fit lands on three and a widow at exactly the width a tablet is held at. */
.stat-row { grid-template-columns: repeat(4, minmax(0, 1fr)); }

@media (max-width: 1040px) {
  .stat-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 540px) {
  .stat-row { grid-template-columns: 1fr; }
}

/* ---------- Tables ---------- */

.table tbody tr { transition: background-color 160ms ease; }

.table tbody tr:hover { background: var(--surface-sunken); }

.table td, .table th { font-variant-numeric: tabular-nums; }

/* The last row of the money tables is a total; it reads as one without a second colour. */
.table tbody tr:last-child strong { color: var(--text); }

@media (prefers-reduced-motion: reduce) {
  .table tbody tr { transition: none; }
}

[data-theme="dark"] .page-header {
  background:
    radial-gradient(120% 150% at 100% 0%, rgba(var(--skin-tint-rgb), .13), transparent 62%),
    linear-gradient(180deg, var(--surface-raised), var(--surface));
}

[data-theme="dark"] .page-header::after {
  background: repeating-linear-gradient(
    135deg,
    rgba(var(--skin-tint-rgb), .06) 0 1px,
    transparent 1px 10px);
}

/* ---------- The creative palette ----------
 *
 * A second skin over the same components: violet on soft lilac, rounder corners, and soft shadows
 * doing the separating that hairlines do in the classic palette.
 *
 * It changes tokens only. Every screen in the product is drawn from these names, so a palette that
 * redefined a component would be a second design system to maintain - and the first screen nobody
 * remembered to restyle would be the one a shop noticed.
 *
 * The dark step is SELECTED for its ground, not computed by flipping the light one: the violet is
 * lifted and desaturated so it still clears contrast on a near-black surface. */

[data-theme="creative"] {
  --surface: #FFFFFF;
  --surface-sunken: #E9E7F2;
  --surface-raised: #FFFFFF;
  --border: #ECEAF5;
  --border-strong: #C7C2E2;

  --text: #2E2A55;

  /* A step darker than the mockup's #6C6791: on the lilac page ground that reads 4.31:1, and a
   * label is body text. On white it was already fine, which is how this kind of miss survives. */
  --text-muted: #68638B;
  --text-subtle: #8781AB;
  --text-on-brand: #FFFFFF;

  --accent: #7D5EE0;
  --accent-hover: #613EBE;
  --accent-soft: #F2F0FA;
  --accent-strong: #613EBE;

  --success: #3C8256;
  --success-soft: #DFF3E4;
  --warning: #B5762A;
  --warning-soft: #FFEED6;
  --danger: #C2415A;
  --danger-soft: #FFE3E6;

  --success-ink: #37784F;
  --warning-ink: #946022;
  --danger-ink: #B33C53;

  /* Bigger radii and softer shadows are the whole character of this palette - a violet box with
   * 6px corners and a hairline border is just the classic theme in a different colour. */
  --radius-sm: 10px;
  --radius: 16px;
  --radius-lg: 24px;
  --shadow-sm: 0 6px 16px rgba(64, 54, 122, .07);
  --shadow: 0 16px 40px rgba(64, 54, 122, .09);
  --shadow-lg: 0 30px 70px rgba(64, 54, 122, .16);

  --font-display: "Tajawal", "IBM Plex Sans Arabic", system-ui, sans-serif;
  --font-figure: "Tajawal", "IBM Plex Sans Arabic", system-ui, sans-serif;

  --skin-tint-rgb: 125, 94, 224;
  --skin-thread-rgb: 108, 103, 145;

  /* White, like the cards - this palette separates planes with shadow rather than with a dark
     block. The chosen item is a soft chip with violet text, not a solid violet bar: a filled
     accent that size becomes the loudest thing on a page whose whole character is quiet. */
  --nav-surface: #FFFFFF;
  --nav-border: #ECEAF5;
  --nav-divider: #ECEAF5;
  --nav-text: #68638B;
  --nav-text-strong: #2E2A55;
  --nav-muted: #8781AB;
  --nav-hover: #F5F4FB;
  --nav-active: #F2F0FA;
  --nav-active-text: #613EBE;
  /* Both stops dark enough for the white letter on them: the lighter violet gave it 2.81:1. */
  --nav-mark: linear-gradient(135deg, #7D5EE0, #613EBE);
  --nav-mark-text: #FFFFFF;

  /* Violet and teal, checked against this surface rather than chosen to match it: 21.0 apart under
   * normal vision and 14.1 under deuteranopia. The classic theme's blue and orange are stronger
   * still, but blue beside a violet page reads as a third accent nobody chose. */
  --chart-series-1: #7D5EE0;
  --chart-series-2: #00929D;

  color-scheme: light;
}

[data-theme="creative-dark"] {
  --surface: #221E3D;
  --surface-sunken: #191630;
  --surface-raised: #292447;
  --border: #37325C;
  --border-strong: #4A4478;

  --text: #EDEBF8;
  --text-muted: #B3ADD6;
  --text-subtle: #8781AB;
  --text-on-brand: #1A1730;

  --accent: #9E8AFA;
  --accent-hover: #B4A5FF;
  --accent-soft: #312B57;
  --accent-strong: #9E8AFA;

  --success: #6FBF8C;
  --success-soft: #24402F;
  --warning: #E0A65A;
  --warning-soft: #3E3220;
  --danger: #E8788F;
  --danger-soft: #3E2330;

  --success-ink: var(--success);
  --warning-ink: var(--warning);
  --danger-ink: var(--danger);

  --radius-sm: 10px;
  --radius: 16px;
  --radius-lg: 24px;
  --shadow-sm: 0 6px 16px rgba(0, 0, 0, .35);
  --shadow: 0 16px 40px rgba(0, 0, 0, .45);
  --shadow-lg: 0 30px 70px rgba(0, 0, 0, .55);

  --font-display: "Tajawal", "IBM Plex Sans Arabic", system-ui, sans-serif;
  --font-figure: "Tajawal", "IBM Plex Sans Arabic", system-ui, sans-serif;

  --skin-tint-rgb: 158, 138, 250;
  --skin-thread-rgb: 179, 173, 214;

  --nav-surface: #1B1832;
  --nav-border: #2E2950;
  --nav-divider: #2E2950;
  --nav-text: #B3ADD6;
  --nav-text-strong: #EDEBF8;
  --nav-muted: #8781AB;
  --nav-hover: #262149;
  --nav-active: #312B57;
  --nav-active-text: #B4A5FF;
  --nav-mark: linear-gradient(135deg, #9E8AFA, #7D5EE0);
  --nav-mark-text: #1A1730;

  /* Stepped down into the dark band rather than reused from the light theme: the first pair tried
   * here sat at L 0.70 and 0.71, too light to read as marks against #221E3D. */
  --chart-series-1: #8D75EB;
  --chart-series-2: #00A1A9;

  color-scheme: dark;
}

/* The hero's ground follows the palette, so the wash is not always the classic gradient with a
 * different tint poured over it. */
[data-theme="creative"] .page-header,
[data-theme="creative-dark"] .page-header {
  border-color: transparent;
  background:
    radial-gradient(120% 150% at 100% 0%, rgba(var(--skin-tint-rgb), .26), transparent 64%),
    linear-gradient(180deg, var(--surface-raised), var(--surface-sunken));
  box-shadow: var(--shadow-sm);
}

[data-theme="ocean"] {
  --surface: #FFFFFF;
  --surface-sunken: #F1F8F8;
  --surface-raised: #FFFFFF;
  --border: #E1ECEE;
  --border-strong: #BFD5D9;

  --text: #0F2A3D;
  --text-muted: #4B6272;
  --text-subtle: #6E8391;
  --text-on-brand: #FFFFFF;

  /* Turquoise for lines and edges; the deeper step for anything filled, because white on the
     lighter turquoise is 3.7:1 - enough for a border, not for a button's label. */
  --accent: #0D9488;
  --accent-hover: #0F766E;
  --accent-soft: #E6F7F5;
  --accent-strong: #0F766E;

  --success: #059669;
  --success-soft: #DDF6EC;
  --warning: #D97706;
  --warning-soft: #FEF3C7;
  --danger: #DC2626;
  --danger-soft: #FEE2E2;

  --success-ink: #047857;
  --warning-ink: #92400E;
  --danger-ink: #B91C1C;

  --radius-sm: 8px;
  --radius: 14px;
  --radius-lg: 20px;
  --shadow-sm: 0 2px 8px rgba(15, 42, 61, .06);
  --shadow: 0 10px 28px rgba(15, 42, 61, .08);
  --shadow-lg: 0 24px 56px rgba(15, 42, 61, .14);

  --skin-tint-rgb: 13, 148, 136;
  --skin-thread-rgb: 14, 165, 233;

  /* White like the front page's bar, the chosen item a soft turquoise chip. The mark keeps the
     brand's gold, as it does on the front page, with a dark letter it reads well against. */
  --nav-surface: #FFFFFF;
  --nav-border: #E1ECEE;
  --nav-divider: #E1ECEE;
  --nav-text: #4B6272;
  --nav-text-strong: #0F2A3D;
  --nav-muted: #6E8391;
  --nav-hover: #F1F8F8;
  --nav-active: #E6F7F5;
  --nav-active-text: #0F766E;
  --nav-mark: linear-gradient(135deg, #F2C377, #D9974A);
  --nav-mark-text: #1A1206;

  --chart-series-1: #0D9488;
  --chart-series-2: #E07A10;

  color-scheme: light;
}

[data-theme="ocean"] .page-header {
  border-color: transparent;
  background:
    radial-gradient(120% 150% at 100% 0%, rgba(13, 148, 136, .16), transparent 62%),
    radial-gradient(90% 120% at 0% 100%, rgba(14, 165, 233, .12), transparent 60%),
    linear-gradient(180deg, #FFFFFF, #F1F8F8);
  box-shadow: var(--shadow-sm);
}

/* ---------- The theme picker ---------- */

.theme-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--space-4);
}

.theme-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
  text-align: start;
  font: inherit;
  color: inherit;
  transition: border-color 160ms ease, box-shadow 160ms ease;
}

.theme-card:hover { border-color: var(--border-strong); }

.theme-card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* The chosen one is marked by a ring AND by the word beside its name - a border alone is a
 * difference in colour, which is the one channel some readers do not have. */
.theme-card.is-chosen {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}

.theme-swatches {
  display: flex;
  gap: 6px;
}

.theme-swatch {
  inline-size: 34px;
  block-size: 34px;
  border-radius: 10px;
  border: 1px solid rgba(0, 0, 0, .08);
}

.theme-name { font-weight: 600; }

.theme-note { font-size: .82rem; color: var(--text-muted); line-height: 1.6; }

@media (prefers-reduced-motion: reduce) {
  .theme-card { transition: none; }
}

/* ---------- Wide tables, on a phone ----------
 *
 * Each row becomes a card carrying its own labels. The class is put on by table-cards.js, on any
 * table with four or more columns - narrow ones stay tables, because a card per row around two
 * facts is chrome, not clarity.
 *
 * The head is hidden from sight but not from a screen reader: the row is still a row to anything
 * reading the markup, and `display: none` would take the column names away from the reader who
 * needs them most. */

@media (max-width: 640px) {
  .table-cards thead {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .table-cards,
  .table-cards tbody,
  .table-cards tr,
  .table-cards td {
    display: block;
    inline-size: 100%;
  }

  .table-cards tr {
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    margin-block-end: var(--space-3);
    padding: var(--space-2) var(--space-4);
  }

  .table-cards tr:last-child { margin-block-end: 0; }

  .table-cards td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-2) 0;
    border-block-end: 1px solid var(--border);
    text-align: start;
  }

  .table-cards td:last-child { border-block-end: none; }

  /* Empty when the cell has no label - a spanning cell, or markup the script has not reached yet.
     It reads as a plain line rather than as a broken one. */
  .table-cards td::before {
    content: attr(data-label);
    color: var(--text-muted);
    font-size: .8rem;
    flex: none;
  }

  /* The row's own scroll container is pointless once nothing is wide. */
  .table-scroll:has(.table-cards) { overflow-x: visible; }
}


/* ---------- Plans: the header badge, the plan cards, the add-on, the upgrade quote ---------- */

/*
 * One colour per plan, set once here and read by the badge and the cards alike, so the plan a shop
 * sees in the header is the same colour as its card on the subscription page. As channels, for the
 * tints; the fill is its own gradient because a flat stone or olive disc reads as a disabled button.
 *
 * Brand hues on purpose, and fixed across the four palettes: a plan's colour is its identity, not
 * part of the theme. Only the text beside them follows the palette.
 */
[data-tier] {
  --tier-rgb: 138, 130, 118;
  --tier-fill: linear-gradient(135deg, #A39B8F, #6B6459);
  --tier-ink: #FFFFFF;
}

[data-tier="basic"] {
  --tier-rgb: 111, 122, 78;
  --tier-fill: linear-gradient(135deg, #95A06B, #5C6640);
}

[data-tier="pro"] {
  --tier-rgb: 176, 125, 70;
  --tier-fill: linear-gradient(135deg, #D9A96C, #8A5C2C);
}

/* Ink and gold: the one plan drawn dark, with the crown in the brand's gold. */
[data-tier="enterprise"] {
  --tier-rgb: 217, 169, 108;
  --tier-fill: linear-gradient(135deg, #3A3128, #1B1813);
  --tier-ink: #D9A96C;
}

[data-tier="trial"] {
  --tier-rgb: 42, 120, 214;
  --tier-fill: linear-gradient(135deg, #5A9BE6, #2A78D6);
}

/* ----- the header ----- */

.app-shop-name { font-family: var(--font-display); }

.plan-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding-block: 3px;
  padding-inline: 3px 11px;
  border-radius: 999px;
  border: 1px solid rgba(var(--tier-rgb), .38);
  background: rgba(var(--tier-rgb), .10);
  color: var(--text);
  font-size: .76rem;
  font-weight: 600;
  line-height: 1.35;
  white-space: nowrap;
  transition: background .15s ease, border-color .15s ease, box-shadow .15s ease;
}

a.plan-chip:hover {
  color: var(--text);
  text-decoration: none;
  background: rgba(var(--tier-rgb), .18);
  border-color: rgba(var(--tier-rgb), .6);
  box-shadow: 0 2px 8px rgba(var(--tier-rgb), .18);
}

.plan-chip-mark {
  display: inline-grid;
  place-items: center;
  inline-size: 20px;
  block-size: 20px;
  border-radius: 50%;
  background: var(--tier-fill);
  color: var(--tier-ink);
  box-shadow: 0 1px 3px rgba(var(--tier-rgb), .45);
}

.plan-chip-extra { color: var(--text-muted); font-weight: 500; }

/* The one date worth a glance - the trial's last day, a cancellation's - after a hairline. */
.plan-chip-note {
  padding-inline-start: 7px;
  border-inline-start: 1px solid rgba(var(--tier-rgb), .35);
  color: var(--text-muted);
  font-weight: 500;
}

@media (max-width: 540px) {
  .plan-chip-extra, .plan-chip-note { display: none; }
}

/* ----- the section on the subscription page ----- */

.plans-section { margin-block: var(--space-6) var(--space-5); }

.plans-section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-4);
  margin-block-end: var(--space-4);
}

.plans-section-title {
  margin: 0 0 var(--space-1);
  font-family: var(--font-display);
  font-size: 1.3rem;
}

.plans-section-sub { margin: 0; max-inline-size: 62ch; font-size: .86rem; color: var(--text-muted); }

/* ----- the cards ----- */

/* As many as fit: four across on a desk, two on a tablet, one on a phone - and the same rule inside
   the narrow signup card, where a fixed four would crush them. */
.plan-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(214px, 1fr));
  gap: var(--space-4);
}

/* Four, two or one - never three and an orphan. Measured on the space the cards actually have
   (the signup card is narrow on a wide screen), so a container query rather than the window. The
   auto-fit above is the fallback for a browser without them. */
.plan-cards { container-type: inline-size; }

@container (min-width: 460px) {
  .plan-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@container (min-width: 940px) {
  .plan-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.plan-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5);
  padding-block-start: calc(var(--space-5) + 4px);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}

/* The plan's colour as a band across the top: enough to tell four cards apart at a glance. */
.plan-card::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  block-size: 4px;
  background: var(--tier-fill);
}

.plan-card[data-tier="enterprise"]::before {
  background: linear-gradient(90deg, var(--brand-bronze), var(--brand-gold), var(--brand-bronze));
}

.plan-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow);
  border-color: rgba(var(--tier-rgb), .45);
}

.plan-card.is-current {
  border-color: rgba(var(--tier-rgb), .75);
  background:
    linear-gradient(180deg, rgba(var(--tier-rgb), .08), transparent 42%),
    var(--surface);
  box-shadow: 0 0 0 3px rgba(var(--tier-rgb), .16), var(--shadow);
}

.plan-card-head { display: flex; align-items: flex-start; gap: var(--space-3); }

.plan-card-mark {
  flex: none;
  display: grid;
  place-items: center;
  inline-size: 38px;
  block-size: 38px;
  border-radius: 11px;
  background: var(--tier-fill);
  color: var(--tier-ink);
  box-shadow: 0 6px 14px rgba(var(--tier-rgb), .28);
}

.plan-card[data-tier="enterprise"] .plan-card-mark {
  box-shadow: inset 0 0 0 1px rgba(217, 169, 108, .55), 0 6px 14px rgba(27, 24, 19, .3);
}

.plan-card-title { flex: 1; min-inline-size: 0; }

.plan-card-name-row { display: flex; align-items: center; flex-wrap: wrap; gap: 4px var(--space-2); }

.plan-card-name {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.12rem;
  font-weight: 700;
  line-height: 1.3;
}

.plan-card-tagline { margin: 0; font-size: .8rem; color: var(--text-muted); }

.plan-card-flag {
  flex: none;
  padding: 2px 9px;
  border-radius: 999px;
  border: 1px solid rgba(var(--tier-rgb), .45);
  background: rgba(var(--tier-rgb), .14);
  color: var(--text);
  font-size: .7rem;
  font-weight: 700;
  white-space: nowrap;
}

.plan-price { display: flex; align-items: flex-end; gap: var(--space-2); margin-block-start: var(--space-1); }

.plan-price-figure {
  font-family: var(--font-figure);
  font-size: 2.35rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -.02em;
}

.plan-price-unit { padding-block-end: 3px; font-size: .74rem; line-height: 1.25; color: var(--text-muted); }

.plan-price.is-small .plan-price-figure { font-size: 1.65rem; }

.plan-price-alt { margin: 0; font-size: .76rem; color: var(--text-subtle); }

/* The same rows in every card, ticked or crossed: the difference between two plans is the rows
   that differ, which the eye finds faster than it reads two paragraphs. */
.plan-features {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin: var(--space-1) 0 0;
  padding: var(--space-3) 0 0;
  border-block-start: 1px dashed var(--border);
  list-style: none;
  font-size: .86rem;
}

.plan-features li { display: flex; align-items: flex-start; gap: var(--space-2); line-height: 1.45; }

.plan-features li::before {
  content: "";
  flex: none;
  inline-size: 18px;
  block-size: 18px;
  margin-block-start: 1px;
  border-radius: 50%;
  background-repeat: no-repeat;
  background-position: center;
  background-size: 11px;
}

.plan-features .is-yes::before {
  background-color: var(--success-soft);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 6.3l2.2 2.2 4.8-5' fill='none' stroke='%236F7A4E' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.plan-features .is-no { color: var(--text-subtle); }

.plan-features .is-no::before {
  background-color: var(--surface-sunken);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3.5 3.5l5 5M8.5 3.5l-5 5' fill='none' stroke='%238A8276' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
}

.plan-features .is-addon::before {
  background-color: var(--accent-soft);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M6 2.8v6.4M2.8 6h6.4' fill='none' stroke='%23B07D46' stroke-width='1.7' stroke-linecap='round'/%3E%3C/svg%3E");
}

.plan-features.is-inline {
  flex: none;
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  margin: 0 0 var(--space-2);
  padding: 0;
  border: 0;
}

.plan-card-foot { display: flex; align-items: center; min-block-size: 40px; margin-block-start: var(--space-1); }

.plan-card-cta { inline-size: 100%; justify-content: center; }

.plan-card-note { font-size: .8rem; color: var(--text-muted); }

/* ----- the devices add-on ----- */

.addon-card {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--space-4) var(--space-5);
  margin-block-start: var(--space-4);
  padding: var(--space-5);
  border: 1px dashed rgba(var(--brand-bronze-rgb), .55);
  border-radius: var(--radius-lg);
  background:
    linear-gradient(120deg, rgba(var(--brand-gold-rgb), .12), transparent 55%),
    var(--surface);
}

.addon-card.is-current {
  border-style: solid;
  border-color: rgba(var(--brand-gold-rgb), .8);
  box-shadow: 0 0 0 3px rgba(var(--brand-gold-rgb), .16);
}

.addon-card-mark {
  display: grid;
  place-items: center;
  inline-size: 50px;
  block-size: 50px;
  border-radius: 14px;
  background: linear-gradient(135deg, var(--brand-gold), var(--brand-bronze));
  color: var(--brand-ink);
  box-shadow: 0 6px 16px rgba(var(--brand-bronze-rgb), .3);
}

.addon-card-title { display: flex; align-items: center; gap: var(--space-2); margin-block-end: var(--space-2); }

.addon-card-side { display: flex; flex-direction: column; align-items: flex-end; gap: var(--space-2); }

.addon-toggle { display: inline-flex; align-items: center; gap: var(--space-2); font-size: .82rem; cursor: pointer; }

@media (max-width: 640px) {
  .addon-card { grid-template-columns: auto 1fr; }

  .addon-card-side {
    grid-column: 1 / -1;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

/* ----- the quote before an upgrade ----- */

.upgrade-offer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-block-end: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border: 1px solid rgba(var(--brand-bronze-rgb), .4);
  border-radius: var(--radius-lg);
  background: var(--accent-soft);
}

.upgrade-offer-lines {
  display: grid;
  grid-template-columns: auto auto;
  gap: 2px var(--space-6);
  max-inline-size: 320px;
  margin-block: var(--space-2);
  font-size: .86rem;
}

.upgrade-offer-lines span:nth-child(even) { text-align: end; }

.upgrade-offer-actions { display: flex; gap: var(--space-2); }

@media (prefers-reduced-motion: reduce) {
  .plan-card, .plan-chip { transition: none; }
  .plan-card:hover { transform: none; }
}

/* ==========================================================================
   Public front page (/ for visitors, /welcome by name)
   Its own palette, in every theme, and all of it in the variables below: a light
   ground, turquoise and ocean blue as the lead, amber as the warm accent, and six
   jewels that colour the features one each. Changing the page's colours is
   changing these lines and nothing else.
   ========================================================================== */

.landing {
  /* words */
  --lp-ink: #0F2A3D;
  --lp-ink-2: #4B6272;
  --lp-ink-3: #6E8391;
  --lp-line: rgba(15, 42, 61, .09);

  /* the lead pair and the warm accent */
  --lp-primary: #0D9488;
  --lp-primary-rgb: 13, 148, 136;
  --lp-secondary: #0EA5E9;
  --lp-secondary-rgb: 14, 165, 233;
  --lp-accent: #F59E0B;
  --lp-accent-rgb: 245, 158, 11;
  --lp-indigo: #6366F1;

  --lp-primary-grad: linear-gradient(135deg, #14B8A6 0%, #0D9488 45%, #0EA5E9 100%);
  --lp-text-grad: linear-gradient(100deg, #0EA5E9 0%, #0D9488 40%, #0F2A3D 85%);
  --lp-line-grad: linear-gradient(90deg, #14B8A6, #0EA5E9, #F59E0B);
  --lp-mark-grad: linear-gradient(135deg, #FFD89A 0%, #F2C377 40%, #D9974A 100%);

  /* grounds */
  --lp-hero-base: linear-gradient(180deg, #F7FFFD 0%, #F1F8FF 100%);
  --lp-soft: #F0FBFA;
  --lp-final: linear-gradient(120deg, #0EA5E9 0%, #0D9488 55%, #0F766E 100%);
  --lp-final-ink: #0F766E;
  --lp-footer: linear-gradient(180deg, #F0FBFA, #F1F6FF);

  /* the six jewels, in the order the feature cards take them */
  --lp-j1: #0D9488; --lp-j1b: #5EEAD4;
  --lp-j2: #0EA5E9; --lp-j2b: #7DD3FC;
  --lp-j3: #6366F1; --lp-j3b: #A5B4FC;
  --lp-j4: #F59E0B; --lp-j4b: #FCD34D;
  --lp-j5: #10B981; --lp-j5b: #6EE7B7;
  --lp-j6: #EC4899; --lp-j6b: #F9A8D4;

  min-height: 100vh;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-sans);
  overflow-x: clip;
}

html:has(.landing) { scroll-behavior: smooth; scroll-padding-top: 80px; }

.landing-wrap { width: min(1160px, 100% - 32px); margin-inline: auto; }
.landing-narrow { width: min(820px, 100% - 32px); }

.landing a { text-decoration: none; }

.landing-announce {
  background: var(--lp-final);
  color: #fff;
  text-align: center;
  font-size: .88rem;
  font-weight: 500;
  padding: 9px 16px;
}
.landing-announce a { color: #fff; font-weight: 700; }
.landing-announce a:hover { text-decoration: underline; }

/* ---- navigation ---- */
.landing-nav {
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(255, 255, 255, .82);
  backdrop-filter: saturate(1.6) blur(14px);
  border-bottom: 1px solid var(--lp-line);
  box-shadow: 0 4px 24px rgba(15, 42, 61, .05);
}
.landing-nav-inner { display: flex; align-items: center; gap: var(--space-5); min-height: 68px; }

.landing-brand { display: inline-flex; align-items: center; gap: 10px; color: var(--lp-ink); }
.landing-brand .app-brand-mark {
  flex: none;
  background: var(--lp-mark-grad);
  color: #1A1206;
  box-shadow: 0 6px 18px rgba(217, 151, 74, .35);
}
.landing-brand-name { font-weight: 800; font-size: 1.12rem; letter-spacing: .2px; }

.landing-links { display: flex; gap: var(--space-5); margin-inline-start: var(--space-5); }
.landing-links a { position: relative; color: var(--lp-ink-2); font-size: .95rem; padding-block: 6px; transition: color .15s; }
.landing-links a::after {
  content: ""; position: absolute; inset-inline: 0; bottom: 0; height: 2px; border-radius: 2px;
  background: var(--lp-primary-grad); transform: scaleX(0); transition: transform .2s ease;
}
.landing-links a:hover { color: var(--lp-primary); }
.landing-links a:hover::after { transform: scaleX(1); }

.landing-actions { display: flex; gap: var(--space-2); margin-inline-start: auto; }

.landing-btn-ghost {
  background: #fff;
  color: var(--lp-ink);
  border: 1px solid rgba(15, 42, 61, .14);
  box-shadow: 0 2px 8px rgba(15, 42, 61, .05);
}
.landing-btn-ghost:hover { background: var(--lp-soft); border-color: rgba(var(--lp-primary-rgb), .5); color: var(--lp-primary); }

.landing .btn-primary {
  position: relative;
  overflow: hidden;
  background: var(--lp-primary-grad);
  color: #fff;
  font-weight: 800;
  border: 0;
  box-shadow: 0 8px 26px rgba(var(--lp-primary-rgb), .35), inset 0 1px 0 rgba(255, 255, 255, .3);
  transition: transform .15s ease, box-shadow .2s ease;
}
/* A sheen that crosses the button on hover. */
.landing .btn-primary::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(110deg, transparent 30%, rgba(255, 255, 255, .4) 50%, transparent 70%);
  transform: translateX(-120%); transition: transform .6s ease;
}
.landing .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 14px 34px rgba(var(--lp-primary-rgb), .45), inset 0 1px 0 rgba(255, 255, 255, .3); background: var(--lp-primary-grad); color: #fff; }
.landing .btn-primary:hover::after { transform: translateX(120%); }

.landing-btn-lg { padding: 14px 30px; font-size: 1.04rem; border-radius: 14px; }

/* ---- hero ---- */
.landing-hero {
  position: relative;
  isolation: isolate;
  background:
    radial-gradient(620px 420px at 90% 5%, rgba(var(--lp-primary-rgb), .20), transparent 62%),
    radial-gradient(560px 460px at 5% 25%, rgba(var(--lp-secondary-rgb), .18), transparent 60%),
    radial-gradient(520px 380px at 50% 110%, rgba(var(--lp-accent-rgb), .16), transparent 62%),
    var(--lp-hero-base);
  color: var(--lp-ink);
  padding-block: 80px 60px;
}
/* A fine grid over the glow - depth without noise. */
.landing-hero::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background-image:
    linear-gradient(rgba(15, 42, 61, .045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(15, 42, 61, .045) 1px, transparent 1px);
  background-size: 44px 44px;
  mask-image: radial-gradient(ellipse at 50% 30%, #000 30%, transparent 75%);
}
/* A stitch line along the hero's foot - the trade's own mark. */
.landing-hero::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: 18px;
  border-bottom: 2px dashed rgba(var(--lp-primary-rgb), .3);
}

.landing-hero-grid {
  display: grid;
  grid-template-columns: 1.05fr .95fr;
  gap: 56px;
  align-items: center;
}

.landing-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 16px;
  border-radius: 999px;
  background: linear-gradient(#fff, #fff) padding-box, var(--lp-line-grad) border-box;
  border: 1px solid transparent;
  color: var(--lp-primary);
  font-size: .86rem;
  font-weight: 700;
  margin-block-end: 18px;
  box-shadow: 0 4px 14px rgba(var(--lp-primary-rgb), .12);
}
.landing-eyebrow::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%;
  background: var(--lp-accent);
  box-shadow: 0 0 0 4px rgba(var(--lp-accent-rgb), .2), 0 0 10px var(--lp-accent);
}

.landing-title {
  font-size: clamp(2rem, 1.3rem + 2.7vw, 3.5rem);
  line-height: 1.3;
  font-weight: 800;
  margin: 0 0 var(--space-5);
  color: var(--lp-ink);
  background: var(--lp-text-grad);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  text-wrap: balance;
}

.landing-lead {
  font-size: clamp(1.02rem, .95rem + .3vw, 1.2rem);
  line-height: 1.95;
  color: var(--lp-ink-2);
  margin: 0 0 var(--space-6);
  max-width: 58ch;
}

.landing-cta-row { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.landing-fineprint { margin: var(--space-3) 0 0; font-size: .86rem; color: var(--lp-ink-3); }
.landing-fineprint::before { content: "✓ "; color: var(--lp-j5); font-weight: 700; }

/* the drawn board */
.landing-visual { position: relative; padding: 24px 8px 36px; }
.landing-visual::before {
  content: "";
  position: absolute; inset: 8% 6%; z-index: 0;
  background: conic-gradient(from 200deg, var(--lp-primary), var(--lp-secondary), var(--lp-indigo), var(--lp-accent), var(--lp-primary));
  filter: blur(60px);
  opacity: .28;
  border-radius: 40px;
}

.landing-device {
  position: relative;
  z-index: 1;
  background: #FFFFFF;
  color: #1E293B;
  border-radius: 18px;
  box-shadow: 0 30px 70px rgba(15, 42, 61, .16), 0 0 0 1px rgba(15, 42, 61, .06);
  overflow: hidden;
  transform: perspective(1400px) rotateY(8deg) rotateX(3deg);
}
.landing-device-bar {
  display: flex; align-items: center; gap: 6px;
  padding: 10px 14px;
  background: linear-gradient(90deg, #ECFDF9, #EEF6FF);
  font-size: .8rem; color: var(--lp-ink-2);
}
.landing-device-bar i { width: 9px; height: 9px; border-radius: 50%; background: #FF6B5E; }
.landing-device-bar i:nth-child(2) { background: #FFC048; }
.landing-device-bar i:nth-child(3) { background: #33C46B; }
.landing-device-bar span { margin-inline-start: auto; font-weight: 700; }

.landing-board { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; padding: 14px; }
.landing-col { border-radius: 12px; padding: 8px; min-height: 190px; background: #F1F5F9; }
.landing-col:nth-child(1) { background: #FFF7E8; }
.landing-col:nth-child(2) { background: #EAF5FF; }
.landing-col:nth-child(3) { background: #E8FAF5; }
.landing-col-head { display: flex; justify-content: space-between; font-size: .78rem; font-weight: 800; padding: 2px 4px 8px; color: #334155; }
.landing-col-head b { background: #fff; border-radius: 999px; padding: 0 8px; font-weight: 700; box-shadow: 0 1px 2px rgba(0,0,0,.06); }

.landing-chip {
  display: grid; gap: 2px;
  background: #fff;
  border-radius: 9px;
  padding: 8px 10px;
  margin-block-end: 8px;
  border-inline-start: 3px solid var(--lp-accent);
  box-shadow: 0 2px 6px rgba(15, 42, 61, .07);
  font-size: .8rem; font-weight: 700;
}
.landing-col:nth-child(2) .landing-chip { border-color: var(--lp-secondary); }
.landing-chip small { font-weight: 400; color: #64748B; font-size: .72rem; }
.landing-chip.is-late { border-color: #EF4444; }
.landing-chip.is-late small { color: #DC2626; font-weight: 600; }
.landing-chip.is-done { border-color: var(--lp-j5); }
.landing-chip.is-done small { color: #059669; }

.landing-float {
  position: absolute;
  z-index: 2;
  display: flex; align-items: center; gap: 10px;
  background: rgba(255, 255, 255, .97);
  color: #1E293B;
  border-radius: 14px;
  padding: 10px 14px;
  box-shadow: 0 16px 36px rgba(15, 42, 61, .16);
  font-size: .82rem;
  animation: landing-float 6s ease-in-out infinite;
}
.landing-float b { display: block; font-size: .85rem; }
.landing-float small { color: #64748B; }
.landing-float-icon {
  display: grid; place-items: center;
  width: 34px; height: 34px; border-radius: 10px;
  color: #fff;
  background: var(--lp-primary-grad);
}
.landing-float-b .landing-float-icon { background: linear-gradient(135deg, var(--lp-j4b), var(--lp-j4)); }
.landing-float-a { inset-inline-end: -12px; top: 0; }
.landing-float-b { inset-inline-start: -8px; bottom: 4px; animation-delay: -3s; }

@keyframes landing-float { 50% { transform: translateY(-8px); } }

/* stats */
.landing-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px;
  margin: 60px 0 0;
}
.landing-stats > div {
  display: flex; flex-direction: column-reverse; gap: 4px;
  padding: 20px 22px;
  border-radius: 16px;
  background: rgba(255, 255, 255, .8);
  border: 1px solid var(--lp-line);
  box-shadow: 0 8px 24px rgba(15, 42, 61, .06);
  backdrop-filter: blur(6px);
}
.landing-stats dd {
  margin: 0; font-size: 1.7rem; font-weight: 800;
  background: linear-gradient(90deg, var(--lp-j1), #0F766E);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
}
.landing-stats > div:nth-child(2) dd { background-image: linear-gradient(90deg, var(--lp-j2), #0369A1); }
.landing-stats > div:nth-child(3) dd { background-image: linear-gradient(90deg, var(--lp-j3), #4338CA); }
.landing-stats > div:nth-child(4) dd { background-image: linear-gradient(90deg, var(--lp-j4), #C2410C); }
.landing-stats dt { font-size: .9rem; color: var(--lp-ink-2); }

/* ---- sections ---- */
.landing-section { position: relative; padding-block: 92px; }
#features.landing-section {
  background:
    radial-gradient(600px 300px at 100% 0%, rgba(var(--lp-secondary-rgb), .07), transparent 70%),
    radial-gradient(600px 300px at 0% 100%, rgba(var(--lp-primary-rgb), .07), transparent 70%);
}
.landing-section-alt {
  background:
    radial-gradient(700px 320px at 50% 0%, rgba(var(--lp-primary-rgb), .10), transparent 70%),
    var(--lp-soft);
}

.landing-section-head { text-align: center; max-width: 720px; margin: 0 auto 52px; }
.landing-section-head h2 {
  font-size: clamp(1.65rem, 1.2rem + 1.5vw, 2.4rem);
  line-height: 1.4;
  font-weight: 800;
  margin: 0 0 var(--space-3);
  text-wrap: balance;
}
.landing-section-head h2::after {
  content: "";
  display: block;
  width: 72px; height: 4px;
  margin: 16px auto 0;
  border-radius: 4px;
  background: var(--lp-line-grad);
}
.landing-section-head p { margin: 0; color: var(--text-muted); font-size: 1.06rem; line-height: 1.9; }

.landing-features { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }

/* Each card takes the next jewel in turn. */
.landing-feature { --c: var(--lp-j1); --c2: var(--lp-j1b); }
.landing-feature:nth-child(6n+2) { --c: var(--lp-j2); --c2: var(--lp-j2b); }
.landing-feature:nth-child(6n+3) { --c: var(--lp-j3); --c2: var(--lp-j3b); }
.landing-feature:nth-child(6n+4) { --c: var(--lp-j4); --c2: var(--lp-j4b); }
.landing-feature:nth-child(6n+5) { --c: var(--lp-j5); --c2: var(--lp-j5b); }
.landing-feature:nth-child(6n+6) { --c: var(--lp-j6); --c2: var(--lp-j6b); }

.landing-feature {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 28px;
  overflow: hidden;
  transition: transform .25s ease, box-shadow .25s ease, border-color .25s ease;
}
.landing-feature::before {
  content: ""; position: absolute; inset-inline: 0; top: 0; height: 3px;
  background: linear-gradient(90deg, var(--c), var(--c2));
  opacity: 0; transition: opacity .25s ease;
}
.landing-feature::after {
  content: ""; position: absolute; width: 180px; height: 180px; border-radius: 50%;
  inset-inline-end: -70px; top: -70px;
  background: radial-gradient(circle, color-mix(in srgb, var(--c) 18%, transparent), transparent 70%);
  pointer-events: none;
}
.landing-feature:hover {
  transform: translateY(-6px);
  border-color: color-mix(in srgb, var(--c) 45%, transparent);
  box-shadow: 0 22px 44px color-mix(in srgb, var(--c) 20%, transparent);
}
.landing-feature:hover::before { opacity: 1; }
.landing-feature-icon {
  position: relative; z-index: 1;
  display: grid; place-items: center;
  width: 52px; height: 52px;
  border-radius: 16px;
  color: #fff;
  background: linear-gradient(135deg, var(--c2), var(--c));
  box-shadow: 0 10px 22px color-mix(in srgb, var(--c) 32%, transparent);
  margin-block-end: 18px;
}
.landing-feature h3 { position: relative; margin: 0 0 8px; font-size: 1.14rem; font-weight: 800; }
.landing-feature p { position: relative; margin: 0; color: var(--text-muted); line-height: 1.85; font-size: .96rem; }

.landing-steps {
  list-style: none; padding: 0; margin: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 22px;
  counter-reset: step;
}
.landing-steps li {
  counter-increment: step;
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 70px 22px 24px;
  box-shadow: var(--shadow-sm);
}
.landing-steps li::before {
  content: counter(step);
  position: absolute; top: 20px; inset-inline-start: 22px;
  display: grid; place-items: center;
  width: 38px; height: 38px; border-radius: 12px;
  color: #fff;
  background: linear-gradient(135deg, var(--lp-j1b), var(--lp-j1));
  box-shadow: 0 8px 18px color-mix(in srgb, var(--lp-j1) 30%, transparent);
  font-weight: 800; font-family: var(--font-figure);
}
.landing-steps li:nth-child(2)::before { background: linear-gradient(135deg, var(--lp-j2b), var(--lp-j2)); box-shadow: 0 8px 18px color-mix(in srgb, var(--lp-j2) 30%, transparent); }
.landing-steps li:nth-child(3)::before { background: linear-gradient(135deg, var(--lp-j3b), var(--lp-j3)); box-shadow: 0 8px 18px color-mix(in srgb, var(--lp-j3) 30%, transparent); }
.landing-steps li:nth-child(4)::before { background: linear-gradient(135deg, var(--lp-j4b), var(--lp-j4)); box-shadow: 0 8px 18px color-mix(in srgb, var(--lp-j4) 30%, transparent); }
.landing-steps h3 { margin: 0 0 6px; font-size: 1.06rem; font-weight: 800; }
.landing-steps p { margin: 0; color: var(--text-muted); line-height: 1.8; font-size: .95rem; }

#pricing.landing-section {
  background:
    radial-gradient(700px 360px at 85% 20%, rgba(var(--lp-secondary-rgb), .08), transparent 70%),
    radial-gradient(600px 360px at 10% 80%, rgba(var(--lp-primary-rgb), .08), transparent 70%);
}

.landing-quotes { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 22px; }
.landing-quote {
  margin: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 28px;
  display: flex; flex-direction: column; gap: 16px;
  box-shadow: var(--shadow-sm);
}
.landing-quote blockquote { margin: 0; line-height: 1.95; font-size: 1.03rem; }
.landing-quote blockquote::before {
  content: "\201D"; display: block; font-size: 3.4rem; line-height: .6; font-weight: 800;
  background: var(--lp-primary-grad);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
}
.landing-quote figcaption { display: grid; gap: 2px; margin-top: auto; }
.landing-quote figcaption span { color: var(--text-subtle); font-size: .88rem; }

.landing-faq { display: grid; gap: 12px; }
.landing-faq details {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 0 22px;
  transition: border-color .15s, box-shadow .2s;
}
.landing-faq details[open] {
  border-color: rgba(var(--lp-primary-rgb), .45);
  box-shadow: 0 12px 30px rgba(var(--lp-primary-rgb), .10);
}
.landing-faq summary {
  cursor: pointer;
  list-style: none;
  display: flex; justify-content: space-between; align-items: center; gap: 16px;
  padding: 19px 0;
  font-weight: 700;
}
.landing-faq summary::-webkit-details-marker { display: none; }
.landing-faq summary::after {
  content: "+";
  flex: none;
  display: grid; place-items: center;
  width: 28px; height: 28px; border-radius: 50%;
  font-size: 1.2rem; line-height: 1;
  color: #fff;
  background: var(--lp-primary-grad);
  transition: transform .2s;
}
.landing-faq details[open] summary::after { transform: rotate(45deg); background: linear-gradient(135deg, var(--lp-j4b), var(--lp-j4)); }
.landing-faq p { margin: 0 0 20px; color: var(--text-muted); line-height: 1.9; }

.landing-final {
  position: relative;
  isolation: isolate;
  background:
    radial-gradient(520px 300px at 8% 10%, rgba(var(--lp-accent-rgb), .30), transparent 60%),
    radial-gradient(520px 320px at 95% 100%, rgba(94, 234, 212, .30), transparent 60%),
    var(--lp-final);
  color: #fff;
  padding-block: 80px;
  overflow: hidden;
}
.landing-final-inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 28px; }
.landing-final h2 { margin: 0 0 8px; font-size: clamp(1.55rem, 1.2rem + 1.3vw, 2.35rem); font-weight: 800; color: #fff; text-shadow: 0 2px 12px rgba(15, 42, 61, .2); }
.landing-final p { margin: 0; color: rgba(255, 255, 255, .95); font-size: 1.06rem; }
/* On the coloured band the main button turns white, so it does not vanish into the band. */
.landing-final .btn-primary { background: #fff; color: var(--lp-final-ink); box-shadow: 0 10px 28px rgba(15, 42, 61, .22); }
.landing-final .btn-primary:hover { background: var(--lp-soft); color: var(--lp-ink); }
.landing-final .landing-btn-ghost { background: transparent; color: #fff; border-color: rgba(255, 255, 255, .6); box-shadow: none; }
.landing-final .landing-btn-ghost:hover { background: rgba(255, 255, 255, .14); color: #fff; }

.landing-footer { position: relative; background: var(--lp-footer); color: var(--lp-ink-2); padding-block: 60px 24px; }
.landing-footer::before {
  content: ""; position: absolute; inset-inline: 0; top: 0; height: 3px;
  background: linear-gradient(90deg, var(--lp-j1), var(--lp-j2), var(--lp-j3), var(--lp-j4));
}
.landing-footer-grid { display: grid; grid-template-columns: 1.4fr repeat(3, 1fr); gap: 32px; }
.landing-footer h3 { color: var(--lp-ink); font-size: .95rem; margin: 0 0 12px; }
.landing-footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.landing-footer a { color: var(--lp-ink-2); transition: color .15s; }
.landing-footer a:hover { color: var(--lp-primary); }
.landing-footer-note { margin: 14px 0 0; line-height: 1.8; font-size: .92rem; max-width: 36ch; }
.landing-copy { margin-top: 40px; padding-top: 20px; border-top: 1px solid var(--lp-line); font-size: .85rem; }

/* ---- smaller screens ---- */
@media (max-width: 960px) {
  .landing-hero-grid { grid-template-columns: 1fr; gap: 32px; }
  .landing-visual { max-width: 560px; margin-inline: auto; width: 100%; }
  .landing-device { transform: none; }
  .landing-features { grid-template-columns: repeat(2, 1fr); }
  .landing-links { display: none; }
  .landing-footer-grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 600px) {
  .landing-hero { padding-block: 48px 44px; }
  .landing-section { padding-block: 64px; }
  .landing-features { grid-template-columns: 1fr; }
  .landing-stats { grid-template-columns: 1fr 1fr; gap: 10px; }
  .landing-stats > div { padding: 16px; }
  .landing-stats dd { font-size: 1.35rem; }
  .landing-hide-sm { display: none; }
  .landing-cta-row .btn { flex: 1 1 100%; text-align: center; justify-content: center; }
  .landing-float { display: none; }
  .landing-board { gap: 6px; padding: 10px; }
  .landing-col { min-height: 150px; }
  .landing-footer-grid { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  html:has(.landing) { scroll-behavior: auto; }
  .landing-float { animation: none; }
  .landing-feature, .landing .btn-primary { transition: none; }
  .landing-feature:hover, .landing .btn-primary:hover { transform: none; }
  .landing .btn-primary::after { display: none; }
}

/* ---- the operator's editor ---- */
.landing-editor-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--space-3);
  align-items: start;
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-sunken);
  margin-block-end: var(--space-3);
}
.landing-editor-row .form-grid { margin: 0; }
.landing-editor-tools { display: flex; flex-direction: column; gap: 4px; }
.landing-editor-tools .btn { padding: 4px 10px; min-height: 0; }
.landing-editor-bar {
  position: sticky; bottom: 0; z-index: 5;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3);
  padding: var(--space-3) 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  margin-block-start: var(--space-5);
}
.landing-editor .field-error { margin: 0; color: var(--danger); font-size: .82rem; }

/* ---------- Support tickets: the conversation, on both sides of the desk ---------- */

.support-thread { display: flex; flex-direction: column; gap: var(--space-3); }

.support-msg {
  max-width: min(640px, 88%);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
/* The reader's own side sits at the start of the line; the other side at the end. */
.support-msg.is-other { align-self: flex-end; background: var(--surface-sunken); }
.support-msg.is-mine { align-self: flex-start; border-color: var(--accent); }
.support-msg-head {
  display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: baseline;
  margin-block-end: var(--space-2); font-size: .82rem; color: var(--text-muted);
}
.support-msg-head strong { color: var(--text); font-size: .9rem; }
.support-msg-body { white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.7; }

.support-files { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-block-start: var(--space-3); }
.support-file {
  display: block; width: 96px; height: 72px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  overflow: hidden; background: var(--surface-sunken);
}
.support-file img { width: 100%; height: 100%; object-fit: cover; display: block; }

.support-pending { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.support-pending .chip { cursor: default; }

.support-note {
  padding: var(--space-3);
  border-inline-start: 3px solid var(--warning-ink);
  background: var(--warning-soft);
  border-radius: var(--radius-sm);
}
.support-note .support-msg-body { color: var(--text); }

.support-facts { display: grid; grid-template-columns: auto 1fr; gap: var(--space-2) var(--space-3); font-size: .9rem; }
.support-facts dt { color: var(--text-muted); }
.support-facts dd { margin: 0; overflow-wrap: anywhere; }

.nav-count {
  margin-inline-start: auto;
  min-width: 20px; padding: 0 6px;
  border-radius: 999px;
  background: var(--accent); color: var(--surface);
  font-size: .75rem; line-height: 20px; text-align: center;
}
