/* Vautech theme: shared components (Tailwind CSS v4). Spec: SPEC.md.
   Every rule is gated on [data-theme='vautech'], so an app with several themes
   can put these classes on its markup unconditionally; other themes ignore
   them. (Exceptions, at the end: the behaviour rules of the date field and
   the toggletip, and the staging banner, which every theme needs.)
   Needs vautech-tokens.css. */

@layer components {
  /* Small-caps SemiBold title, as in "Vautech | Factuur". Needs a font with a
     real smcp feature (the Fira Sans OFL TTFs have it), or the browser fakes
     small caps with scaled capitals. */
  [data-theme='vautech'] .vt-title,
  [data-theme='vautech'] .vt-brand {
    font-weight: var(--app-weight-title);
    font-variant-caps: small-caps;
  }

  /* Brand line:
     <span class="vt-brand">Vautech <span class="vt-pipe" aria-hidden="true">|</span> Factuur</span>
     Literal spaces either side (as on the invoice) keep the accessible name
     "Vautech Factuur". The pipe has the weight and colour of the words. */
  /* One-line fact list joined by pipes: <ul class="vt-pipe-list"><li>KvK …</li>… */
  [data-theme='vautech'] .vt-pipe-list {
    display: flex;
    flex-wrap: wrap;
    list-style: none;
    margin: 0;
    padding: 0;
  }
  [data-theme='vautech'] .vt-pipe-list > li + li::before {
    content: '|';
    margin-inline: 0.3em;
  }

  /* Focus: 2px solid outline in --c-ring. */
  [data-theme='vautech'] :focus-visible {
    outline: 2px solid var(--c-ring);
    outline-offset: 2px;
  }

  /* Room below every table: when a table scrolls
     sideways, an overlay scrollbar (macOS) lands on this strip instead of on
     the last row. In the components layer, so a utility (mb-0) or app CSS on
     a table wins. */
  [data-theme='vautech'] table {
    margin-bottom: 0.75rem;
  }

  /* Ledger table: open frame, rule under the header, vertical rules between
     columns, ruled total row, unruled Medium amount-due row. Headers are
     normal case (not uppercase). In body rows the column rules stop short of
     the row edges, leaving a small gap between rows. */
  [data-theme='vautech'] .vt-ledger {
    --vt-row-gap: 4px;            /* gap in the column rules between body rows */
    --vt-column-rule: var(--c-rule);
    width: 100%;
    border-collapse: collapse;
    text-align: left;
    font-variant-numeric: tabular-nums;
  }
  [data-theme='vautech'] .vt-ledger :is(th, td) {
    position: relative;           /* anchors the column rule below */
    --vt-rule-inset: calc(var(--vt-row-gap) / 2); /* where the column rule starts and ends */
    padding: 0.3em 0.6em;
    text-align: inherit; /* table sets left; a text-right utility on the table still wins */
    vertical-align: top;
    border: 0;
    border-right: 1px solid transparent; /* keeps the layout; the rule is drawn below */
    font-weight: var(--app-weight-data);
  }
  [data-theme='vautech'] .vt-ledger :is(th, td):last-child {
    border-right: 0;
  }
  /* Column rules. Every one is drawn the same way, on the cell edge where a
     collapsed 1px border would sit, so the shortened ones in body rows and the
     full ones in the header and total rows line up at any screen density.
     A border, not a background, so it prints. Cells must not clip their
     overflow (overflow: hidden would cut the rule in half). */
  [data-theme='vautech'] .vt-ledger tr:not(.vt-due) > :is(th, td):not(:last-child)::after {
    content: '';
    position: absolute;
    top: var(--vt-rule-inset);
    bottom: var(--vt-rule-inset);
    right: -0.5px;
    border-left: 1px solid var(--vt-column-rule);
    pointer-events: none;
  }
  /* Full height in the header, and across the total rows' own rules. */
  [data-theme='vautech'] .vt-ledger thead :is(th, td) {
    --vt-rule-inset: 0px;
  }
  [data-theme='vautech'] .vt-ledger tr.vt-total > :is(th, td) {
    --vt-rule-inset: -1px;
  }
  [data-theme='vautech'] .vt-ledger thead th {
    font-weight: var(--app-weight-bold);
    text-transform: none;
    letter-spacing: normal;
    border-bottom: 1px solid var(--c-rule);
  }
  [data-theme='vautech'] .vt-ledger .vt-num {
    text-align: right;
  }
  [data-theme='vautech'] .vt-ledger tr.vt-total > * {
    border-top: 1px solid var(--c-rule);
    border-bottom: 1px solid var(--c-rule);
  }
  [data-theme='vautech'] .vt-ledger tr.vt-due > * {
    border: 0;
    font-weight: var(--app-weight-bold);
  }
  /* Editable grids: on screen only the header rule is black and the column
     rules are light, so they don't box in the inputs. In print the inputs
     flatten to text, so the full black ledger returns. */
  @media screen {
    [data-theme='vautech'] .vt-ledger.vt-editable {
      --vt-column-rule: var(--c-line);
    }
  }

  /* Tabs: the active tab gets a 2px black underline. Drawn as a background
     image, because utilities (shadow-*, border-*) would override a box-shadow
     or border from this layer. Toggles don't use vt-tab: their selected option
     is marked with a trailing pipe in app markup. */
  [data-theme='vautech'] .vt-tab[aria-current='page'],
  [data-theme='vautech'] .vt-tab[aria-selected='true'] {
    background-image: linear-gradient(var(--c-ink), var(--c-ink));
    background-size: 100% 2px;
    background-position: bottom;
    background-repeat: no-repeat;
  }

  /* Notices: <div role="alert" class="vt-notice vt-notice-danger">…</div> */
  [data-theme='vautech'] .vt-notice {
    border: 1px solid var(--c-rule);
    border-left-width: 3px;
    padding: 0.6rem 0.9rem;
    color: var(--c-ink);
    background: var(--c-surface);
  }
  [data-theme='vautech'] .vt-notice-warn {
    border-color: var(--c-warn-line);
    background: var(--c-warn-wash);
    color: var(--c-warn-ink);
  }
  [data-theme='vautech'] .vt-notice-danger {
    border-color: var(--c-danger-line);
    background: var(--c-danger-wash);
    color: var(--c-danger-ink);
  }

  /* Badge: a small square label, e.g. "Draft". */
  [data-theme='vautech'] .vt-badge {
    display: inline-block;
    border: 1px solid currentColor;
    border-radius: 0;
    padding: 0.05rem 0.4rem;
    font-size: 0.75rem;
    font-weight: var(--app-weight-bold);
    font-variant-caps: small-caps;
  }
  [data-theme='vautech'] .vt-badge-warn {
    color: var(--c-warn-ink);
    background: var(--c-warn-wash);
  }

  /* Date field (js/vautech-date.js). Text that is not a date gets a red edge
     and a message under the field; the message carries the meaning.
     !important: the app's own field border (a utility or an unlayered class)
     would otherwise win over this layer. betaaloverzicht does the same. */
  [data-theme='vautech'] .vt-date[aria-invalid='true'] {
    border-color: var(--c-danger-line) !important;
  }
  [data-theme='vautech'] .vt-date[aria-invalid='true']:focus-visible {
    outline-color: var(--c-danger-ink) !important;
  }
  [data-theme='vautech'] .vt-date-message:not([hidden]) {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.75rem;
    font-weight: var(--app-weight-bold);
    color: var(--c-danger-ink);
  }

  /* Date field in print: the input gives way to its dd-mm-yyyy text. This is
     behaviour, not looks, so unlike the rest it is not gated on the theme. */
  .vt-date-print {
    display: none;
  }
  @media print {
    .vt-date,
    .vt-date-message {
      display: none !important;
    }
    .vt-date-print {
      display: block;
      white-space: nowrap;
    }
  }
  /* Lucide icons are drawn with 1px lines at any size. Matches the
     "lucide" class that lucide-react and lucide-static put on every icon. */
  [data-theme='vautech'] svg.lucide :is(path, line, polyline, polygon, rect, circle, ellipse) {
    vector-effect: non-scaling-stroke;
    stroke-width: 1px;
  }

  /* Icon buttons (guides/icons.md): faint at rest; on hover a square in a
     palette hue's line, wash and ink. Blue by default; -danger red,
     -positive green, vt-hue-* any hue. Icons 16px, 12px inside a ledger. */
  [data-theme='vautech'] .vt-icon-button {
    --vt-hover-line: var(--vt-blue-line);
    --vt-hover-wash: var(--vt-blue-wash);
    --vt-hover-ink: var(--vt-blue-ink);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 1px solid transparent;
    background: none;
    color: var(--c-faint);
    cursor: pointer;
  }
  [data-theme='vautech'] .vt-icon-button svg {
    width: var(--vt-icon-size, 16px);
    height: var(--vt-icon-size, 16px);
  }
  [data-theme='vautech'] .vt-ledger .vt-icon-button {
    --vt-icon-size: 12px;
  }
  [data-theme='vautech'] .vt-icon-button:hover {
    border-color: var(--vt-hover-line);
    background: var(--vt-hover-wash);
    color: var(--vt-hover-ink);
  }
  [data-theme='vautech'] .vt-icon-button:disabled {
    opacity: 0.4;
    cursor: default;
  }
  [data-theme='vautech'] .vt-icon-button:disabled:hover {
    border-color: transparent;
    background: none;
    color: var(--c-faint);
  }
  /* Meaning: destructive and confirming actions. */
  [data-theme='vautech'] .vt-icon-button-danger {
    --vt-hover-line: var(--c-danger-line);
    --vt-hover-wash: var(--c-danger-wash);
    --vt-hover-ink: var(--c-danger-ink);
  }
  [data-theme='vautech'] .vt-icon-button-positive {
    --vt-hover-line: var(--vt-green-line);
    --vt-hover-wash: var(--vt-green-wash);
    --vt-hover-ink: var(--vt-green-ink);
  }
  /* Any palette hue. */
  [data-theme='vautech'] .vt-hue-red { --vt-hover-line: var(--vt-red-line); --vt-hover-wash: var(--vt-red-wash); --vt-hover-ink: var(--vt-red-ink); }
  [data-theme='vautech'] .vt-hue-orange { --vt-hover-line: var(--vt-orange-line); --vt-hover-wash: var(--vt-orange-wash); --vt-hover-ink: var(--vt-orange-ink); }
  [data-theme='vautech'] .vt-hue-yellow { --vt-hover-line: var(--vt-yellow-line); --vt-hover-wash: var(--vt-yellow-wash); --vt-hover-ink: var(--vt-yellow-ink); }
  [data-theme='vautech'] .vt-hue-green { --vt-hover-line: var(--vt-green-line); --vt-hover-wash: var(--vt-green-wash); --vt-hover-ink: var(--vt-green-ink); }
  [data-theme='vautech'] .vt-hue-blue { --vt-hover-line: var(--vt-blue-line); --vt-hover-wash: var(--vt-blue-wash); --vt-hover-ink: var(--vt-blue-ink); }
  [data-theme='vautech'] .vt-hue-violet { --vt-hover-line: var(--vt-violet-line); --vt-hover-wash: var(--vt-violet-wash); --vt-hover-ink: var(--vt-violet-ink); }
  [data-theme='vautech'] .vt-hue-brown { --vt-hover-line: var(--vt-brown-line); --vt-hover-wash: var(--vt-brown-wash); --vt-hover-ink: var(--vt-brown-ink); }
  @media print {
    [data-theme='vautech'] .vt-icon-button {
      display: none;
    }
  }

  /* Drag handle: no hover square, a grab cursor. Keyboard reordering is the
     app's job. */
  [data-theme='vautech'] .vt-drag-handle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--c-faint);
    cursor: grab;
  }
  [data-theme='vautech'] .vt-drag-handle:active {
    cursor: grabbing;
  }
  [data-theme='vautech'] .vt-drag-handle svg {
    width: var(--vt-icon-size, 16px);
    height: var(--vt-icon-size, 16px);
  }
  [data-theme='vautech'] .vt-ledger .vt-drag-handle {
    --vt-icon-size: 12px;
  }
  /* An icon button inside a text box (guides/icons.md): no hover square;
     the input gets room for it. */
  [data-theme='vautech'] .vt-field-action {
    position: relative;
    display: block;
  }
  /* !important: the app's own field padding (a utility or unlayered class)
     would otherwise cover the icon. */
  [data-theme='vautech'] .vt-field-action > :is(input, select) {
    padding-right: 2rem !important;
  }
  [data-theme='vautech'] .vt-field-action > button {
    position: absolute;
    top: 50%;
    right: 0.25rem;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--c-faint);
    cursor: pointer;
  }
  [data-theme='vautech'] .vt-field-action > button svg {
    width: 12px;
    height: 12px;
  }
  @media print {
    [data-theme='vautech'] :is(.vt-drag-handle, .vt-field-action > button) {
      display: none;
    }
  }

  /* Toggletip (guides/toggletip.md). The term reads as text with a dashed underline; the tip is a square box
     with a light edge, below the term. */
  [data-theme='vautech'] .vt-term {
    cursor: help;
    text-decoration-line: underline;
    text-decoration-style: dashed;
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
  }
  [data-theme='vautech'] .vt-tip {
    width: 18rem;
    margin-top: 0.25rem;
    border: 1px solid var(--c-line);
    background: var(--c-surface);
    padding: 0.5rem 0.75rem;
    color: var(--c-body);
    font-size: 0.875rem;
    font-weight: var(--app-weight-body);
    line-height: 1.4;
    text-align: left;
  }

  /* Staging banner: the same in every theme, so not gated. 4.7:1. */
  .vt-staging-banner {
    background: #e11d48;
    color: #ffffff;
    padding: 0.375rem 1rem;
    text-align: center;
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.25rem;
    text-transform: uppercase;
    letter-spacing: 0.025em;
  }

  /* Toggletip behaviour, in every theme (not gated): the term is a bare
     button that sits in running text, the tip floats below it, and on paper
     the explanation follows the term in brackets instead. */
  .vt-toggletip {
    position: relative;
    display: inline-block;
  }
  .vt-term {
    appearance: none;
    margin: 0;
    border: 0;
    padding: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: inherit;
  }
  .vt-tip {
    position: absolute;
    left: 0;
    top: 100%;
    z-index: 20;
    display: block;
  }
  .vt-tip[hidden] {
    display: none;
  }
  @media print {
    .vt-toggletip {
      display: inline;
    }
    .vt-term {
      text-decoration: none !important;
    }
    .vt-tip,
    .vt-tip[hidden] {
      position: static !important;
      display: inline !important;
      width: auto;
      margin: 0;
      border: 0;
      padding: 0;
      background: none;
      font-size: inherit;
    }
    .vt-tip::before { content: ' ('; }
    .vt-tip::after { content: ')'; }
  }
}
