/* Depends on: tokens.css -- linked as separate <link>
   tags by every template that uses this file, NOT @import-ed here.
   @import is a serialized waterfall: the browser cannot discover an
   imported file until it has downloaded and parsed the one importing
   it, so this site's deepest chain (tokens -> nav -> calendar ->
   event_detail) cost four sequential round trips before first paint.
   Separate links are all visible in the initial HTML and download in
   parallel. Templates list dependencies first, so the cascade is
   unchanged -- see core/tests/test_template_lint.py, which fails if
   an @import is reintroduced here. */
/* Content that must exist for screen readers but not show visually --
   section headings on full-bleed pages, labels the visual design conveys
   with an icon or placeholder. Standard clip technique; stays in the a11y
   tree and the tab order. */
.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Skip link -- base.html makes it the first focusable element on every page,
   jumping keyboard/AT users straight past the rail and topbar to <main
   id="contenido">. Off-screen until focused. */
.skip-link {
  position: fixed;
  top: 10px;
  left: 10px;
  z-index: 100;
  padding: 10px 16px;
  border-radius: 9px;
  background: var(--accent);
  color: var(--ink);
  font: 700 13px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  text-decoration: none;
  transform: translateY(calc(-100% - 16px));
  transition: transform 0.15s ease;
}
.skip-link:focus {
  transform: translateY(0);
  outline: 2px solid var(--text-primary);
  outline-offset: 2px;
}

/* Resting colour of every menu label (top bar links, the rail, the
   dropdown panels). --text-secondary/--text-tertiary read as disabled on
   the dark ground, so a label could only be made out on hover; this one is
   legible at rest and still a clear step below the --text-primary that
   hover and the active item use. */
:root { --nav-text: var(--text-soft); }

/* Shared topbar nav-links menu — included on every standard content page
   alongside that page's own stylesheet (which supplies .topbar/.wrap/.brand). */
/* min-width:0 + overflow-x:auto at EVERY width, not just on phones: the
   global nav rail (base.html) now takes 64px off the usable row, and the
   old inline menu -- brand + ~9 links + .topbar-right -- no longer fits on
   a laptop either. Without this the menu pushed .topbar-right past the
   viewport's right edge and the whole page scrolled sideways from ~1000px
   down. It stays a flex item that can shrink and scroll inside itself, so
   it never widens the topbar row; when there is room it lays out at its
   natural width and .topbar-right's `margin-left:auto` still parks it at
   the end. */
.nav-links {
  display: flex; align-items: center; gap: 2px; margin-left: 10px;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.nav-links::-webkit-scrollbar { display: none; }
/* Flat by default: no pill, no fill. Weight and color carry the state,
   which is what "minimal" costs here -- four items instead of eleven means
   a hover background is no longer needed to tell them apart. */
.nav-link {
  flex-shrink: 0;
  padding: 7px 10px; font-size: 13.5px; font-weight: 500;
  color: var(--nav-text); white-space: nowrap;
}
.nav-link:hover { color: var(--text-primary); }
.nav-link.active { color: var(--text-primary); font-weight: 600; }

@media (max-width: 980px) {
  /* On phones the menu also grows to fill the row (nothing else needs the
     space there), so every link is one short swipe away. The scroll
     behaviour itself is now set unconditionally above. */
  .nav-links {
    flex: 1 1 auto;
    min-width: 120px;
  }
  /* .search-form (search.css) needs a matching mobile rule of its own too
     -- see that file for why: sharing this topbar row, it was winning
     every space fight against nav-links above regardless of what's set
     here (a same-specificity tie between two separately-<link>ed
     stylesheets resolves by document order, not which file "should" win
     logically), crushing nav-links to a literal 0px strip. */
}

/* ============================================================
   Shared content-page top bar (core/_topbar.html, plus the pages
   that keep their own <header class="topbar"> for a page-specific
   right-hand action). Was ~11 drifted copies across the page
   stylesheets -- see docs/frontend-sweep-2026-09/PRE-PROD-REVIEW.md
   #7. Canonical form is the sticky glass bar the majority already
   used; the landing page and the login page keep their own
   transparent-overlay .topbar (directory.css / login.css), which
   is a real page-specific override, not drift.
   ============================================================ */
.topbar {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 56px;
  padding: 0 18px;
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--bg, var(--surface));
}
.topbar .brand {
  display: flex; align-items: center; gap: 9px;
  font-weight: 800; font-size: 15px; white-space: nowrap;
  color: var(--text-primary);
}
.topbar .brand-logo { height: 32px; width: auto; display: block; border-radius: 8px; }
.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.btn-ghost {
  padding: 9px 14px; border-radius: 8px; font-size: 13px; font-weight: 600;
  color: var(--text-secondary); white-space: nowrap;
}
.btn-ghost:hover { background: var(--surface); color: var(--text-primary); }
.btn-ghost.icon-only { padding: 9px; display: grid; place-items: center; }
/* "← Volver" links, one look everywhere: a quiet pill that lights up in the
   accent on hover and nudges the arrow's side. */
