/* ==========================================================================
   responsive.css  —  Responsive Web Design layer
   --------------------------------------------------------------------------
   Loaded LAST, after every other stylesheet, so it can correct fixed-width
   rules without editing 27 files. Remove the one <link> and the app returns
   to its previous layout exactly — that is deliberate: this is reviewable and
   revertable in a single line.

   WHY THIS FILE EXISTS
   --------------------
   Before it, MacConf had 2 @media rules in 3,408 lines of CSS, and both were
   in admin-users.css. The workspace, header, footer, sidebar and parameter
   tables had none. The layout was tuned at one width and simply got worse away
   from it — which is exactly the reported symptom: fine on a 20" monitor,
   cramped on a 14" laptop.

   WHY 14" HURTS AND 20" DOES NOT
   ------------------------------
   Media queries see CSS pixels, not inches. A 14" 1920x1080 laptop at
   Windows' default 125% scaling reports a 1536px viewport; at 150% it reports
   1280px. A 20" monitor at 100% reports 1920px. So "looks good on 20in" and
   "looks bad on 14in" is the same CSS asked to work at 1920px and at 1280px —
   a third less room — with nothing telling it to adapt.

   THE FOUR ROOT CAUSES FOUND BY MEASUREMENT
   -----------------------------------------
   1. Fixed pixel widths that cost the same absolute space at every viewport:
      .global-search-wrapper input  380px
      .toolbar-search .search-input 280px
      .range-input / .sequence-input 100px each (x6 columns in the volt matrix)
      .param-card grid 220px 1fr 110px !important
   2. Dead space from a capped editor inside an uncapped column:
      .column-value is 68% but .parameter-input has max-width:400px, so at
      1920px roughly 690px of the value column was empty while at 1280px the
      inputs were still cramped. Wide screens wasted room; narrow ones ran out.
   3. Percentage columns for the type badge and help button (7% / 5%). At
      1280px that is 73px and 52px — borderline for a "DIGITAL" badge, and
      the first thing to be squeezed out of view.
   4. `body { overflow: hidden }` ("IDE-style: no whole-page scroll"). This
      makes overflow far worse than untidy: content past the right edge is
      UNREACHABLE, not merely off-screen. At 1024px `.header-right` extended
      120px past the viewport, so those controls could not be reached at all.

   BREAKPOINTS
   -----------
     > 1600px   large monitor            — the reference layout
    <= 1600px   14" 1080p @125% (1536)   — the most common laptop
    <= 1440px   small monitor / laptop
    <= 1280px   14" 1080p @150%
    <= 1120px   small laptop, split-screen
    <=  960px   narrow / tablet landscape
    <=  768px   tablet portrait

   Fluid first, breakpoints second: most rules here use clamp()/min() so they
   adapt continuously and there is no snap at a threshold. Media queries are
   used only where a layout has to genuinely change shape (stacking, hiding,
   wrapping), which is what they are good at.

   Conventions
   -----------
   - No !important unless overriding a source rule that already uses it. Each
     such case is commented with what it is fighting.
   - Nothing here changes colour, spacing rhythm or type scale at the
     reference width. At > 1600px this file is close to a no-op by design, so
     the layout the team already approved is untouched.
   ========================================================================== */


/* ==========================================================================
   1. APP SHELL — the page must never scroll sideways
   --------------------------------------------------------------------------
   With body{overflow:hidden}, horizontal overflow hides controls permanently.
   A CSS grid track will not shrink below its content unless told to, and
   `min-width:0` is what tells it. Without this, one wide table pushes the
   whole shell wider than the screen.
   ========================================================================== */

html {
  overflow-x: hidden;
}

body {
  /* keep the intended no-page-scroll behaviour, but make sideways overflow
     structurally impossible rather than merely hidden */
  overflow-x: hidden;
  max-width: 100vw;
}

