/*
 * view_project.php — the public project page.
 *
 * Moved out of a 242-line inline block. What the guards then had to say about it is
 * recorded beside each change below; the block had never been read by any of them.
 */

/* The body rule that was here set background-color: #f4f7f6. css/styles.css line
   400 already sets it to var(--background-color), #F5F5F5, which measures 1.01:1
   against it: an override that overrode nothing anyone can see. */

.project-view-container {
    max-width: 1100px;
    margin: 120px auto 40px;
}

.project-header h1 {
    font-size: 3rem;
    margin-bottom: 5px;
    color: var(--text-color);
}

.project-header .project-by {
    font-size: 1.25rem;
    /* #7f8c8d is 3.48:1 on white and 3.19:1 on the #F5F5F5 page ground, against the
       4.5:1 this text needs at 1.2rem regular. --gray is the guide's supporting-text
       value, #666666 at 5.74:1, and it passes on both grounds at any size. */
    color: var(--gray);
    margin-bottom: 30px;
}

.project-header .project-by a {
    color: var(--brand-text);
    text-decoration: none;
    font-weight: 600;
}

.project-header .project-by a:hover {
    text-decoration: underline;
}

.project-layout {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: 40px;
}

/* Allow grid columns to shrink so long, unbreakable content (e.g. a pasted
   URL) wraps instead of forcing the whole page to scroll horizontally. */
.project-main-content,
.project-sidebar {
    min-width: 0;
}

.project-main-content {
    background: #fff;
    padding: 30px;
    border-radius: 8px;
    box-shadow: var(--shadow-sm);
}

.project-main-content h2 {
    font-size: 1.75rem;
    color: var(--text-color);
        /* --border-subtle. Measured on view_project.php: this underline sits on
       white, where the guide's border value is #ECECEC at 1.18:1. #ecf0f1 is
       Flat UI 'clouds' and was 1.15:1 - off the ramp rather than a different
       design decision. */
    border-bottom: 2px solid var(--border-subtle);
    padding-bottom: 10px;
    margin-top: 0;
    margin-bottom: 20px;
}

.project-main-content p {
    font-size: 1rem;
    line-height: 1.8;
    color: var(--text-color);
    overflow-wrap: anywhere;
}

.project-sidebar .details-card {
    background: #fff;
    padding: 25px;
    border-radius: 8px;
    box-shadow: var(--shadow-sm);
    margin-bottom: 30px;
}

.details-card h3 {
    font-size: 1.5rem;
    margin-top: 0;
    margin-bottom: 20px;
    color: var(--text-color);
}

.details-card .detail-item {
    margin-bottom: 20px;
}

.details-card .detail-item strong {
    display: block;
    /* The four detail labels - the non-profit's name, Required Skills, Time
       Commitment, Expected Duration - at 0.9rem weight 700. 14.4px bold is NOT large
       text: the bar for that is 18.66px bold, so these need 4.5:1 and #7f8c8d gave
       3.48:1. They are the labels a volunteer reads to decide whether to apply.

       Invisible to every sweep this project has run, because two gaps lined up:
       tools/measure-contrast.sh asked for this page with no ?id and measured the
       "not found" notice page, and tools/probes/contrast.js had no `strong` in its
       selector. Both are fixed; this is the defect they were hiding. */
    color: var(--gray);
    font-size: 0.875rem;
    margin-bottom: 5px;
    text-transform: uppercase;
    /* 0.12em. The guide allows ALL-CAPS on kicker labels "with wide tracking, 0.28em,
       never at default spacing"; this had none at all. 0.28em is the guide's figure for
       a 13px eyebrow and is too much for a 0.9rem label above a value, so it sits at
       the floor the guard enforces rather than at the eyebrow's setting. */
    letter-spacing: 0.12em;
}

.details-card .detail-item p,
.details-card .detail-item .skills-container {
    font-size: 1rem;
    color: var(--text-color);
    margin: 0;
    overflow-wrap: anywhere;
}

.details-card .detail-item a {
    color: var(--brand-text);
}

