/* ============================================================================
   TEZTRAK CHECKBOX — the one checkbox in the app (2026-09-18)

   WHY THIS FILE EXISTS
   Before it, the control was defined eight times over: three passes in
   trakzo-map.css for dialogs, a separate one for .checkbox-inline, one for the
   sidebar history form, one more inside the Camera/Media dialog, and two in
   trakzo-admin.css (pages and dialogs). They disagreed on size (16 vs 18), on
   corner (4, 5, 6), and on which element draws the box — some painted it on the
   label, some on label::before — so whenever two met in one screen they
   half-applied over each other and produced the bugs reported through September:
   a squashed blob beside "Devices limit", an unclickable box, a white edge
   around a ticked box.

   This file is now the only place the control is described. Everything that
   follows is the whole component: the box, the tick, the hit area and the
   states. To change how a checkbox looks anywhere in the product, change it
   HERE — and nowhere else.

   WHERE IT APPLIES
   It is keyed to the markup the app already writes, so no template had to change
   for it to take effect:

     A.  <div class="checkbox">            upstream/Bootstrap 3, a separate label.
           <input type="checkbox">         The label is often EMPTY, in which case
           <label for=""></label>          the box is the whole control.
         </div>

     B.  <label class="checkbox-inline">   Bootstrap's inline form, input inside.
           <input type="checkbox"> Text
         </label>

         ...but the app ALSO writes .checkbox-inline as a plain <div> around a
         separate label (Password change > Autogenerate). Which element draws the
         box therefore depends on the tag, not the class: a <label> container
         draws it itself, anything else leaves it to the label inside.

     C.  <label class="tz-check">          What new code should write. The Blade
           <input type="checkbox">         component <x-checkbox> renders this;
           <span>Text</span>               see Tobuli/Views/components/checkbox.blade.php
         </label>

   HOW IT IS BUILT
   The native input stays in the DOM and stays the hit target — it is made
   invisible and stretched over the control, never collapsed to 0x0, because a
   label with for="" is not bound to anything and a collapsed input leaves
   nothing to click. The box is drawn on ::before and the tick is a background
   image on that same box, so one element carries both and they cannot drift
   apart.

   ABOUT !important
   The legacy skins (light-blue.css, updated.css, assets/custom/css.css) declare
   their own checkbox with !important and cannot be edited safely — one of them
   is the previous developer's and is still relied on elsewhere. The component
   therefore declares !important too, and this file is loaded last. That is the
   only reason for it; do not read it as a licence to fight this file with more
   !important from outside. Change it here instead.

   TOKENS
   Size, colour and corner come from the variables below. Override them on a
   container to vary a checkbox in one place (see "sizes" at the end) rather than
   writing a new rule for the control.
   ============================================================================ */

body.trakzo{
  --tz-check-size:18px;
  --tz-check-radius:6px;
  --tz-check-gap:9px;
  --tz-check-bg:var(--raised);
  --tz-check-ring:var(--line);
  --tz-check-ring-hover:var(--line-strong);
  --tz-check-on:var(--lime);
  --tz-check-mark:#FFFFFF;
  --tz-check-mark-size:12px;
  /* the tick. One stroked path, coloured by the mark token at build time below */
  --tz-check-tick:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FFFFFF' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'><path d='M4 12.5 9.5 18 20 6.5'/></svg>");
  --tz-check-dash:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FFFFFF' stroke-width='3.4' stroke-linecap='round'><path d='M6 12h12'/></svg>");
}

/* ---------------------------------------------------------------------------
   1. THE CONTAINER
   .checkbox keeps Bootstrap's block behaviour (one per line, as the forms that
   use it expect); the inline variants stay inline. Spacing between checkboxes
   belongs to the screen, not to the control, so no margins are set here.
   --------------------------------------------------------------------------- */
body.trakzo .checkbox,
body.trakzo .checkbox-inline,
body.trakzo .tz-check{
  position:relative !important;
  display:flex !important;align-items:center !important;
  gap:var(--tz-check-gap) !important;
  min-height:0 !important;padding:0 !important;
  line-height:1.35 !important;vertical-align:middle;
  cursor:pointer}