.back-link {
  display: inline-flex; align-items: center; gap: 8px; width: fit-content;
  padding: 8px 16px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface-2); color: var(--text-primary);
  font-size: 13px; font-weight: 700; line-height: 1.2; white-space: nowrap;
  transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease, transform 0.15s ease;
}
.back-link:hover { border-color: var(--accent-line); background: var(--accent-soft); color: var(--accent); transform: translateX(-2px); }
.topbar .back-link { padding: 7px 14px; font-size: 12.5px; }

/* The site's buttons -- one set, defined once. Page stylesheets used to each carry
   their own .btn-primary / .btn-outline (four copies, four paddings, ten-odd pixels
   of difference between them). Quiet by default: a filled neutral, no border; the one
   coloured button is the page's main action. .btn-outline stays as an alias so the
   templates that use it need no change. A page that needs a full-width or otherwise
   special one (the checkout in transactor.css) overrides it there. */
.btn-primary, .btn-secondary, .btn-outline {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 16px; border: 0; border-radius: 8px;
  font-family: inherit; font-size: 13px; font-weight: 600; line-height: 1.3; white-space: nowrap;
  cursor: pointer; transition: background .15s ease, color .15s ease;
}
.btn-primary { background: var(--accent); color: #04150c; font-weight: 700; }
.btn-primary:hover { background: var(--accent-strong); }
.btn-secondary, .btn-outline { background: var(--surface-2); color: var(--text-primary); }
.btn-secondary:hover, .btn-outline:hover { background: var(--surface-hover); }
.btn-secondary.danger, .btn-outline.danger { color: var(--critical); }
.btn-primary svg, .btn-secondary svg, .btn-outline svg { width: 14px; height: 14px; flex-shrink: 0; }

/* Account actions (core/_topbar_account.html): bell + avatar menu. */
.tb-icon {
  position: relative; width: 36px; height: 36px; border-radius: 10px;
  display: grid; place-items: center; color: var(--text-secondary);
}
.tb-icon:hover { background: var(--surface); color: var(--text-primary); }
.tb-icon svg { width: 19px; height: 19px; }
.tb-badge {
  position: absolute; top: 3px; right: 3px; min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 999px; background: var(--accent); color: #04150c;
  font-size: 10px; font-weight: 800; line-height: 16px; text-align: center;
  box-shadow: 0 0 0 2px var(--bg, var(--surface));
}
.account-menu { position: relative; }
.account-toggle {
  list-style: none; display: flex; align-items: center; gap: 4px; cursor: pointer;
  padding: 3px 6px 3px 3px; border-radius: 999px; color: var(--text-secondary);
}
.account-toggle::-webkit-details-marker { display: none; }
.account-toggle:hover, .account-menu[open] .account-toggle { background: var(--surface); color: var(--text-primary); }
.tb-avatar {
  width: 32px; height: 32px; border-radius: 50%; overflow: hidden; flex-shrink: 0;
  display: grid; place-items: center; font-size: 13px; font-weight: 700;
  background: var(--surface-2, var(--surface)); color: var(--text-primary);
  border: 1px solid var(--line);
}
.tb-avatar img { width: 100%; height: 100%; object-fit: cover; }
.account-chev { width: 14px; height: 14px; transition: transform 0.15s ease; }
.account-menu[open] .account-chev { transform: rotate(180deg); }
.account-panel {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  display: flex; flex-direction: column; min-width: 200px; padding: 6px;
  border: 1px solid var(--line); border-radius: 12px; background: var(--surface);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.28);
}
.account-name {
  padding: 8px 12px 10px; margin-bottom: 4px; border-bottom: 1px solid var(--line);
  font-size: 13px; font-weight: 700; color: var(--text-primary); white-space: nowrap;
}
.account-panel form { display: contents; }
.account-logout {
  width: 100%; text-align: left; background: none; border: none; font: inherit;
  font-size: 13px; font-weight: 500; cursor: pointer;
}
/* The one filled call-to-action button (the top bar's "Entrar", form submits). */
.btn-accent {
  padding: 9px 16px; border-radius: 8px; font-size: 13px; font-weight: 700; white-space: nowrap;
  background: var(--accent); color: #04150c; border: 0; cursor: pointer;
  box-shadow: 0 0 18px -6px var(--accent);
  transition: background 0.15s ease, box-shadow 0.15s ease;
}
.btn-accent:hover { background: var(--accent-strong); box-shadow: 0 0 22px -4px var(--accent); }
/* In the top bar the button is a compact call to action, not a form button. */
.topbar .btn-accent { padding: 6px 13px; font-size: 12.5px; border-radius: 7px; box-shadow: 0 0 14px -6px var(--accent); }
.btn-ghost.icon-only svg { width: 16px; height: 16px; }

