/* ─────────────────────────────────────────────────────────────────────────────
   SGT APPEARANCE — Light / Dark / System, for real.
   ─────────────────────────────────────────────────────────────────────────────

   WHY THIS FILE EXISTS. The platform had a two-state cycle that set a `theme`
   cookie and reloaded. Measured in a real browser, choosing Dark on the
   platform home page changed nothing at all: body background stayed
   rgb(246,248,254) in every state and <html> carried no data-theme. Three
   separate reasons, all of them fixed here or beside it:

     1. "System" did not exist. config('design.modes') is light|dark|
        high_contrast, so a System choice was coerced to light, and NOT ONE
        prefers-color-scheme rule existed in any stylesheet — the device
        preference could not reach the page even in principle.
     2. The marketing home page read SiteSetting design.mode — a GLOBAL
        operator setting — not the visitor's cookie. A visitor's choice was
        structurally incapable of affecting it.
     3. ThemeResolver::buildTokens('dark') returned --bg:#ffffff, because
        TokenStore's stored tokens are merged AFTER the mode tokens and stomp
        them. So even where dark was resolved, the surface stayed white.

   HOW THIS FIXES IT WITHOUT DEPENDING ON ANY OF THAT.

   `data-appearance` on <html> is the visitor's CHOICE (light|dark|system) and
   is written SERVER-SIDE from the cookie, before a single byte of body. The
   MODE is then resolved by CSS alone:

     :root[data-appearance="dark"]                        -> dark
     @media (prefers-color-scheme: dark)
       :root[data-appearance="system"]                    -> dark

   That is why System genuinely follows the operating system and why there is
   NO FLASH: no JavaScript participates in first paint. A JS-applied theme is
   applied after the first frame is already on screen, which is precisely the
   flash the old public layout produced.

   SPECIFICITY IS LOAD-BEARING, NOT DECORATION. `:root[data-appearance="…"]`
   scores (0,1,1) and beats the `:root` (0,0,1) blocks that layouts inline into
   <head> — including ThemeResolver's stomped --bg:#ffffff and the dark-first
   tenant-client block. An external stylesheet cannot otherwise outrank inline
   <style>, so without the attribute in the selector this file would lose every
   time and the bug would survive the fix.

   TWO TOKEN FAMILIES, deliberately. The admin surfaces use
   --bg/--bg2/--bg3/--text/--text2/--text3/--border; the marketing and tenant
   surfaces use --bg/--bg-2/--ink/--ink-2/--ink-3/--line. Both are set here so
   one control governs every surface instead of each layout inventing its own.

   color-scheme is set alongside the tokens so the browser's OWN furniture —
   scrollbars, form controls, spellcheck underlines, the canvas behind an
   overscroll — follows too. Without it a dark page keeps white scrollbars and
   an unreadable date picker, which is the tell of a theme that was painted
   rather than declared.
   ───────────────────────────────────────────────────────────────────────── */

/* ── The declared light surface ───────────────────────────────────────────────
   Stated explicitly rather than left to the default, so an EXPLICIT Light
   choice also overrides a layout whose own default is dark (tenant-client is
   dark-first). "Light" has to mean light everywhere, not "whatever the layout
   happened to start as". */
:root[data-appearance="light"] {
  /* COLOUR-SCHEME ONLY — NO TOKEN OVERRIDES, DELIBERATELY.
     The first version of this file also set --bg/--text here, and that shifted
     the platform home page's light paper from #F6F8FE to #f8fafc: a visible
     change to the default appearance that nobody asked for, caught by measuring
     the light state before and after rather than only testing dark.
     Light must remain byte-identical to what ships today, so the only thing
     declared here is the browser's own furniture. Layouts whose default is dark
     (tenant-client) already switch to light off data-theme="light", which
     Appearance::htmlAttributes() emits for this choice. */
  color-scheme: light;
}

:root[data-appearance="system"] { color-scheme: light dark; }

/* ── The dark surface ─────────────────────────────────────────────────────────
   Values match the dark block already in admin.css so a dark admin screen does
   not shift appearance when this file loads; the marketing/tenant family uses
   the deeper navy those surfaces were designed against. */
