/* Breacer -- components
 * ============================================================================
 * One place per component (phase 2.1 of docs/plan-van-operatie.md, 2 Sep
 * 2026). Before this file, .btn-blue, .btn-quiet, .brand, .line, [hidden]
 * and the focus ring stood in FIVE places (index.css, dash.css and the
 * inline style of accounts, notifyshare and breacer), each just slightly
 * different: a pill of 999px here, 8px there; 40px tall here, 44 there;
 * 700 bold here, 600 there. Measured with a CSS parser over all
 * stylesheets: 76 selectors in more than one file, 65 with a different
 * body. "44px on every button" was thus five rules in five places, and the
 * 2 Sep 2026 measurement (zero touch targets under 44) only held as long
 * as nobody touched one of the five.
 *
 * LOAD ORDER on every page: design.css, tokens.css, componenten.css, then
 * the page's own stylesheet. With equal specificity, whatever comes later
 * wins, so a page CAN override a component -- and exactly that is what
 * test/components-drift.test.mjs forbids: outside this file, no rule may
 * exist with exactly a component selector (`.btn-blue`, `.btn-blue:hover`).
 * COMPOSITION is allowed: `.bulk-bar .btn-quiet`, `.btn-blue.wide`,
 * `.actions .btn-quiet` say something about a component IN a context, and
 * that is what a page is supposed to do.
 *
 * What DELIBERATELY does not live here, with the reason:
 *   .pill               appears once, in index.css, with forty lines
 *                      around it that only carry meaning there;
 *   .row-check etc.     the checkmarks of My Triggers: placement and
 *                      component are one thing there (negative margins in
 *                      the row), and they exist on one page;
 *   .bar, .center,    layout, not a component: the same ROLE per page
 *   .box, .footer        with a different size (sticky with blur on the
 *                      dashboard, static on the front door, centered on
 *                      accounts).
 *
 * All tokens in here live in tokens.css or design.css; a custom property
 * that does not exist falls back SILENTLY (paid for twice, dearly, in this
 * project), so the drift test checks every var() below against those two.
 */

/* --- Primitives -------------------------------------------------------------
 * Without this rule, the hidden attribute loses to every explicit display
 * rule (display:flex on a toast, inline-flex on a button). This has once
 * been an undo toast that stayed PERMANENTLY at the bottom of the screen
 * and swallowed the clicks of the bulk bar underneath it, while `.hidden`
 * was neatly set to true. Measure the rendered height, not the property. */
[hidden] { display: none !important; }

/* Only for a screen reader. Not display:none -- then it won't read it. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* One visible focus ring for everything that can receive focus. :focus-visible
 * and not :focus: a mouse click leaves no ring, a Tab does. Blue, because
 * blue means interaction; green means status. */
:focus-visible {
  outline: 2px solid var(--blauw);
  outline-offset: 3px;
}

/* --- The brand mark ---------------------------------------------------------
 * An inline SVG with fill="currentColor" (assets/brand.svg; brand-drift.test.mjs
 * keeps every copy equal). The shape is PORTRAIT (ratio 0.785, measured on
 * the source): width follows from height via aspect-ratio, otherwise the
 * mark gets stretched. The HEIGHT differs per page (32 on the front door,
 * 26 in the 56px dashboard bar, 22 on accounts) and that is a size, not a
 * different component: the page sets --merk-hoogte and --merk-naam-grootte
 * on its .bar.
 */
.brand {
  display: inline-flex;
  align-items: center;
  min-height: 44px;            /* a link is a touch target like any other */
  gap: var(--sp-2);
  text-decoration: none;
  color: var(--tekst);
}
.brand-mark {
  display: block;
  flex: none;
  height: var(--merk-hoogte, 26px);
  width: auto;
  aspect-ratio: 1599 / 2036;
  color: var(--tekst);
}
.brand-name {
  font-size: var(--merk-naam-grootte, var(--fs-md));
  font-weight: 600;
  letter-spacing: var(--track-md);
  white-space: nowrap;         /* the brand name wrapped onto two lines on a phone */
}

/* --- Buttons ------------------------------------------------------------------
 * Blue = the next step (one per screen), quiet = the second button, danger =
 * irreversible deletion (the only thing red is used for in this product),
 * link = a button that goes somewhere, ghost = the second button next to a
 * blue one on the front door (black with a hairline, like the pill).
 *
 * 44px is the design-audit floor for everything you touch. Here, and nowhere
 * else. display:inline-flex and border:0 are there so an <a> and a <button>
 * with the same class look identical -- breacer.html and accounts.html put
 * these classes on links.
 */
