/* Utilities: plumbing only — layout, spacing, text one-offs. Identity, state,
   and theming belong in component files. Verbose names and logical properties
   throughout (Fizzy convention). Several utilities read custom properties as
   parameters, noted inline. */
@layer utilities {
  /* Text size */
  .txt-x-small { font-size: var(--text-x-small); }
  .txt-small { font-size: var(--text-small); }
  .txt-normal { font-size: var(--text-normal); }
  .txt-medium { font-size: var(--text-medium); }
  .txt-x-large { font-size: var(--text-x-large); }

  /* Text color */
  .txt-subtle { color: var(--color-ink-subtle); }
  .txt-faint { color: var(--color-ink-faint); }
  .txt-negative { color: var(--color-negative); }

  .overflow-ellipsis {
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* Parameter: --lines (default 2) */
  .overflow-line-clamp {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: var(--lines, 2);
    overflow: hidden;
  }

  /* Weight */
  .weight-semibold { font-weight: 600; }

  /* Flex and grid plumbing */
  .flex { display: flex; }
  .flex-inline { display: inline-flex; }
  .flex-column { display: flex; flex-direction: column; }
  .flex-row-reverse { display: flex; flex-direction: row-reverse; }
  .flex-wrap { flex-wrap: wrap; }
  .grid { display: grid; }
  /* A wrapper that is not a box: a button_to's <form>, a turbo-frame around
     a grid item. Said twice inline in layout.css before it had a name. */
  .contents { display: contents; }
  /* A <button> that is not a control but a thing you can press — a face in
     the pings strip, a pending file in the composer. Hand-rolled in two
     components before it had a name; the third made it this. */
  .unbuttoned { padding: 0; background: none; border: none; cursor: pointer; }

  .align-start { align-items: flex-start; }
  .align-center { align-items: center; }
  .align-end { align-items: flex-end; }

  .justify-center { justify-content: center; }
  .justify-end { justify-content: flex-end; }
  .justify-space-between { justify-content: space-between; }

  .flex-item-grow { flex: 1 1 auto; }
  .flex-item-no-shrink { flex-shrink: 0; }
  .flex-item-justify-end { margin-inline-start: auto; }
  /* A flex item's min-size defaults to its content, which is what keeps
     ellipsis from ever engaging inside one. This is the release valve. */
  .flex-item-shrinkable { min-inline-size: 0; }

  /* Parameters: --row-gap / --column-gap */
  .gap {
    gap: var(--row-gap, var(--block-space)) var(--column-gap, var(--inline-space));
  }
  .gap-half {
    gap: var(--row-gap, var(--block-space-half))
      var(--column-gap, var(--inline-space-half));
  }
  .gap-double {
    gap: var(--row-gap, var(--block-space-double))
      var(--column-gap, var(--inline-space-double));
  }

  /* Padding (logical) */
  .pad { padding: var(--block-space) var(--inline-space-double); }
  .pad-half { padding: var(--block-space-half) var(--inline-space); }
  .pad-block { padding-block: var(--block-space); }
  .pad-block-half { padding-block: var(--block-space-half); }

  /* Margin (logical) */
  .margin-none { margin: 0; }
  .margin-block { margin-block: var(--block-space); }
  .margin-block-start { margin-block-start: var(--block-space); }
  .margin-block-start-half { margin-block-start: var(--block-space-half); }
  .margin-block-end { margin-block-end: var(--block-space); }
  .margin-block-end-half { margin-block-end: var(--block-space-half); }
  .margin-block-end-double { margin-block-end: var(--block-space-double); }
  .center { margin-inline: auto; }

  /* Size */
  .max-width-prose { max-inline-size: 65ch; }

  /* Position */
  .position-relative { position: relative; }

  /* Fills and borders. Parameters: --fill-color, --border-color */
  .fill { background-color: var(--fill-color, var(--color-surface)); }

  .border { border: var(--border-size) solid var(--border-color, var(--color-line)); }
  .border-block-start { border-block-start: var(--border-size) solid var(--border-color, var(--color-line)); }
  .border-block-end { border-block-end: var(--border-size) solid var(--border-color, var(--color-line)); }
  .borderless { border: none; }

  .border-radius { border-radius: var(--border-radius); }

  .shadow { box-shadow: var(--shadow); }

  /* Visibility and accessibility */
  .hidden { display: none; }
  /* Installed as a web app, the browser's own affordances are not there —
     an install nudge, a download link iOS cannot save — so the page drops
     them; and a help recipe for the OS only applies inside the installed app. */
  .hide-in-pwa {
    @media (display-mode: standalone) {
      display: none;
    }
  }
  .hide-in-browser {
    @media not (display-mode: standalone) {
      display: none;
    }
  }
  .hide-in-ios-pwa {
    @media (display-mode: standalone) {
      @supports (-webkit-touch-callout: none) {
        display: none;
      }
    }
  }

  /* The selector list is joined rather than the treatment restated (AGENTS.md):
     the rename frame compacts a form it does not own the markup of, so it
     cannot add the class — but it must not own a second copy of these six
     declarations either. */
  .for-screen-reader,
  .inline-rename .label {
    block-size: 1px;
    clip-path: inset(50%);
    inline-size: 1px;
    overflow: hidden;
    position: absolute;
    white-space: nowrap;
  }

  /* A keyboard hint on a device with no keyboard is 47px of a cramped header
     spent saying nothing (measured on the jump button at 390px, where it left
     the breadcrumbs 2px). Fizzy hangs this on every <kbd> it draws. */
  .hide-on-touch {
    @media (hover: none) {
      display: none;
    }
  }

  /* ——— Plumbing the ported card board asks for ———
     Fizzy's two, copied at their values. They arrived with the board because
     its markup is fizzy's; they are plumbing by the same test everything above
     passes, so they live here rather than in the board's own stylesheet. */

  /* A scroller with no visible bar. The board scrolls horizontally past its
     columns and each column scrolls its own cards, and a bar on either would
     draw a line across the design. */
  .hide-scrollbar {
    -ms-overflow-style: none;
    scrollbar-width: none;

    &::-webkit-scrollbar {
      display: none;
    }
  }

  /* A glyph set back from its label. Parameterised, so a caller can dial it. */
  .translucent { opacity: var(--opacity, 0.66); }
}