/* The topbar search pill. search.css adds the .search-form wrapper and the
   typeahead dropdown; this is the box itself, here so the calendar-shell
   pages (which don't carry their own .search rule) render it correctly. */
.topbar .search {
  flex: 1; max-width: 460px;
  display: flex; align-items: center; gap: 9px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 9px; padding: 9px 13px; color: var(--text-tertiary);
}
.topbar .search svg { width: 15px; height: 15px; flex-shrink: 0; }
.topbar .search input {
  flex: 1; min-width: 0; background: none; border: none;
  color: var(--text-primary); font-family: inherit; font-size: 13.5px;
  padding: 1px 2px; /* the browser default these fields always had */
}
.topbar .search input::placeholder { color: var(--text-tertiary); }

@media (max-width: 640px) {
  /* .brand + nav-links + search + .topbar-right stop fitting one row on a
     phone -- give .topbar-right its own wrapped row rather than letting it
     push the page wider than the viewport. */
  .topbar { height: auto; flex-wrap: wrap; row-gap: 8px; padding-top: 10px; padding-bottom: 10px; }
  .topbar-right { flex-basis: 100%; flex-wrap: wrap; justify-content: flex-end; margin-left: 0; }

  /* Two rows, not three: row 1 is brand + search icon + the account cluster
     (Entrar / avatar), row 2 is the scrolling links with "Explorar" beside
     them. The links' basis leaves room for Explorar, so the pair always
     wraps together. `.topbar .topbar-right` outranks the same rule that
     the page stylesheets (dashboard.css, ...) repeat above. */
  .topbar .brand { order: 1; margin-right: auto; }
  .topbar .search-icon-link { order: 2; }
  .topbar .topbar-right { order: 3; flex: 0 0 auto; margin-left: 0; }
  .topbar .nav-links { order: 4; flex: 1 0 calc(100% - 130px); margin-left: 0; min-width: 0; }
  .topbar .nav-menu-inline { order: 5; margin-left: 0; }
  .nav-menu-inline .nav-menu-panel { left: auto; right: 0; }

  /* Signed in, the links live in the bottom rail and .nav-links is empty, yet it still took a whole
     row and pushed "Explorar" onto a second (a third at 360 px). One row instead: logo, Explorar,
     then search and the account cluster -- a little tighter than on a laptop so a 375 px phone fits. */
  .topbar:has(.nav-links[data-empty]) { flex-wrap: nowrap; column-gap: 4px; padding-left: 12px; padding-right: 12px; }
  .topbar:has(.nav-links[data-empty]) .nav-links { display: none; }
  .topbar:has(.nav-links[data-empty]) .brand { margin-right: 0; }
  .topbar:has(.nav-links[data-empty]) .brand-logo { height: 28px; }
  .topbar:has(.nav-links[data-empty]) .nav-menu-inline { order: 1; margin-right: auto; }
  .topbar:has(.nav-links[data-empty]) .nav-menu-inline .nav-menu-toggle { padding: 6px 8px; font-size: 13px; }
  .topbar:has(.nav-links[data-empty]) .nav-menu-inline .nav-menu-panel { left: 0; right: auto; }
  .topbar:has(.nav-links[data-empty]) .topbar-right { flex-basis: auto; flex-wrap: nowrap; gap: 2px; }
  .topbar:has(.nav-links[data-empty]) .tb-icon { width: 34px; height: 34px; }
  .topbar:has(.nav-links[data-empty]) .account-chev { display: none; }

  /* Signed out, two rows rather than three: logo, search, "Crear cuenta" and "Entrar" on the first
     (they wrapped onto a row of their own), the scrolling links with Explorar on the second. */
  .topbar:has(.nav-links:not([data-empty])) { column-gap: 6px; padding-left: 12px; padding-right: 12px; }
  .topbar:has(.nav-links:not([data-empty])) .brand-logo { height: 28px; }
  .topbar:has(.nav-links:not([data-empty])) .topbar-right { flex-wrap: nowrap; gap: 6px; }
  .topbar:has(.nav-links:not([data-empty])) .topbar-right .btn-ghost,
  .topbar:has(.nav-links:not([data-empty])) .topbar-right .btn-accent { padding: 6px 10px; font-size: 12.5px; white-space: nowrap; }
}
@media (max-width: 374px) {
  /* A narrow phone keeps the logo's mark and drops its wordmark (the SVG's first 30% is the mark),
     signed in or out. */
  .topbar .brand-logo { width: 30px; height: 28px; object-fit: cover; object-position: left center; }
}

