/* ==========================================================================
   Typography, type scale, root font ramp, focus, overflow guard, folder tree indent.
   Owning feature: shared / base
   Load order is defined in Views/Shared/_CssIncludes.cshtml — do not reorder.
   ========================================================================== */

/* ==========================================================================
   Typography — Google Sans Flex (Google Fonts) with system fallback.
   Loaded via shared layout (`<link rel="stylesheet">`) so only the four weights
   below are fetched, with `display=swap` to avoid invisible text.
   ========================================================================== */
:root {
  --fh-font-sans: "Google Sans Flex", "Google Sans", system-ui, -apple-system,
                  "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans",
                  "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
}

/* Modular type scale — the ONLY font-size/weight/leading/tracking values the
   app may use. Components used to hard-code ~40 ad-hoc sizes (0.82rem, 0.86rem,
   0.775rem, 10px, …), so two equal-level labels on different pages could differ
   by a px and there was no shared answer to "how big is a page title?". This
   block replaces that with one step-based rem scale.

   Sizes are pure rem, so every step inherits the root clamp's 360px→768px ramp
   and the ≥2560px bump automatically (a px-based floor would break that). The
   px notes are at the 16px reference root; on a 360px phone the whole scale
   sits at 87.5% of those numbers, which is the intended behaviour — one
   proportional shrink, not a per-component pixel fight. The smallest *text*
   step (xs) is the ~12px accessibility floor at the reference root; 2xs exists
   for decorative glyphs only and must never carry prose.

   Naming: --fh-text (no suffix) is the ink COLOUR token; every --fh-text-* with
   a step suffix is a SIZE token. Reading `font-size: var(--fh-text-sm)` against
   `color: var(--fh-text)` reads as "13px" vs "ink" respectively.

   Roles
   -----
   --fh-text-2xs 0.6875rem (11px)  carets, chevrons, dots, sort arrows — glyphs
                                   only, never words.
   --fh-text-xs   0.75rem (12px)   micro labels: uppercase column headers,
                                   badges, timestamps, kbd, hint bars.
   --fh-text-sm   0.8125rem (13px) secondary/meta text, dense table & list body.
   --fh-text-base 0.875rem (14px)  app body default: controls, buttons, nav,
                                   cards, menus, modal/dropdown body text.
   --fh-text-md   0.9375rem (15px) emphasized body: the "+ New" primary CTA,
                                   auth inputs and buttons.
   --fh-text-lg   1rem (16px)      modal titles, item/card names, section names.
   --fh-text-xl   1.125rem (18px)  empty-state titles, brand, preview h3.
   --fh-text-2xl  1.25rem (20px)   small headings (preview h2, stat values).
   --fh-text-3xl  1.5rem (24px)    page titles (.fh-page-title), preview h1.
   --fh-text-4xl  1.75rem (28px)   Home/login titles, hero quota/stat numbers.
   --fh-text-5xl  2.25rem (36px)   display glyphs (empty-state icons).
   --fh-text-6xl  3rem (48px)      hero glyphs (drag overlay, empty trash,
                                   details-panel thumb, preview icon). */
:root {
  --fh-text-2xs: 0.6875rem;
  --fh-text-xs: 0.75rem;
  --fh-text-sm: 0.8125rem;
  --fh-text-base: 0.875rem;
  --fh-text-md: 0.9375rem;
  --fh-text-lg: 1rem;
  --fh-text-xl: 1.125rem;
  --fh-text-2xl: 1.25rem;
  --fh-text-3xl: 1.5rem;
  --fh-text-4xl: 1.75rem;
  --fh-text-5xl: 2.25rem;
  --fh-text-6xl: 3rem;

  /* Weight roles — 400 body, 500 labels/buttons/chips/active row, 600 headings
     + selected/active chrome + column headers + item names, 700 page titles
     and hero numbers. Equal-level text must render at the same weight, so if a
     new control "feels" like an existing one it should reuse that control's
     weight rather than inventing a new one. */
  --fh-weight-regular: 400;
  --fh-weight-medium: 500;
  --fh-weight-semibold: 600;
  --fh-weight-bold: 700;

  /* Line-height roles — none for glyph-only rows, tight for titles (so
     multi-line Vietnamese card names keep their vertical rhythm without
     colliding), snug for compact meta/secondary text, normal for body copy. */
  --fh-leading-none: 1;
  --fh-leading-tight: 1.25;
  --fh-leading-snug: 1.35;
  --fh-leading-normal: 1.5;

  /* Letter-spacing roles — tight for headings, tighter for display sizes
     (≥3xl), normal for body (default, rarely written), wide for uppercase
     micro-labels and small tracked headings. The old code drifted across
     eleven values (-0.04em … 0.1em); these four cover every case. */
  --fh-tracking-tight: -0.01em;
  --fh-tracking-tighter: -0.02em;
  --fh-tracking-normal: 0;
  --fh-tracking-wide: 0.05em;
}

/* Root font size drives every rem in the app. It used to step 14px → 16px at a
   hard `min-width: 768px` boundary, so 767px and 768px rendered the whole UI at
   a 14% different scale — a visible reflow jump landing exactly on the
   768x1024 tablet target. A clamp() ramp interpolates the same 14px → 16px
   across the phone→tablet range instead, then holds 16px through laptop
   widths. Large displays step up again from 1920 so a 4K panel isn't stuck
   on 16px body text (see the wide-screen blocks below). */
