/* ==========================================================================
   PRS Review - cookie consent banner and preferences panel.

   Self-contained on purpose. Nothing here depends on Bootstrap, on redesign.css,
   or on any other stylesheet in this folder, and nothing here targets a selector
   it does not own. Every rule is scoped to a .prs-consent- class. This partial is
   emitted into <head> on every page of the site including the 17 Layout=null views
   (signup, login, and the whole test and oral engine), so a rule that leaked would
   leak everywhere at once and would be found by a customer rather than by us.

   The markup this styles is built by wwwroot/js/consent/prs-consent.js. Every node
   it creates carries ng-non-bindable, and no rule below assumes any other attribute.

   ONE EXCEPTION, and it is the video placeholder. Home/Index.cshtml,
   Home/Qbank.cshtml and Home/Oralboard.cshtml emit an EMPTY host element carrying
   data-prs-consent-video and no <script> - JW Player is disclosed as advertising
   and is therefore injected by the consent manager after the advertising grant,
   not by the view. .prs-consent-placeholder styles what the script puts inside
   that host while the grant is absent. The host element itself is the views'
   (it keeps its own id and sizing); everything inside it is this file's.

   ONE RULE BELOW TOUCHES AN ELEMENT THIS COMPONENT DOES NOT OWN:
   body.prs-consent-has-banner, which is the compensating offset for the fixed
   banner. It is scoped behind a .prs-consent- class, it is added and removed by
   the script, and the script restores whatever padding-bottom the page had.

   Z-INDEX. Measured, not guessed. The highest value anywhere in this folder is
   angular-toastr.css:82 at 999999; the redesign sheets top out at 10002. A consent
   dialog that a toast can cover is a consent dialog somebody can be talked past, so
   1000001 it is - one above the highest thing that exists, rather than a nine-digit
   number nobody can reason about later.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Shared button

   🔴 ACCEPT AND REJECT ARE THE SAME BUTTON, AND THIS BLOCK ENFORCES IT RATHER
   THAN MERELY DECLINING TO BREAK IT.

   The old note said they "cannot drift apart" because there was no per-button
   rule to change. That was not enough to make the claim true, for three reasons
   this block now closes:

     1. min-width was a FLOOR, not a size. Two buttons whose labels differ in
        width render at different widths as soon as either label passes 150px -
        which "Accept all" and "Reject all" do not today, and which the first
        translation, the first rewording, or the first brand with a longer verb
        does. The pair now share one fixed flex basis, so they are the same box
        whatever is written on them.
     2. This sheet did not own every property that carries prominence. It set
        colour, size and weight and left letter-spacing, text-transform,
        box-shadow, opacity, filter, transform and flex behaviour to be
        inherited - and these buttons live inside pages that also load Bootstrap
        and four redesign sheets, any of which can reach a bare <button>. They
        are all pinned below, so a rule somebody else writes cannot make one of
        these two louder than the other.
     3. Nothing said what the honest residue is. One of them is written first;
        that is unavoidable and it is not a prominence difference, because they
        are adjacent, identical, on the same row, at the same visual level, and
        neither is separated from the other by the ghost button.

   Making Reject smaller, lighter, greyer, outlined, or lower down is a dark
   pattern, and it is the single easiest thing to introduce here by accident -
   hence this note and the matching one in prs-consent.js, so that neither file
   can be tidied on its own.
   -------------------------------------------------------------------------- */

.prs-consent-btn {
    display: inline-block;
    box-sizing: border-box;
    margin: 0;
    padding: 12px 22px;
    min-width: 150px;
    border: 2px solid transparent;
    border-radius: 6px;
    font-family: inherit;
    font-size: 15px;
    font-weight: 600;
    font-style: normal;
    line-height: 1.2;
    letter-spacing: normal;
    text-align: center;
    text-decoration: none;
    text-transform: none;
    box-shadow: none;
    opacity: 1;
    filter: none;
    transform: none;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
}

/* 🔴 THE PAIR. Accept all, Reject all and Save preferences all carry
   --decision, and every one of them is the same box: one basis, no growing, no
   shrinking, no reordering. flex-basis rather than width so the narrow-screen
   block layout below still takes over cleanly. `order` is pinned because a
   single `order: -1` somewhere else is all it would take to promote one of
   them, and that change would not look like a dark pattern in a diff. */
