/*
  Inter — the font Tabler's own demo uses, self-hosted.

  Tabler's CSS asks for "Inter Var" first but ships no font files and declares no
  @font-face, so without this the panel silently fell back to Segoe UI. Confirmed against
  preview.tabler.io, which loads Inter as a variable face (100-900) and renders every
  element in it.

  One 48KB file: the LATIN subset of the weight axis. That covers the whole 100-900 range
  in a single download, so the headings at 600 and the labels at 500 come from the same
  file as body text at 400 — no separate weight requests. Italic is omitted; the panel
  uses none, and a browser can synthesise it if something ever does.

  Absolute URL because this stylesheet is served from /<org>/<crop>/admin/ while the font
  lives at the origin root — a relative path would resolve per tenant and 404.

  font-display:swap so text paints in the fallback immediately rather than blocking; on a
  scale house's connection a blank table is worse than a brief font change.
*/
@font-face {
  font-family: "Inter Var";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/vendor/inter/inter-latin-wght-normal.woff2") format("woff2-variations");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212,
    U+2215, U+FEFF, U+FFFD;
}

/*
  HarvestLog over Tabler.

  Loaded AFTER vendor/tabler/tabler.min.css, so these same-specificity rules win. The
  panel should read as HarvestLog — the amber accent and warm dark surfaces from §11 of
  the design doc — not as a stock Tabler demo. Only variables and a few component tweaks
  live here; layout and components come from Tabler itself.

  Tabler is Bootstrap-based, so its dark palette hangs off [data-bs-theme=dark]. Every
  admin page sets that on <html>: the scale house is a dark room and the panel has never
  had a light mode.
*/

[data-bs-theme="dark"] {
  /* Surfaces — Tabler's stock dark is blue-grey (#111827); ours is warm neutral. */
  --tblr-body-bg:              #1a1a1c;
  --tblr-body-bg-rgb:          26, 26, 28;
  --tblr-body-color:           #f2f2f4;
  --tblr-body-color-rgb:       242, 242, 244;

  --tblr-bg-surface:           #242428;
  --tblr-bg-surface-primary:   #242428;
  --tblr-bg-surface-secondary: #2c2c31;
  --tblr-bg-surface-tertiary:  #2c2c31;

  --tblr-border-color:         #3a3a40;
  --tblr-border-color-translucent: #3a3a40;

  --tblr-secondary:            #b9b9c0;
  --tblr-secondary-color:      #b9b9c0;
  --tblr-secondary-bg:         #2c2c31;

  /* Accent. Amber is the primary action colour everywhere in this project. */
  --tblr-primary:              #f0a24a;
  --tblr-primary-rgb:          240, 162, 74;
  --tblr-success:              #3fb950;
  --tblr-success-rgb:          63, 185, 80;
  --tblr-danger:               #e5484d;
  --tblr-danger-rgb:           229, 72, 77;
  --tblr-warning:              #f0a24a;

  /* Inputs. Tabler's dark form background is its blue-grey gray-900, which reads as navy
     next to our warm neutral surfaces — the fields looked like they belonged to a
     different app. Sunk slightly below the card, as the pre-Tabler pages had them. */
  --tblr-bg-forms: var(--tblr-body-bg);

  /*
    Typography is Tabler's, deliberately NOT overridden.

    An earlier version of this file replaced --tblr-font-sans-serif with a system-ui
    stack, which silently discarded Tabler's own typography. Tabler's stack is
    "Inter Var", Inter, then -apple-system / Segoe UI / Roboto — so removing the override
    changes nothing visible until Inter is actually present, and everything the moment it
    is. Sizes come from --tblr-font-size-* (base 0.875rem, h1 1.5 → h6 0.625rem); no
    admin page should hardcode a pixel size.
  */
}

/*
  MIGRATION BRIDGE — the pre-Tabler variable names, aliased to the Tabler ones.

  The shared dialogs in shared.js style themselves with --surf / --acc / --t1 / --border,
  which used to come from a :root block in every page. A Tabler page has no such block,
  so without these the dialogs render transparent with a light border — invisible on a
  dark page. The other six admin pages still define and use these names directly, so the
  aliases must stay until all of them are converted AND shared.js is moved onto --tblr-*.

  Aliased rather than duplicated so there is still one source of truth for each colour.
*/
[data-bs-theme="dark"] {
  --bg:     var(--tblr-body-bg);
  --surf:   var(--tblr-bg-surface);
  --surf2:  var(--tblr-bg-surface-secondary);
  --border: var(--tblr-border-color);
  --t1:     var(--tblr-body-color);
  --t2:     var(--tblr-secondary-color);
  --t3:     #8a8a92;
  --acc:    var(--tblr-primary);
  --green:  var(--tblr-success);
  --red:    var(--tblr-danger);

  /*
    The sheet-number pill's red, deliberately NOT --red.

    --red is the danger colour and is used for errors on the page background, where it
    measures fine. The pill puts it on its own 15%-tinted background, and there the same
    hex came to 3.39:1 — under the 4.5:1 minimum, and the only one of the three pills that
    failed (green is 4.76:1, orange 5.47:1). Lightening it to #ff7a7a brings the pill to
    4.77:1 without touching the colour every error message on the panel depends on.
  */
  --pill-red: #ff7a7a;

  /* The pills' tinted grounds. Variables rather than literals in shared.js, so a theme
     can retune them — a 15% tint that reads as a soft wash on black is nearly invisible
     on white. */
  --pill-red-bg:   rgba(255,122,122,.15);
  --pill-green-bg: rgba(63,185,80,.15);
  --pill-acc-bg:   rgba(240,162,74,.15);

  /* Text ON a solid accent fill. The accent flips light-to-dark between themes, so
     anything sitting on it has to flip the other way — hardcoding either one leaves that
     text unreadable in the other mode. */
  --on-acc: #17130e;
}