/* The sidebar width is written as an INLINE STYLE on <body> by the FOUC script
   and the resizer (localStorage 'macconf-sidebar-width'), so no stylesheet can
   override it. Bounding it at the point of USE honours the user's choice while
   stopping a width saved on a big monitor from eating a small screen.
   min() keeps the collapsed state working: min(60px, 26vw) is still 60px. */
body {
  grid-template-columns: min(var(--sidebar-width, 240px), 26vw) 1fr;
}

/* Every grid/flex child that contains a table or long text needs this, or it
   refuses to shrink and becomes the widest thing on the page. */
.workspace,
.workspace-container,
.workspace-toolbar-wrapper,
.header,
.header-left,
.header-right,
.macconf-footer,
.footer-group,
#section-content-area,
.parameter-table-container,
.parameter-editor,
.parameter-editor-custom {
  min-width: 0;
}

/* NOTE: .ce-col is deliberately absent from the list above. See section 9 -
   giving it min-width:0 collapses the grid track it lives in and pushes the
   Execute button off-screen. */


/* ==========================================================================
   2. FLUID TOKENS
   --------------------------------------------------------------------------
   The default sidebar width steps down as the viewport does. Declared on
   :root so a class-based override (body.sidebar-collapsed) and the inline
   style both still win, in that order.
   ========================================================================== */

:root {
  --gutter: clamp(12px, 1.4vw, 24px);
}

@media (max-width: 1600px) { :root { --sidebar-width: 224px; } }
@media (max-width: 1440px) { :root { --sidebar-width: 208px; } }
@media (max-width: 1280px) { :root { --sidebar-width: 200px; } }
@media (max-width: 1120px) { :root { --sidebar-width: 176px; } }

/* Keep the sidebar chrome legible as the rail narrows, instead of letting
   "CONFIG SECTIONS" and the counters wrap into ragged two-line blocks. */
@media (max-width: 1440px) {
  /* class names taken from fragments/sidebar.html - guessing them is how the
     first attempt at this rule ended up doing nothing */
  .sidebar-title-text {
    font-size: 0.7rem;
    letter-spacing: 0.03em;
    white-space: nowrap;
  }
  .sidebar-counts-wrapper {
    display: flex;
    flex-wrap: wrap;
    gap: 2px 10px;
    font-size: 0.68rem;
  }
  .sidebar-counts-wrapper > span {
    white-space: nowrap;
  }
  #mainSidebar .sidebar-link {
    font-size: 0.86rem;
    padding-left: 10px;
    padding-right: 10px;
  }
}

/* Below this a full sidebar costs more than it returns: collapse to an icon
   rail by default. The user can still expand it — this only changes where the
   layout starts from. */
@media (max-width: 960px) {
  :root { --sidebar-width: 60px; }
  .sidebar-link span,
  .sidebar-headline-wrapper,
  .sidebar-counts-wrapper,
  .sidebar-search-container,
  .sidebar-resizer {
    display: none;
  }
  #mainSidebar .sidebar-link {
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
  }
}


/* ==========================================================================
   3. HEADER
   --------------------------------------------------------------------------
   .header is a flex row with a 380px search inside it. At 1024px the right
   group measured 869px and ran 120px past the edge, taking the logout and
   user controls out of reach. Making the search fluid and the groups
   shrinkable fixes the cause; hiding decoration at small widths protects the
   controls that matter.
   ========================================================================== */

.header {
  padding-left: var(--gutter);
  padding-right: var(--gutter);
  gap: clamp(8px, 1vw, 16px);
}

.header-left,
.header-right {
  gap: clamp(8px, 0.9vw, 16px);
  flex: 0 1 auto;
}

/* the search is the one element that should give up space first */
.global-search-wrapper {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  justify-content: flex-end;
}

.global-search-wrapper input {
  width: 100%;
  min-width: 0;
  max-width: 380px;         /* never larger than the original design */
}