.btn-blue {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 44px;
  padding: 10px var(--sp-4);
  border: 0;
  border-radius: var(--r-sm);
  background: var(--blauw-knop);
  color: #FFFFFF;
  font-family: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: filter var(--dur-fast) var(--ease);
}
.btn-blue:hover { filter: brightness(1.08); }
.btn-blue:disabled { opacity: 0.5; cursor: default; }

.btn-quiet {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  flex: none;
  min-height: 44px;
  padding: 5px var(--sp-3);
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  background: none;
  color: var(--tekst);
  font-family: inherit;
  font-size: var(--fs-xs);
  text-decoration: none;
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease);
}
.btn-quiet:hover:not(:disabled) { border-color: var(--rand); }
.btn-quiet:disabled { opacity: 0.5; cursor: default; }

/* Red here means "irreversible", and that is the only thing red is used
   for in this product. */
.btn-danger { color: var(--rood); }
.btn-danger:hover { border-color: var(--rood); }

.btn-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;             /* a text link is also a touch target */
  margin-top: var(--sp-2);
  text-decoration: none;
}

.btn-ghost {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 13px var(--sp-5);
  border: var(--rand-dikte) solid var(--rand);
  border-radius: var(--r-full);
  background: var(--surface-0);
  color: var(--tekst);
  font-family: inherit;
  font-size: var(--fs-md);
  font-weight: 600;
  letter-spacing: var(--track-md);
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.btn-ghost:hover { border-color: var(--rand-actief); }
.btn-ghost:active { transform: scale(0.98); }

/* --- The menu -----------------------------------------------------------------
 * Black glass with a hairline: the same material as the pill, the dropdowns
 * and the loading pill (the browser test compares their computed style).
 * Anchored bottom-left at the corner buttons of the front door; the
 * dashboard's profile menu and the plus menu only set a different anchor
 * (.menu-profile, .menu-plus), never a different material.
 */
.menu {
  position: absolute;
  left: 100%;
  bottom: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 232px;
  margin-left: var(--sp-2);
  padding: var(--sp-2);
  border: var(--rand-dikte) solid var(--rand);
  border-radius: var(--r-md);
  background: var(--glas);
  backdrop-filter: var(--glas-waas);
  -webkit-backdrop-filter: var(--glas-waas);
  box-shadow: var(--shadow-raised);
  transform-origin: bottom left;
  animation: menuKomtOp var(--dur-base) var(--ease-enter) both;
}
@keyframes menuKomtOp {
  from { opacity: 0; transform: scale(0.86) translateY(-6px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}
/* Fallback for browsers without backdrop-filter: then just black, because a
 * transparent panel WITHOUT blur lets the text underneath show through. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .menu { background: var(--surface-0); }
}

.menu-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  /* 44px: the design-audit floor for everything you touch; the menu is
     operated on a phone with a thumb. */
  min-height: 44px;
  padding: 10px var(--sp-3);
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--tekst);
  font-family: inherit;
  font-size: var(--fs-md);
  font-weight: 500;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease);
}
.menu-row:hover { background: var(--surface-1); }

/* --- The switch -----------------------------------------------------------
 * A real checkbox with appearance:none: it keeps its keyboard behavior, its
 * label association and its role. A <div> with a click handler has none of
 * that and has to rebuild it all by hand. The transparent border IS the
 * touch target (64x44), background-clip keeps the visible part at 48x28.
 */
.switch {
  flex: none;
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  width: 64px;                       /* 48 visible + 2x8 target */
  height: 44px;                      /* 28 visible + 2x8 target */
  border: 8px solid transparent;     /* the border IS the touch target; the knob sits relative to the inner box */
  border-radius: var(--r-full);
  background: rgba(255,255,255,0.14);
  background-clip: padding-box;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease);
}
.switch::after {
  content: '';
  position: absolute;
  top: 3px; left: 3px;
  width: 22px; height: 22px;
  border-radius: var(--r-full);
  background: #FFFFFF;
  transition: transform var(--dur-fast) var(--ease);
}
/* Green here means STATUS ("this is on"), not interaction -- that is why
   it is not blue. -color and not the shorthand: the shorthand would reset
   the clip on the target. */
.switch:checked { background-color: var(--groen); }
.switch:checked::after { transform: translateX(20px); }
.switch:disabled { opacity: 0.4; cursor: default; }