.skills-container {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.skill-tag {
    background-color: var(--primary-tint);
    color: var(--brand-text-alt);
    padding: 5px 12px;
    border-radius: 20px;
    font-size: 0.875rem;
    font-weight: 600;
}

/* Status Badges */
.status-badge {
    display: inline-block;
    padding: 6px 15px;
    border-radius: 50px;
    font-size: 0.875rem;
    font-weight: 700;
    text-transform: uppercase;
    /* Was 0.5px, which is 0.031em at this size - the jammed kind of all-caps the
       guide's second half exists to prevent. */
    letter-spacing: 0.12em;
    margin-bottom: 15px;
}

/* THE BADGES WERE UNREADABLE, AND THAT IS WHY THEY CHANGED.
 *
 * All four were Chakra UI's palette - #319795, #3182ce, #38a169, #e53e3e on their own
 * tints - and all four measured BELOW the 4.5:1 this project holds itself to:
 *
 *     Completed   3.14:1     Active      3.35:1
 *     In progress 3.72:1     Canceled    3.86:1
 *
 * StatusPaletteTest knows Bootstrap, Tailwind and Material and did not know Chakra, so
 * nothing flagged them, and no contrast probe had ever opened this page because it
 * needs a database. They were found by rendering the markup in a harness.
 *
 * THE ROLE MAPPING IS A JUDGEMENT AND IT IS MINE
 *
 * Five states, and the guide has five roles once warning has a readable text colour:
 *
 *     active       Info      open, accepting applications - the state the Info role was
 *                            argued for in the first place
 *     in_progress  Warning   matched and under way; amber reads as in-flight
 *     completed    Success   done
 *     canceled     Error     abandoned
 *     archived     Neutral   no longer listed, and not a failure
 *
 * Each pair is its own text token on its own tint, measured: 5.16, 5.22, 5.39, 5.00 and
 * 5.27. Canceled as Error is the one I would argue with - it is a terminal state rather
 * than a fault - but Neutral is taken by archived and red is what a reader expects. */
.status-active {
    background-color: var(--status-info-tint);
    color: var(--status-info-text);
    border: 1px solid var(--status-info);
}

/* IN PROGRESS IS INFO, BECAUSE THE GUIDE NAMES IT.
 *
 * docs/style-guide.md's Status colours section says so in as many words, and names
 * projects while doing it: "a project that is open or in progress is neither finished,
 * nor in need of attention, nor wrong, and saying it in green, amber or red says
 * something untrue about it. Info covers the neutral, non-urgent case - open, in
 * progress, informational - and nothing else."
 *
 * This rule said amber. That reading was recorded above as a judgement - "in_progress
 * Warning; matched and under way, amber reads as in-flight" - and it is the half of that
 * mapping the brief overrules. The rest of it stands and is unchanged.
 *
 * The tree already agreed with the guide everywhere else: sections/status_tags.css puts
 * .pv-status-in_progress on the info tint, and the admin dashboard's project table does
 * too. This page was the last surface painting a working project amber, so a member
 * reading their own project saw a colour the two dashboards did not use for it.
 *
 * THE SPLIT ABOVE IS WHAT MADE THIS SAFE. `pending` and `admin_paused` both pointed at
 * this class, so recolouring it alone would have moved three states to fix one. They
 * have their own rules below, carrying exactly the values this one used to, so the only
 * badge whose colour changes is In Progress. Measured on the fixture's eight statuses,
 * before and after: one row differs. */
.status-in_progress {
    background-color: var(--status-info-tint);
    color: var(--status-info-text);
    border: 1px solid var(--status-info);
}

/* `.status-pending` STOOD HERE AND IS GONE, 2026-10-20.
 *
 * It was added days earlier to keep `pending` amber while `in_progress` moved onto the
 * Info role the guide names, and it carried a note about the two member dashboards
 * painting the same status blue. That disagreement is settled by DELETION rather than by
 * picking a colour: `pending` is no longer a project status at all. Nothing in this
 * application ever wrote it - the only `status = 'pending'` anywhere is on
 * project_applications, a different table where it means a volunteer is awaiting a reply
 * - and production held zero projects in it.
 *
 * A stray row stays readable if one ever appears: ProjectService::statusLabel() falls
 * back to ucfirst() and renders "Pending", and the switch in view_project.php falls to
 * its default and gives it the Info treatment. It is simply not a state this product
 * produces.
 *
 * `admin_paused` keeps the warning role, which is why the rule below now stands alone.
 * Full reasoning in services/ProjectService.php::STATUS_LABELS. */

.status-admin_paused {
    background-color: var(--status-warning-tint);
    color: var(--status-warning-text);
    border: 1px solid var(--status-warning-border);
}

.status-completed {
    background-color: var(--status-success-tint);
    color: var(--status-success-text);
    border: 1px solid var(--status-success);
}

.status-canceled {
    background-color: var(--status-error-tint);
    color: var(--status-error-text);
    border: 1px solid var(--status-error);
}

.status-archived {
    background-color: var(--status-neutral-tint);
    color: var(--status-neutral);
    border: 1px solid var(--border-default);
}

.cta-section {
    text-align: center;
    padding: 30px;
    background: #fdfdfd;
        /* --border-default, NOT --border-subtle, and the reason is this rule's own
       fill. background #fdfdfd against the #F5F5F5 behind it is 1.07:1, so the
       panel is invisible except for its border - the border is the whole
       boundary rather than a seam between two surfaces that already differ.
       Measured both sides: #ecf0f1 gave 1.13 against the fill and 1.05 against
       the ground, #ECECEC gives 1.16 and 1.08, #DADADA gives 1.37 and 1.28. */
    border: 1px solid var(--border-default);
    border-radius: 8px;
}

.cta-section p {
    font-size: 1.25rem;
    color: var(--gray);
    margin-bottom: 20px;
}

.cta-button {
    font-size: 1rem;
}

/* NO DISABLED RULES HERE ANY MORE, AND THE REASON IS IN THE ONE THAT WAS.
 *
 * It read: "the global .cta-button is a vivid animated gradient with no :disabled
 * treatment, so a disabled button still reads as clickable." That was true when it was
 * written and stopped being true when css/styles.css grew a shared rule on
 * `button:disabled` - one treatment for all nine button classes, plus the three in the
 * dashboard that were on no list.
 *
 * What is deleted with it is seven !important declarations, all of them fighting a
 * global rule that no longer needs fighting. A component painting its own disabled
 * state is what DisabledStateTest now forbids: two looks is how one of them stops being
 * maintained, and this page's grey #cccccc was the only one anybody had maintained. */

.not-found {
    text-align: center;
    padding: 50px;
}

#apply-feedback {
    margin-top: 15px;
    font-weight: bold;
}

