/* ============================================================================
   BASE — reset, element defaults, and the accessibility floor.
   Loads after tokens.css. Nothing here has a class selector: this layer sets
   what an unstyled element looks like so components can be additive.
   ========================================================================= */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html,
body {
    margin: 0;
    padding: 0;
    min-height: 100%;
    /* No page-level scroll on the app shell: the content column is the sole
       scroll container (see .content-wrapper in layout.css). Stops the whole
       page — and with it the sticky header — rubber-banding on overscroll. */
    overscroll-behavior: none;
}

body {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    line-height: var(--leading-normal);
    color: var(--text);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
}

/* Headings are Outfit and carry NO default margin — every component states its
   own spacing. Inherited heading margins were a major source of the old
   sheet's accidental rhythm, where a panel's padding depended on which heading
   level happened to be first. */
h1, h2, h3, h4, h5, h6 {
    margin: 0;
    font-family: var(--font-display);
    font-weight: var(--weight-semibold);
    line-height: var(--leading-snug);
    color: var(--text);
}

h1 {
    font-size: var(--text-xl);
    font-weight: var(--weight-bold);
    line-height: var(--leading-tight);
    letter-spacing: var(--tracking-tight);
}

h2 { font-size: var(--text-lg); }
h3 { font-size: var(--text-md); }
h4 { font-size: var(--text-sm); }

p {
    margin: 0;
}

/* Prose blocks inside content get a measure. Tables, toolbars and charts are
   not prose and opt out by not being <p>. */
main p {
    max-width: var(--measure);
}

/* A LINK IS UNDERLINED BY DEFAULT, and affordances opt out.

   WCAG 1.4.1 (Use of Color, level A) is not satisfied by colour plus a HOVER
   underline: hover is unavailable to a keyboard or touch user, and it is not a
   visual presentation the criterion counts. The portal failed this wherever
   prose carried a link — the AI-providers signpost, the keyword page's
   "Configure an AI provider", the dashboard's "API keys", the expired-link
   notices.

   The direction of the rule is the load-bearing part, not the underline. Listing
   the prose containers instead (p, li, dd, .help, .notice, .says) fixes exactly
   today's pages and fails OPEN forever after: a link in a <td>, a <dt>, a
   <summary> or a bare <div> is colour-alone again and nothing says so — an
   invisible failure, which is the worst kind to leave in a system other people
   will add pages to. Inverted, the failure is visible in the other direction: a
   new affordance that should not be underlined turns up underlined and its
   author fixes it in the same sitting.

   It is also the cheaper set to maintain. Inclusion costs one selector per prose
   container TIMES one per affordance class that can appear inside one; opt-out
   costs one per affordance class, and every class below already exists because
   the thing already has styling. */
a {
    color: var(--accent-text);
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* Deliberately NO text-decoration here. `a:hover` is (0,1,1) and would outrank
   every (0,1,0) opt-out below, re-underlining every button and nav item on
   hover — which is exactly the bug the old rule needed a second exception list
   to undo. */
a:hover {
    color: var(--accent-hover);
}

/* The closed set of links that are not prose. Each is an affordance whose shape,
   fill or position already says "this is a control", so an underline would only
   add noise: buttons, the skip link, the back link, sortable column headers, the
   pager, the search clear, every rail item, the configuration jump list, and the
   vendored tour popover. */
.btn,
.skip-link,
.page-back,
.sort-link,
.pager__btn,
.pager__page,
.catalog-search__clear,
.portal-nav-link,
.portal-nav__heading,
.portal-sidebar__brand-link,
.portal-sidebar__account-link,
.config-section-nav a,
.driver-popover a {
    text-decoration: none;
}

ul, ol {
    margin: 0;
    padding-left: var(--space-5);
}

li + li {
    margin-top: var(--space-1);
}

code, pre, kbd, samp {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    font-size: 0.9em;
}

code {
    padding: 0.1em 0.35em;
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    /* Full-strength ink: an inline code span is the literal the reader has to
       find or retype ("paste before </body>", "open theme.liquid"), so it is the
       operative token of its sentence, not an aside. The mono face and the inset
       already mark it as code — muting it too would rank it BELOW the prose it
       clarifies. */
    color: var(--text);
}

button,
input,
select,
textarea {
    font: inherit;
    color: inherit;
}

img {
    max-width: 100%;
    height: auto;
}

hr {
    height: 1px;
    margin: 0;
    border: 0;
    background: var(--border);
}

/* ---------------------------------------------------------------- FOCUS
   One visible ring for every focusable thing, on the token that measures
   past 3:1 in its own theme. :focus-visible so a mouse click on a button
   does not leave a ring behind, but keyboard traversal always shows one.
   outline (not box-shadow) so it follows each component's border-radius and
   survives forced-colors mode.
   Deliberately sets ONLY outline properties: an outline already follows the
   element's own border-radius, so declaring a radius here would reshape every
   control at the moment it takes focus. */
:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

/* ------------------------------------------------------- REDUCED MOTION
   Every transition and animation in the system is feedback, so there is
   nothing here that must survive the preference. Blanket-disable rather than
   curate: a new component cannot forget to opt in. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ------------------------------------------------------------ SKIP LINK
   Off-screen until focused. First focusable element in the shell. */
.skip-link {
    position: absolute;
    left: var(--space-3);
    top: var(--space-3);
    z-index: var(--z-overlay);
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-md);
    background: var(--accent);
    color: #ffffff;
    font-weight: var(--weight-medium);
    transform: translateY(-200%);
    transition: transform var(--motion-fast) var(--ease-out);
}

.skip-link:focus-visible {
    transform: translateY(0);
    color: #ffffff;
    text-decoration: none;
}

/* Screen-reader-only text that still needs to be announced.
   .shop-preview__announce joins this rule rather than restating it: preview.js
   EMITS that class name, so it cannot simply use .visually-hidden in markup —
   but there is no reason for a second copy of the declaration. */
.visually-hidden,
.shop-preview__announce {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}