.prs-consent-btn--decision {
    flex: 0 0 170px;
    order: 0;
    background: #123a5f;
    border-color: #123a5f;
    color: #ffffff;
}

/* And the same for every button in the two rows, so the ghost controls cannot
   be promoted past the decision pair either. */
.prs-consent-banner__actions .prs-consent-btn,
.prs-consent-panel__footer .prs-consent-btn {
    order: 0;
}

.prs-consent-btn--decision:hover,
.prs-consent-btn--decision:focus {
    background: #0d2b47;
    border-color: #0d2b47;
    color: #ffffff;
}

.prs-consent-btn--ghost {
    background: transparent;
    border-color: #123a5f;
    color: #123a5f;
}

.prs-consent-btn--ghost:hover,
.prs-consent-btn--ghost:focus {
    background: #eef3f8;
    color: #0d2b47;
}

/* A visible focus ring, on every interactive thing, in both the old and the new
   form. :focus-visible is what a mouse user should not see; :focus is the fallback
   for the browsers that do not support it, and an always-visible ring is far better
   than an invisible one on a dialog somebody may be driving entirely by keyboard. */
.prs-consent-btn:focus,
.prs-consent-banner a:focus,
.prs-consent-panel a:focus,
.prs-consent-category__input:focus {
    outline: 3px solid #f0a202;
    outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   The banner
   -------------------------------------------------------------------------- */

.prs-consent-banner {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1000001;
    box-sizing: border-box;
    padding: 20px 24px;
    background: #ffffff;
    border-top: 3px solid #123a5f;
    box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.18);
    font-family: "Public Sans", "Segoe UI", Arial, sans-serif;
    color: #1f2933;
    /* The banner is the only thing on the page that must be reachable, so it is
       allowed to scroll internally on a short viewport rather than push its own
       buttons off the bottom of the screen. */
    max-height: 70vh;
    overflow-y: auto;
}

.prs-consent-banner:focus {
    outline: 3px solid #f0a202;
    outline-offset: -3px;
}

/* --------------------------------------------------------------------------
   🔴 M4 - THE BANNER MUST NOT COVER THE BOTTOM OF THE PAGE.

   position: fixed takes the banner out of flow, so without this every page has
   its last few hundred pixels hidden underneath it - and on a short viewport
   there is nothing left to scroll, so what is under there is unreachable rather
   than merely awkward. On this site that regularly means a submit button: the
   contact form, the scholarship form and the signup form all end at the bottom
   of their page.

   --prs-consent-banner-height is measured and set by prs-consent.js, because the
   height is not knowable from here: the copy rewraps at every width, the buttons
   stack below 768px, and the whole thing is capped at 70vh with its own
   scrollbar. The 220px fallback is only ever used in the moment between the
   class landing and the measurement, and it is deliberately generous - too much
   padding is invisible, too little hides a button.

   The class goes on <body> and comes off again when the banner is answered, and
   the JS restores whatever padding-bottom the page already had. -------------- */

body.prs-consent-has-banner {
    padding-bottom: var(--prs-consent-banner-height, 220px);
}

.prs-consent-banner__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    max-width: 1320px;
    margin: 0 auto;
}

.prs-consent-banner__copy {
    flex: 1 1 420px;
    min-width: 0;
}

.prs-consent-banner__title {
    margin: 0 0 6px 0;
    font-size: 18px;
    font-weight: 700;
    line-height: 1.3;
    color: #123a5f;
}

.prs-consent-banner__body {
    margin: 0 0 8px 0;
    font-size: 14px;
    line-height: 1.55;
    color: #3e4c59;
}

.prs-consent-banner__privacy {
    display: inline-block;
    font-size: 14px;
    font-weight: 600;
    color: #123a5f;
    text-decoration: underline;
}

.prs-consent-banner__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    flex: 0 0 auto;
}

/* --------------------------------------------------------------------------
   The preferences panel
   -------------------------------------------------------------------------- */

/* The overlay is a visual dim and nothing else - prs-consent.js attaches no click
   handler to it on purpose, so a mis-click cannot close a dialog that may have been
   opened from the first-run banner. */
.prs-consent-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1000001;
    background: rgba(15, 23, 32, 0.55);
}