/* ============================================================
   Global left nav rail (core/templates/core/_navrail.html)
   Rendered site-wide by templates/base.html for signed-in users.
   :has() scopes the body offset to pages that actually show it: a
   signed-out visitor has no rail, so no offset.
   ============================================================ */
/* --rail-w lets a full-bleed block (standings' .board-card) size itself off
   the space the rail leaves rather than the whole viewport. */
body:has(.navrail) { padding-left: 72px; --rail-w: 72px; }

.navrail {
  position: fixed;
  left: 0; top: 0; bottom: 0;
  width: 72px;
  z-index: 40;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 10px 0;
  background: var(--bg, var(--surface));
  border-right: 1px solid var(--line);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
}
.navrail::-webkit-scrollbar { display: none; }

/* 10px labels, not the 8.5px this rail used to need: seven items fit
   without cramming, so the text can be read. The active state is a 2px
   bar on the rail edge rather than a filled pill -- one accent mark per
   screen instead of a block of color. */
.navrail .nav-item,
.navrail .nav-menu-toggle {
  flex-shrink: 0;
  position: relative;
  width: 64px;
  min-height: 48px;
  padding: 5px 2px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  color: var(--nav-text);
  font-size: 10px;
  font-weight: 500;
  line-height: 1.15;
  text-align: center;
}
.navrail .nav-item svg,
.navrail .nav-menu-toggle svg { width: 20px; height: 20px; }
.navrail .nav-item:hover,
.navrail .nav-menu-toggle:hover { color: var(--text-primary); }
.navrail .nav-item.active { color: var(--text-primary); }
.navrail .nav-item.active::before {
  content: "";
  position: absolute;
  left: -4px; top: 50%;
  width: 2px; height: 22px;
  margin-top: -11px;
  border-radius: 0 2px 2px 0;
  background: var(--accent);
}
.navrail-spacer { flex: 1 0 6px; }

/* ---- Grouped menus (rail "Cuenta", top bar "Explorar") ----
   <details>, so no JavaScript and nothing new for the CSP to allow. The
   panel is position:fixed because .navrail sets overflow-y:auto, which
   would clip an absolutely positioned child against the 72px rail. */
.nav-menu { flex-shrink: 0; }
.nav-menu-toggle { cursor: pointer; list-style: none; }
.nav-menu-toggle::-webkit-details-marker { display: none; }
.nav-menu-panel {
  position: fixed;
  z-index: 60;
  display: flex;
  flex-direction: column;
  min-width: 190px;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.28);
}
.navrail .nav-menu-panel { left: 76px; bottom: 12px; }
.nav-sub-item {
  padding: 9px 12px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 500;
  color: var(--nav-text);
  white-space: nowrap;
}
/* A use-case cluster inside a menu: a thin rule separates it from the one above. */
.nav-sub-group { display: flex; flex-direction: column; }
.nav-sub-group + .nav-sub-group { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--line-soft, var(--line)); }
.nav-sub-item:hover { color: var(--text-primary); background: var(--surface-2, var(--bg)); }
.nav-sub-item.active { color: var(--text-primary); font-weight: 600; }

/* The top bar's own menu sits under its summary rather than beside it.
   It is a sibling of .nav-links, not a child: .nav-links is a scroll
   container (overflow-x:auto, which makes overflow-y compute to auto too),
   and a panel hanging below the summary from inside it was clipped by that
   -- "Explorar" opened and showed nothing. The negative margin cancels the
   topbar's own 14px flex gap so it still sits 2px from the last link, the
   way it did when it was one of them. */
