/*
 * Base layer: reset, document defaults and the three layout primitives.
 *
 * Loaded after Bootstrap so it can win on the handful of element selectors it
 * cares about, without needing !important. It deliberately does not restyle
 * Bootstrap components -- that happens per component, so each one can be moved
 * over and verified on its own.
 */

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Bootstrap 3 sets `html { font-size: 10px }` so that authors can treat 1rem as
   10px. Every token in tokens.css is expressed in rem, so under that root the
   whole system resolved to 62.5% of its intended size -- body text came out at
   10px. Bootstrap itself uses no rem at all (its own sizes are px throughout),
   so resetting the root costs nothing and restores the scale.
   100% rather than 16px on purpose: it honours a reader who has raised their
   browser's default font size instead of overriding them. */
html {
  font-size: 100%;
}

body {
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--color-text);
  background: var(--color-bg);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* Bootstrap sets `word-wrap: break-word` nowhere useful and lets long tokens --
   bankgiro numbers, addresses, tenant emails -- push the page sideways on a
   phone. The admin has no content that benefits from horizontal page scroll. */
body {
  overflow-wrap: break-word;
}

/* --- Headings -------------------------------------------------------------
 *
 * Bootstrap is gone and nothing replaced its heading rules, so every h1-h6 in
 * the admin had been running on user-agent defaults: h1 at 2em, h2 at 1.5em,
 * h3 at 1.17em, h4-h6 at or below body size, each with an em-relative margin.
 * Two consequences, both visible on /admin/hus/:id.
 *
 * The sizes came from the browser rather than from the ramp, so they were not
 * on the ramp: 32/24/18.7/16/13.3/10.7 against a 12/14/16/18/22/28 system.
 * And h4 -- the level most of the older templates reach for -- resolved to
 * exactly body size, which is why those pages read as one undifferentiated
 * block of 16px text no matter how many sections they are divided into.
 *
 * The levels are bound to the ramp below. They are also, deliberately, only
 * three distinct sizes plus a fourth at body size: an admin page needs a
 * subject, a division and a section, and past that the honest signal is a
 * label (see .field__label) rather than a fifth heading nobody can rank.
 *
 * Margin is stated rather than left to the UA because an em-relative margin
 * scales with the heading, so the gap above a 28px h1 and a 16px h4 differed
 * by nearly 2:1 for no reason. A fixed pair keeps one rhythm down the page,
 * and :first-child drops the top margin so a heading opening a card or a grid
 * cell sits flush with the box rather than pushing itself off the top edge. */
h1,
h2,
h3,
h4,
h5,
h6 {
  margin: var(--space-5) 0 var(--space-3);
  font-weight: 600;
  line-height: var(--leading-snug);
  text-wrap: balance;
}

h1:first-child,
h2:first-child,
h3:first-child,
h4:first-child,
h5:first-child,
h6:first-child {
  margin-top: 0;
}

/* The two display sizes take the tighter leading and pull their tracking in;
   see --tracking-tight in tokens.css for why system-ui needs it up here and
   not below. */
h1 {
  font-size: var(--text-2xl);
  font-weight: 700;
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
}

h2 {
  font-size: var(--text-xl);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
}

h3 {
  font-size: var(--text-lg);
}

/* Body size, and that is the point: h4 is the smallest heading that is still a
   heading, and it separates itself by weight rather than by size. Anything
   that wants to be quieter than this is a label, not a heading. */
h4 {
  font-size: var(--text-base);
}