@media (max-width: 1440px) {
  .global-search-wrapper input { max-width: 300px; }
}
@media (max-width: 1280px) {
  .global-search-wrapper input { max-width: 240px; }
}

/* The breadcrumb and the machine label are the least load-bearing things in
   the header, so they are what goes when room runs out. */
@media (max-width: 1200px) {
  .header .breadcrumb,
  .header-left .breadcrumb-separator {
    display: none;
  }
}

/* Search + sort now live INSIDE #machineDropdown's own SearchableDropdown
   control, not as separate elements riding along beside it, so there is
   nothing here to shrink or hide on a schedule any more - the dropdown
   button itself already sizes like #machineDropdown used to. */
@media (max-width: 1120px) {
  /* the dropdown carries the machine name, so the word "Machine:" is redundant */
  .machine-selector-label,
  label[for="machineDropdown"] {
    display: none;
  }
  #machineDropdown,
  .searchable-dropdown {
    max-width: 26vw;
  }
}

@media (max-width: 960px) {
  /* below this the search moves into the section toolbar, which already has one */
  .global-search-wrapper { display: none; }
  .header { gap: 8px; }

  /* The navigation chip keeps its icon but drops its label. It is the round
     trip between the workspace and command execution, so it must survive
     every width - the title attribute carries the meaning. */
  .nav-chip-label { display: none; }
  .nav-chip,
  .btn-cmd { padding: 6px 8px; }
}

/* The validation pill is important enough to keep, but not to let it push
   anything off-screen. */
.validation-status-pill,
#validation-status,
.config-validity-badge {
  flex: 0 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: min(28vw, 320px);
}


/* ==========================================================================
   4. SECTION TOOLBAR  (section title + in-section search + Rollback + Save)
   --------------------------------------------------------------------------
   Four items on one line with a 280px search. Wrapping is the correct
   behaviour here: the buttons stay full size and drop to a second line rather
   than shrinking into unreadable stubs.
   ========================================================================== */

.workspace-toolbar,
.section-header,
.section-header-actions {
  flex-wrap: wrap;
  gap: clamp(8px, 1vw, 16px);
  min-width: 0;
}

.toolbar-search {
  flex: 1 1 220px;
  min-width: 0;
}

.toolbar-search .search-input {
  width: 100%;
  min-width: 0;
  max-width: 280px;         /* the original width, as a ceiling not a floor */
}

@media (max-width: 1280px) {
  .toolbar-search .search-input { max-width: 220px; }
}


/* ==========================================================================
   5. PARAMETER ROWS — the dead-space fix
   --------------------------------------------------------------------------
   Was:  .column-name 20%  |  .column-value 68%  |  .column-type 7%  |  help 5%
         .parameter-input  max-width: 400px

   The percentages scale, but the editor inside the value column did not, so
   the extra width became empty space instead of a wider input. And 7%/5% for
   the badge and help button shrink exactly when they can least afford to.

   Now: the label column is fluid within sane bounds, the type and help
   columns are FIXED in pixels so they can never be squeezed out, and the
   value column takes whatever is left — with an input that actually uses it.
   ========================================================================== */

.parameter-table {
  table-layout: fixed;
  width: 100%;
}

/* IMPORTANT: plain percentages, NOT clamp().
   Under `table-layout: fixed` a column width must resolve to a definite
   length. `width: clamp(130px, 26%, 260px)` does not - the percentage has no
   definite basis in the fixed-table algorithm - so the column silently falls
   back to `auto` and the algorithm splits the leftover space EQUALLY between
   the auto columns. Measured result: the label and value columns both became
   429px, so the label got a 429px empty block and the volt matrix was forced
   into a scroll box. Percentages and pixels both resolve correctly here. */
.column-name  { width: 24%; }
.column-value { width: auto; }
.column-type  { width: 96px; }
.column-help  { width: 52px; }

@media (max-width: 1440px) {
  .column-name { width: 26%; }
}