.nav-menu-inline { position: relative; display: flex; align-items: center; margin-left: -12px; }
.nav-menu-inline .nav-menu-toggle {
  padding: 7px 10px;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--nav-text);
  white-space: nowrap;
  cursor: pointer;
  list-style: none;
}
.nav-menu-inline .nav-menu-toggle::after { content: " \25BE"; }
.nav-menu-inline .nav-menu-toggle:hover { color: var(--text-primary); }
.nav-menu-inline[open] .nav-menu-toggle { color: var(--text-primary); }
.nav-menu-inline .nav-menu-panel { position: absolute; top: 100%; left: 0; margin-top: 6px; }

/* Below 900px the vertical rail becomes a fixed bottom bar -- every
   destination still reachable, horizontally scrollable, no JS. */
@media (max-width: 900px) {
  body:has(.navrail) { padding-left: 0; padding-bottom: 56px; --rail-w: 0px; --rail-h: 56px; }
  .navrail {
    left: 0; right: 0; top: auto; bottom: 0;
    width: auto;
    height: 56px;
    flex-direction: row;
    align-items: stretch;
    padding: 0 4px;
    gap: 1px;
    border-right: none;
    border-top: 1px solid var(--line);
    overflow-x: auto;
    overflow-y: hidden;
  }
  .navrail .nav-item,
  .navrail .nav-menu-toggle { width: auto; min-height: 0; height: 100%; padding: 0 10px; }
  .navrail .nav-item.active::before {
    left: 50%; top: 0;
    width: 22px; height: 2px;
    margin: 0 0 0 -11px;
    border-radius: 0 0 2px 2px;
  }
  /* Bottom bar, so the panel opens upward and spans the row instead of
     flying off the 72px left edge it no longer has. */
  .navrail .nav-menu-panel { left: 8px; right: 8px; bottom: 60px; min-width: 0; }
  .navrail-spacer { display: none; }
}

/* ============================================================
   Page heading -- the one definition. Was three drifted copies
   (calendar.css 28px/34px, import.css 24px/30px, standings.css
   28px/46px), so the same title changed size and spacing from page
   to page. Markup everywhere is
     <div class="page-head"><div class="aurora-glow"></div><h1>..</h1><p>..</p></div>
   (an optional <div class="sub"> under the <p>). Pages that need a
   smaller heading inside a card or section use .sub-head instead.
   ============================================================ */
/* margin-bottom: the aurora is clipped at this box's edge, so without it any
   controls placed right after (filters, chips, dropdowns) touch that edge. */
.page-head { padding: 34px 0 22px; margin-bottom: 18px; position: relative; isolation: isolate; overflow: hidden; }
.page-head h1 { font-size: 28px; font-weight: 800; letter-spacing: -0.01em; }
.page-head p { font-size: 14px; color: var(--text-secondary); margin-top: 8px; max-width: 60ch; }
.page-head .sub { font-size: 12.5px; color: var(--text-tertiary); margin-top: 4px; }

/* ============================================================
   Dropdowns -- the one look for every <select>, in the mockups' style: a
   dark rounded field with a thin border, a chevron, and a green focus ring.
   Page stylesheets set only layout (width, flex, compact padding/size), never
   background/border/colour, so a new <select> needs no CSS to match. The
   chevron colour is baked into the data URI, so it has a per-theme copy.
   ============================================================ */