.prs-consent-panel {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 1000002;
    box-sizing: border-box;
    width: 92%;
    max-width: 720px;
    max-height: 88vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 24px;
    background: #ffffff;
    border-radius: 10px;
    box-shadow: 0 18px 48px rgba(0, 0, 0, 0.35);
    font-family: "Public Sans", "Segoe UI", Arial, sans-serif;
    color: #1f2933;
}

.prs-consent-panel:focus {
    outline: 3px solid #f0a202;
    outline-offset: -3px;
}

.prs-consent-panel__header {
    margin: 0 0 12px 0;
}

.prs-consent-panel__title {
    margin: 0;
    font-size: 22px;
    font-weight: 700;
    line-height: 1.25;
    color: #123a5f;
}

.prs-consent-panel__intro {
    margin: 0 0 10px 0;
    font-size: 14px;
    line-height: 1.55;
    color: #3e4c59;
}

.prs-consent-panel__privacy {
    display: inline-block;
    margin: 0 0 18px 0;
    font-size: 14px;
    font-weight: 600;
    color: #123a5f;
    text-decoration: underline;
}

.prs-consent-panel__body {
    margin: 0;
}

/* --------------------------------------------------------------------------
   Whether a server copy of the decision exists

   prs-consent.js writes this line only when a record was actually attempted in
   this page's life, and only in wording that is true of what happened. The
   not-recorded variant is the one that has to be readable rather than pretty:
   it is a statement that the visitor's choice is in force but that we hold no
   evidence of it, and it is the line a support call will be about.
   #5c3d00 on #fff6e5 is 9.2:1. -------------------------------------------- */

.prs-consent-panel__record {
    box-sizing: border-box;
    margin: 0 0 16px 0;
    padding: 10px 14px;
    border-radius: 6px;
    border-left: 4px solid #123a5f;
    background: #eef3f8;
    font-size: 13.5px;
    line-height: 1.55;
    color: #23313f;
}

.prs-consent-panel__record--not-recorded {
    border-left-color: #a5600a;
    background: #fff6e5;
    color: #5c3d00;
    font-weight: 600;
}

.prs-consent-panel__footer {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 22px;
    padding-top: 18px;
    border-top: 1px solid #dfe5ec;
}

/* --------------------------------------------------------------------------
   A category row
   -------------------------------------------------------------------------- */

.prs-consent-category {
    padding: 14px 0;
    border-bottom: 1px solid #eaeff5;
}

.prs-consent-category__head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
}

/* A real checkbox, enlarged rather than replaced. Replacing it with a styled span
   is how a toggle stops being announced, stops being reachable by keyboard, and
   stops responding to Space - none of which is acceptable on the one control the
   whole feature is about. */
.prs-consent-category__input {
    width: 20px;
    height: 20px;
    margin: 0;
    flex: 0 0 auto;
    cursor: pointer;
    accent-color: #123a5f;

    /* 🔴 THE CONTROL MUST DRAW ITSELF, AND THIS LINE IS WHY IT DOES.
       style.css:80 applies `-webkit-appearance: none` to `button, input, textarea` across the
       whole application. On a checkbox that removes the box, the tick and the border and
       leaves a completely invisible 20x20 element - present, focusable, checkable, and
       painting nothing. The consent panel shipped exactly that: four categories with four
       invisible toggles, on the one screen whose entire purpose is letting somebody see and
       change what they have agreed to.
       style.css now excludes checkboxes and radios from that reset, so this is belt and
       braces - but it stays, because this stylesheet claims in its own header to be
       self-contained and that claim has to survive somebody restoring the global rule. The
       native control is used deliberately rather than a custom SVG: it is the one thing that
       is guaranteed to keep working with a screen reader, high-contrast mode, forced-colours
       mode and the Space key, none of which is optional on a consent control. */
    -webkit-appearance: auto;
    -moz-appearance: auto;
    appearance: auto;
}

.prs-consent-category__input:disabled {
    cursor: not-allowed;
    opacity: 0.65;
}

.prs-consent-category__label {
    font-size: 16px;
    font-weight: 700;
    line-height: 1.3;
    color: #123a5f;
    cursor: pointer;
}

.prs-consent-category__input:disabled + .prs-consent-category__label {
    cursor: default;
}

.prs-consent-category__locked {
    padding: 3px 10px;
    border-radius: 999px;
    background: #eef3f8;
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #123a5f;
}

.prs-consent-category__body {
    margin: 8px 0 0 30px;
    font-size: 13.5px;
    line-height: 1.55;
    color: #52606d;
}