@media (max-width: 1280px) {
  .column-name { width: 27%; }
  .column-type { width: 88px; }
  .column-help { width: 44px; }
}

.parameter-row td {
  padding-left: clamp(8px, 0.9vw, 16px);
  padding-right: clamp(8px, 0.9vw, 16px);
}

/* Long ids such as Analyse_Max_allowed_dif_btw_MEn_MEx_Trig must wrap rather
   than widen the column. */
.parameter-label,
.parameter-name {
  overflow-wrap: anywhere;
  word-break: break-word;
  min-width: 0;
}

/* Use the room that is actually there. 640px is wide enough for every real
   value in the schema and still leaves the row balanced on a large monitor. */
.parameter-input {
  width: 100%;
  max-width: min(100%, 640px);
}

/* .param-card is laid out by components/tooltip.css with
   `grid-template-columns: 220px 1fr 110px !important`. !important here is
   required to override !important there — it is not a shortcut. */
.param-card {
  grid-template-columns: clamp(140px, 22%, 260px) minmax(0, 1fr) auto !important;
  gap: clamp(8px, 0.8vw, 12px) !important;
}

.param-label {
  /* tooltip.css forces nowrap + ellipsis, which hides the end of long ids on a
     narrow screen. Wrapping keeps the whole id readable, which matters more
     than a single-line row. */
  white-space: normal !important;
  overflow: visible !important;
  text-overflow: clip !important;
  overflow-wrap: anywhere !important;
}

.param-meta-actions {
  /* was pinned to exactly 110px in all three dimensions */
  width: auto !important;
  min-width: 0 !important;
  max-width: none !important;
}

@media (max-width: 960px) {
  /* Stack the row: label above editor. Four columns stop being legible before
     this width, and a stacked row reads better than four crushed ones. */
  .parameter-table,
  .parameter-table tbody,
  .parameter-table tr,
  .parameter-table td {
    display: block;
    width: auto;
  }
  .parameter-table thead { display: none; }
  .parameter-row {
    padding: 12px clamp(8px, 2vw, 16px);
  }
  .parameter-row td { padding: 4px 0; }
  .parameter-name { font-weight: 600; }
  .parameter-type,
  .parameter-help-column {
    display: inline-block;
    width: auto;
    vertical-align: middle;
  }
  .parameter-input { max-width: 100%; }

  .param-card {
    grid-template-columns: minmax(0, 1fr) !important;
    gap: 6px !important;
  }
}


/* ==========================================================================
   6. COMPOSITE EDITORS  (volt matrix, channel pickers, periodic, RFID…)
   --------------------------------------------------------------------------
   These are the widest things in the app. The min/max volt matrix is six
   columns of 100px fixed inputs plus labels — 633px measured, which ran 60px
   past the viewport at 1024px.

   Two rules, applied to every composite container:
     a) the inputs become fluid, with a floor that still fits "-0.500000"
     b) the container — not the page — owns the horizontal scroll

   (b) is the important one. A wide table that scrolls inside its own box is
   usable. A wide table that widens the page hides the footer buttons.
   ========================================================================== */

.range-pair-container,
.editable-matrix-container,
.boolean-matrix-container,
.ordered-sequence-container,
.periodic-table-wrapper,
.rfid-table-container,
.table-scroll-container,
.trigger-inline-container,
.chcfg-multi-picker-container,
.chcfg-single-picker-container,
.filter-composite-container,
.matrix-switch-container,
.entry-exit-container,
.phone-list-container,
.ip-address-container,
.linked-url-container {
  max-width: 100%;
  min-width: 0;
  overflow-x: auto;
  /* momentum scrolling on trackpads, and a visible scrollbar so it is
     discoverable that there is more to the right */
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}

/* Fluid numeric inputs. 68px still shows "-0.500000" at 0.85rem; the ceiling
   keeps them from sprawling on a large monitor. */