body.trakzo .checkbox-inline,
body.trakzo .tz-check{display:inline-flex !important}
/* A box with no text, in a table cell, is only as wide as its box, so it follows
   the cell's text-align like any other cell content. As a full-width row it sat
   at the cell's left edge whatever the cell asked for: Admin > Users > Edit >
   Permissions centres View/Edit/Delete and their headings, and every box landed
   90px left of its heading, under the column before (2026-09-26). In a
   left-aligned cell the box stays exactly where it was. The .modal pair has to
   outrank trakzo-map.css "8. checkbox rows", which makes every checkbox in a
   dialog a full-width form row — right for a box with its text, not for a cell. */
body.trakzo td > .checkbox:has(> label:empty),
body.trakzo th > .checkbox:has(> label:empty),
body.trakzo .modal .modal-body td > .checkbox:has(> label:empty),
body.trakzo .modal .modal-body th > .checkbox:has(> label:empty){display:inline-flex !important}
/* a container that is not itself a label never draws the box — the label does */
body.trakzo .checkbox::before,body.trakzo .checkbox::after,
body.trakzo div.checkbox-inline::before,body.trakzo div.checkbox-inline::after{
  content:none !important;display:none !important}

/* ---------------------------------------------------------------------------
   2. THE HIT TARGET
   The input covers its container so the box AND its text are clickable, with a
   floor of one box so a control that is only a box still has something to hit.
   Opacity, not display:none — a hidden input is not focusable and would take
   keyboard use away with it.
   --------------------------------------------------------------------------- */
body.trakzo .checkbox > input[type=checkbox],
body.trakzo .checkbox-inline > input[type=checkbox],
body.trakzo .tz-check > input[type=checkbox]{
  position:absolute !important;left:0 !important;top:50% !important;
  transform:translateY(-50%) !important;
  width:100% !important;height:100% !important;
  min-width:var(--tz-check-size) !important;min-height:var(--tz-check-size) !important;
  margin:0 !important;padding:0 !important;
  opacity:0 !important;cursor:pointer !important;z-index:3 !important}

/* A control that is only a box must not reach past it onto whatever sits
   alongside — a users-list cell is 36px wide for an 18px box. */
body.trakzo .checkbox:has(> label:empty) > input[type=checkbox],
body.trakzo div.checkbox-inline:has(> label:empty) > input[type=checkbox],
body.trakzo .tz-check:not(:has(.tz-check-label)) > input[type=checkbox]{
  width:var(--tz-check-size) !important;max-width:var(--tz-check-size) !important}
/* ...unless the box IS its own column, where filling it is the bigger target */
body.trakzo .checkbox.input-group-btn:has(> label:empty) > input[type=checkbox]{
  width:100% !important;max-width:100% !important;min-width:0 !important}

/* ---------------------------------------------------------------------------
   3. THE LABEL
   In form A the label is a sibling and may be empty; in B and C the text is
   inside. Either way it is laid out as a row and never draws anything itself.
   --------------------------------------------------------------------------- */
body.trakzo .checkbox > label,
body.trakzo div.checkbox-inline > label,
body.trakzo .tz-check > .tz-check-label{
  display:flex !important;align-items:center !important;
  gap:var(--tz-check-gap) !important;
  margin:0 !important;padding:0 !important;
  min-height:0 !important;min-width:0 !important;
  font-weight:500 !important;line-height:1.35 !important;cursor:pointer;
  background:transparent !important;box-shadow:none !important;border:0 !important;
  border-radius:0 !important}
body.trakzo .checkbox > label:empty,
body.trakzo div.checkbox-inline > label:empty{
  flex:0 0 var(--tz-check-size) !important;
  width:var(--tz-check-size) !important;height:var(--tz-check-size) !important;
  align-self:center !important}

/* ---------------------------------------------------------------------------
   4. THE BOX
   One element draws the box and the mark. In form A it hangs off the label; in
   B and C the container is the label, so it hangs off the container.
   --------------------------------------------------------------------------- */