h5,
h6 {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

a {
  color: var(--color-link);
}

/* No underline on hover. Bootstrap adds one to every link, which in a table or
   a row of actions means a line flickering under whatever the pointer passes
   over. Hover shifts the colour instead, and rows and cards carry their own
   hover surface.

   Note this leaves link colour as the only thing marking a link inside running
   prose. That is fine across the admin, where links sit in rows, cells and
   toolbars that signal themselves -- if a page of real body copy turns up,
   underline links in that block rather than reverting this. */
a:hover,
a:focus {
  color: var(--color-brand);
  text-decoration: none;
}

/* Every focusable thing gets a visible ring. Bootstrap 3 shipped
   `outline: none` on several controls, which left keyboard users with no
   indication of position at all. */
:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

img,
svg,
video {
  max-width: 100%;
  height: auto;
}

/* A fieldset is the only element that can carry a <legend>, and a legend is the
   only way to name a group of inputs to a screen reader -- so grouped forms
   have to use one. Everything below is the browser's own default getting out of
   the way: the sunken border and padding, and `min-inline-size: min-content`,
   which refuses to let the box be narrower than its widest child and so pushes
   a grid of inputs past its container instead of letting the inputs shrink. */
fieldset {
  min-inline-size: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

/* Inputs do not inherit the document font by default, and a font-size below
   16px makes iOS Safari zoom the viewport on focus -- which is why tapping a
   field in the admin currently throws the layout sideways on an iPhone. */
input,
select,
textarea,
button {
  font: inherit;
  color: inherit;
}

@media (max-width: 47.9375rem) {
  input,
  select,
  textarea {
    font-size: 1rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* --- Layout primitives ---------------------------------------------------
 *
 * These three replace essentially all real use of the 12-column grid. The
 * audit found 53 .row and 100 .col-*, of which 41 were col-md-12 -- that is,
 * no grid at all. None of these need a breakpoint to work on a phone.
 */

/* Vertical rhythm between siblings. */
.stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.stack-sm {
  gap: var(--space-2);
}

/* A row of things that wraps rather than overflowing. Button groups, filter
   bars, badge rows, the action links above a table. */
.cluster {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}
/* Columns that reflow by available width instead of by breakpoint. The card
   width is overridable per instance: `style="--col-min: 22rem"`. */
.grid-auto {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(min(var(--col-min, 18rem), 100%), 1fr));
}

/* A grid item's automatic minimum size is its min-content width, so one wide
   thing inside a column -- the Hyresgäster table on /admin/hus/:id -- makes
   the item wider than the track it sits in and hangs over the column beside
   it. The .scroll-x wrapper admin_nav.js puts around every table cannot help
   while the box it is in refuses to be narrower than the table. Zero here
   lets the column keep the track's width and the table scroll inside it. */
.grid-auto > *,
.grid-2 > *,
.grid-3 > * {
  min-width: 0;
}

/* Explicit column counts, for a grid that also holds a full-width row.
   .grid-auto is the better default, but it does not compose with .grid-full:
   an item spanning `1 / -1` occupies auto-fit's surplus tracks, so they never
   collapse. A two-column form in a container wide enough for four tracks then
   lays out as 2 columns of content plus 2 empty ones -- half the page unused
   and every label squeezed. Where the column count is known and a full-width
   row is present, state the count instead of deriving it. */
.grid-2,
.grid-3 {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr;
}
@media (min-width: 48rem) {
  /* minmax(0, ...) rather than 1fr alone: a long unbroken string in a cell
     otherwise sets the track's floor and pushes the grid past its container. */
  .grid-2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .grid-3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* Span every column of the enclosing .grid-auto. Form actions, a full-width
   table or a heading that belongs to the whole grid rather than one column --
   these were col-md-12 under Bootstrap, which is to say "not a column at all".
   Harmless on a flex or block parent, so it is safe on a shared partial that
   is rendered both inside and outside a grid. */
.grid-full {
  grid-column: 1 / -1;
}

/* A centred document column. The tenant-facing contract and invoice render in
   admin/empty, which has no page chrome to bound them -- their width came from
   col-md-10 inside Bootstrap's .container. These are read rather than scanned,
   so they keep an explicit measure of their own once both of those are gone. */
.doc {
  max-width: 60rem;
  margin-inline: auto;
  line-height: var(--leading-relaxed);
}

/* Constrain running prose to a readable measure -- and give it reading leading
   while we are here. --leading-normal is set for scanning a table, which is
   half a step tight for a paragraph anyone actually reads through. */
.measure {
  max-width: var(--measure);
  line-height: var(--leading-relaxed);
}

/* --- Utilities ----------------------------------------------------------- */

/* Visible to screen readers, not on screen. Used by the drawer and search
   toggles, which are icon-only. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Any wide thing -- a table, a code block, a diagram -- scrolls inside its own
   box so the page body never scrolls sideways. */
.scroll-x {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-inline: contain;
}

@media (max-width: 47.9375rem) {
  /* Let dense admin tables use the narrow page gutter too. Cell padding still
     keeps the first and last values away from the physical screen edge. */
  .scroll-x {
    margin-inline: calc(var(--space-2) * -1);
  }
}