/* --------------------------------------------------------------------------
   The disclosure list
   -------------------------------------------------------------------------- */

.prs-consent-disclosure {
    margin-top: 20px;
    padding-top: 18px;
    border-top: 1px solid #dfe5ec;
}

.prs-consent-disclosure__title {
    margin: 0 0 12px 0;
    font-size: 15px;
    font-weight: 700;
    color: #123a5f;
}

.prs-consent-disclosure__list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.prs-consent-disclosure__item {
    padding: 10px 0;
    border-bottom: 1px solid #f0f3f7;
}

.prs-consent-disclosure__name {
    display: inline-block;
    margin-right: 8px;
    font-family: Consolas, Menlo, Monaco, "Courier New", monospace;
    font-size: 13px;
    font-weight: 700;
    color: #1f2933;
    word-break: break-all;
}

.prs-consent-disclosure__tag {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    background: #eef3f8;
    font-size: 11.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #123a5f;
}

.prs-consent-disclosure__purpose {
    display: block;
    margin-top: 5px;
    font-size: 13px;
    line-height: 1.5;
    color: #52606d;
}

/* 🔴 M3 - CONTRAST. This was #7b8794 on #ffffff, which is 3.66:1 and fails
   WCAG 2.1 AA for normal-size text (4.5:1 required; it is 12.5px italic, so the
   large-text 3:1 allowance does not apply). It carries the RETENTION PERIOD -
   how long each thing stays on the visitor's device - which is not decoration
   and is the single most-squinted-at line in the panel.

   #616c78 on #ffffff is 5.35:1. It keeps the line quieter than the purpose text
   above it (#52606d, 6.45:1), so the visual hierarchy the italic was there for
   survives; it is simply no longer built out of illegibility. Any future edit to
   this value has to be measured, not eyeballed. */
.prs-consent-disclosure__life {
    display: block;
    margin-top: 3px;
    font-size: 12.5px;
    font-style: italic;
    color: #616c78;
}

/* --------------------------------------------------------------------------
   The post-decision confirmation
   -------------------------------------------------------------------------- */

.prs-consent-confirm {
    position: fixed;
    left: 16px;
    bottom: 16px;
    z-index: 1000001;
    box-sizing: border-box;
    max-width: 420px;
    padding: 14px 18px;
    background: #123a5f;
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
    font-family: "Public Sans", "Segoe UI", Arial, sans-serif;
    font-size: 13.5px;
    line-height: 1.5;
    color: #ffffff;
}

.prs-consent-confirm:focus {
    outline: 3px solid #f0a202;
    outline-offset: 2px;
}

.prs-consent-confirm__line,
.prs-consent-confirm__record {
    margin: 0;
}

/* The second line exists in the DOM from the start and is empty until the
   server record settles, so the strip does not jump when it fills. :empty keeps
   the gap from appearing before there is anything to separate. #ffe6b8 on
   #123a5f is 9.6:1. */
.prs-consent-confirm__record {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid rgba(255, 255, 255, 0.35);
    font-weight: 600;
    color: #ffe6b8;
}

.prs-consent-confirm__record:empty {
    margin: 0;
    padding: 0;
    border-top: 0;
}

/* --------------------------------------------------------------------------
   The video placeholder

   🔴 THIS IS WHAT IS ON THE PAGE WHERE JW PLAYER IS NOT. The three public views
   that show a video emit an empty host element and no script; prs-consent.js
   fills it with this until advertising is granted. It has to look deliberate
   rather than broken - a blank box reads as a bug and gets "fixed" by putting
   the script back.
   -------------------------------------------------------------------------- */

.prs-consent-placeholder {
    box-sizing: border-box;
    max-width: 640px;
    margin: 0 auto;
    padding: 28px 24px;
    border: 2px dashed #c3cedb;
    border-radius: 10px;
    background: #f7f9fc;
    font-family: "Public Sans", "Segoe UI", Arial, sans-serif;
    text-align: center;
}

.prs-consent-placeholder__title {
    margin: 0 0 8px 0;
    font-size: 16px;
    font-weight: 700;
    line-height: 1.3;
    color: #123a5f;
}

.prs-consent-placeholder__body {
    margin: 0 0 16px 0;
    font-size: 13.5px;
    line-height: 1.6;
    color: #3e4c59;
}