/*
  ── LIGHT MODE ────────────────────────────────────────────────────────────────

  The scale house is a dark room and that is still the default, but the panel is also
  opened on an iPad in a truck cab at midday and on a laptop in an office with windows.
  Dark-on-bright is unreadable through a windscreen.

  Built as a MIRROR of the block above rather than as Tabler's stock light theme: the
  same warm neutral family, so the two modes are one product seen under different light
  rather than two designs. Every variable the dark block sets is set here, so nothing can
  fall through to a Bootstrap default that is blue-grey.

  THE ACCENT DARKENS. Amber at #f0a24a is 2.1:1 on white — fine as a large fill on a dark
  ground, illegible as text on a light one. #9a5a12 keeps the same hue and reaches 5.2:1,
  so links, focus rings and the accent text stay readable without becoming a different
  colour. Solid amber fills keep the light amber and take dark text, which is the same
  trade the dark mode already makes in reverse.
*/
[data-bs-theme="light"] {
  --tblr-body-bg:              #f7f6f3;
  --tblr-body-bg-rgb:          247, 246, 243;
  --tblr-body-color:           #23232a;
  --tblr-body-color-rgb:       35, 35, 42;

  --tblr-bg-surface:           #ffffff;
  --tblr-bg-surface-primary:   #ffffff;
  --tblr-bg-surface-secondary: #f0eeea;
  --tblr-bg-surface-tertiary:  #f0eeea;

  /*
    DARKER THAN LOOKS RIGHT ON A DIM SCREEN, because the screens this runs on are not dim.

    #dcd9d2 was picked against an ordinary monitor, where it reads as a quiet division
    between zones. On a high-brightness HDR panel in daylight the white surfaces bloom and
    a line four shades off white stops registering at all — the cards lose their edges and
    the page reads as one sheet. This is the same perceptual effect that made two buttons
    of identical colour look like different yellows.

    Bolder, not black: the line still has to be a division rather than a rule, and dark
    mode is untouched because a light line on a dark surface never had the problem.
  */
  --tblr-border-color:             #c6c1b6;
  --tblr-border-color-translucent: #c6c1b6;

  --tblr-secondary:            #5f5f6b;
  --tblr-secondary-color:      #5f5f6b;
  --tblr-secondary-bg:         #f0eeea;

  /*
    TWO AMBERS, BECAUSE THEY DO TWO JOBS.

    --tblr-primary is the amber as TEXT: links, focus rings, the accent word in a
    sentence. It has to be dark to be legible on white, which is why it is #9a5a12.

    --hl-fill-primary is the amber as a FILL, and a fill has no such problem — the text
    on it flips dark instead. Collapsing the two is what drained the panel in light mode:
    every gold button on the page turned a flat brown, and the buttons are most of what
    anyone looks at.
  */
  --tblr-primary:              #9a5a12;
  --tblr-primary-rgb:          154, 90, 18;
  --hl-fill-primary:           #eaa03f;
  --hl-fill-primary-hover:     #d8912f;
  /*
    Turned up, deliberately. The first pass picked each of these for text contrast on
    white and then used them for badges, borders and pills as well — which is how a
    green that measured 5:1 ended up looking grey next to the dark mode's. These are
    still above 4.5:1 as text and considerably closer to the colours the dark mode uses.
  */
  --tblr-success:              #12873a;
  --tblr-success-rgb:          18, 135, 58;
  --tblr-danger:               #cf2027;
  --tblr-danger-rgb:           207, 32, 39;
  --tblr-warning:              #a8630c;
  --tblr-warning-rgb:          168, 99, 12;

  /* Forms sit ON the card here rather than sunk below it: a white field on a white card
     needs its border to do the work, and a grey field would read as disabled. */
  --tblr-bg-forms: #ffffff;

  --bg:     var(--tblr-body-bg);
  --surf:   var(--tblr-bg-surface);
  --surf2:  var(--tblr-bg-surface-secondary);
  --border: var(--tblr-border-color);
  --t1:     var(--tblr-body-color);
  --t2:     var(--tblr-secondary-color);
  --t3:     #7c7c86;
  --acc:    var(--tblr-primary);
  --green:  var(--tblr-success);
  --red:    var(--tblr-danger);

  /* The pill's red, mirrored. On a light tint the problem inverts: the dark-mode
     #ff7a7a is 1.9:1 here, so the pill takes a DARKER red than the page's danger colour
     rather than a lighter one. 5.9:1 on its own tinted background. */
  --pill-red: #9e1f24;

  /*
    THE PILLS HAVE TO CARRY ON A WHITE PAGE.

    A tint that reads as a clear coloured ground on black is very nearly the page itself
    on white — the first pass raised these from the dark mode's 15% to 10-12%, which was
    the wrong direction, and the pills flattened into three grey chips with coloured
    text. On a light ground a wash needs roughly double, not less.

    The text darkens to match, so the contrast on the stronger ground goes up rather than
    down: these are read at a glance across a scale house, not studied.
  */
  --pill-red-bg:   rgba(158,31,36,.22);
  --pill-green-bg: rgba(18,135,58,.22);
  --pill-acc-bg:   rgba(154,90,18,.24);

  /* White on the darkened amber. */
  --on-acc: #ffffff;
}

/* Amber is a LIGHT accent, so white-on-amber fails contrast. Primary buttons and solid
   amber badges take the dark surface colour for their text instead. */
[data-bs-theme="dark"] .btn-primary,
[data-bs-theme="dark"] .btn-primary:hover,
[data-bs-theme="dark"] .btn-primary:focus,
[data-bs-theme="dark"] .btn-warning,
[data-bs-theme="dark"] .badge.bg-primary {
  color: #1a1a1c;
}

/*
  THE GOLD BUTTON SURVIVES THE LIGHT MODE.

  It used to become the darkened amber with white text — legible, and the wrong call. The
  amber IS this product: it is the Save button on every page, the pill on every link, the
  thing the eye goes to. Rendered brown it stopped reading as the same application, and
  the panel lost most of its colour in one substitution, because buttons are most of what
  is on a page.

  A fill does not need the text contrast a link does; it needs contrast with what sits ON
  it, and that flips dark. So the button takes the same gold as the dark mode with dark
  text, exactly the trade the dark mode already makes in reverse. --tblr-primary stays
  dark for anything that is genuinely text.
*/
[data-bs-theme="light"] .btn-primary,
[data-bs-theme="light"] .btn-warning,
[data-bs-theme="light"] .badge.bg-primary,
[data-bs-theme="light"] .badge.bg-warning {
  --tblr-btn-bg: var(--hl-fill-primary);
  --tblr-btn-border-color: var(--hl-fill-primary);
  --tblr-btn-color: #23232a;
  --tblr-btn-hover-bg: var(--hl-fill-primary-hover);
  --tblr-btn-hover-border-color: var(--hl-fill-primary-hover);
  --tblr-btn-hover-color: #23232a;
  --tblr-btn-active-bg: var(--hl-fill-primary-hover);
  --tblr-btn-active-border-color: var(--hl-fill-primary-hover);
  --tblr-btn-active-color: #23232a;
  --tblr-btn-disabled-bg: var(--hl-fill-primary);
  --tblr-btn-disabled-border-color: var(--hl-fill-primary);
  --tblr-btn-disabled-color: #23232a;
  background-color: var(--hl-fill-primary);
  border-color: var(--hl-fill-primary);
  color: #23232a;
}
[data-bs-theme="light"] .btn-primary:hover,
[data-bs-theme="light"] .btn-primary:focus,
[data-bs-theme="light"] .btn-primary:active,
[data-bs-theme="light"] .btn-warning:hover,
[data-bs-theme="light"] .btn-warning:focus,
[data-bs-theme="light"] .btn-warning:active {
  background-color: var(--hl-fill-primary-hover);
  border-color: var(--hl-fill-primary-hover);
  color: #23232a;
}

/*
  THE SOFT BADGES, TURNED UP.

  Tabler's -lt badges are a ~10% tint of the colour with the colour as text. On a dark
  surface that lands as a clearly coloured chip; on white the same tint is all but the
  page itself, so Done, Shared, Approved and every status on the panel faded to grey
  text in a grey box. Stronger ground, darker text, and they read as the same chips the
  dark mode has.
*/
/* !important, because Tabler's own -lt rules carry it. Without matching it the
   overrides parse, apply to nothing, and the chips stay pale. */