.range-input,
.sequence-input,
.matrix-input,
.periodic-input {
  width: 100%;
  min-width: 68px;
  max-width: 132px;
}

@media (max-width: 1280px) {
  .range-input,
  .sequence-input,
  .matrix-input,
  .periodic-input {
    min-width: 62px;
    max-width: 104px;
  }
}

.range-pair-table,
.periodic-table,
.rfid-table {
  width: 100%;
  min-width: 0;
}

.range-pair-table td,
.range-pair-table th {
  padding-left: clamp(2px, 0.4vw, 8px);
  padding-right: clamp(2px, 0.4vw, 8px);
}

/* No breakpoint reshapes the volt matrix on purpose.
   With the label column no longer stealing 429px, the six-column table (456px
   measured) fits inside its cell down to about 1024px. Below that the
   container scroll above handles it, and at <=960px the whole parameter row
   stacks, which gives the matrix the full width anyway.

   An earlier attempt re-flowed it with `display:block` plus nth-child
   grid-column rules. It worked, but it depended on the renderer emitting
   exactly six cells per row in a fixed order - the kind of coupling that
   breaks silently the next time Renderers.js changes. Scrolling a table that
   is genuinely too wide is honest and cannot rot. */

/* Grids that already wrap only need a fluid track. */
.sequence-grid,
.rfid-inputs-grid,
.matrix-grid,
.trigger-inline-grid {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(6px, 0.8vw, 12px);
  min-width: 0;
}

.rfid-table-unit { min-width: 0; }

/* rfid-antenna.css pins .rfid-table-container to min-width:500px, which forces
   the page wider than a 1024px viewport. Let it scroll inside itself instead. */
.rfid-table-container {
  min-width: 0;
}
.rfid-table {
  min-width: 460px;         /* below this the diagram is unreadable, so scroll */
}


/* ==========================================================================
   7. FOOTER
   --------------------------------------------------------------------------
   Six action buttons plus a status line, space-between, no wrapping. On a
   narrow screen the buttons collide with the status text.
   ========================================================================== */

.macconf-footer {
  padding-left: var(--gutter);
  padding-right: var(--gutter);
  gap: clamp(8px, 1vw, 16px);
  flex-wrap: nowrap;
}

.footer-group {
  gap: clamp(6px, 0.7vw, 12px);
  min-width: 0;
}