html {
  font-family: var(--fh-font-sans);
  /* 0.875rem (14px) at 360px wide → 1rem (16px) at 768px, then held through
     1919px. Expressed in rem, not px, so a reader who has raised their
     browser's default font size still gets it honoured (a px root size
     silently overrides that preference). */
  font-size: clamp(0.875rem, 0.7647rem + 0.4902vw, 1rem);
  font-feature-settings: "cv11", "ss01", "ss03";
}

/* Large-display type ramp — each band starts at the previous band's ceiling
   so the scale actually moves at the breakpoint (the old ≥2560 clamp still
   evaluated to 1rem at 2560px). Caps at 1.25rem so 5K/8K doesn't become a
   slide deck.
   1920–2559: 1rem (16px) → 1.125rem (18px)
   2560–3839: 1.125rem (18px) → 1.25rem (20px)
   ≥3840:     hold 1.25rem (20px) */
@media (min-width: 1920px) and (max-width: 2559.98px) {
  html {
    /* 1rem at 1920 → 1.125rem at 2560: 0.625rem + 0.3125vw */
    font-size: clamp(1rem, 0.625rem + 0.3125vw, 1.125rem);
  }
}
@media (min-width: 2560px) and (max-width: 3839.98px) {
  html {
    /* 1.125rem at 2560 → 1.25rem at 3840: 0.875rem + 0.1563vw */
    font-size: clamp(1.125rem, 0.875rem + 0.1563vw, 1.25rem);
  }
}
@media (min-width: 3840px) {
  html {
    font-size: 1.25rem;
  }
}

body {
  font-family: var(--fh-font-sans);
  font-optical-sizing: auto;
}

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
  font-family: var(--fh-font-sans);
  font-weight: var(--fh-weight-semibold);
  letter-spacing: var(--fh-tracking-tight);
  color: var(--fh-text);
}
/* Bootstrap's own heading ladder (2.5rem…1rem) is off the app's scale, so it
   gets mapped onto the type tokens — page titles, preview, modals and any
   plain Bootstrap heading then all speak the same size language. */
h1, .h1 { font-size: var(--fh-text-3xl); }
h2, .h2 { font-size: var(--fh-text-2xl); }
h3, .h3 { font-size: var(--fh-text-xl); }
h4, .h4 { font-size: var(--fh-text-lg); }
h5, .h5 { font-size: var(--fh-text-md); }
h6, .h6 { font-size: var(--fh-text-base); }

/* Bootstrap CSS variables — overrides apply to Bootstrap modals, dropdowns,
   tables, forms, and every component that reads `--bs-body-font-*`. */
:root {
  --bs-font-sans-serif: var(--fh-font-sans);
  --bs-body-font-family: var(--fh-font-sans);
  /* Bootstrap's Reboot defaulted unclassed text to 1rem/400/#212529 — a
     second, inconsistent typography beside the app's 0.875rem body. Point the
     whole Bootstrap layer at the same tokens so tables, modals, dropdowns,
     forms, toasts and badges inherit the app's sizes, weights and inks. */
  --bs-body-font-size: var(--fh-text-base);
  --bs-body-font-weight: var(--fh-weight-regular);
  --bs-body-line-height: var(--fh-leading-normal);
  --bs-body-color: var(--fh-text);
  --bs-secondary-color: var(--fh-muted);
  --bs-heading-color: var(--fh-text);
}

/* Keyboard-only focus ring. Was on `:focus`, which fired on every mouse click
   too and painted a ring over buttons the user had merely pressed; and its
   inner `white` halo was a literal, so on the dark sidebar it drew a white
   band. `:focus-visible` restricts it to keyboard/AT focus, and the halo now
   reads from the surface token so it works on light and dark chrome alike. */
.btn:focus-visible, .btn-link.nav-link:focus-visible,
.form-control:focus-visible, .form-check-input:focus-visible {
  outline: none;
  box-shadow: 0 0 0 0.1rem var(--fh-focus-halo, #fff), 0 0 0 0.25rem #258cfb;
}
.fh-sidebar {
  --fh-focus-halo: #fff;
}

/* Page-level overflow guard. Individual surfaces are responsible for scrolling
   their own wide content (tables live in .table-responsive, the breadcrumb in
   its own scroller); this makes sure that when one of them regresses the page
   itself still can't grow a horizontal scrollbar and shear the fixed navbar
   and sidebar away from the content. `overflow-x: clip` rather than `hidden`
   so it doesn't turn <body> into a scroll container — `hidden` would break
   `position: sticky` on .fh-content-head.

   Deliberately on `html` only, not also on `body`: overflow set on the root
   element propagates to the viewport, and sticky positioning is resolved
   against that same viewport scrollport, so the guard and .fh-content-head's
   `position: sticky` don't interact. A clip container on `body` would sit
   *between* the sticky element and the viewport, which is the arrangement
   that breaks it. */
html {
  position: relative;
  min-height: 100%;
  overflow-x: clip;
}

body {
  /* The old `margin-bottom: 60px` paired with the default template's
     `.footer { position: absolute; bottom: 0 }` — markup this app no longer
     renders (.fh-footer is in normal flow). All it did was leave 60px of dead
     grey below the footer on every page at every width. */
  max-width: 100%;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
  color: var(--bs-secondary-color);
  text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
  text-align: start;
}

/* Folder tree (Browse sidebar + move/copy picker modals) — Windows-Explorer-style
   nesting: each depth level gets its own indent plus a guide line so parent/child
   relationships stay visible at a glance, however deep the tree goes. */
.tree-children {
  margin-left: 0.55rem;
  padding-left: 0.85rem;
  border-left: 1px solid #dee2e6;
}

.tree-row:hover {
  background-color: var(--fh-primary-soft, #eff6ff);
}

.tree-link {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