body.trakzo .checkbox > label::before,
body.trakzo div.checkbox-inline > label::before,
body.trakzo label.checkbox-inline::before,
body.trakzo .tz-check::before{
  content:"" !important;display:block !important;
  position:static !important;top:auto !important;left:auto !important;
  flex:0 0 var(--tz-check-size) !important;
  width:var(--tz-check-size) !important;height:var(--tz-check-size) !important;
  margin:0 !important;padding:0 !important;
  border:0 !important;border-radius:var(--tz-check-radius) !important;
  transform:none !important;
  background-color:var(--tz-check-bg) !important;
  background-image:none !important;
  background-repeat:no-repeat !important;
  background-position:50% 50% !important;
  background-size:var(--tz-check-mark-size) var(--tz-check-mark-size) !important;
  box-shadow:inset 0 0 0 1.5px var(--tz-check-ring) !important;
  /* the glyph fonts of the old skins leak through ::before; neutralise them */
  font-size:0 !important;color:transparent !important;font-family:inherit !important;
  text-indent:0 !important;
  transition:background-color .12s ease, box-shadow .12s ease}

/* the old skins also draw a second mark on ::after — there is only one box here */
body.trakzo .checkbox > label::after,
body.trakzo div.checkbox-inline > label::after,
body.trakzo label.checkbox-inline::after,
body.trakzo .tz-check::after{
  content:none !important;display:none !important}

/* ---------------------------------------------------------------------------
   5. STATES
   --------------------------------------------------------------------------- */
body.trakzo .checkbox > input[type=checkbox]:checked + label::before,
body.trakzo div.checkbox-inline > input[type=checkbox]:checked + label::before,
body.trakzo label.checkbox-inline:has(> input[type=checkbox]:checked)::before,
body.trakzo .tz-check:has(> input[type=checkbox]:checked)::before{
  background-color:var(--tz-check-on) !important;
  background-image:var(--tz-check-tick) !important;
  box-shadow:none !important;border:0 !important}

body.trakzo .checkbox > input[type=checkbox]:indeterminate + label::before,
body.trakzo div.checkbox-inline > input[type=checkbox]:indeterminate + label::before,
body.trakzo label.checkbox-inline:has(> input[type=checkbox]:indeterminate)::before,
body.trakzo .tz-check:has(> input[type=checkbox]:indeterminate)::before{
  background-color:var(--tz-check-on) !important;
  background-image:var(--tz-check-dash) !important;
  box-shadow:none !important}

body.trakzo .checkbox:hover > label::before,
body.trakzo div.checkbox-inline:hover > label::before,
body.trakzo label.checkbox-inline:hover::before,
body.trakzo .tz-check:hover::before{
  box-shadow:inset 0 0 0 1.5px var(--tz-check-ring-hover) !important}
body.trakzo .checkbox:hover > input[type=checkbox]:checked + label::before,
body.trakzo div.checkbox-inline:hover > input[type=checkbox]:checked + label::before,
body.trakzo label.checkbox-inline:has(> input[type=checkbox]:checked):hover::before,
body.trakzo .tz-check:has(> input[type=checkbox]:checked):hover::before{
  box-shadow:none !important;filter:brightness(1.06)}

body.trakzo .checkbox > input[type=checkbox]:focus-visible + label::before,
body.trakzo div.checkbox-inline > input[type=checkbox]:focus-visible + label::before,
body.trakzo label.checkbox-inline:has(> input[type=checkbox]:focus-visible)::before,
body.trakzo .tz-check:has(> input[type=checkbox]:focus-visible)::before{
  outline:2px solid var(--lime-s) !important;outline-offset:2px !important}

body.trakzo .checkbox:has(> input[type=checkbox]:disabled),
body.trakzo .checkbox-inline:has(> input[type=checkbox]:disabled),
body.trakzo .tz-check:has(> input[type=checkbox]:disabled),
body.trakzo .checkbox.disabled{opacity:.5 !important;cursor:default}
body.trakzo .checkbox:has(> input[type=checkbox]:disabled) > input,
body.trakzo .checkbox-inline:has(> input[type=checkbox]:disabled) > input,
body.trakzo .tz-check:has(> input[type=checkbox]:disabled) > input{cursor:default !important}

/* ---------------------------------------------------------------------------
   6. SIZES
   Set a token, not a new rule. `.tz-check--sm` on the control, or
   `--tz-check-size` on any ancestor to size a whole region at once.
   --------------------------------------------------------------------------- */
body.trakzo .tz-check--sm{--tz-check-size:16px;--tz-check-radius:5px;--tz-check-mark-size:11px}
body.trakzo .tz-check--lg{--tz-check-size:22px;--tz-check-radius:7px;--tz-check-mark-size:15px}