.active-file-indicator {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (max-width: 1440px) {
  .macconf-footer .btn,
  .macconf-footer button {
    padding-left: 10px;
    padding-right: 10px;
    font-size: 0.8rem;
  }
}

@media (max-width: 1200px) {
  /* the description line is the least critical thing down here */
  .active-file-desc,
  .active-file-indicator .desc {
    display: none;
  }
}

@media (max-width: 1024px) {
  /* The status text is informational; the action buttons are not. Give the
     buttons the room and let the middle group go. */
  .macconf-footer > .footer-group:nth-child(2),
  .active-file-indicator {
    display: none;
  }
}

@media (max-width: 768px) {
  /* Two rows of buttons, and the shell gives the footer the height for it. */
  body { --footer-height: 96px; }
  .macconf-footer {
    height: auto;
    min-height: 96px;
    flex-wrap: wrap;
    justify-content: center;
    padding-top: 8px;
    padding-bottom: 8px;
  }
}


/* ==========================================================================
   8. MODALS
   --------------------------------------------------------------------------
   deployment-modal.css uses a fixed width:600px, and modals.css a
   max-width:1100px — both larger than a small viewport.
   ========================================================================== */

.macconf-modal,
.modal-content,
.macconf-modal-content,
.deployment-modal {
  width: min(96vw, 1100px);
  max-width: 96vw;
  max-height: 90vh;
  overflow-y: auto;
}

.deployment-modal,
.deployment-modal-content {
  width: min(96vw, 600px);
}

.rollback-table-container,
.modal-table-container {
  max-height: min(60vh, 400px);
  overflow: auto;
}

.modal-table,
.rollback-table {
  min-width: 0;
}

@media (max-width: 768px) {
  .modal-footer,
  .macconf-modal-footer {
    flex-wrap: wrap;
    gap: 8px;
  }
}


/* ==========================================================================
   9. COMMAND EXECUTION PAGE
   --------------------------------------------------------------------------
   .ce-selection-area is `grid-template-columns: 1fr 1.5fr 2fr`, and the third
   column holds the request preview, a copy button and the Execute button in an
   un-wrapping flex row.

   A CAUTIONARY NOTE, because this was got wrong once here: an `fr` track's
   minimum is `auto`, i.e. its content size. That is why the third track
   naturally grew past its 2fr share (measured 602px instead of 456px) to fit
   those controls. Adding a blanket `min-width: 0` to .ce-col removed that
   floor, the track collapsed to the pure ratio, and the Execute button - the
   one control the page exists for - was pushed 105px off-screen.

   `min-width: 0` is NOT a free "make it responsive" switch. It permits a track
   to shrink below its content, which is right for text that can wrap or a
   table that scrolls, and wrong for a row of fixed-size controls. So here the
   grid is made to re-flow into fewer columns instead, and the one child that
   CAN give up space - the preview - is the one told to shrink.
   ========================================================================== */

.ce-selection-area {
  /* re-flow to fewer columns as the viewport narrows, instead of crushing
     three fixed-ratio columns. min(100%, 260px) stops the track demanding
     260px when the container itself is narrower than that. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: clamp(12px, 1.4vw, 24px);
}

/* deliberately NOT min-width: 0 - see the note above */
.ce-col {
  max-width: 100%;
}

/* the inner "preview + copy + execute" row: let it wrap as a last resort */
.ce-col > div {
  min-width: 0;
  flex-wrap: wrap;
}

/* the preview is the only element in that row that can afford to give up
   space, so it is the one that shrinks */
.ce-request-preview {
  flex: 1 1 0;
  min-width: 0;
  overflow-x: auto;
  white-space: nowrap;
}

.btn-execute,
#btnCopyRequest {
  flex-shrink: 0;
}

.ce-result-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  gap: clamp(8px, 1vw, 16px);
}

.ce-response-container,
.ce-response-pre {
  max-width: 100%;
  overflow-x: auto;
  overflow-wrap: anywhere;
}

.ce-response-pre {
  white-space: pre-wrap;
}

.ce-warning-banner,
.warning-actions,
.ce-info-row {
  flex-wrap: wrap;
  gap: 8px;
  min-width: 0;
}

.ce-select {
  width: 100%;
  min-width: 0;
}

.command-execution-header {
  flex-wrap: wrap;
  gap: clamp(8px, 1vw, 16px);
}

@media (max-width: 768px) {
  .ce-card { padding: 14px; }
}


/* ==========================================================================
   10. ADMIN PAGES
   --------------------------------------------------------------------------
   admin-users.css already has the only two media queries in the codebase
   (1100px and 700px), so these rules complement rather than replace them:
   fluid tracks, and wide tables that scroll inside their own container.
   ========================================================================== */

.admin-layout,
.admin-grid {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr));
  gap: clamp(12px, 1.4vw, 24px);
}

.admin-table-container,
.table-responsive,
.admin-table-wrapper {
  /* Track T10: the actual markup on all 3 admin pages uses
     .admin-table-wrapper (id="tableWrapper"), not .admin-table-container
     or .table-responsive -- neither of which appears anywhere in the
     templates. This rule never matched anything real, so a wide table
     (Machines' especially) had no horizontal-scroll container of its own
     and just overflowed the page at narrow widths. */
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: thin;
}

.admin-subnav {
  /* Track T10: the per-page tab bar (Users/Commands/Machines sub-nav)
     is a plain flex row with no wrap set -- on a narrow viewport its
     buttons ran off the edge instead of dropping to a second line. */
  flex-wrap: wrap;
}