/* --- The row --------------------------------------------------------------
 * A settings row: name on the left (itself a 44px touch target, because the
 * label toggles the switch next to it), value as a caption, and a switch or
 * button on the right. Accounts had a DATA ROW with the same name (name + a
 * value that may wrap, with a divider line); over there it has been called
 * .detail since 2 Sep 2026, because two things with the same name is
 * exactly the mistake this file exists to prevent.
 */
.lines { margin: 0; padding: 0; list-style: none; }
.line {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 44px;
  font-size: var(--fs-sm);
}
.line-name { display: flex; align-items: center; flex: 1; min-width: 0; min-height: 44px; }
.line-value {
  color: var(--tekst-gedempt);
  font-size: var(--fs-xs);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* A channel that has turned itself off is asking something of you. */
.line-value[data-attention="op"] { color: var(--amber); }

/* --- The undo toast -------------------------------------------------------------
 * Replaces confirm(): execute immediately with six seconds of think time,
 * and the server call only follows AFTER that time -- so there is really
 * something to undo.
 */
.toast {
  position: fixed;
  left: 50%;
  bottom: var(--sp-6);
  z-index: 40;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border: var(--rand-dikte) solid var(--rand);
  border-radius: var(--r-full);
  background: rgba(6, 6, 10, 0.82);
  backdrop-filter: var(--glas-waas);
  font-size: var(--fs-sm);
  animation: toastKomtOp var(--dur-base) var(--ease-enter) backwards;
}
@keyframes toastKomtOp {
  from { opacity: 0; transform: translate(-50%, 12px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}
/* Undo is the only way out of an action that has ALREADY happened, and you
   have six seconds for it. The touch target was 37x19 -- under the 44px of
   the design audit, and right at the button where a mistap is most costly.
   The negative margin keeps the toast as tall as it was: the TARGET grows,
   the shape does not. */
.toast-btn {
  flex: none;
  min-width: 44px;
  min-height: 44px;
  margin: -12px 0;
  padding: 0 var(--sp-2);
  border: 0;
  background: none;
  color: var(--blauw);
  font-family: inherit;
  font-weight: 600;
  cursor: pointer;
}
.toast-btn:hover { text-decoration: underline; text-underline-offset: 3px; }

/* On a phone: edge to edge, above the thumb bar (64px). The keyframe loses
   its -50%, because the toast is then no longer centered via a transform. */
@media (max-width: 720px) {
  .toast { left: var(--sp-4); right: var(--sp-4); bottom: calc(var(--sp-4) + 64px); transform: none; }
  @keyframes toastKomtOp {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: translateY(0); }
  }
}

@media (prefers-reduced-motion: reduce) {
  .menu { animation: none; }
  .switch, .switch::after { transition: none; }
  .toast { transition: none; animation: none; }
}

/* --- Input: one material for every field (design audit 6 Sep 2026) --------
 * Text fields, time fields, dropdowns and text areas shared NO style: the
 * dashboard had .field (32px, and that name collided with the tension
 * field, which set 24px margin underneath it), accounts its own .input at
 * 14px rounding, the fine-tuning .fine-field at 33px, and <select> and
 * <input type=time> were bare: white system chrome on OLED black. Now one
 * component: 44px tall, hairline, the glass, and its own chevron on a
 * select (appearance: none, otherwise the browser draws its own). */
.input {
  box-sizing: border-box;
  min-height: 44px;
  padding: 10px var(--sp-3);
  border: var(--rand-dikte) solid var(--rand);
  border-radius: var(--r-sm);
  background-color: var(--glas);
  color: var(--tekst);
  font: inherit;
  font-size: var(--fs-sm);
  line-height: 1.3;
  transition: border-color var(--dur-fast) var(--ease);
}
.input::placeholder { color: var(--tekst-gedempt); opacity: 1; }
.input:hover:not(:disabled) { border-color: var(--rand-actief); }
.input:focus-visible { outline: none; border-color: var(--blauw); }
.input:disabled { opacity: 0.5; }
textarea.input { resize: vertical; min-height: 64px; }
select.input {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 36px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-opacity='0.7' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 16px 16px;
  cursor: pointer;
}
/* The browser itself draws the dropdown list; black with white is the only
   thing it honors everywhere. */
select.input option { background: #000000; color: #FFFFFF; }
.input[type="time"], .input[type="date"], .input[type="number"] {
  color-scheme: dark;
  font-variant-numeric: tabular-nums;
}