/* ---------------------------------------------------------------------------
   7. RADIOS (2026-09-24)

   Everything above is written for input[type=checkbox]. The app also ships
   radios in the same .checkbox-inline markup — the TCP / UDP pair on the
   device dialog's Forward row is the visible one — and they fell between the
   rules: the box was drawn, but the CHECKED state only ever matched
   `input[type=checkbox]:checked`, so a selected radio looked exactly like an
   unselected one. Measured: with TCP checked and UDP not, both rendered
   rgb(23,27,33), no mark, identical. There was no way to see which protocol a
   device was using.

   So radios get the state rules they were missing, and a round box, because a
   square radio reads as a checkbox and implies you can tick both.
   --------------------------------------------------------------------------- */

/* round, not rounded-square — that is what tells you it is a one-of-many choice */
body.trakzo .checkbox:has(> input[type=radio]) > label::before,
body.trakzo div.checkbox-inline:has(> input[type=radio]) > label::before,
body.trakzo label.checkbox-inline:has(> input[type=radio])::before{
  border-radius:50% !important}

/* selected: filled, with a dot punched out of the centre. A radial-gradient
   rather than a background-image so it scales with --tz-check-size. */
body.trakzo .checkbox > input[type=radio]:checked + label::before,
body.trakzo div.checkbox-inline > input[type=radio]:checked + label::before,
body.trakzo label.checkbox-inline:has(> input[type=radio]:checked)::before{
  background-color:var(--tz-check-on) !important;
  background-image:radial-gradient(circle at 50% 50%,
      #fff 0 calc(var(--tz-check-size) * 0.20),
      transparent calc(var(--tz-check-size) * 0.20 + 0.5px)) !important;
  background-size:100% 100% !important;
  box-shadow:none !important;border:0 !important}

/* hover, matching the checkbox behaviour above */
body.trakzo .checkbox:hover > input[type=radio] + label::before,
body.trakzo div.checkbox-inline:hover > input[type=radio] + label::before{
  box-shadow:inset 0 0 0 1.5px var(--tz-check-ring-hover) !important}
body.trakzo .checkbox:hover > input[type=radio]:checked + label::before,
body.trakzo div.checkbox-inline:hover > input[type=radio]:checked + label::before{
  box-shadow:none !important;filter:brightness(1.06)}

/* keyboard focus, same as the checkbox */
body.trakzo .checkbox > input[type=radio]:focus-visible + label::before,
body.trakzo div.checkbox-inline > input[type=radio]:focus-visible + label::before{
  outline:2px solid var(--lime-s) !important;outline-offset:2px !important}

/* ---------------------------------------------------------------------------
   8. DISABLED MUST NOT UN-HIDE THE NATIVE CONTROL (2026-09-24)

   This component hides the real input (opacity:0) and draws the box itself.
   The dialog skin separately dims every disabled input in a modal to
   opacity:.55 — which is right for a text field and wrong here: it made the
   browser's OWN radio fade back into view alongside the drawn one. Two circles
   per choice, with the label text squeezed past both.

   Seen on the Forward row of the device dialog: unticking Forward disables the
   TCP / UDP radios, and that is exactly when it appeared.

   So the hidden input stays hidden whatever its state, and the WRAPPER carries
   the dimming instead — which is what the checkbox half of this file already
   did, and the radios were simply never added to it.
   --------------------------------------------------------------------------- */
body.trakzo .checkbox > input[type=checkbox]:disabled,
body.trakzo .checkbox > input[type=radio]:disabled,
body.trakzo div.checkbox-inline > input[type=checkbox]:disabled,
body.trakzo div.checkbox-inline > input[type=radio]:disabled,
body.trakzo label.checkbox-inline > input[type=checkbox]:disabled,
body.trakzo label.checkbox-inline > input[type=radio]:disabled,
body.trakzo .tz-check > input[type=checkbox]:disabled,
body.trakzo .tz-check > input[type=radio]:disabled{
  opacity:0 !important}

/* the wrapper shows the disabled state, the same way the checkboxes already do */
body.trakzo .checkbox:has(> input[type=radio]:disabled),
body.trakzo .checkbox-inline:has(> input[type=radio]:disabled){
  opacity:.5 !important;cursor:default}
body.trakzo .checkbox:has(> input[type=radio]:disabled) > input,
body.trakzo .checkbox-inline:has(> input[type=radio]:disabled) > input{
  cursor:default !important}
