/*
    THE STYLE LAYER: what this library says about how its OWN markup looks, and nothing else.

    Every rule here targets a data-meliora-* hook this library ships. There is no palette, no font, no
    spacing scale and nothing an application would recognise as a theme -- two applications that link
    this file and style nothing else still look like each other only in the sense that two unstyled
    pages do.

    WHY IT EXISTS. Step 6a shipped semantic markup with documented hooks and no visual opinion, and the
    hooks arrived with nothing behind them: the popover panel had no positioning, so opening the inbox
    inserted its list into the header's flex row and reflowed the chrome. That is a broken control
    rather than an unstyled one, and no build can see it. This file is the same promise the fallback
    views make for markup -- a fragment added in a later version WORKS, plainly, in an application that
    has never styled it.

    HOW AN APPLICATION OVERRIDES ANY OF IT: by naming the same thing once, in app.css. Everything below
    is inside one native cascade layer, and anything UNLAYERED beats everything layered regardless of
    specificity and regardless of source order. So no application ever fights an attribute selector's
    specificity or reaches for !important, and nothing here needs to be careful about how tightly it
    selects.

    WHAT MUST NEVER GO IN HERE: the shared class vocabulary -- field, field-error, errors, flash, muted,
    actions, recovery-codes, btn, toolbar, pill, tables, header chrome. Those belong to app.css and
    anonymous.css, which New-App writes with every one of them, so a generated application already has
    them. The rule that follows is the load-bearing one: THIS LIBRARY MAY NOT INVENT NEW VOCABULARY
    CLASS NAMES. A new visual concept in a later version gets a data- hook, which this file styles;
    a new class would be a rule every existing application is silently missing, which is the exact
    failure this file exists to close.

    SYSTEM COLOURS, NOT A PALETTE. The popover panel needs an opaque background or it renders over the
    page content unreadably -- that is function, not decoration. Canvas and CanvasText are the CSS
    system colours, so they follow the `color-scheme` both application stylesheets declare and commit
    this file to no colour of its own.

    WHICH PUTS AN OBLIGATION ON THE APPLICATION, and it is easy to miss. An application offering a
    THEME must pin color-scheme to match it, or these controls follow the operating system while the
    rest of the page follows the theme -- and the two disagree exactly when a reader has chosen light
    on a dark machine or the reverse. That shipped: the settings dialog rendered dark inside a light
    page. It cannot be fixed here, because the fix is a colour decision and this file may not make
    one. See the note in Arcana's app.css.

    See docs\design-style-layer.md. The hooks themselves are documented in the views that emit them, and
    StyleLayerTests asserts every one of them is named below.
*/
@layer meliora {

    /* ---- The popover mechanic, shared by every fragment this library ships ---- */

    /* The panel is positioned against this, so the root is the containing block. Without it the panel
       resolves its offsets against whatever ancestor happens to be positioned -- in the application
       shell, nothing is, so it would land against the viewport. */
    [data-meliora-popover] {
        position: relative;
        display: inline-block;
    }

    /* THE RULE WHOSE ABSENCE WAS THE BUG. Absolutely positioned, so an open panel overlays the page
       instead of joining the header's flex row and pushing the chrome around.

       Right-aligned because every fragment this library ships sits at the right-hand end of the
       header strip; an application that puts one elsewhere overrides one line. */
    [data-meliora-popover-panel] {
        position: absolute;
        top: 100%;
        right: 0;
        z-index: 100;

        min-width: 18rem;
        max-width: min(28rem, 90vw);

        /* Opaque, or the page shows through the text. See the note on system colours above. */
        background: Canvas;
        color: CanvasText;
        border: 1px solid rgba(128, 128, 128, .45);
        padding: .5rem .75rem;
        text-align: left;

        /* A list of any length has to stay reachable. An absolutely positioned panel does not extend
           the page, so without this a long inbox runs off the bottom of the viewport with nothing to
           scroll. */
        max-height: 70vh;
        overflow-y: auto;
    }

    /* The UA sheet already does this, and an application that gives the panel its own display value
       silently loses it. Scoped to the panel rather than declared globally, because [hidden] on the
       application's own markup is none of this file's business. */
    [data-meliora-popover-panel][hidden] {
        display: none;
    }

    /* THE BADGE sits over the toggle's corner, so the toggle is its containing block. What the badge
       looks like is the shell's; that it is a count in a corner is the mechanic. */
    [data-meliora-popover-toggle] {
        position: relative;
    }

    [data-meliora-inbox-count] {
        position: absolute;
        top: -.5rem;
        right: -.5rem;
        line-height: 1;
    }

    /* ---- The dialog mechanic, which the settings panel uses instead of the popover ----

       FAR LESS HERE THAN THE POPOVER NEEDS, and that is the element doing the work rather than this
       file. A <dialog> centres itself, paints a ::backdrop, traps focus and closes on Escape with no
       help; the popover above needs positioning or an open panel joins the header's flex row and
       reflows the chrome around it.

       So what is left is a size that suits a nav column beside a body, and the same
       stay-reachable rule the panel has. Nothing here is a palette. */

    [data-meliora-dialog] {
        display: inline-block;
    }

    /* THE PANEL IS ONE FIXED SIZE, NOT A RANGE, AND THAT IS THE POINT OF THIS BLOCK.

       It was min-width 34rem / max-width 48rem with a content-driven height capped at 85vh, so the
       dialog RESIZED EVERY TIME A SECTION CHANGED -- three radio buttons gave a short narrow box and a
       long preference list gave a tall wide one, with the whole thing jumping under the pointer that
       had just clicked a link in the rail. The nav moved out from under the cursor between one click
       and the next, which is the sort of thing that reads as broken rather than as unstyled.

       WHICH MAKES IT STRUCTURE RATHER THAN DECORATION, and therefore this file's. docs\design-app-shell.md
       section 1 draws that line and section 3 states it for the shell's own regions: the positioning is
       the contract and the paint is the application's. Colours and fonts stay theirs.

       THE COST IS AN EMPTY-LOOKING BOX FOR A SHORT SECTION, and it is worth paying. A dialog that keeps
       its shape is a surface a person can aim at; one that fits its contents is one they chase.

       ONE SIZE PER VIEWPORT, not one size everywhere -- min() collapses to the viewport on a small
       screen, and what must not change is the size WHILE SWITCHING SECTIONS.

       [open] IS LOAD-BEARING AND ITS ABSENCE SHIPPED. What keeps a closed <dialog> out of the page is
       the UA rule dialog:not([open]) { display: none }, and an author rule beats the UA origin
       whatever cascade layer it sits in -- so a bare display here overrode it and the panel rendered
       as an ordinary 48rem block. dialog.js moves the panel to the end of <body> so no ancestor can
       hide a modal, which is why it appeared BELOW the footer on every signed-in page.

       IT PRESENTED AS THREE SEPARATE FAULTS AND WAS ONE. A blank settings box under the content; a
       Close button that "did nothing", because close() removes [open] from an element this rule was
       showing anyway; and no dismiss-on-outside-click, because a panel that was never shown modally
       paints no ::backdrop for the click handler to see.

       SO NOTHING IN THIS FILE MAY SET display ON THE PANEL OUTSIDE [open]. The rest of the box is
       here for tidiness rather than necessity -- a closed dialog is display:none and could carry any
       width at all -- but the one declaration that must stay behind the attribute is this one.

       IT WAS FOUND BY RUNNING THE APPLICATION, AND IT IS NOW ASSERTED. Every markup-level check was
       green throughout and would be again -- the hooks were correct and Web.Tests reads HTML, so this
       was a computed style nothing looked at. StyleLayerTests.The_panel_is_only_displayed_when_it_is_open
       reads THIS FILE and fails on a bare [data-meliora-dialog-panel] rule, which is the only place
       the defect can be seen without a browser. */
    [data-meliora-dialog-panel][open] {
        width: min(75rem, 92vw);
        height: min(38rem, 88vh);

        /* THE PANEL ITSELF NO LONGER SCROLLS; its body does -- see below. Scrolling here took the
           navigation rail out of view with the content, so a long section hid the way out of itself. */
        display: flex;
        flex-direction: column;
        overflow: hidden;

        /* THE PAGE BEHIND A MODAL SHOULD NOT SCROLL WITH IT. The element makes the page inert to
           clicks and to focus; it does not stop the wheel, so without this the content behind slides
           about under an open dialog. It sat in its own [open] block until [open] moved up here. */
        overscroll-behavior: contain;

        /* Opaque, or the page shows through the text. See the note on system colours above. */
        background: Canvas;
        color: CanvasText;
        border: 1px solid rgba(128, 128, 128, .45);
    }

    /* A card, not a task: the About dialog is as tall as what it holds, narrower than the settings
       dialog, and still capped so a long _AboutExtra scrolls inside it. Later in the file than the
       fixed size above, which it overrides for this one dialog. */
    [data-meliora-about-dialog][open] {
        width: min(34rem, 92vw);
        /* fit-content, not auto: a modal dialog is pinned top and bottom, and auto would fill the gap. */
        height: fit-content;
        max-height: 85vh;
    }

    /* The question before an action that cannot be undone: a small card as tall as its sentence. */
    [data-meliora-confirm-dialog][open] {
        width: min(28rem, 92vw);
        height: fit-content;
        max-height: 85vh;
    }

    /* The header keeps its height and the layout takes the rest. min-height:0 is what actually lets the
       body scroll: a flex item's automatic minimum is its content, so without it the layout grows past
       the panel instead of the body scrolling inside it. */
    [data-meliora-dialog-panel] > [data-meliora-dialog-header] {
        flex: 0 0 auto;
    }

    [data-meliora-dialog-panel] > [data-meliora-dialog-body] {
        flex: 1 1 auto;
        min-height: 0;
        display: flex;
        flex-direction: column;
    }

    [data-meliora-dialog-panel] [data-meliora-settings-layout] {
        flex: 1 1 auto;
        min-height: 0;
        align-items: stretch;
    }

    /* A SECTION BODY OF ANY LENGTH HAS TO STAY REACHABLE, which is the rule the panel used to carry.
       It moves here so the rail stays put while the body scrolls.

       SCOPED TO THE DIALOG, AND THAT SCOPING IS LOAD-BEARING. _SettingsPanel.cshtml has two callers --
       this dialog and the /Settings page -- and on the page a fixed-height scrolling body would be
       wrong: a page is allowed to be long, and the browser already scrolls it. */
    [data-meliora-dialog-panel] [data-meliora-settings-body] {
        overflow-y: auto;
        overscroll-behavior: contain;
    }

    /* THE TITLE ROW: heading on the left, close on the right, and a rule under both. Structure rather
       than appearance -- without it the close control stacks under the heading, in the middle of the
       dialog, which is a broken-looking control rather than an unstyled one. Same category as the
       popover's positioning above. */
    [data-meliora-dialog-header] {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: 1rem;

        padding-bottom: .5rem;
        margin-bottom: .75rem;
        border-bottom: 1px solid rgba(128, 128, 128, .35);
    }

    [data-meliora-dialog-header] h2 {
        margin: 0;
        font-size: 1.05rem;
    }

    /* ---- The inbox, rendered into the panel AND by /Inbox. Both callers get these. ---- */

    [data-meliora-inbox-list] {
        list-style: none;
        margin: 0;
        padding: 0;
    }

    [data-meliora-inbox-item] + [data-meliora-inbox-item] {
        border-top: 1px solid rgba(128, 128, 128, .3);
    }

    [data-meliora-inbox-item] {
        padding: .5rem 0;
    }

    [data-meliora-inbox-item] h3 {
        font-size: 1rem;
        margin: 0 0 .15rem;
    }

    [data-meliora-inbox-item] p {
        margin: .25rem 0;
    }

    [data-meliora-inbox-item] time {
        font-size: .8rem;
        opacity: .7;
    }

    /* UNREAD IS DISTINGUISHABLE WITHOUT COLOUR, for the same reason the status pills carry their own
       words: the reading has to survive a monochrome screen and a reader who cannot separate hues.
       data-severity is deliberately NOT styled -- it is a hook for an application to hang a colour on,
       and this library has no opinion about which. */
    [data-meliora-inbox-item][data-read="false"] h3 {
        font-weight: 700;
    }

    /* Two forms per item, one button each. Left alone they stack, which turns a three-line
       notification into a six-line one in a panel that is already narrow. */
    [data-meliora-inbox-item] form {
        display: inline;
    }

    /* ---- Settings: the navigation and the section beside it ---- */

    /* A SIDEBAR NOW, AND IT USED TO BE A ROW. The old note here said a two-column layout "would need a
       container this library does not ship -- and inside an 18rem popover a sidebar is the wrong
       answer anyway". Both halves were true and both stopped being true together: the panel moved into
       a 34rem dialog, where a row of links above the body wastes the width it was given, and
       _SettingsPanel now ships the container.

       ONE CONTAINER, TWO CALLERS, so the dialog and /Settings still agree. That was the objection to
       changing this at all and it is answered by putting the wrapper in the shared partial rather than
       in the dialog's own markup.

       IT WRAPS TO ONE COLUMN ON A NARROW VIEWPORT, because a 12rem rail beside a body inside 92vw of a
       phone is two cramped columns instead of one readable one. */
    [data-meliora-settings-layout] {
        display: flex;
        flex-wrap: wrap;
        align-items: flex-start;
        gap: 1rem;
    }

    [data-meliora-settings-nav] {
        display: flex;
        flex-direction: column;
        gap: .15rem;

        flex: 0 0 8.25rem;
        min-width: 8rem;
    }

    /* THE BODY TAKES WHAT IS LEFT, and min-width:0 is what stops a long unbroken string in a section
       pushing the rail off the edge -- a flex item's automatic minimum is its content, not zero. */
    [data-meliora-settings-body] {
        flex: 1 1 18rem;
        min-width: 0;
    }

    /* Which section is showing, again without colour. */
    [data-meliora-settings-link][data-current="true"] {
        font-weight: 700;
    }

    /* WHICH THEME IS IN FORCE, on the rail's own precedent and for the same reason.

       A CONTROL THAT CANNOT SAY WHICH OF ITS STATES IS CURRENT IS BROKEN RATHER THAN UNSTYLED, which
       is the line this file draws everywhere else -- the popover's positioning, the dialog's title
       row. Three identical buttons offering system, light and dark, with nothing marking the one you
       are already on, is the same category of defect: it was reported as "the appearance section
       doesn't show me what the current selection is".

       THE HOOK WAS ALREADY THERE AND NOTHING ANSWERED IT. data-current is rendered on each choice and
       aria-current beside it, so assistive technology has always been told; only the sighted reader
       was not. The application may of course say it with colour instead -- this is the plain answer
       that stops it being invisible in an application that has said nothing.

       ON THE BUTTON, because data-current sits on the form and the form is not the visible thing. */
    [data-meliora-appearance-choice][data-current="true"] button {
        font-weight: 700;
    }

    /* ---- Notification preferences: the library's own settings section ---- */

    /* One row per purpose, the channels across it; a cell holds one control and nothing wraps. */
    [data-meliora-preferences] {
        border-collapse: collapse;
        width: 100%;
    }

    [data-meliora-preference] form {
        margin: 0;
    }

    /* A REQUIRED CHANNEL IS SHOWN AND DISABLED, NEVER HIDDEN -- the section's one real decision, and
       the styling has to carry it. A control that looks ordinary but refuses every click reads as
       broken; dimmed and not-allowed reads as "not yours to change", which is what it is. */
    [data-meliora-preference] [data-required="true"] button {
        opacity: .6;
        cursor: not-allowed;
    }

    /* ---- The announcement strip ------------------------------------------

       ONE RULE HERE IS LOAD-BEARING AND THE REST IS TIDINESS: the one that hides the announcements
       that are not current. It is keyed on data-rotating, which ONLY announcements.js sets -- so a
       blocked script leaves every announcement visible and stacked, which is plain and correct,
       rather than leaving a reader looking at one of four with no way to know.

       Getting that backwards is invisible in every test that runs with scripts enabled. */

    [data-meliora-announcements] {
        display: flex;
        align-items: center;
        gap: .5rem;
        justify-content: flex-end;
    }

    /* Only once the script has taken over. Without the attribute this selector matches nothing. */
    [data-meliora-announcements][data-rotating="true"] [data-meliora-announcement-item]:not([data-current="true"]) {
        display: none;
    }

    /* One row, Hide last: the current item lends its words and its Hide form to the root, so the
       count can sit between them without moving in the markup. */
    [data-meliora-announcements][data-rotating="true"] [data-meliora-announcement-item][data-current="true"] {
        display: contents;
    }
    [data-meliora-announcements] [data-meliora-announcement-count] { order: 1; }
    [data-meliora-announcements] [data-meliora-announcement-dismiss] { order: 2; }
    [data-meliora-announcements] [data-meliora-announcement-restore] { order: 3; }

    [data-meliora-announcements] [data-meliora-announcement-item] {
        display: flex;
        align-items: center;
        gap: .5rem;
        min-width: 0;
    }

    /* The words are what may be long; everything beside them is fixed. Truncating here rather than on
       the row is what keeps the Hide button from being pushed off the end of a header. */
    [data-meliora-announcements] [data-meliora-announcement-body] {
        flex: 1 1 auto;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* EVERYTHING BESIDE THE WORDS REFUSES TO SHRINK, and the count is why this rule exists.

       A flex item shrinks by default, and the count had no rule of its own at all -- so in a narrow
       strip it was squeezed below the width of "2 of 4" and WRAPPED, while the body beside it
       truncated correctly. Two failures that look alike and are not: the body is meant to lose
       characters, and the count is meant to lose nothing.

       IT SHOWED UP WHEN AN APPLICATION MADE THE STRIP NARROWER, which is the point -- the library
       cannot know how much room a host will give it, so "the words are the only thing that yields"
       has to hold at every width rather than at the comfortable ones. The Hide and restore buttons
       take the same rule for the same reason. */
    [data-meliora-announcements] [data-meliora-announcement-count],
    [data-meliora-announcements] form,
    [data-meliora-announcements] button {
        flex-shrink: 0;
        white-space: nowrap;
    }

    /* The fade is a transition on opacity and nothing else, so prefers-reduced-motion -- which the
       script honours by skipping it -- has nothing left to disagree with. */
    [data-meliora-announcements] {
        transition: opacity 180ms;
    }

    [data-meliora-announcements][data-fading="true"] {
        opacity: 0;
    }

    @media (prefers-reduced-motion: reduce) {
        [data-meliora-announcements] {
            transition: none;
        }
    }

    [data-meliora-announcements] form {
        margin: 0;
    }

    /* A row that is scheduled rather than showing, on the publisher's board. Dimmed rather than
       hidden: "not yet" is a state somebody scheduled on purpose and needs to be able to see. */
    [data-meliora-announcement-board] [data-live="false"] {
        opacity: .65;
    }

    [data-meliora-announcement-board] form {
        display: inline;
        margin: 0;
    }
    /* ==== The account screens' mechanics: structure only; the look is the shell's ============= */

    /* A password field with a reveal button inside its right edge. */
    [data-meliora-reveal] {
        position: relative;
    }
    [data-meliora-reveal] input {
        padding-right: 3.6rem;
    }
    [data-meliora-reveal-toggle] {
        position: absolute;
        right: .35rem;
        top: 50%;
        transform: translateY(-50%);
    }

    /* One box per digit, built by meliora.js into the container the view renders hidden. */
    [data-meliora-code-boxes] {
        display: flex;
        gap: .5rem;
    }
    [data-meliora-code-box] {
        width: 2.75rem;
        height: 3.25rem;
        text-align: center;
        padding: 0;
    }

    /* Four bars under a new password, lit from the left. */
    [data-meliora-strength-bars] {
        display: flex;
        gap: .25rem;
        margin-top: .5rem;
    }
    [data-meliora-strength-bars] i {
        flex: 1;
        height: 3px;
        border-radius: 2px;
    }
}