/* --------------------------------------------------------------------------
   The appended "Cookie preferences" fallback

   🔴 IN FLOW AT THE END OF <body>, NEVER FIXED. prs-consent.js appends this only
   on a page whose markup carries no data-prs-consent-open anywhere - the
   dashboard before its footer is updated, the admin back office, and the twenty
   Layout=null views, which include the whole test and oral engine. A floating
   control would sit over a fullscreen examination, which is the interruption
   this component refuses everywhere else, so it sits at the very end of the
   document instead: reachable, last in the tab order, and covering nothing.
   -------------------------------------------------------------------------- */

.prs-consent-reopen {
    box-sizing: border-box;
    clear: both;
    padding: 18px 16px;
    text-align: center;
    font-family: "Public Sans", "Segoe UI", Arial, sans-serif;
    font-size: 13px;
    line-height: 1.5;
}

.prs-consent-reopen__link {
    color: #123a5f;
    text-decoration: underline;
}

.prs-consent-reopen__link:focus {
    outline: 3px solid #f0a202;
    outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   Announced but not seen

   The banner carries one of these so a screen reader is told politely that a
   cookie choice is waiting, WITHOUT focus being moved. The old code moved focus
   to the banner on every page load, which interrupts a screen reader mid-page
   and discards a keyboard user's place; see the I8 note in prs-consent.js.

   clip and clip-path together, not display:none and not visibility:hidden -
   both of those remove the element from the accessibility tree, which is the
   one thing it exists to be in.
   -------------------------------------------------------------------------- */

.prs-consent-visually-hidden {
    position: absolute !important;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    white-space: nowrap;
    border: 0;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
}

/* --------------------------------------------------------------------------
   Narrow screens

   The buttons go full width and stack, still identical to each other. Stacking is
   the moment Reject is most likely to end up visually subordinate, so the rule sets
   the width on .prs-consent-btn itself rather than on any individual button.
   -------------------------------------------------------------------------- */

@media (max-width: 767px) {
    .prs-consent-banner {
        padding: 16px;
        max-height: 80vh;
    }

    .prs-consent-banner__inner {
        display: block;
    }

    .prs-consent-banner__actions {
        display: block;
        margin-top: 16px;
    }

    .prs-consent-btn {
        display: block;
        width: 100%;
        min-width: 0;
        margin: 0 0 10px 0;
    }

    .prs-consent-panel {
        width: 100%;
        max-width: none;
        max-height: 100%;
        top: 0;
        left: 0;
        transform: none;
        border-radius: 0;
        padding: 18px 16px 24px 16px;
    }

    .prs-consent-panel__footer {
        display: block;
    }

    .prs-consent-confirm {
        left: 12px;
        right: 12px;
        max-width: none;
    }
}

/* --------------------------------------------------------------------------
   High contrast and reduced motion

   There is no animation in this component at all, which is a deliberate choice
   rather than an omission: a consent dialog that fades in is a consent dialog that
   can be clicked through before it is readable. The block below is here so that a
   later addition has somewhere obvious to be honest about it.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    .prs-consent-banner,
    .prs-consent-panel,
    .prs-consent-confirm {
        transition: none;
        animation: none;
    }
}

@media (forced-colors: active) {
    .prs-consent-banner,
    .prs-consent-panel,
    .prs-consent-confirm {
        border: 1px solid CanvasText;
    }

    .prs-consent-btn {
        border: 2px solid ButtonText;
    }
}

/* --------------------------------------------------------------------------
   Print

   The banner is chrome, not content. Nobody wants it on a printed test review, and
   js/noprint.js already exists in this codebase for exactly this class of problem.
   -------------------------------------------------------------------------- */

@media print {
    .prs-consent-banner,
    .prs-consent-overlay,
    .prs-consent-panel,
    .prs-consent-confirm,
    .prs-consent-reopen {
        display: none !important;
    }

    /* The placeholder stays, because on a printed page it is the honest answer
       to "there is a video here" - but without the control, which cannot be
       clicked on paper. */
    .prs-consent-placeholder .prs-consent-btn {
        display: none !important;
    }

    /* 🔴 And the banner's offset comes off with it. Leaving 220px of padding on
       <body> puts a blank final page on every printed test review. */
    body.prs-consent-has-banner {
        padding-bottom: 0 !important;
    }
}