.admin-list-toolbar {
  /* Track T10: the "Active/Disabled" tab links + search box row above
     each admin table (Users/Commands/Machines) had NO class at all --
     just an inline `display:flex; justify-content:space-between` with
     no wrap. Verified by rendering the actual page at 768px: this row
     alone (not the table) was what forced the whole page to scroll
     horizontally, because its search input has a fixed pixel width and
     nothing let the row drop to a second line. Named it so this and the
     rule below can actually reach it -- .admin-filters two rules above
     was written for exactly this shape but never matched any real
     markup. */
  flex-wrap: wrap;
  row-gap: 10px;
}

.admin-list-toolbar .search-bar {
  /* The inline `width: 280px` on the input stays (higher specificity
     for that property), but max-width isn't set inline, so this still
     clamps it once the row wraps and the input no longer has 280px of
     spare room. */
  max-width: 100%;
  box-sizing: border-box;
}

.admin-main-column,
.admin-side-column {
  /* Track T10: same root cause as the .admin-card fix above, but a
     different class name -- the Commands page's manage-table panel is
     .admin-main-column (not .admin-card), and the Create/Edit side
     panels on all 3 pages sit in .admin-side-column. Both are grid
     items inside .admin-container with no min-width override, so their
     default min-width:auto floors them at their content's intrinsic
     width (Commands' "Requires Parameter?" column, in this case) instead
     of the grid track's minmax(0, ...) sizing. Verified by rendering
     Commands at 768px: .admin-table-wrapper's own overflow-x:auto never
     kicked in because .admin-main-column grew past its track first,
     forcing .workspace itself to pick up an extra, unintended horizontal
     scrollbar instead of the scroll staying contained inside the table
     wrapper. */
  min-width: 0;
}

.admin-table,
table.admin-table {
  min-width: 0;
}

.admin-top-nav {
  flex-wrap: wrap;
  gap: 8px;
  padding-left: var(--gutter);
  padding-right: var(--gutter);
}

@media (max-width: 1120px) {
  .admin-nav-card {
    font-size: 0.875rem;
    padding: 8px 12px;
  }
}

.admin-form-grid,
.admin-filters {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(8px, 1vw, 16px);
  min-width: 0;
}

.admin-form-grid input,
.admin-form-grid select,
.admin-filters input,
.admin-filters select {
  min-width: 0;
  flex: 1 1 180px;
}


/* ==========================================================================
   11. LONG CONTENT AND CODE
   --------------------------------------------------------------------------
   INI previews and validation messages are long single tokens. Without an
   explicit wrap rule they set the width of everything around them.
   ========================================================================== */

pre,
code,
.ini-preview,
.ini-preview-content,
.code-input-field,
.validation-message,
.validation-errors {
  max-width: 100%;
  overflow-x: auto;
  overflow-wrap: anywhere;
}

#ini-preview-modal pre {
  white-space: pre;
  overflow: auto;
  max-height: 70vh;
}

.tooltip-content,
.macconf-tooltip {
  max-width: min(92vw, 420px);
}


/* ==========================================================================
   12. TOUCH AND ACCESSIBILITY
   --------------------------------------------------------------------------
   A coarse pointer needs a larger target than a mouse. This keys off the
   input device rather than the viewport, so a touchscreen laptop gets it at
   any width and a mouse-driven small window does not lose density.
   ========================================================================== */

@media (pointer: coarse) {
  button,
  .btn,
  .sidebar-link,
  select,
  input[type="text"],
  input[type="number"],
  input[type="password"] {
    min-height: 40px;
  }
  .param-help,
  .help-button {
    min-width: 32px;
    min-height: 32px;
  }
}

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

/* Keyboard focus must stay visible after all of the above. */
:focus-visible {
  outline: 2px solid var(--primary, #0a58ca);
  outline-offset: 2px;
}