/* The status text tokens, and the error one is a fix rather than a tidy-up.
 *
 * These were the CSS keywords `green` and `red`. Keyword red is #FF0000, which is
 * 4.00:1 on white - below the 4.5:1 this project holds itself to, on the message that
 * tells somebody their application did not go through. Keyword green is #008000 at
 * 5.14:1 and passed, which is how the pair survived: half of it was fine.
 *
 * --status-error-text is 5.73:1 and --status-success-text is 5.76:1. */
#apply-feedback.success {
    color: var(--status-success-text);
}

#apply-feedback.error {
    color: var(--status-error-text);
}

/* Redesigned Button State - Scoped to Not Found section only */
.not-found .button {
    display: inline-block;
    padding: 12px 32px;
    /* The tokens, not a second copy of the gradient. This rule restated
       linear-gradient(135deg, #FF4D9A 0%, #e51fff 100%) by hand, which is
       --gradient-primary written out, and the day the brand moves one of them moves. */
    background: var(--gradient-primary);
    color: var(--on-brand);
    text-decoration: none;
    border-radius: 50px;
    font-weight: 600;
    font-size: 1rem;
    letter-spacing: 0.3px;
    /* The not-found notice, reached with an id no row has. hover swaps the gradient
       (135deg pink-to-magenta becomes 45deg magenta-to-pink), drops the shadow and lifts
       -2px. background-image is named because BOTH ends are linear-gradients with the same
       number of stops, which interpolates; a gradient against a flat colour would not. */
    transition: background-image var(--duration-fast) var(--ease-standard),
                box-shadow var(--duration-fast) var(--ease-standard),
                transform var(--duration-fast) var(--ease-standard);
    box-shadow: var(--shadow-brand);
    border: none;
    margin-top: 20px;
}

.not-found .button:hover {
    background: var(--gradient-secondary);
    transform: translateY(-2px);
    /* BRAND IS TERMINAL, so this keeps --shadow-brand from the resting rule rather than
       stepping to --shadow-lg. That step looked like a deepening and is not: pink to
       near-black, and the alpha FALLS from .28 to .12, on a button that is still a
       gradient throughout the hover. docs/style-guide.md now rules on this. The lift
       and the gradient swap are the feedback. */
}

/* THE BOX-SHADOW IS GONE FROM THIS PRESS, AND THE GUIDE ALREADY SETTLED IT SIX LINES
   ABOVE. This rule used to step --shadow-brand down to --shadow-sm, which is not a
   shadow getting shallower: rgba(255,77,154,.28) 0 10px 30px becomes
   rgba(26,26,26,.06) 0 2px 8px - a different shadow in a different hue, on a button
   that is still a gradient.

   Two clauses in docs/style-guide.md collided. Buttons says "Press: reduce the
   shadow"; Shadows says BRAND IS TERMINAL, because the other three are one neutral
   family that deepens by blur and alpha together while brand is a single rung in
   another hue with nothing above it. Nothing below it either, which is the half that
   was never written down.

   The guide resolves the identical conflict for HOVER in the paragraph directly above:
   "a brand-filled control keeps its shadow and the lift plus the fill swap are the
   feedback." Press is the same mechanism, so this is derived rather than chosen.

   The press still reads: transform returns to 0, so the -2px lift visibly collapses,
   and the gradient swap from :hover stays. This was the ONLY press in the tree that
   reduced a shadow by changing its hue. */
.not-found .button:active {
    transform: translateY(0);
}

@media (max-width: 1024px) {
    .project-layout {
        grid-template-columns: 1fr;
    }

    .project-header h1 {
        font-size: 2rem;
    }
}

/* THE PAGE EDGE IS 16px BELOW 480 - docs/style-guide.md, Small.

   Measured at 390: this page's edge was 8px - the browser's body margin and nothing
   else, because .project-view-container declares max-width and auto margins and no
   horizontal padding. Zeroing that margin for the 16px rule left content FLUSH against
   the viewport, measured at 0. The rule gave every other page an edge and took this
   one's away, because this page never had an edge of its own to raise.

   Horizontal only: the vertical spacing is this component's own decision and the
   guide's rule is about the edge. */
@media (max-width: 480px) {
    .project-view-container {
        padding-left: 16px;
        padding-right: 16px;
    }
}