[data-bs-theme="light"] .bg-green-lt  { background: rgba(18,135,58,.16)  !important; color: #0d6b2c !important; }
[data-bs-theme="light"] .bg-red-lt    { background: rgba(207,32,39,.14)  !important; color: #a0161c !important; }
[data-bs-theme="light"] .bg-yellow-lt { background: rgba(216,145,47,.24) !important; color: #7d4a08 !important; }
[data-bs-theme="light"] .bg-blue-lt   { background: rgba(32,107,196,.14) !important; color: #17509a !important; }

/*
  NO MONOSPACE ANYWHERE IN THE PANEL.

  Weights, ticket numbers and device ids used to be set in var(--tblr-font-monospace),
  on the reasoning that they are read as data rather than prose. The flaw is that the
  value is a STACK, not a font — Consolas on Windows, Courier New on an iPhone, Monaco
  on a Mac — so the same number was a different typeface on every device, and on a phone
  it landed on the weakest face of the three.

  Everything is Inter now. Alignment was the only thing monospace was really buying, and
  tabular figures give that without a second typeface: every digit takes the same width,
  so a column of weights still lines up exactly.

  These class names are kept and simply re-pointed, so any markup still carrying .mono or
  .text-mono gets tabular Inter rather than silently reverting to a monospace face.
*/
.mono, .num, td.num, th.num, input.num, .text-mono, .font-monospace,
code, kbd, samp, pre {
  font-family: var(--tblr-font-sans-serif) !important;
}

/*
  Numbers are set exactly like the words around them — no tabular figures.

  Removing monospace, this first asked for tabular-nums so a column of weights would still
  line up. That solved alignment and reintroduced the original complaint: Inter's tabular
  digits are much wider than its normal ones (11111 measures 130px tabular against 81px
  proportional), so a gross weight still did not look like the rest of the page. Numbers
  now render identically to body text.

  The cost is real and deliberate: gross, tare and net no longer line up digit-for-digit
  down a column. They stay right-aligned, so the ones, tens and hundreds columns still
  end at the same place, which is most of what made them comparable.

  The pills keep their tabular figures — a sheet number is a fixed-width code (YY-G-NNN)
  in a column of other sheet numbers, and ragged ones read as broken rather than as prose.
*/

/*
  Form controls inherit Inter's character variants.

  Tabler sets font-feature-settings "cv03","cv04","cv11" on the body, but browsers do not
  pass that into <input>, <select> or <textarea> — they compute `normal`. So the same
  digits looked one way in a table and another way in the box you typed them into. This
  is a browser default, not a Tabler choice, and it has to be undone explicitly.
*/
input, select, textarea, button {
  font-feature-settings: inherit;
}
/* <code> is used here for literal values a person types — a CSV header, a filename.
   Without the monospace face it needs some other mark, or it disappears into the
   sentence around it. */
code { background: var(--tblr-bg-surface-secondary); border-radius: 3px; padding: 1px 5px; }
td.num, th.num { text-align: right; }
/* Weight and time inputs. Right-aligned so the digits of gross, tare and net line up
   vertically — the scaler is comparing them at a glance, not reading them as words. */
input.num { text-align: right; }
/* A read-only field is showing a derived value (net, acreage), not inviting a change. */
.form-control[readonly] { color: var(--tblr-secondary-color); }

/*
  The domain pills stay exactly as they were — sheet-no red, sheet green, link gold.
  Tabler has badges, but these encode meaning specific to this system and are already
  consistent across every page via shared.js. Kept, not replaced (design doc §12).
*/

/* Tables inside cards: let a wide table scroll rather than crush its columns on a
   phone. `.table-responsive` is Tabler's wrapper; this is the floor below which the
   columns stop being legible. */
.table-responsive > table { min-width: 600px; }

/*
  iOS: stop wide tables dragging the whole page sideways.

  Tabler's .card is a COLUMN flex container, so its children are flex items and default
  to min-width:auto — "never shrink below your content". Chromium still constrains a
  scrolling child to the card, but WebKit honours min-width:auto and lets the
  .table-responsive stretch to the full width of its table. On an iPhone that pushed the
  table out past the card's border and the page off the side of the screen, while the
  same page measured perfectly clean in Chromium.

  min-width:0 is the standard flex-item fix; max-width:100% is belt and braces. Applied
  to every card child, not just tables, so anything wide added later behaves too.
*/
.card > *, .card-body > * { min-width: 0; }
.card > .table-responsive, .card-body > .table-responsive { max-width: 100%; }
/* A card must never be wider than the column it sits in, whatever it contains. */
.page-body .card { max-width: 100%; }

/*
  The top bar carries farm, crop and season. On a narrow phone the farm name is the part
  that can give way — it truncates — while the two switchers keep their full width, since
  losing them costs the user the ability to change context at all.
*/
#hl-navbar .navbar-brand { min-width: 0; flex-shrink: 1; overflow: hidden; }
/*
  The crop and season switchers need air between them.

  Tabler zeroes .nav-link horizontal padding while the navbar is collapsed, so on a phone
  the two dropdowns sat flush against each other and read as one run-on string —
  "Potato ⌄Season 2026 ⌄". They are two separate controls and have to look like it.
  A gap rather than padding, so the space is only ever BETWEEN them and never adds a
  dead margin at the right edge of a narrow screen.
*/
#hl-navbar .navbar-nav.flex-row { flex-shrink: 0; gap: .875rem; }
/* Keeps the pair off the very edge of the screen on a phone. */
#hl-navbar .navbar > .container-xl { padding-right: .5rem; }

/*
  A flush table sitting at the edge of a card must follow the card's rounded corners.

  .table-responsive scrolls, so its overflow already clips — but with square corners, so
  the header band and the last row painted straight over the card's rounded outline. It
  is most obvious on the coloured cards, where the band visibly cuts the orange or green
  border at each corner. `inherit` picks up whichever radius the card is using.
*/
.card > .table-responsive:first-child { border-top-left-radius: inherit; border-top-right-radius: inherit; }
.card > .table-responsive:last-child  { border-bottom-left-radius: inherit; border-bottom-right-radius: inherit; }

/* The action column on every table: right-aligned and never wrapped, so a row's buttons
   stay on one line and stay together. It is what overflows first on a narrow screen,
   which is exactly why the wrapper above has to scroll. */
td.acts { white-space: nowrap; text-align: right; }

/*
  A row you can act on should say so under the cursor.

  Rows that open a sheet, a load or a link are clickable, but nothing marked them out —
  on a wide table the eye loses which line it is on somewhere around the fifth column,
  and clicking the wrong row opens the wrong ticket. Whole-row highlight, not cell.

  Pointer devices only: on a touch screen :hover sticks after a tap and leaves a row
  looking selected when it is not.
*/
@media (hover: hover) and (pointer: fine) {
  tbody tr.pick:hover > td,
  tbody tr.ld:hover > td,
  tbody tr[data-id]:hover > td,
  tbody tr[data-fcard]:hover > td {
    /*
      background-COLOR, never the shorthand. The shorthand resets background-image too,
      and the source-tinted columns (.jd, .wx) carry their tint as an image precisely so
      this highlight can slide underneath it. The shorthand here is what made a hovered
      row's green and blue columns go flat surface grey — black, in dark mode.
    */
    background-color: var(--tblr-bg-surface-secondary);
  }
}

/*
  Sortable column headings.

  `.sortable` is added by the shared sorter, so a heading only looks interactive when it
  actually is. The arrow is reserved with a fixed-width slot rather than appended, so a
  heading does not jump sideways the first time it is sorted.
*/
th.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
th.sortable::after {
  content: '';
  display: inline-block;
  width: 0.85em;
  text-align: right;
  color: var(--tblr-primary);
}
th.sortable[data-sort="asc"]::after  { content: '\2191'; }
th.sortable[data-sort="desc"]::after { content: '\2193'; }
@media (hover: hover) and (pointer: fine) {
  th.sortable:hover { color: var(--tblr-primary); }
}

/*
  The working sheet's pills sat directly against the table header below them, so the
  green pill's border and the header rule touched and read as one boxed-in strip.

  The margin alone did nothing: the pills live in a `.card-body pb-0`, whose zero bottom
  padding is what actually closes the gap. The space has to come from the card body.
*/
.sheethead { margin-bottom: 4px; }
#sheetzone > .card-body.pb-0 { padding-bottom: 1rem !important; }

/*
  Dialog text at the panel's normal reading size.

  Tabler's .modal inherits the body's 0.875rem, which is fine for a dense table and small
  for a dialog you are reading a decision out of — the assign-to-link dialog especially,
  where the whole content is one sentence and one control.
*/
.modal-body, .modal-body .form-label, .modal-body .form-control, .modal-body .form-select {
  font-size: 1rem;
}
.modal-title { font-size: 1.15rem; }

/* A date input centred its text while every other field left-aligns. WebKit does that by
   default; nothing had overridden it. */
input[type="date"], input[type="time"], input[type="datetime-local"] {
  text-align: left;
}

/* Icon + label inside a button. Tabler's .btn is already a flex row with a gap, so this
   only needs to stop an icon being squashed when the button is tight. */
.btn > svg { flex-shrink: 0; }

/* The nav's active page should be unmistakable at a glance in a busy room. */
.navbar .nav-link.active,
.navbar .nav-item.active > .nav-link {
  color: var(--tblr-primary) !important;
  font-weight: 600;
}

/*
  Columns that came from John Deere, in John Deere green.

  The Fields zone puts machine-measured figures next to scale-house ones, and the two
  are true at different moments — the combine knows when the pass ended, the scale not
  until the truck is weighed. The tint is what stops them being read as one table of
  equally current numbers. Deliberately faint: this is a source marking, not a warning,
  and it sits under text that still has to be legible in both themes.
*/
/*
  THE COLOUR IS THE PLATFORM'S, so it is a variable rather than green typed thirty times.

  John Deere is green today. Case IH is red, Trimble is blue, and a farm may one day run
  two of them at once — at which point the marking has to say WHICH machine reported,
  not merely that a machine did. Setting --hl-src-rgb on a table (or on the page) retunes
  every tint below it; nothing else has to change.

  The class is still `.jd`, because renaming it would touch every admin page for no
  behaviour, and the day a second platform lands it can gain a sibling.
*/
:root { --hl-src-rgb: 54, 124, 43; }        /* John Deere green */
[data-bs-theme="dark"] { --hl-src-rgb: 124, 200, 90; }

/*
  THE SECOND SOURCE: sky blue, for the weather.

  Its own variable rather than a shade of the first. Operations Center and the sky are
  two outside services that answer at different moments and fail independently, and the
  whole point of tinting a figure is to say WHICH outside thing said it. A weather
  reading in Deere green would be a lie told in a colour.
*/
:root { --hl-wx-rgb: 2, 132, 199; }         /* sky blue */
[data-bs-theme="dark"] { --hl-wx-rgb: 56, 189, 248; }

/*
  ── THE TAB STRIP ON CONNECTIONS ────────────────────────────────────────────────

  Each tab wears its own service's colour, so the strip says what is behind each pane
  before it is opened. Selected is a filled tab; the rest are outlines of the same hue.

  They are BUTTONS, not links: pressing the tab that is already open collapses its pane
  to nothing, which is a thing a control does and not a place a link goes.
*/
.hl-tabs { display: flex; flex-wrap: wrap; gap: .5rem; }
.hl-tab {
  --hl-tab-rgb: var(--hl-src-rgb);
  border: 2px solid rgba(var(--hl-tab-rgb), .85);
  background: transparent;
  color: rgb(var(--hl-tab-rgb));
  font-weight: 600;
  border-radius: 8px;
  padding: .45rem 1.1rem;
  line-height: 1.3;
}
.hl-tab:hover { background: rgba(var(--hl-tab-rgb), .14); }
/* Filled when its pane is open. White text on both themes: the fill is dark green or
   dark blue in light mode and bright in dark mode, and the darker of the two decides. */
.hl-tab.is-on { background: rgb(var(--hl-tab-rgb)); color: #fff; }
[data-bs-theme="dark"] .hl-tab.is-on { color: #10151a; }
.hl-tab-wx { --hl-tab-rgb: var(--hl-wx-rgb); }
/*
  WEATHER COLUMNS, the sky-blue counterpart of .jd.

  Same specificity fight, same answer — see the note on .jd above. These out-specify
  Tabler's own cell rule on purpose; a bare .wx is one class and loses.

  A third source needs a third colour: the air is neither Deere's figures nor the scale
  house's, and tinting it green would say a machine reported it.
*/
/* Image, not color, so the row hover shows through — see the note on .jd above. */
.wx { background-image: linear-gradient(rgba(var(--hl-wx-rgb), .10), rgba(var(--hl-wx-rgb), .10)); }
.table tbody td.wx,
.table tbody th.wx { background-image: linear-gradient(rgba(var(--hl-wx-rgb), .10), rgba(var(--hl-wx-rgb), .10)); }
.table thead th.wx { background: rgba(var(--hl-wx-rgb), .16); }
[data-bs-theme="light"] .wx { background-image: linear-gradient(rgba(var(--hl-wx-rgb), .16), rgba(var(--hl-wx-rgb), .16)); }
[data-bs-theme="light"] .table tbody td.wx,
[data-bs-theme="light"] .table tbody th.wx { background-image: linear-gradient(rgba(var(--hl-wx-rgb), .16), rgba(var(--hl-wx-rgb), .16)); }
[data-bs-theme="light"] .table thead th.wx { background: rgba(var(--hl-wx-rgb), .26); }
thead th.wx { border-bottom: 3px solid rgba(var(--hl-wx-rgb), .75); }

/* The weather card's own heading row, the sky-blue counterpart of .jd-card. */
.wx-card thead th {
  background: rgba(var(--hl-wx-rgb), .18);
  border-bottom: 2px solid rgba(var(--hl-wx-rgb), .55);
}
[data-bs-theme="light"] .wx-card thead th { background: rgba(var(--hl-wx-rgb), .22); }

/*
  GREEN COLUMNS. ONE FLAT TINT, EVERY ROW.

  SPECIFICITY IS THE WHOLE STORY HERE, and getting it wrong twice is what produced first
  a banded column and then no colour at all.

  Tabler paints every cell with `.table > :not(caption) > * > *`, which counts as one
  class and one element. A bare `.jd` is one class and loses, so the tint never applied
  from that rule at all — what used to paint it was an accident: a `nth-child(3n)` rule
  specific enough to win, which is why the green appeared in stripes. Removing that rule
  removed the only thing painting the cells.

  So the cell rules now out-specify Tabler on purpose and say so. No nth-child, no theme
  attribute needed to win — the colour comes from --hl-src-rgb, which the theme changes.
*/
/*
  The tint is a BACKGROUND-IMAGE, not a background-color — the same two-layer trick the
  sticky headings use, for the same reason from the other side. The row hover paints a
  background-color on every cell; as a color it slides UNDER this translucent gradient,
  so a hovered row highlights and the column stays its colour. When the tint was itself
  a background-color, hover simply replaced it — a green or blue cell went flat surface
  grey, which in dark mode reads as the column going black under the pointer.
*/
.jd { background-image: linear-gradient(rgba(var(--hl-src-rgb), .10), rgba(var(--hl-src-rgb), .10)); }
.table tbody td.jd,
.table tbody th.jd { background-image: linear-gradient(rgba(var(--hl-src-rgb), .10), rgba(var(--hl-src-rgb), .10)); }
.table thead th.jd { background: rgba(var(--hl-src-rgb), .16); }
/*
  A FARM WITH NO OPERATIONS CENTER CREDENTIALS SEES NO JOHN DEERE COLUMNS.

  Set on <body> from the bootstrap flag. Every such column already carries `.jd` to tint
  it, so hiding by the same class takes the headings and the cells together and cannot
  fall out of step with the tint — a column that were hidden in one and not the other
  would shift every cell after it one place left.

  `!important` for the same specificity reason the tints above have to fight: those rules
  are `.table tbody td.jd`, two classes and an element, so a bare `.no-jd .jd` loses to
  them on background and would lose here too if display were contested.
*/
/*
  `.jd-only` hides with the John Deere columns without being tinted like one.

  `.jd` means two things at once — "this came off a machine", which paints it green, and
  "this is meaningless without Operations Center", which hides it. That is fine on a
  table cell and wrong on a control: the Refresh button wore the column tint as a green
  background, which made a button look like a piece of Deere's data. Anything that only
  needs the second meaning carries this instead.
*/
body.no-jd .jd, body.no-jd .jd-only { display: none !important; }

/*
  ── THE PANEL USES THE MONITOR IT IS ON ─────────────────────────────────────────

  Tabler's .container-xl stops at 1320px, which is a sensible cap for a page of prose and
  the wrong one for this: these are wide tables, and a Browse row carries a dozen columns
  that were being squeezed into two thirds of a widescreen while the other third sat
  empty. Every page's header, tabs and body use the same container, so they are widened
  together — widening only the body would step the header in from the content beneath it.

  Only above 1400px, so every one of Tabler's own breakpoints below that is untouched and
  the iPad in the scale house is unaffected.

  Capped rather than edge to edge. 95vw keeps a margin so the cards do not fuse to the
  bezel, and the 2200px ceiling is there because on an ultrawide a table row stops being
  readable long before it stops fitting — following a row across three feet of glass is a
  head movement, not a glance.
*/
/*
  AND IT GROWS SMOOTHLY, rather than in steps.

  This applied only above 1400px, so between roughly 1200 and 1400 the container sat at
  Tabler's fixed 1320 while the window kept growing — the page stayed put, margins grew,
  and then it snapped wide the moment 1400 was crossed. That dead stretch is the gap.

  The cap is a single expression at every width instead, so the page tracks the window
  continuously. 95vw still keeps the cards off the bezel and 2200px is still the ceiling,
  for the reason below; what is gone is the breakpoint in the middle.
*/
.container-xl { max-width: min(95vw, 2200px); }

/*
  ── A ZONE IS DRAGGED FROM ITS BOTTOM-RIGHT CORNER ──────────────────────────────

  How many rows a zone should show is a different answer on every farm, every screen and
  every morning: four sheets waiting or forty, a laptop or the scale house's widescreen.
  A fixed cap is right for one of those and wrong for the rest.

  `resize` needs a non-visible overflow, which every scroll zone already has, so the
  browser draws the handle and no JS is needed to move it. The second rule is what makes
  it work in both directions: resize sets an inline HEIGHT, a max-height would cap that,
  and a zone that can be dragged shorter but never taller reads as a broken handle. Once
  there is a height — dragged, or restored on load — the cap steps out of the way.

  The cap therefore has to live in a stylesheet rather than a style attribute: an inline
  max-height outranks any rule trying to lift it.
*/
/*
  ── THE FIELD LIST'S THREE STATES ───────────────────────────────────────────────

  Green is in this crop's database, red is set aside, and a plain row has not been
  decided. Carried as background-IMAGES for the same reason the source tints are: the row
  hover is a background-colour, and it slides underneath rather than replacing them, so a
  green row stays green under the pointer instead of going flat grey.

  Faint. This is a state marking on a table somebody reads across, not a warning — at
  full strength forty green rows are a wall, and the one red row stops being the thing
  the eye goes to.

  The farm band is a heading, not a state, so it gets weight rather than colour.
*/
.oc-included > td { background-image: linear-gradient(rgba(47,158,68,.13), rgba(47,158,68,.13)); }
.oc-excluded > td { background-image: linear-gradient(rgba(214,57,57,.13), rgba(214,57,57,.13)); }
.oc-excluded > td:nth-child(3) { text-decoration: line-through; text-decoration-color: rgba(214,57,57,.6); }
tr.oc-farm > td {
  font-weight: 700; letter-spacing: .04em;
  background: var(--tblr-bg-surface-secondary);
  border-top: 1px solid var(--tblr-border-color);
}

/*
  An armed alert bell, filled rather than outlined.

  `fill` on the path, not a colour on the button: the icons are stroked outlines, so a
  text colour alone changes the outline and leaves the middle empty — which at a glance is
  the same shape as the silent one. Filling the body is what makes "this will make a
  sound" readable without looking closely.
*/
/*
  ── WHICH CROP, WHICH SEASON ────────────────────────────────────────────────────

  These two decide what every figure on every page means, and they were nav links in the
  same ink and weight as Browse and Reports — so the only thing distinguishing a potato
  tab from a wheat one was set to look like somewhere to go rather than a fact about
  where you are.

  Amber and bold, with the season a shade quieter than the crop: the crop chooses the
  database, the season chooses a year within it, and the type should say which of those
  is the larger statement. Both stay dropdowns — they are also how you switch.

  Uppercase for the crop only. "POTATO" beside "Season 2026" reads as a label and a
  qualifier; both shouted would be two headlines competing.
*/
.nav-link.hl-crop .nav-link-title {
  color: var(--tblr-primary);
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
}
.nav-link.hl-season .nav-link-title {
  color: var(--tblr-primary);
  font-weight: 600;
}
/* The archive marker keeps its own colour — it is a warning, not part of the label. */
.nav-link.hl-season .nav-link-title .text-orange { font-weight: 500; }

.hl-bell-on { color: var(--tblr-primary); }
.hl-bell-on svg { fill: currentColor; fill-opacity: .35; }

/*
  A FLOOR ON THE DRAG.

  `resize: vertical` moves the BOTTOM edge, which can never rise above the element's own
  top — that would be a negative height. So on a zone whose top sits partway down the
  page, dragging upward stops responding once the cursor passes that top edge while the
  mouse carries on moving, which reads as the resizer dying halfway up the screen.

  Nothing in CSS can lift that: the bottom edge cannot outrank the top. What a floor does
  is make it stop at a size that still shows something, instead of collapsing toward a
  sliver first and only then going dead. Roughly three rows and the header.
*/
.hl-resize { overflow: auto; resize: vertical; min-height: 8rem; }
/*
  THE GRIP IS DRAWN, because the browser's own is built for a white page.

  Chrome's default resizer is a pale diagonal graphic on a transparent ground — on the
  panel's dark surfaces it reads as a small white notch cut out of the corner of the card,
  which looks like a rendering fault rather than a handle.

  Replaced with two strokes in the border colour, so it is the same grey as every other
  division on the page and works in both themes without a second rule. Sized in the
  gradient rather than by a border, which the resizer does not honour.

  Firefox draws its own themed grip and ignores this; Safari uses the WebKit pseudo like
  Chrome. No browser is left without a visible handle either way.
*/
.hl-resize::-webkit-resizer {
  background-color: transparent;
  background-image: linear-gradient(
    135deg,
    transparent 0 42%,
    var(--tblr-border-color) 42% 54%,
    transparent 54% 66%,
    var(--tblr-border-color) 66% 78%,
    transparent 78%
  );
}
/*
  !important, and not for convenience. The caps it has to overrule are written at every
  specificity the panel uses — `.zonescroll` and `.inboxscroll` are classes, but the Links
  zone sets its 560px through `#links-scroll`, and an ID beats any number of classes. A
  zone whose cap happened to be written as an ID would otherwise be the one zone that
  could be dragged shorter and never taller, which is a bug nobody would connect to a
  selector.
*/
.hl-resize[style*="height"] { max-height: none !important; }

/*
  ── A ROW THAT ANSWERS THE FINGER ───────────────────────────────────────────────

  Rows that open something — the sheet inbox, the loads list, a field's card — showed a
  hover on a desktop and nothing at all under a finger. A tap that opens a dialog a
  moment later, with no acknowledgement in between, reads as a tap that missed, so the
  scaler taps again and the second one lands on whatever the dialog put there.

  Applied to the CELLS rather than the row, because a <tr> is not a painting surface in
  a table: a background on it is drawn under the cells' own and never seen. Carried as
  background-color so the source tints above — which are background-IMAGES precisely so
  a highlight can slide beneath them — keep their colour while the row is held.

  The mouse gets it too. It is the same statement to both, and a button that depresses
  under a pointer is not a touch affordance, it is feedback.
*/
tr.pick:active > td,
tr.ld:active > td,
tr[data-fcard]:active > td {
  background-color: var(--tblr-bg-surface-secondary);
}
/*
  iOS paints its own grey flash over anything tappable, on its own schedule and in its
  own colour. Turned off so the rule above is the only answer, rather than two of them
  fighting over one row.
*/
tr.pick, tr.ld, tr[data-fcard] { -webkit-tap-highlight-color: transparent; }

/*
  ── THE FILTER BOX AND ITS CLEAR ────────────────────────────────────────────────

  Every zone that filters gets the same box and the same X, from hlFilterBox() — the
  panel had a "Clear" button beside some lists, nothing at all beside others, and no way
  to empty a filter except selecting the text. One shape, defined once, so they cannot
  drift apart the next time a zone gains a filter.

  LEFT, not right, and inside the field. The right-hand end of these inputs is where the
  text ends up as it is typed, so a control there is under the cursor exactly when it is
  most likely to be hit by accident. The left is empty whatever has been typed.

  Shown only when there is something to clear: an X on an empty box is a control that
  does nothing, and the row of them across a page reads as clutter.
*/
.hl-filterbox { position: relative; }
/*
  Padded only while the X is actually there. A constant 2.1rem indented every placeholder
  in the panel to make room for a control that appears once something has been typed — so
  an empty box looked wrongly aligned against every other input on the page, which is most
  of the time a filter box is looked at.

  The text shifting when the X appears is the right kind of movement: it happens at the
  moment the control arrives, so it reads as making room rather than as a jump.
*/
.hl-filterbox.has-value > .form-control { padding-left: 2.1rem; }
.hl-filterbox > .hl-filterclear {
  position: absolute; left: .3rem; top: 50%; transform: translateY(-50%);
  display: none; align-items: center; justify-content: center;
  width: 1.5rem; height: 1.5rem; padding: 0; line-height: 1;
  border: 0; border-radius: 50%; background: transparent;
  color: var(--tblr-secondary); font-size: 1.15rem; cursor: pointer;
}
.hl-filterbox.has-value > .hl-filterclear { display: flex; }
.hl-filterbox > .hl-filterclear:hover { background: var(--tblr-bg-surface-secondary); color: var(--tblr-body-color); }
/* The small variant used in Setup's reference lists, where the input is form-control-sm. */
.hl-filterbox.has-value > .form-control-sm { padding-left: 1.9rem; }
.hl-filterbox > .form-control-sm ~ .hl-filterclear { width: 1.3rem; height: 1.3rem; font-size: 1rem; }

/* A whole ROW the pull's filters claimed, in the full pulled-fields view — the same
   tint as .jd, carried as an image so the hover colour slides underneath it. */
.table tbody tr.src-match > td { background-image: linear-gradient(rgba(var(--hl-src-rgb), .10), rgba(var(--hl-src-rgb), .10)); }

/* A fault on a page nobody is looking at, said in the menu. Deliberately a dot and not
   a count: there is one John Deere connection per farm, so a number could only ever
   be 1. */
/*
  THE CORNER, NOT THE END OF THE LINE.

  It used to sit inline after the label, vertically centred — which puts a coloured dot
  exactly where a full stop goes, so it read as punctuation on the end of the word rather
  than as a mark on the item. A notification badge belongs at the top right, clear of the
  text, which is where every other application puts one and therefore where the eye
  already looks for it.

  Positioned against `.nav-link-title.has-badge` rather than the link: the link is as wide
  as its padding makes it, so the dot would drift away from the word on a short label and
  sit under it on a long one. The title box is the word.

  A little room is reserved on the right so the dot has somewhere to be that is not the
  next menu item — it overhangs the text, but only into the link's own padding.
*/
.nav-link-title.has-badge { position: relative; padding-right: .5rem; }
.nav-badge {
  position: absolute;
  top: -.1rem;
  right: -.1rem;
  width: .5rem; height: .5rem;
  border-radius: 50%;
  background: var(--tblr-danger, #d63939);
}
.nav-badge.d-none { display: none !important; }

/*
  BLUE, BECAUSE NOTHING IS BROKEN.

  Red is a fault and orange is a warning; a driver waiting to be let in is neither. It is
  somebody standing at the window, and the only wrong response is not noticing.

  Same bare dot as the one beside it — the dot's job is to send somebody to the page, and
  the page says who and how many. A count here would be a second place for the same fact
  to be told, and the one that goes stale.
*/
.nav-badge-blue { background: #2f6fd0; }
[data-bs-theme="dark"] .nav-badge-blue { background: #4a90e2; }

/*
  ── BUTTONS: ONE RULE, SO A PAGE STOPS LOOKING LIKE FOUR PAGES ──────────────────

  Ghost buttons are gone. A control with no outline reads as text until it is hovered,
  which is how a page ends up with things that look like labels and things that look
  like buttons doing the same kind of job.

    in a card HEADER      btn-sm         primary action btn-primary,
                                         others btn-outline-secondary / -danger
    in a card BODY        full size      same three
    inside a .lrow        btn-sm         btn-outline-primary

  One btn-primary per card: the thing you came to that card to do.

  ── GROUPS ──────────────────────────────────────────────────────────────────────

  Fields and buttons that belong to each other sit inside one outline, with a small
  heading. A card body that is a flat run of inputs and buttons makes the reader work
  out the grouping from spacing alone, and spacing is exactly what gets lost when a
  panel is redrawn or read on a phone.
*/
.group {
  border: 1px solid var(--tblr-border-color);
  border-radius: var(--tblr-border-radius, 4px);
  padding: .875rem;
  margin-bottom: 1rem;
}
.group:last-child { margin-bottom: 0; }
.group > .group-title {
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--tblr-secondary-color);
  margin-bottom: .75rem;
}
/* The row of buttons that acts on the group it closes. */
.group-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin-top: .875rem;
}

/*
  A bordered list of rows, each with something on the left and a control on the right.

  These classes were invented in setup.html and their rules stayed in that page's own
  <style> block. The Connections page then used the same markup and got NOTHING — no
  flex, no padding, no border, no gap — so the organization name and its button sat
  against each other with nowhere to breathe. Rules that two pages use belong here.

  Wraps rather than squeezes: on a phone the button drops under the name instead of
  crushing it to two characters and an ellipsis.
*/
.list {
  border: 1px solid var(--tblr-border-color);
  border-radius: var(--tblr-border-radius, 4px);
}
.list .lrow {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .5rem 1rem;
  padding: .625rem .75rem;
  border-bottom: 1px solid var(--tblr-border-color);
}
.list .lrow:last-child { border-bottom: none; }
/* The name takes the slack so the control is pushed to the right edge. */
.list .lrow > .form-check { flex: 1 1 12rem; min-width: 0; }

/*
  TEN ROWS, THEN SCROLL.

  A contractor's John Deere account can hold hundreds of clients, and the whole list
  rendered inline pushed every step after it — crop types, fields, the pull button —
  off the bottom of the screen. Ten is enough to recognise the account and short
  enough to leave the sequence visible.

  Derived from the row height rather than a round number of pixels, so a change to
  .lrow padding cannot quietly turn this into nine and a half. The variable is the
  single place to correct if that measurement ever drifts: content line (1.25rem) +
  padding (.625rem twice) + the 1px rule between rows.
*/
.list.rows-10 {
  --hl-lrow-h: calc(1.25rem + 1.25rem + 1px);
  max-height: calc(var(--hl-lrow-h) * 10);
  overflow-y: auto;
}

/*
  Coloured panels need a THICKER edge in light mode.

  A tinted background carries the meaning well enough on a dark surface, but on a white
  one a 1px pale border and a 6%-opacity fill are nearly the same colour as the page —
  the panel reads as a plain box and the green or amber does no work at all. A 4px bar
  down the leading edge is the cheapest way to make the colour survive a bright screen,
  and it stays out of the way of the text.
*/
.alert { border-left-width: 4px; }
.alert-success { border-left-color: var(--tblr-success); }
.alert-warning { border-left-color: var(--tblr-warning); }
.alert-danger  { border-left-color: var(--tblr-danger); }
.alert-info    { border-left-color: var(--tblr-info); }

/* The same problem on the Fields zone's machine-reported columns: a 10% tint vanishes
   on white. The heading keeps a solid rule under it so the group is still readable as a
   group even where the fill is faint. Colour from --hl-src-rgb, like the rest. */
[data-bs-theme="light"] .jd { background-image: linear-gradient(rgba(var(--hl-src-rgb), .16), rgba(var(--hl-src-rgb), .16)); }
[data-bs-theme="light"] .table tbody td.jd,
[data-bs-theme="light"] .table tbody th.jd { background-image: linear-gradient(rgba(var(--hl-src-rgb), .16), rgba(var(--hl-src-rgb), .16)); }
[data-bs-theme="light"] .table thead th.jd { background: rgba(var(--hl-src-rgb), .26); }
[data-bs-theme="light"] .table tbody tr.src-match > td { background-image: linear-gradient(rgba(var(--hl-src-rgb), .16), rgba(var(--hl-src-rgb), .16)); }
thead th.jd { border-bottom: 3px solid rgba(var(--hl-src-rgb), .75); }

/*
  AN OUTLINED CARD IS ONE THAT WANTS SOMETHING.

  The rim used to say what KIND of thing a card held — blue for links, green for sheets —
  which meant almost every card on the page had one, and a marking that is everywhere
  marks nothing. It says one thing now: there is work waiting in here. Sheets to place,
  drivers asking to pair. A card nobody has to act on is left plain.

  No exceptions. The John Deere cards used to carry one as a SOURCE marking and it was
  wrong twice over — it was not the platform's green once Tabler had toned it, and a
  results table demands nothing of anybody. They carry a tinted heading row instead.

  2px, and the whole way round rather than a bar down one edge: these are peers on a page,
  not alerts stacked in a column, and a left-edge rule reads as "this one is special" when
  each is simply itself.
*/
.card.border-primary,
.card.border-success,
.card.border-warning,
.card.border-danger,
.card.border-info,
.card.border-azure {
  border-width: 2px;
}

/*
  A CARD WHOSE WHOLE CONTENTS CAME FROM THE MACHINE.

  Where a table mixes sources — Browse's HarvestLog Fields zone — the green marks the
  COLUMNS that are Deere's, because the point is telling them from the scale's. Where
  everything in the card came from one pull, marking a column says nothing and quietly
  implies the others are ours. So the HEADING ROW carries it.

  The heading only, and no rim: an outlined card on this panel means work is waiting in
  it, and a table of results asks for nothing. Faint, because this is a source marking
  rather than a warning, and it sits under text that stays legible in both themes.
*/
.jd-card thead th {
  background: rgba(var(--hl-src-rgb), .18);
  border-bottom: 2px solid rgba(var(--hl-src-rgb), .55);
}
[data-bs-theme="light"] .jd-card thead th { background: rgba(var(--hl-src-rgb), .22); }

/*
  The little "i" that opens a zone's explanation.

  Defined here rather than on one page because two pages now carry one, and a third
  will: an affordance that means "there is something to read here" has to look identical
  everywhere or it stops being recognised as the same thing.
*/
.hl-info {
  cursor: pointer;
  color: var(--tblr-secondary-color);
  border: 1px solid var(--tblr-border-color);
  background: transparent;
  border-radius: 50%;
  width: 19px;
  height: 19px;
  padding: 0;
  line-height: 1;
  font-size: .75rem;
  font-style: italic;
  font-weight: 700;
  font-family: Georgia, 'Times New Roman', serif;   /* a serif i reads as an i, not an l */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.hl-info:hover, .hl-info:focus-visible {
  color: var(--tblr-primary);
  border-color: var(--tblr-primary);
}
/* Beside the heading, not riding on its baseline. */
.card-title .hl-info { margin-left: .5rem; vertical-align: middle; }

/*
  A short farm address, set apart from a farm that has a real name. The letters were
  spaced out — "W H B" — and are not any more; the italic is what marks it now.

  The padding is not decoration. An italic glyph leans PAST its advance width, so the
  last letter's tail sits outside the box the browser measured — and a "B" at the end of
  a slug lost its corner wherever the container clipped or the next element began. Two
  pixels is the lean; padding gives it somewhere to be.
*/
.org-slug {
  font-style: italic;
  padding-right: 2px;
}

/*
  ── UNDER THE NOTCH ─────────────────────────────────────────────────────────────

  The panel's pages declare viewport-fit=cover, so on a phone the page owns the whole
  screen including the strip behind the Dynamic Island. A tall dialog — the field card is
  the tallest — is centred in that whole screen and its top slid up behind the island,
  taking the field name and the close button with it.

  Insetting the DIALOG rather than the page: the backdrop should still cover the screen
  edge to edge, because a dark overlay that stops short of the island looks like a bug of
  its own. Only the content it holds needs to keep clear.

  A centred modal also needs its available height reduced by the same amount, or the
  padding pushes the bottom off instead of shortening the box.
*/
@media (max-width: 1199.98px) {
  .modal .modal-dialog {
    padding-top: env(safe-area-inset-top);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .modal .modal-dialog-centered {
    min-height: calc(100% - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  }
  /* The field card scrolls inside itself rather than growing past the screen. */
  .modal .modal-content { max-height: calc(100dvh - env(safe-area-inset-top) - env(safe-area-inset-bottom) - 16px); }
  .modal .modal-body { overflow-y: auto; }
}

/*
  ── THE HAMBURGER'S CONTROL BLOCKS ──────────────────────────────────────────────

  Appearance, Crop and Season are three button groups stacked in the collapsed menu, and
  they were three different heights: the theme buttons carry an icon beside their label
  and the others carry text alone, so each group sized itself to its own content. Stacked,
  that reads as three unrelated controls rather than one set.

  So the buttons share a height and their labels centre in it, whether or not there is an
  icon. The spacing between blocks is set here too rather than on each host, so adding a
  fourth needs no new margin.

  Phone widths only — above MD these live on the bar and in the profile menu, where they
  are laid out by their own rules.
*/
/* Follows the header: the tabs now collapse at lg, so the menu they collapse INTO is
   styled below lg too. */
@media (max-width: 991.98px) {
  #hl-theme-menu, #hl-tenant-menu, #hl-season-menu { margin-top: 1rem !important; }
  #hl-theme-menu .btn,
  #hl-tenant-menu .btn,
  #hl-season-menu .btn {
    min-height: 2.25rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .35rem;
  }
  /* NOT full width — see the note in hlPaintThemeControls. Stretched across a phone each
     button gets an inch of empty space around a two-word label, and the group sits wider
     than the page titles above it. They size to their labels; the shared height is what
     makes them a set. */
  /* One rhythm between blocks: the crop group carried its own mb-2, so the gap under Crop
     was larger than the one under Appearance. The host margin is the only spacing now. */
  #hl-tenant-menu .btn-group { margin-bottom: 0 !important; }
  /*
    THE SELECTED BUTTON DRAWS ITS OWN EDGE, and draws it on top.

    Buttons in a group overlap by a pixel on purpose — Bootstrap pulls each one back over
    its neighbour so the shared border is a single line rather than two. Whichever button
    is painted LAST wins that pixel, so the filled yellow one at the right-hand end laid
    its background over the outline of the button beside it and the group looked like it
    had lost a border.

    Lifting the active button above its neighbours means its own border is the one that
    survives the overlap, which is the line that should win: it is the edge of the thing
    currently chosen. `position: relative` because z-index does nothing to a static box.
  */
  #hl-theme-menu .btn-group > .btn.btn-primary,
  #hl-tenant-menu .btn-group > .btn.btn-primary,
  #hl-season-menu .btn-group > .btn.btn-primary {
    position: relative;
    z-index: 2;
  }
  /* The little grey caption above each group, on one rhythm. */
  #hl-theme-menu > .text-secondary,
  #hl-tenant-menu > .text-secondary,
  #hl-season-menu > .text-secondary { margin-bottom: .35rem !important; }
}

/*
  ── THE MARK, CENTRED ON A SMALL SCREEN ────────────────────────────────────────

  Below md the top bar carries three things: the hamburger on the left, the account chip
  on the right, and the mark. In normal flow the mark sits immediately after the toggle,
  so it reads as a label hanging off the menu button rather than as the identity of the
  page — and because the two ends are different widths, no amount of auto margin puts it
  in the middle.

  Taken OUT of the flow and pinned to the centre of the bar instead, which is the only way
  to centre against two unequal neighbours. pointer-events stays on so it remains
  clickable, but it takes no width, so the toggle and the chip lay out as though it were
  not there and cannot be pushed around by it.

  Above md it returns to the flow untouched — see the note in shared.js about the mark
  anchoring the right-hand end of the bar at desktop widths.
*/
@media (max-width: 767.98px) {
  .navbar > .container-xl,
  .navbar > .container-fluid { position: relative; }

  #hl-brand {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    margin: 0;
    padding: 0;
    /* The farm name is already d-none below xl; this keeps the box to the icon itself so
       the centring is the ICON's centre and not a text box's. */
    width: auto;
    max-width: 40vw;
  }
}

/*
  ── THE FIELD CARD ──────────────────────────────────────────────────────────────

  These rules were in browse.html, which was the only page the card could be opened
  from. It opens from the dashboard now too — the card itself moved to shared.js — and
  a page-local stylesheet cannot follow it. So they live here, with everything else the
  panel shares.

  Nothing about them changed in the move. Left alone deliberately, so that if the card
  ever looks wrong on one page and right on another, it is not because the styling was
  quietly rewritten on its way across.
*/

/*
  THE FIELD CARD'S SECTIONS, kept apart.

  The card was one continuous run of tiles and lines: acreages, rates, sky, storage and
  Deere's own figures all at the same rhythm, so nothing said where one subject ended
  and the next began. Each block now carries a quiet heading and real space beneath it,
  and a hairline divides them — a rule rather than a bigger gap, because whitespace
  alone at this density reads as an accident.

  The last block takes no rule or margin, so the card does not end on a line pointing at
  the table below it.
*/
.fc-block { padding-bottom:14px; margin-bottom:14px; border-bottom:1px solid var(--tblr-border-color); }
.fc-block:last-of-type { padding-bottom:0; margin-bottom:16px; border-bottom:0; }
.fc-head {
  font-size:11px; font-weight:700; letter-spacing:.09em; text-transform:uppercase;
  color:var(--tblr-secondary); margin-bottom:10px;
}
/* The tiles inside a block sit closer to their heading than the blocks do to each
   other, or the grouping the heading creates is undone by the spacing. */
.fc-block .row > div { margin-bottom:10px; }
/*
  A PILL IS THE SAME SIZE AS A PLAIN FIGURE.

  `.badge` carries its own font-size, so every number wearing the green source pill
  printed a step smaller than the ones beside it in plain type. Deere's figures then
  looked like footnotes to the scale house's — a difference in importance, when the
  only difference is where the number came from.

  `inherit` rather than a fixed size, so it tracks .fs-3 if that ever changes. The grey
  unit suffix beside a value stays .fs-5: that IS subordinate, and correctly smaller.
*/
.fc-block .fs-3 .badge {
  font-size:inherit; font-weight:700; vertical-align:baseline; padding:.1em .45em;
}
/*
  THE FIELD'S IDENTITY IN OPERATIONS CENTER, printed as a reference.

  Monospace because it is an identifier and not prose — a UUID set in a proportional
  face is unreadable back to somebody checking it against a screen in Operations Center.
  `user-select:all` so one click takes the whole of it and not a word between hyphens.

  It also happens to be the fastest way to tell a real field from a seeded one: Deere's
  ids are UUIDs, and a demo farm's are not.

  THE FAMILY IS SET HERE rather than left to Bootstrap's `font-monospace` utility, which
  was tried first and lost: the computed face came back as Inter, the panel's proportional
  body font, so the id printed in exactly the type this rule exists to avoid. Naming the
  stack in the rule that owns the element settles it without depending on which of two
  frameworks' utilities wins.
*/
.fc-jdid {
  font-family: var(--tblr-font-monospace, ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace);
  font-size:11px; letter-spacing:.02em; user-select:all;
}