:root[data-appearance="dark"] {
  color-scheme: dark;
  /* THE TENANT FRONT-SITE FAMILY. front/layout.blade.php declares its own
     palette — --bg-soft, --bg-dark, --text-mid, --text-soft — and the hero is
     painted from `linear-gradient(180deg, var(--bg), var(--bg-soft))`. Setting
     only --bg/--text left --bg-soft at #f8f9fb, so the hero graded from dark
     navy into near-white and the page still LOOKED light while its body and
     footer had gone dark. Measured, not guessed: that is what the owner saw. */
  --bg-soft:  #131C2E;
  --bg-dark:  #060910;
  --text-mid: #CBD5E1;
  --text-soft:#94A3B8;
  --on-dark:  #FFFFFF;

  --bg:    #0f172a;
  --bg2:   #1e293b;
  --bg3:   #334155;
  --text:  #f1f5f9;
  --text2: #94a3b8;
  /* Lifted from #64748b. Dark mode is not an inversion: the step that reads
     as "quiet" on white reads as "gone" on slate — measured at 2.2:1 against
     the card behind it, under even the 3:1 large-text line. */
  --text3: #8896aa;
  --border:#334155;
  /* Accent and semantic colours used as TEXT need a readable step; used as a
     fill they do not. See admin.css for the full note. */
  --accent-on-surface:  color-mix(in srgb, var(--accent) 45%, #ffffff);
  --success-on-surface: #5ddaa0;
  --warning-on-surface: #f0b657;
  --danger-on-surface:  #f98a8a;
  --ink:   #F8FAFC;
  --ink-2: #CBD5E1;
  --ink-3: #94A3B8;
  --line:  #1E293B;
  --bg-2:  #131C2E;
  --shadow:    0 1px 3px rgba(0,0,0,0.3);
  --shadow-md: 0 4px 12px rgba(0,0,0,0.4);
}

@media (prefers-color-scheme: dark) {
  /* SYSTEM, resolved by the browser at first paint. This is the whole reason
     the feature can be honest about following the device. */
  :root[data-appearance="system"] {
    /* THE TENANT FRONT-SITE FAMILY. front/layout.blade.php declares its own
       palette — --bg-soft, --bg-dark, --text-mid, --text-soft — and the hero is
       painted from `linear-gradient(180deg, var(--bg), var(--bg-soft))`. Setting
       only --bg/--text left --bg-soft at #f8f9fb, so the hero graded from dark
       navy into near-white and the page still LOOKED light while its body and
       footer had gone dark. Measured, not guessed: that is what the owner saw. */
    --bg-soft:  #131C2E;
    --bg-dark:  #060910;
    --text-mid: #CBD5E1;
    --text-soft:#94A3B8;
    --on-dark:  #FFFFFF;
    --bg:    #0f172a;
    --bg2:   #1e293b;
    --bg3:   #334155;
    --text:  #f1f5f9;
    --text2: #94a3b8;
    /* Same lift as the explicit-dark block above. The system-dark path is the
       one most readers actually land on, so leaving it behind would have made
       the fix invisible to them. */
    --text3: #8896aa;
    --border:#334155;
    --accent-on-surface:  color-mix(in srgb, var(--accent) 45%, #ffffff);
    --success-on-surface: #5ddaa0;
    --warning-on-surface: #f0b657;
    --danger-on-surface:  #f98a8a;
    --ink:   #F8FAFC;
    --ink-2: #CBD5E1;
    --ink-3: #94A3B8;
    --line:  #1E293B;
    --bg-2:  #131C2E;
    --shadow:    0 1px 3px rgba(0,0,0,0.3);
    --shadow-md: 0 4px 12px rgba(0,0,0,0.4);
  }
}

/* ── Make the dark surface actually paint ────────────────────────────────────
   Setting tokens is not the same as using them: a page that paints its own body
   colour would take the dark tokens and still look white, which is exactly the
   defect being fixed. Scoped to dark ONLY — on a light page the existing paper
   is already right, and overriding it here is what caused the regression noted
   above. html carries it too so overscroll and short pages match. */
:root[data-appearance="dark"],
:root[data-appearance="dark"] body { background-color: var(--bg); }
:root[data-appearance="dark"] body { color: var(--text, var(--ink)); }

@media (prefers-color-scheme: dark) {
  :root[data-appearance="system"],
  :root[data-appearance="system"] body { background-color: var(--bg); }
  :root[data-appearance="system"] body { color: var(--text, var(--ink)); }
}

/* ── The control ─────────────────────────────────────────────────────────────
   A three-way segmented control. Logical properties throughout so it mirrors
   in Arabic and Kurdish without a second rule; 44px targets per the operator
   ethos; the selected state carries a tick AND weight, never colour alone, so
   it survives colour-blindness and high-contrast. */
.appearance-control {
  display: inline-flex;
  gap: .15rem;
  padding: .2rem;
  border: 1px solid var(--border, var(--line, #e2e8f0));
  border-radius: 999px;
  background: var(--bg2, var(--bg-2, #fff));
}
.appearance-control button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .3rem;
  min-height: 44px;
  min-width: 44px;
  padding-inline: .7rem;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--text2, var(--ink-2, #475569));
  font: inherit;
  font-size: .82rem;
  cursor: pointer;
  white-space: nowrap;
}
.appearance-control button:hover { background: var(--bg3, rgba(127,127,127,.12)); }
.appearance-control button[aria-checked="true"] {
  background: var(--bg3, rgba(127,127,127,.18));
  color: var(--text, var(--ink, #0f172a));
  font-weight: 800;
}
.appearance-control button[aria-checked="true"]::before { content: "✓"; font-size: .8em; }
.appearance-control button:focus-visible { outline: 2px solid var(--accent, #3b82f6); outline-offset: 2px; }
@media (max-width: 420px) {
  /* The label is the icon's explanation, not its duplicate — on a narrow phone
     the icons plus the accessible name carry it and three full words do not
     fit beside a logo and a menu button. */
  .appearance-control button .appearance-label { display: none; }
  .appearance-control button { padding-inline: .45rem; }
}

/* ─────────────────────────────────────────────────────────────────────────
   ON A PHONE THIS COLLAPSES TO ONE BUTTON, BECAUSE THREE ATE THE NAVIGATION.

   Hiding the labels was not enough and the measurement says so: three buttons
   at min-width 44px plus gaps and padding is 145px, and the admin bar needed
   437px inside a 390px viewport — so 47px of the navigation was clipped off
   the right edge and menu items became unreachable. Reported from a real
   phone, and the reason the earlier check missed it is that the document
   itself never overflowed; the bar clipped internally.

   Collapsed, only the CURRENT choice is shown — about 48px — and focus opens
   the other two. Touch works because a tap focuses the button before it
   activates: first tap reveals, second chooses. Re-choosing what is already
   chosen is idempotent, so the first tap costs nothing.

   No JavaScript, so it behaves the same on the first paint as on any later
   one, and it uses logical properties throughout so Arabic and Kurdish mirror
   without a second rule.
   ───────────────────────────────────────────────────────────────────────── */
@media (max-width: 560px) {
  /* ── A THEME ICON, AND A POPOVER. NOT A PILL. ─────────────────────────────
     The first attempt collapsed three buttons to one but kept the label, so
     "✓ ☀ Light ▾" still ran to about 105px in a phone header that also had a
     language selector and a session timer. The owner's photograph showed the
     result: desktop controls filling the width, then wrapping over the page.

     So on a phone this is a 44px icon showing the CURRENT choice, and the
     other two arrive in a popover that is POSITIONED ABSOLUTELY — opening it
     cannot widen the bar or push anything sideways, which is what an inline
     reveal would have done.

     Still no JavaScript, so it is correct on the very first paint. Still a
     radiogroup. Logical properties throughout, so Arabic and Kurdish mirror
     without a second rule. */
  .appearance-control {
    position: relative;
    border: 0;
    background: transparent;
    padding: 0;
    gap: 0;
  }

  /* Collapsed: the current choice only, as an icon. */
  .appearance-control button[aria-checked="false"] { display: none; }
  .appearance-control button .appearance-label { display: none; }
  .appearance-control button[aria-checked="true"] {
    min-width: 44px; min-height: 44px;
    padding-inline: 0;
    border-radius: 10px;
  }
  .appearance-control button[aria-checked="true"]::before { content: none; }
  .appearance-control button[aria-checked="true"]::after { content: none; }

  /* Open: the two alternatives drop below as a popover, out of flow. */
  /* FIXED, not absolute, and pinned to the VIEWPORT edge.
     Anchored to the 44px button it looked right at 390px and ran off the LEFT
     edge at 320px — the button sits mid-bar, and a 132px panel hanging from
     its inline-end simply does not fit beside it. Only opening the control
     and looking showed that; the closed state measured perfectly. */
  .appearance-control:focus-within button[aria-checked="false"] {
    display: inline-flex;
    position: fixed;
    inset-inline-end: .5rem;
    min-width: 132px;
    min-height: 44px;
    justify-content: flex-start;
    padding-inline: .6rem;
    background: var(--bg2, #fff);
    border: 1px solid var(--border, #e2e8f0);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(15, 23, 42, .18);
    z-index: 200;
  }
  .appearance-control:focus-within button[aria-checked="false"] .appearance-label { display: inline; }
  /* WHICH SLOT EACH OPTION TAKES depends on which one is currently chosen,
     because the chosen one is the icon in the bar and the other two are the
     menu. Written out for all three cases rather than guessed with a single
     offset — a fixed offset per value leaves a hole wherever the active
     choice would have sat. :has() is already used elsewhere in this admin
     (the topbar chrome-toggle rule), so it is not a new dependency. */
  .appearance-control:focus-within:has(button[value="light"][aria-checked="true"])  button[value="dark"]   { top: 60px; }
  .appearance-control:focus-within:has(button[value="light"][aria-checked="true"])  button[value="system"] { top: 106px; }
  .appearance-control:focus-within:has(button[value="dark"][aria-checked="true"])   button[value="light"]  { top: 60px; }
  .appearance-control:focus-within:has(button[value="dark"][aria-checked="true"])   button[value="system"] { top: 106px; }
  .appearance-control:focus-within:has(button[value="system"][aria-checked="true"]) button[value="light"]  { top: 60px; }
  .appearance-control:focus-within:has(button[value="system"][aria-checked="true"]) button[value="dark"]   { top: 106px; }
}}

/* ── The admin shell ─────────────────────────────────────────────────────────
   MEASURED, NOT ASSUMED. With Dark selected, the admin body went dark while the
   sidebar stayed rgb(248,250,252) with rgb(31,41,55) text — a half-dark admin,
   which fails a real look at the screen even though every base token had
   resolved correctly (--bg2 really was #1e293b).

   THE CAUSE, and why the obvious fixes lost. layouts/admin.blade.php declares a
   complete LIGHT nav palette scoped to `.sidebar` and then applies it with
   `!important`:

       .sidebar { --nav-bg:#f8fafc; --nav-text:#1f2937; ... }
       .sidebar { background:var(--nav-bg) !important; color:var(--nav-text) !important; }

   So repainting `.sidebar` directly is a fight with `!important`, and the first
   attempt here won the background and lost the text — producing a dark sidebar
   with #1f2937 labels on it, invisible, which is worse than the bug it replaced.

   THE FIX IS TO ANSWER THE QUESTION THE CODE IS ALREADY ASKING. Those rules read
   tokens; they simply had no dark values to read. Redefining the same seven
   tokens at higher specificity (`:root[data-appearance="dark"] .sidebar` scores
   (0,2,1) against the (0,1,0) of `.sidebar`) makes the existing !important rules
   paint dark by themselves — no override, no !important of our own, and the
   layout keeps ownership of how the sidebar is drawn. */
:root[data-appearance="dark"] .sidebar,
:root[data-appearance="system"] .sidebar { /* system narrowed by the query below */
  color-scheme: dark;
}

:root[data-appearance="dark"] .sidebar {
  --nav-bg:        #1e293b;
  --nav-bg-line:   #334155;
  --nav-text:      #e2e8f0;
  --nav-text-dim:  #94a3b8;
  --nav-hover:     #334155;
  --nav-active:    #60a5fa;
  --nav-active-bg: #1e3a5f;
}

@media (prefers-color-scheme: dark) {
  :root[data-appearance="system"] .sidebar {
    --nav-bg:        #1e293b;
    --nav-bg-line:   #334155;
    --nav-text:      #e2e8f0;
    --nav-text-dim:  #94a3b8;
    --nav-hover:     #334155;
    --nav-active:    #60a5fa;
    --nav-active-bg: #1e3a5f;
  }
}

/* ── The last white surfaces on a dark admin page ────────────────────────────
   Measured on /admin with Dark selected: six elements still computed
   rgb(255,255,255). Not a mystery each — three distinct causes:

     • the dashboard health strip paints `background: var(--card-bg, #fff)`
       and --card-bg is never defined, so the fallback wins;
     • `.btn.light` is a deliberately pale button variant;
     • `.topbar-more-menu` is the overflow dropdown.

   The first is fixed the right way — by defining the token the markup already
   asks for — and the other two by giving those two components a dark variant.
   Nothing here is a blanket "repaint everything": a rule like that would also
   repaint tenant surfaces that own their palettes. */
:root[data-appearance="dark"] {
  --card-bg: #1e293b;
}

:root[data-appearance="dark"] .btn.light,
:root[data-appearance="dark"] .topbar-more-menu {
  background: var(--bg2);
  color: var(--text);
  border-color: var(--border);
}
:root[data-appearance="dark"] .topbar-more-menu .tm-item { color: var(--text2); }
:root[data-appearance="dark"] .topbar-more-menu .tm-item:hover { background: var(--bg3); color: var(--text); }

@media (prefers-color-scheme: dark) {
  :root[data-appearance="system"] {
    --card-bg: #1e293b;
  }
  :root[data-appearance="system"] .btn.light,
  :root[data-appearance="system"] .topbar-more-menu {
    background: var(--bg2);
    color: var(--text);
    border-color: var(--border);
  }
  :root[data-appearance="system"] .topbar-more-menu .tm-item { color: var(--text2); }
  :root[data-appearance="system"] .topbar-more-menu .tm-item:hover { background: var(--bg3); color: var(--text); }
}

/* The page header strip. Painted rgba(255,255,255,.92) — translucent rather
   than pure white, which is why a pure-white sweep missed it while the eye did
   not: on a dark page it was the one pale band left, carrying the page title.
   Measured by luminance rather than by colour equality this time. */
:root[data-appearance="dark"] .page-header { background: rgba(30, 41, 59, .92); color: var(--text); }
@media (prefers-color-scheme: dark) {
  :root[data-appearance="system"] .page-header { background: rgba(30, 41, 59, .92); color: var(--text); }
}

/* ─────────────────────────────────────────────────────────────────────────
   WHERE THERE IS ROOM, DO NOT COLLAPSE.

   The collapse above is correct for a header bar and was measured into
   existence: three 44px buttons plus gaps clipped 47px off the admin
   navigation on a 390px phone. But the sign-in, password and two-factor
   screens are not header bars. There the control sits by itself in the
   middle of a 440px card with the whole width free — and collapsed it reads
   as one unlabelled dark square with a glyph in it. Seen on the sign-in page
   at 390px: a mystery button under "Sign in", on the first screen a customer
   ever meets.

   So the card opts out. The same radiogroup, the three choices visible and
   named, wrapping if it must. No change to the header behaviour the
   measurement justified.
   ───────────────────────────────────────────────────────────────────────── */
@media (max-width: 560px) {
  .appearance-roomy .appearance-control {
    position: static;
    flex-wrap: wrap;
    justify-content: center;
    border: 1px solid var(--border, var(--line, #e2e8f0));
    background: var(--bg2, var(--bg-2, #fff));
    padding: .2rem;
    gap: .15rem;
  }
  .appearance-roomy .appearance-control button[aria-checked="false"] { display: inline-flex; }
  .appearance-roomy .appearance-control button .appearance-label { display: inline; }
  .appearance-roomy .appearance-control button[aria-checked="true"] {
    min-width: 44px; min-height: 44px;
  }
  /* AND IT STAYS IN THE CARD WHEN TAPPED. The opt-out above only undid the
     CLOSED state. Tapping a choice focuses it, :focus-within switched the
     header-bar popover back on, and the two other choices jumped out of the
     card to the screen's top-right corner as fixed dark panels — seen by the
     owner on the sign-in page, Oct 2026. Here the options are already on
     show, so the popover has nothing to do: undo every property it sets. */
  .appearance-roomy .appearance-control:focus-within button[aria-checked="false"] {
    position: static;
    inset: auto;
    min-width: 44px;
    justify-content: center;
    padding-inline: .7rem;
    background: transparent;
    border: 0;
    border-radius: 999px;
    box-shadow: none;
    z-index: auto;
  }
}

/* THE CARD IS LIGHT AT EVERY WIDTH AND IN EVERY THEME — the auth shell paints
   it #fff explicitly — so the control on it takes light ink rather than the
   platform tokens, which resolve dark and put a slate pill in the middle of a
   white card. Stated, not inherited, for the same reason the emails state
   every colour: there is no surrounding token set here to agree with. */
.appearance-roomy .appearance-control {
  background: transparent;
  border-color: rgba(15, 23, 42, .12);
}
.appearance-roomy .appearance-control button { color: #475569; }
.appearance-roomy .appearance-control button:hover { background: rgba(15, 23, 42, .05); }
.appearance-roomy .appearance-control button[aria-checked="true"] {
  background: rgba(15, 23, 42, .07);
  color: #0f172a;
}