:root {
  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b96a3' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}
:root[data-theme="light"] {
  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b665c' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}
select {
  -webkit-appearance: none; appearance: none;
  font: inherit; font-size: 13px; line-height: 1.3;
  color: var(--text-primary);
  background-color: var(--surface);
  background-image: var(--select-chevron);
  background-repeat: no-repeat; background-position: right 11px center; background-size: 12px;
  border: 1px solid var(--line); border-radius: 10px;
  padding: 9px 32px 9px 12px;
  max-width: 100%; cursor: pointer;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
select:hover { border-color: var(--line-hover); }
select:focus { outline: none; border-color: var(--accent); }
select:focus-visible { box-shadow: 0 0 0 3px var(--accent-soft); }
select:disabled { opacity: 0.5; cursor: not-allowed; }
select[multiple], select[size]:not([size="1"]) { background-image: none; padding-right: 12px; cursor: default; }
select option { background: var(--surface-raised); color: var(--text-primary); }

/* Reserve the scrollbar's width on every page. A short page (no scrollbar) and
   a long one (scrollbar) otherwise have different widths, so the centred
   column -- and the page title in it -- sits ~7px further right on the short
   one. Has no effect where scrollbars overlay the content (macOS default). */
html { scrollbar-gutter: stable; }

/* Text fields and textareas -- the same field as the dropdowns above. :where()
   keeps the specificity at zero, so any page rule (a borderless comment box, a
   compact table input) still wins; this only catches fields nobody styled,
   which used to render as white browser boxes. */
:where(input[type="text"], input[type="email"], input[type="url"], input[type="number"],
       input[type="password"], input[type="search"], input[type="tel"], input[type="date"],
       input[type="time"], input:not([type]), textarea) {
  font-family: inherit; font-size: 13px; color: var(--text-primary);
  background-color: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  padding: 9px 12px; max-width: 100%;
}
:where(input[type="text"], input[type="email"], input[type="url"], input[type="number"],
       input[type="password"], input[type="search"], input[type="tel"], input[type="date"],
       input[type="time"], input:not([type]), textarea):focus { outline: none; border-color: var(--accent); }
:where(input, textarea)::placeholder { color: var(--text-tertiary); }

/* Checkboxes, radios and file pickers: the accent colour and a button that
   matches the site's other buttons, instead of the browser's grey defaults. */
input[type="checkbox"], input[type="radio"], input[type="range"], progress { accent-color: var(--accent); }
input[type="file"] { color: var(--text-secondary); font-size: 13px; max-width: 100%; }
input[type="file"]::file-selector-button {
  font: inherit; font-size: 12.5px; font-weight: 700; margin-right: 12px; padding: 7px 14px;
  border: 1px solid var(--line); border-radius: 8px; cursor: pointer;
  background: var(--surface-raised); color: var(--text-primary);
  transition: border-color 0.15s ease, color 0.15s ease;
}
input[type="file"]:hover::file-selector-button { border-color: var(--accent-line); color: var(--accent); }

/* ============================================================
   Empty state -- the one definition. An account page with nothing in it
   yet (Mis pagos, Mis fotos, Tu plan on Free) used to be a single grey
   sentence under the title, which read as a page that failed to load.
   Markup:
     <div class="empty-state"><svg>..</svg><h2>..</h2><p>..</p><a class="empty-cta">..</a></div>
   ============================================================ */
.empty-state {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 6px; padding: 40px 24px; margin: 8px 0 20px;
  border: 1px dashed var(--line); border-radius: 16px;
  background: linear-gradient(175deg, var(--surface) 0%, var(--card-gradient-end, var(--surface)) 100%);
}
.empty-state > svg {
  width: 42px; height: 42px; padding: 9px; margin-bottom: 6px; box-sizing: border-box;
  border-radius: 12px; color: var(--accent); background: var(--accent-soft);
  border: 1px solid var(--accent-line);
}
/* div.empty-state, not .empty-state: page sheets such as store.css style a bare
   `.store-page h2` (uppercase, tracked) at the same specificity and load later. */
div.empty-state h2 { font-size: 16px; font-weight: 700; color: var(--text-primary); margin: 0; text-transform: none; letter-spacing: 0; }
div.empty-state p { font-size: 13.5px; color: var(--text-secondary); max-width: 46ch; margin: 0; }
.empty-state .empty-cta {
  margin-top: 12px; padding: 10px 18px; border-radius: 9px;
  background: var(--accent); color: #04150c; font-size: 13.5px; font-weight: 700;
}
.empty-state .empty-cta:hover { background: var(--accent-strong); color: #04150c; }

/* The mockups' highlight panel (docs: "stinter mockups.pdf"): one per screen,
   on the thing that matters most there -- the balance, the next event, the
   circuit's numbers, the action you came to do. Accent outline, a faint
   green wash and a soft glow. Mi saldo's .balance-hero and the calendar's
   .cal-next are the same recipe, written before this class existed. */
.glow-panel {
  border: 1px solid var(--accent-line) !important;
  border-radius: 16px;
  background: linear-gradient(160deg, rgba(0, 230, 118, 0.08) 0%, var(--card-gradient-end, var(--surface)) 65%) !important;
  box-shadow: 0 0 30px -14px var(--accent);
}

.nav-item-locked { opacity: 0.6; }
.nav-item-locked:hover { opacity: 0.85; }

/* The demo account's banner (core/_demo_banner.html): on every page, above the content. */
.demo-banner {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: center; gap: 4px 10px;
  padding: 8px 16px; background: var(--amber-soft); border-bottom: 1px solid var(--amber);
  color: var(--text-primary); font-size: 13px; line-height: 1.4; text-align: center;
}
.demo-banner strong { color: var(--amber); text-transform: uppercase; letter-spacing: 0.06em; font-size: 12px; }
