/* ==========================================================================
   Blacktip Industries - btpro.com.au
   Brand tokens sampled directly from BLACKTIP_INDUSTRIES_logo_new_Full.jpg
   ========================================================================== */

/* --------------------------------------------------------------------------
   Archivo - self-hosted, no external font request.
   Variable font: one file covers weights 100-900, so every weight the design
   uses is served by a single ~35 KB download.
   SIL Open Font License 1.1 - see assets/fonts/OFL.txt
   -------------------------------------------------------------------------- */

@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 100%;
  font-display: swap;
  src: url('../assets/fonts/archivo-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 100%;
  font-display: swap;
  src: url('../assets/fonts/archivo-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --charcoal:       #363435;   /* logo wordmark */
  --charcoal-deep:  #262425;
  --charcoal-soft:  #4A4849;
  --charcoal-ink:   #2A2A2A;   /* dark text on brand blue - 4.54:1, passes AA */
  --grey:           #97989A;   /* logo "INDUSTRIES" */
  --grey-light:     #C9CACC;
  --grey-mid:       #7E7F82;   /* UI state outlines - 3.60:1 on --neutral */
  --blue:           #009ADA;   /* logo wave */
  --blue-dark:      #0080B8;
  --blue-light:     #33AFE2;   /* hover for the dark-text button - 5.72:1 */
  --blue-wash:      #E6F5FC;
  --paper:          #FEFEFE;
  --neutral:        #F2F3F4;
  --line:           #E1E3E5;

  --shell:   1240px;
  --gutter:  clamp(20px, 5vw, 56px);
  /* The base corner. 2px read as "square, but not quite", which is the least
     deliberate corner a design can have. */
  --radius:  8px;

  --font: "Archivo", "Helvetica Neue", Arial, system-ui, sans-serif;

  /* ------------------------------------------------------------------------
     DESIGN SYSTEM TOKENS (specification AI).

     These are the values Settings -> Design System may override. The published
     design writes a small :root block that redefines a subset of them, and
     nothing else in the application is allowed to invent its own button
     geometry, focus ring or corner radius: a component asks for a token.

     The defaults below reproduce the approved Phase 0 rendering exactly, so a
     site with no published design looks precisely as it did before the design
     system existed.
     ---------------------------------------------------------------------- */

  /* --- TYPOGRAPHY -------------------------------------------------------
     Type is addressed by ROLE, not by HTML tag. "Settings" above a page title
     is an EYEBROW wherever it appears; the title is a PAGE TITLE. A page asks
     for the role and gets the type, so the same thing looks the same in every
     screen that uses it. */

  --font-size-page-title: 32px;
  --font-size-section:    24px;
  --font-size-subsection: 19px;
  --font-size-body:       16px;
  --font-size-small:      14px;
  --font-size-label:      14px;
  --font-size-helper:     13px;
  --font-size-eyebrow:    12px;
  --font-size-table-head: 12px;

  --line-height-body:     1.65;
  --line-height-heading:  1.2;

  --weight-body:          400;
  --weight-label:         600;
  --weight-heading:       700;

  --tracking-eyebrow:     0.12em;
  --tracking-heading:     -0.01em;

  /* --- SPACING ----------------------------------------------------------
     One scale, in multiples of the base unit. A page uses a step from it
     rather than inventing 11px because 11px looked right in one place. */

  --space-unit:  4px;
  --space-1:  calc(var(--space-unit) * 1);
  --space-2:  calc(var(--space-unit) * 2);
  --space-3:  calc(var(--space-unit) * 3);
  --space-4:  calc(var(--space-unit) * 4);
  --space-5:  calc(var(--space-unit) * 5);
  --space-6:  calc(var(--space-unit) * 6);
  --space-8:  calc(var(--space-unit) * 8);
  --space-10: calc(var(--space-unit) * 10);

  --card-padding: 24px;
  --field-gap:    20px;
  --group-gap:    12px;
  --section-gap:  24px;

  /* --- BUTTON GEOMETRY --------------------------------------------------
     THREE SIZES, AND THE HEIGHT IS STATED.

     A button used to be as tall as its padding plus its line box made it:
     15px above and below a 15px/1.65 line came to about 59 pixels, most of it
     empty, and it moved whenever the type changed. The owner rejected that
     proportion in review, and rightly — the old "small" button was closer to
     what a normal one should be.

     So a button now has an explicit HEIGHT and no vertical padding at all. The
     label is centred in the box by flexbox, which means changing the font size
     changes the type and nothing else, and an <a class="btn"> and a
     <button class="btn"> cannot come out different heights however they are
     nested.

     SIZE IS SEPARATE FROM STYLE. --primary is a style, --lg is a size, and any
     style may be used at any size. */

  --btn-height-lg:     48px;
  --btn-height-md:     40px;
  --btn-height-sm:     32px;

  --btn-font-lg:       15px;
  --btn-font-md:       14px;
  --btn-font-sm:       13px;

  --btn-padding-x-lg:  26px;
  --btn-padding-x-md:  18px;
  --btn-padding-x-sm:  12px;

  /* Sibling actions in a group are at least this wide, so Apply and Clear are
     the same size and do not differ because of the letters in them. */
  --btn-min-width-lg:  140px;
  --btn-min-width-md:  104px;
  --btn-min-width-sm:  80px;

  /* Tight, because the box no longer depends on the line box. 1.65 inside a
     fixed-height button only risks clipping a descender. */
  --btn-line-height:   1.2;
  --btn-radius:        8px;
  --btn-border-width:  1px;
  --btn-weight:        600;
  /* Title Case, as written, rather than shouted. A published design can set
     this back to `uppercase` without touching a stylesheet. */
  --btn-transform:     none;
  --btn-tracking:      0.01em;

  /* --- FORM CONTROL GEOMETRY -------------------------------------------
     One control family: a text input, a select, a search box and the date
     field are the same height as each other and as a medium button. The filter
     bar is why this is stated rather than left to each control: an input sized
     by its padding and a select sized by the browser came out visibly
     different heights, side by side, in the same row. */

  --control-height:    40px;
  --control-height-sm: 32px;
  --control-font:      15px;
  --control-padding-x: 12px;
  --control-padding-y: 8px;   /* textareas only; single-line controls use height */

  /* --- TABLE AND GRID CELLS -------------------------------------------- */

  --cell-padding-x:    10px;
  --cell-padding-y:    8px;

  --icon-size:         20px;
  --icon-size-sm:      16px;
  --icon-btn-size:     40px;
  --icon-gap:          10px;

  --tab-padding-y:     8px;
  --tab-padding-x:     14px;

  /* The logo on the signed-out card screens. A HEIGHT, like the header's, so
     the shared brand mark and any container configured around it are presented
     the same way there as everywhere else. */
  --logo-height-auth:  54px;

  /* The smallest a control may be and still be usable with a thumb. This is a
     SYSTEM rule, not an admin setting. */
  --touch-target:      32px;

  /* --- BORDERS, CORNERS, SHADOWS --------------------------------------- */

  --border-width:      1px;
  --border-strong:     2px;

  /* Two corner decisions, resolved in PHP from a SQUARE / ROUNDED keyword
     (Btpro\Core\DesignSystem::cornerDeclarations). Buttons and the controls
     beside them share one; cards, panels and dialogs share the other. */
  --card-radius:       10px;
  --control-radius:    8px;
  --modal-radius:      14px;

  /* Restrained, and layered: a card lifts a little, a dialog lifts clearly.
     Depth is used to say what is on top of what, never for decoration. */
  --shadow-1: 0 1px 2px rgba(38, 36, 37, .06), 0 1px 3px rgba(38, 36, 37, .05);
  --shadow-2: 0 2px 6px rgba(38, 36, 37, .06), 0 8px 24px rgba(38, 36, 37, .10);
  --shadow-3: 0 4px 12px rgba(38, 36, 37, .08), 0 20px 48px rgba(38, 36, 37, .16);

  /* --- STATES ----------------------------------------------------------- */

  --focus-width:       3px;
  --focus-colour:      var(--blue);
  --focus-offset:      2px;
  --disabled-opacity:  0.45;
}

/* --------------------------------------------------------------------------
   TYPOGRAPHY ROLES.

   Available as classes for new markup, and consumed by the semantic selectors
   the application already uses, so both routes lead to the same type. A page
   that needs a section heading asks for one; it does not pick a font size.
   -------------------------------------------------------------------------- */

.t-page-title {
  font-size: var(--font-size-page-title);
  line-height: var(--line-height-heading);
  font-weight: var(--weight-heading);
  letter-spacing: var(--tracking-heading);
}

.t-section {
  font-size: var(--font-size-section);
  line-height: var(--line-height-heading);
  font-weight: var(--weight-heading);
  letter-spacing: var(--tracking-heading);
}

.t-subsection {
  font-size: var(--font-size-subsection);
  line-height: var(--line-height-heading);
  font-weight: var(--weight-heading);
}

.t-body      { font-size: var(--font-size-body);  line-height: var(--line-height-body); font-weight: var(--weight-body); }
.t-body-sm   { font-size: var(--font-size-small); line-height: var(--line-height-body); font-weight: var(--weight-body); }
.t-label     { font-size: var(--font-size-label); line-height: var(--line-height-body); font-weight: var(--weight-label); }
.t-helper    { font-size: var(--font-size-helper); line-height: var(--line-height-body); color: var(--grey-mid); }

.t-eyebrow {
  font-size: var(--font-size-eyebrow);
  font-weight: var(--weight-heading);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}

.t-table-head {
  font-size: var(--font-size-table-head);
  font-weight: var(--weight-heading);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.t-button {
  font-size: var(--btn-font-md);
  font-weight: var(--btn-weight);
  letter-spacing: var(--btn-tracking);
  text-transform: var(--btn-transform);
  line-height: var(--btn-line-height);
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; scroll-padding-top: 96px; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.65;
  color: var(--charcoal);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}

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

a { color: var(--blue-dark); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3, h4 { margin: 0; line-height: 1.08; letter-spacing: -0.02em; font-weight: 800; }

.shell { max-width: var(--shell); margin: 0 auto; padding: 0 var(--gutter); }

.skip-link {
  position: absolute; left: -9999px; top: 0;
  background: var(--blue); color: var(--charcoal-ink);
  padding: 12px 20px; z-index: 100; font-weight: 700;
}
.skip-link:focus { left: 0; }

/* Visible keyboard focus everywhere. Blue ring measures 3.16:1 on the light
   sections and 4.5:1 on charcoal - both clear the 3:1 required of a focus
   indicator. Filled blue buttons override this above with an inset dark ring. */
:focus-visible { outline: 3px solid var(--blue); outline-offset: 2px; }
.section--dark :focus-visible,
.hero :focus-visible,
.card--dark :focus-visible,
.footer :focus-visible { outline-color: var(--paper); }
.hero .btn--primary:focus-visible,
.footer .btn--primary:focus-visible { outline-color: var(--charcoal-ink); }

/* --- shared type ---------------------------------------------------------- */

.eyebrow {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--blue);
  margin: 0 0 18px;
}

.section-title { font-size: clamp(30px, 4.2vw, 46px); }

.lede {
  font-size: clamp(17px, 1.6vw, 20px);
  line-height: 1.6;
  color: var(--charcoal-soft);
  max-width: 62ch;
}

/* --- bracket motif, taken from the logo's open square frame --------------- */

.frame { position: relative; }
.frame::before,
.frame::after {
  content: ""; position: absolute;
  width: 30px; height: 30px;
  pointer-events: none;
}
.frame::before { top: -8px;    left: -8px;  border-top: 3px solid var(--blue);    border-left: 3px solid var(--blue); }
.frame::after  { bottom: -8px; right: -8px; border-bottom: 3px solid var(--blue); border-right: 3px solid var(--blue); }

/* --- buttons -------------------------------------------------------------- */

/* THE button. Every control in the application and on the public site uses it
   with one of the variants below; no page defines its own button geometry.

   Every state keeps the SAME box: the border is present on all four sides in
   every state and never changes width, and hover changes colour only. A state
   that added or removed one edge would move the text and shift the layout
   around it, which is exactly the fault the owner found on ORDER LOGIN. */

.btn {
  /* MEDIUM is the default size, and the one nearly every control should use.
     A page asks for a size only when it wants something other than medium. */
  --btn-height:    var(--btn-height-md);
  --btn-font-size: var(--btn-font-md);
  --btn-padding-x: var(--btn-padding-x-md);
  --btn-min-width: var(--btn-min-width-md);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  /* THE BOX IS THE HEIGHT. No vertical padding: the label is centred by
     flexbox, so the font may change without the button changing size, and
     nothing has to be recalculated when the type does change. */
  height: var(--btn-height);
  padding: 0 var(--btn-padding-x);
  font-family: inherit;
  font-size: var(--btn-font-size);
  font-weight: var(--btn-weight);
  letter-spacing: var(--btn-tracking);
  text-transform: var(--btn-transform);
  /* Stated, not inherited: without it an <a class="btn"> and a
     <button class="btn"> lay their labels out differently. */
  line-height: var(--btn-line-height);
  white-space: nowrap;
  border-radius: var(--btn-radius);
  border: var(--btn-border-width) solid transparent;
  background: transparent;
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease,
              box-shadow .15s ease;
  text-decoration: none;
}

/* THE THREE SIZES. Each sets the same four properties, so a size class is a
   complete answer and never a partial override of another one.

   These come after `.btn` deliberately: they carry the same specificity, so
   source order is what makes a size class win. */
.btn--lg {
  --btn-height:    var(--btn-height-lg);
  --btn-font-size: var(--btn-font-lg);
  --btn-padding-x: var(--btn-padding-x-lg);
  --btn-min-width: var(--btn-min-width-lg);
}

.btn--md {
  --btn-height:    var(--btn-height-md);
  --btn-font-size: var(--btn-font-md);
  --btn-padding-x: var(--btn-padding-x-md);
  --btn-min-width: var(--btn-min-width-md);
}

.btn--sm {
  --btn-height:    var(--btn-height-sm);
  --btn-font-size: var(--btn-font-sm);
  --btn-padding-x: var(--btn-padding-x-sm);
  --btn-min-width: var(--btn-min-width-sm);
}
.btn:hover { text-decoration: none; }

/* One focus treatment for every variant, from one token. */
.btn:focus-visible {
  outline: var(--focus-width) solid var(--focus-colour);
  outline-offset: var(--focus-offset);
}

/* Filled brand-blue CTA, site-wide: DARK text, never white.
   #2A2A2A on #009ADA = 4.54:1  ·  #2A2A2A on #33AFE2 = 5.72:1 (hover).
   White on #009ADA would be 3.16:1 and is deliberately not used. */
.btn--primary { background: var(--blue); color: var(--charcoal-ink); border-color: var(--blue); }
.btn--primary:hover { background: var(--blue-light); border-color: var(--blue-light); color: var(--charcoal-ink); }
/* Focus ring sits INSIDE the filled button so it stays visible on both the
   light sections and the charcoal hero. */
.btn--primary:focus-visible {
  outline: var(--focus-width) solid var(--charcoal-ink);
  outline-offset: calc(-1 * var(--focus-width));
}

/* For DARK surfaces only. On a light panel its near-white label disappears;
   css/app.css carries a guard that makes that visible rather than silent. */
.btn--ghost { border-color: var(--grey); color: var(--paper); }
.btn--ghost:hover { border-color: var(--paper); background: rgba(255,255,255,.06); }

/* The secondary control: a complete outline on all four sides, in every state. */
.btn--outline { border-color: var(--charcoal); color: var(--charcoal); }
.btn--outline:hover { background: var(--charcoal); color: var(--paper); border-color: var(--charcoal); }

/* Quieter than outline: for a control that must be available without competing
   with the primary action on the same row. */
.btn--neutral { border-color: var(--line); background: var(--neutral); color: var(--charcoal); }
.btn--neutral:hover { border-color: var(--grey-mid); background: var(--line); color: var(--charcoal); }

/* Destructive: recognisable BEFORE it is pressed, and never the primary
   colour. --confirm is the filled form used inside a destructive dialog,
   where the action is the point of the dialog. */
.btn--danger { border-color: var(--charcoal); color: var(--danger, #B3261E); background: transparent; }
.btn--danger:hover { background: var(--danger-wash, #FCEBEA); color: var(--danger, #B3261E); }

.btn--confirm { border-color: var(--danger, #B3261E); background: var(--danger, #B3261E); color: var(--paper); }
.btn--confirm:hover { border-color: #8E1E17; background: #8E1E17; color: var(--paper); }

/* --------------------------------------------------------------------------
   ACTION GROUP.

   Sibling actions presented together — APPLY and CLEAR, SAVE and CANCEL,
   CANCEL and DELETE — share a minimum width, so they are the same size and do
   not differ because of the letters in them. That is the whole rule: it is a
   property of the GROUP, not of any one button, so a lone call to action
   elsewhere still sizes to its own content.
   -------------------------------------------------------------------------- */

.action-group,
.form-actions,
.app__actions,
.row-actions,
.modal__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--group-gap);
  align-items: center;
}

.action-group > .btn,
.action-group > form > .btn,
.form-actions > .btn,
.app__actions > .btn,
.row-actions > .btn,
.row-actions > form > .btn,
.modal__actions > .btn {
  min-width: var(--btn-min-width);
}

/* A group of icon-only or deliberately tight controls opts out. Equal width is
   a courtesy between siblings of the same kind, not a rule that should stretch
   a toolbar of eleven small buttons across the page. */
.action-group--tight > .btn,
.action-group--tight > form > .btn { min-width: 0; }

/* On a narrow screen a row of equal-width buttons becomes a stack of
   full-width ones, which is the same rule expressed for a thumb. */
@media (max-width: 480px) {
  .action-group,
  .form-actions,
  .app__actions,
  .modal__actions { flex-direction: column; align-items: stretch; }

  .action-group > .btn,
  .action-group > form,
  .action-group > form > .btn,
  .form-actions > .btn,
  .app__actions > .btn,
  .modal__actions > .btn { width: 100%; }
}

/* --------------------------------------------------------------------------
   HIDDEN MEANS HIDDEN.

   The browser's own rule is a bare attribute selector, so ANY class that sets
   `display` out-ranks it. `.alert { display: flex }` did exactly that, and the
   row editor's "Unable to save" banner appeared, in full, on a page where
   nothing had failed - because the markup said `hidden` and the class said
   flex, and the class won.

   Whether an element is hidden cannot depend on which component it happens to
   be. This is a system rule in the same sense as the focus ring (AI.16): the
   application says `hidden`, and the element is not there.
   -------------------------------------------------------------------------- */

[hidden] { display: none !important; }

/* --------------------------------------------------------------------------
   DARK SURFACE.

   A dark panel is a design-system CONTEXT rather than a background colour
   somebody set. Declaring it means the controls inside it know they are on
   dark, which is what the ghost button needs — and it is why the component
   preview could show an unreadable one: a guard meant for light panels was
   reaching into a deliberately dark box and painting the label charcoal on
   charcoal.
   -------------------------------------------------------------------------- */

.surface--dark {
  background: var(--charcoal-deep);
  color: var(--paper);
}

.surface--dark .btn--ghost {
  border-color: var(--grey-light);
  color: var(--paper);
  background: transparent;
}

.surface--dark .btn--ghost:hover {
  border-color: var(--paper);
  background: rgba(255, 255, 255, .10);
  color: var(--paper);
}

/* One disabled treatment, and one busy treatment, for every variant. A busy
   button keeps its label so the row does not resize while a request runs. */
.btn[disabled],
.btn[aria-disabled="true"] {
  opacity: var(--disabled-opacity);
  cursor: not-allowed;
}

.btn[disabled],
.btn[aria-disabled="true"] { pointer-events: none; }

/* A button waiting on the server. The state already existed - Save & Exit,
   Submit and the dialog's confirming action all set it - but it only changed
   the cursor, which is invisible on a touch screen and easy to miss on a
   desktop. It now dims and carries a small spinner, so a slow save looks like
   a slow save rather than a button that did nothing. */
.btn[data-busy="true"] {
  cursor: progress;
  opacity: 0.75;
}

.btn[data-busy="true"]::after {
  content: "";
  display: inline-block;
  width: 0.85em;
  height: 0.85em;
  margin-left: var(--space-2);
  vertical-align: -0.1em;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: btpro-spin 0.7s linear infinite;
}

@keyframes btpro-spin { to { transform: rotate(360deg); } }

/* Motion is a preference, and a spinner that cannot spin still has to say the
   button is busy. */
@media (prefers-reduced-motion: reduce) {
  .btn[data-busy="true"]::after {
    animation: none;
    border-top-color: currentColor;
    opacity: 0.5;
  }
}

/* --- header --------------------------------------------------------------- */

.header {
  position: sticky; top: 0; z-index: 50;
  background: rgba(254,254,254,.96);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}
.header__bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; min-height: 88px;
}
/* logo is 1068x244 (~4.38:1) - height-locked, never distorted */
.header__logo img { height: 46px; width: auto; }

.nav { display: flex; align-items: center; gap: 34px; }

/* The underline affordance belongs to navigation LINKS, and only to them.
   `.nav a` used to match the header buttons too, and it out-ranks `.btn--*`:
   it replaced ORDER LOGIN's bottom border with a transparent one, so the
   button rendered with three sides, and on hover it painted that one edge
   brand-blue. The button was not at fault and neither was the underline; the
   selector was. `:not(.btn)` is the fix, and it means a button placed in the
   nav is simply a button. */
.nav a:not(.btn) {
  font-size: 14px; font-weight: 600; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--charcoal);
  padding: 6px 0; border-bottom: 3px solid transparent;
}
.nav a:not(.btn):hover { color: var(--blue-dark); border-bottom-color: var(--blue); text-decoration: none; }

/* A header button is the same button as everywhere else, at the medium size
   the rest of the application uses. It no longer needs geometry of its own:
   medium IS the size a header button should be. */

.nav-toggle {
  display: none; width: 44px; height: 44px;
  border: 1px solid var(--line); background: transparent;
  border-radius: var(--control-radius); cursor: pointer;
  align-items: center; justify-content: center;
}
.nav-toggle span { display: block; width: 20px; height: 2px; background: var(--charcoal); position: relative; }
.nav-toggle span::before,
.nav-toggle span::after { content: ""; position: absolute; left: 0; width: 20px; height: 2px; background: var(--charcoal); }
.nav-toggle span::before { top: -6px; }
.nav-toggle span::after  { top:  6px; }

/* --- hero ----------------------------------------------------------------- */

/* The hero image bleeds off the right edge of the viewport while the copy stays
   aligned to the shell grid - the kitchen shot is the lead image and needs the
   width to work. */
.hero {
  background: var(--charcoal-deep);
  color: var(--paper);
  position: relative; overflow: hidden;
}
.hero__inner {
  display: grid; grid-template-columns: 1fr 1fr;
  min-height: clamp(520px, 62vw, 680px);
}
.hero__copy {
  display: flex; align-items: center; justify-content: flex-end;
  padding: clamp(56px, 7vw, 88px) clamp(28px, 4vw, 64px) clamp(56px, 7vw, 88px) var(--gutter);
  position: relative; z-index: 1;
}
.hero__copy::after {
  content: ""; position: absolute; left: -20%; bottom: -40%;
  width: 90%; aspect-ratio: 1;
  background: radial-gradient(circle, rgba(0,154,218,.20), transparent 62%);
  pointer-events: none; z-index: -1;
}
.hero__copy-wrap { width: 100%; max-width: calc(var(--shell) / 2 - var(--gutter)); }

.hero h1 {
  font-size: clamp(36px, 4.4vw, 60px);
  margin: 0 0 24px;
}
.hero h1 em { font-style: normal; color: var(--blue); }
.hero__lede { color: var(--grey-light); font-size: clamp(16.5px, 1.4vw, 19px); max-width: 48ch; margin: 0 0 34px; }
.hero__actions { display: flex; flex-wrap: wrap; gap: 14px; }

.hero__figure { position: relative; }
.hero__figure img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center;
}
/* Soften the join so the photograph reads as part of the charcoal block
   rather than a pasted-on rectangle. */
.hero__figure::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, var(--charcoal-deep) 0%, rgba(38,36,37,.55) 12%, rgba(38,36,37,0) 38%);
  pointer-events: none;
}

.hero__spec {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 1px; background: rgba(255,255,255,.16);
  border-top: 1px solid rgba(255,255,255,.16);
  margin: clamp(36px, 4vw, 52px) 0 0;
}
.hero__spec > div { background: var(--charcoal-deep); padding: 22px 4px 24px; }
.hero__spec dt { font-size: 12px; letter-spacing: .16em; text-transform: uppercase; color: var(--grey); margin-bottom: 8px; }
.hero__spec dd { margin: 0; font-size: clamp(17px, 1.8vw, 22px); font-weight: 700; }

/* --- generic section ------------------------------------------------------ */

.section { padding: clamp(64px, 8vw, 110px) 0; }
.section--neutral { background: var(--neutral); }
.section--dark { background: var(--charcoal); color: var(--paper); }
.section--dark .lede { color: var(--grey-light); }

.section__head { max-width: 70ch; margin-bottom: clamp(40px, 5vw, 60px); }
.section__head .lede { margin-top: 20px; }

/* --- services ------------------------------------------------------------- */

.services { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }

.card {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 34px 30px 30px;
  display: flex; flex-direction: column;
  position: relative;
  transition: border-color .15s ease, transform .15s ease;
}
.card::after {
  content: ""; position: absolute; left: -1px; right: -1px; bottom: -1px;
  height: 4px; background: var(--blue);
  transform: scaleX(0); transform-origin: left;
  transition: transform .22s ease;
}
.card:hover { border-color: var(--grey-light); transform: translateY(-3px); }
.card:hover::after { transform: scaleX(1); }

.card__index {
  font-size: 12px; font-weight: 700; letter-spacing: .18em;
  color: var(--grey); margin-bottom: 16px;
}
.card h3 { font-size: 23px; margin-bottom: 16px; }
.card ul { list-style: none; margin: 0; padding: 0; }
.card li {
  font-size: 15.5px; color: var(--charcoal-soft);
  padding: 7px 0 7px 20px; position: relative;
  border-top: 1px solid var(--line);
}
.card li:first-child { border-top: 0; }
.card li::before {
  content: ""; position: absolute; left: 0; top: 16px;
  width: 8px; height: 2px; background: var(--blue);
}

/* laser engraving card - distinct capability, distinct weight */
.card--dark { background: var(--charcoal); border-color: var(--charcoal); color: var(--paper); }
.card--dark h3 { color: var(--paper); }
.card--dark .card__index { color: var(--blue); }
.card--dark li { color: var(--grey-light); border-top-color: rgba(255,255,255,.12); }
.card--dark:hover { border-color: var(--charcoal-soft); }
.card__note { margin: 20px 0 0; font-size: 14px; color: var(--grey-light); }
.card__note a { color: var(--blue); }

/* --- doors, panels & cabinetry showcase ----------------------------------- */

.showcase { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(28px, 4vw, 52px); }
.showcase__item { margin: 0; }
.showcase__item .frame { overflow: hidden; border-radius: var(--radius); }
.showcase__item img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  transition: transform .5s ease;
}
.showcase__item:hover img { transform: scale(1.03); }
.showcase__item figcaption { padding: 26px 2px 0; }
.showcase__item h3 {
  font-size: 23px; margin-bottom: 12px;
  padding-bottom: 14px; border-bottom: 3px solid var(--blue);
  display: inline-block;
}
.showcase__item p { margin: 0; color: var(--charcoal-soft); font-size: 16px; max-width: 46ch; }

/* --- capabilities --------------------------------------------------------- */

.cap__grid {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(32px, 5vw, 64px); align-items: start;
}
.cap__block h3 { font-size: 15px; letter-spacing: .1em; text-transform: uppercase; margin-bottom: 16px; }

.chips { display: flex; flex-wrap: wrap; gap: 8px; list-style: none; margin: 0; padding: 0; }
.chips li {
  font-size: 14px; font-weight: 500;
  padding: 8px 14px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.spec-strip {
  margin: 40px 0 0;
  border-left: 4px solid var(--blue);
  padding: 4px 0 4px 22px;
}
.spec-strip dl { margin: 0; }
.spec-strip dt { font-size: 12px; letter-spacing: .16em; text-transform: uppercase; color: var(--grey); }
.spec-strip dd { margin: 4px 0 0; font-size: 26px; font-weight: 800; }
.spec-strip__note { margin: 12px 0 0; font-size: 14.5px; color: var(--charcoal-soft); max-width: 46ch; }

/* --- laser engraving & marking -------------------------------------------- */

.laser__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }

.laser-panel {
  background: var(--neutral);
  border: 1px solid var(--line);
  border-top: 4px solid var(--blue);
  border-radius: var(--radius);
  overflow: hidden;
}
.laser-panel__media { background: var(--charcoal-deep); }
.laser-panel__media img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
}
.laser-panel__body { padding: 32px 32px 32px; }
.laser-panel__kicker {
  font-size: 12px; font-weight: 700; letter-spacing: .2em;
  text-transform: uppercase; color: var(--blue);
  margin: 0 0 10px;
}
.laser-panel h3 { font-size: clamp(22px, 2.4vw, 28px); margin-bottom: 10px; }
.laser-panel__machine {
  margin: 0; font-size: 14.5px; font-weight: 600;
  color: var(--grey); letter-spacing: .01em;
}

.laser-spec {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 1px; background: var(--line);
  border: 1px solid var(--line);
  margin: 26px 0 0;
}
.laser-spec > div { background: var(--paper); padding: 18px 18px 20px; }
.laser-spec--wide { grid-column: 1 / -1; }
.laser-spec dt {
  font-size: 11.5px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--grey); margin-bottom: 7px; line-height: 1.4;
}
.laser-spec dd { margin: 0; font-size: 20px; font-weight: 800; letter-spacing: -0.01em; }

.laser-panel__label {
  font-size: 12px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--charcoal); margin: 30px 0 14px;
}

.laser-list { list-style: none; margin: 0; padding: 0; }
.laser-list li {
  font-size: 15.5px; color: var(--charcoal-soft);
  padding: 7px 0 7px 20px; position: relative;
  border-top: 1px solid var(--line);
}
.laser-list li:first-child { border-top: 0; }
.laser-list li::before {
  content: ""; position: absolute; left: 0; top: 16px;
  width: 8px; height: 2px; background: var(--blue);
}

.laser-panel__caption {
  margin: 12px 0 0; font-size: 13.5px; color: var(--grey);
}

.laser-source {
  margin-top: 30px; padding-top: 26px;
  border-top: 2px solid var(--charcoal);
}
.laser-source__title {
  font-size: 18px; font-weight: 800; letter-spacing: -0.01em;
  color: var(--charcoal); margin: 0 0 4px;
}
.laser-source__for {
  margin: 0; font-size: 14.5px; color: var(--charcoal-soft);
}
.laser-source .laser-panel__label { margin-top: 22px; }

.laser-panel__note {
  margin: 26px 0 0; padding-left: 18px;
  border-left: 2px solid var(--grey-light);
  font-size: 14.5px; color: var(--charcoal-soft);
}

.laser__footnote {
  margin: 32px 0 0; padding: 22px 26px;
  background: var(--neutral);
  border: 1px solid var(--line);
  border-left: 4px solid var(--charcoal);
  border-radius: var(--radius);
  font-size: 15px; color: var(--charcoal-soft);
  max-width: 92ch;
}
.laser__footnote strong { color: var(--charcoal); }

/* --- laser example galleries ---------------------------------------------- */
/* One large preview per laser source, with a thumbnail row that swaps it.
   Works without JS: the preview and every thumbnail still render. */

.gal { margin: 22px 0 0; }

.gal__stage {
  margin: 0;
  background: var(--charcoal-deep);
  border: 1px solid var(--line);
  overflow: hidden;
}
.gal__main {
  display: block; width: 100%; height: auto;
  aspect-ratio: 4 / 3; object-fit: cover;
}

.gal__caption {
  margin: 10px 0 0;
  font-size: 13.5px; color: var(--grey);
}

.gal__thumbs {
  list-style: none; margin: 12px 0 0; padding: 0;
  display: grid; gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(66px, 1fr));
}

/* Three states, one geometry: a 2px outline at 2px offset.
   grey = "the thumbnail you are pointing at / navigating to"
   blue = "the thumbnail currently selected"
   Selection wins over BOTH hover and keyboard focus, so once a thumbnail is
   selected it stays solid blue - there is no combined focus-and-selected
   appearance. Grey answers "where am I", blue answers "what is chosen".

   Colours are measured against the panel background #F2F3F4 (--neutral):
   --grey-mid 3.60:1 and --blue-dark 3.95:1 both clear the 3:1 required of a
   non-text state indicator. Plain --grey (2.60:1) and --blue (2.85:1) were
   measured against the same background and rejected. */
.gal__thumb {
  display: block; width: 100%; padding: 0;
  background: var(--charcoal-deep);
  border: 1px solid var(--line);
  border-radius: 0;
  cursor: pointer;
  outline: 2px solid transparent;   /* reserve the geometry; no visible default */
  outline-offset: 2px;
  transition: outline-color .15s ease;
}
.gal__thumb img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 4 / 3; object-fit: cover;
  opacity: .6; transition: opacity .15s ease;
}
/* Hover and keyboard focus brighten identically. Both are (0,2,1), the same as
   the selected rule below, which is declared later and therefore wins with 1. */
.gal__thumb:hover img,
.gal__thumb:focus-visible img { opacity: .82; }

/* Hover and keyboard focus share one appearance. This overrides the site-wide
   blue focus ring for these controls only, so grey never reads as selected. */
.gal__thumb:hover,
.gal__thumb:focus-visible { outline-color: var(--grey-mid); }

/* Declared last: equal specificity to :hover and :focus-visible, so selection
   survives both. */
.gal__thumb[aria-pressed="true"] img { opacity: 1; }
.gal__thumb[aria-pressed="true"] { outline-color: var(--blue-dark); }

/* --- about ---------------------------------------------------------------- */

.about__grid { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(32px, 5vw, 72px); align-items: center; }
.about__stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px; background: rgba(255,255,255,.16); margin: 40px 0 0; }
.about__stats > div { background: var(--charcoal); padding: 24px 20px; }
.about__stats dt { font-size: 12px; letter-spacing: .16em; text-transform: uppercase; color: var(--grey); margin-bottom: 6px; }
.about__stats dd { margin: 0; font-size: 19px; font-weight: 700; }

/* --- contact -------------------------------------------------------------- */

.contact__grid { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(32px, 5vw, 64px); }
.contact__heading { font-size: 15px; letter-spacing: .1em; text-transform: uppercase; }

.contact__tiles { display: grid; gap: 14px; margin: 32px 0 0; }
.contact__tile {
  display: flex; flex-direction: column; gap: 4px;
  border: 1px solid var(--line); border-left: 4px solid var(--blue);
  border-radius: var(--radius); padding: 20px 24px;
  transition: background-color .15s ease;
}
a.contact__tile:hover { background: var(--blue-wash); text-decoration: none; }
.contact__label { font-size: 12px; letter-spacing: .16em; text-transform: uppercase; color: var(--grey); }
.contact__value { font-size: clamp(19px, 2vw, 24px); font-weight: 700; color: var(--charcoal); }
.contact__tile address { font-style: normal; font-size: 19px; font-weight: 600; color: var(--charcoal); line-height: 1.5; }

.quote-list { counter-reset: q; list-style: none; margin: 24px 0 0; padding: 0; }
.quote-list li {
  counter-increment: q;
  position: relative; padding: 14px 0 14px 44px;
  border-top: 1px solid var(--line);
  color: var(--charcoal-soft); font-size: 16px;
}
.quote-list li::before {
  content: counter(q, decimal-leading-zero);
  position: absolute; left: 0; top: 15px;
  font-size: 12px; font-weight: 700; letter-spacing: .1em; color: var(--blue);
}

/* --- footer --------------------------------------------------------------- */

.footer { background: var(--charcoal-deep); color: var(--grey-light); padding: clamp(52px, 6vw, 76px) 0 32px; font-size: 15px; }
.footer__grid { display: grid; grid-template-columns: 1.3fr 1fr 1fr; gap: clamp(28px, 4vw, 56px); }
.footer__logo {
  display: inline-block; background: var(--paper);
  padding: 14px 18px; border-radius: var(--radius); margin-bottom: 20px;
}
.footer__logo img { height: 38px; width: auto; }
.footer h4 { font-size: 12px; letter-spacing: .16em; text-transform: uppercase; color: var(--paper); margin-bottom: 16px; }
.footer ul { list-style: none; margin: 0; padding: 0; }
.footer li { padding: 5px 0; }
.footer a { color: var(--grey-light); }
.footer a:hover { color: var(--blue); }
.footer address { font-style: normal; line-height: 1.8; }
.footer__base {
  margin-top: 48px; padding-top: 24px;
  border-top: 1px solid rgba(255,255,255,.14);
  display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between;
  font-size: 13.5px; color: var(--grey);
}

/* --- responsive ----------------------------------------------------------- */

@media (max-width: 1000px) {
  .services { grid-template-columns: repeat(2, 1fr); }
  .footer__grid { grid-template-columns: 1fr 1fr; }
  .laser__grid { grid-template-columns: 1fr; }
  .showcase { grid-template-columns: 1fr; }
}

@media (max-width: 860px) {
  .header__bar { min-height: 72px; }
  .header__logo img { height: 34px; }
  .nav-toggle { display: flex; }

  .nav {
    position: absolute; left: 0; right: 0; top: 100%;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--paper);
    border-bottom: 1px solid var(--line);
    padding: 8px var(--gutter) 22px;
    display: none;
  }
  .nav[data-open="true"] { display: flex; }
  .nav a { padding: 15px 0; border-bottom: 1px solid var(--line); }
  .nav a:hover { border-bottom-color: var(--line); }
  .nav .btn { display: inline-flex; justify-content: center; margin-top: 18px; }

  .cap__grid,
  .about__grid,
  .contact__grid { grid-template-columns: 1fr; }

  /* Hero stacks: photograph on top, copy beneath, both full width. */
  .hero__inner { grid-template-columns: 1fr; min-height: 0; }
  .hero__copy {
    order: 2; justify-content: flex-start;
    padding: clamp(40px, 7vw, 64px) var(--gutter);
  }
  .hero__copy-wrap { max-width: none; }
  .hero__figure { order: 1; position: relative; height: clamp(240px, 52vw, 380px); }
  .hero__figure img { position: absolute; }
  .hero__figure::after {
    background: linear-gradient(0deg, var(--charcoal-deep) 0%, rgba(38,36,37,0) 42%);
  }
  .hero__spec { grid-template-columns: 1fr; }
}

@media (max-width: 620px) {
  body { font-size: 16px; }
  .services { grid-template-columns: 1fr; }
  .footer__grid { grid-template-columns: 1fr; }
  .about__stats { grid-template-columns: 1fr; }
  .laser-spec { grid-template-columns: 1fr; }
  .laser-panel__body { padding: 26px 22px; }
  .gal__thumbs { grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); }
  .showcase__item figcaption { padding-top: 20px; }
  .hero__actions .btn { flex: 1 1 100%; justify-content: center; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition: none !important; }
}

/* --------------------------------------------------------------------------
   Order portal entry links (AB step 3).

   The only stylesheet addition made by the /orders/ module on the permanent
   public site. It styles nothing that already existed: it applies solely to the
   new "Order routed doors online" and portal links, which render only while
   PORTAL_ENABLED is true and disappear with the module (C.7, RETIRE-2).
   -------------------------------------------------------------------------- */

.portal-cta { margin: 16px 0 0; font-weight: 700; }
.showcase__item .portal-cta { margin: 16px 0 0; }

/* --------------------------------------------------------------------------
   /orders/ portal entry page (Phase 0).

   Two additions, both scoped so nothing on the permanent public pages moves:
   the dark-section contrast correction matches no element in index.html (its
   only .spec-strip sits in a neutral section), and .portal-hero exists solely
   on the portal entry template.
   -------------------------------------------------------------------------- */

/* Supporting note under a spec strip on a dark background. The default
   --charcoal-soft is a dark-on-dark near-miss there; --grey-light is the same
   value .section--dark already gives .lede, so the dark sections stay
   consistent and the text is comfortably readable without going stark white. */
.section--dark .spec-strip__note { color: var(--grey-light); }

/* Introduction. Built like the home page hero rather than as a card dropped
   into a section: the image fills its half of the grid and bleeds to the
   viewport edge, and the same soft gradient join makes it read as part of the
   charcoal block instead of a pasted-on rectangle. The copy column keeps the
   heading, lede, both calls to action and the spec strip together. */
.portal-hero { position: relative; overflow: hidden; }
.portal-hero__inner {
  display: grid; grid-template-columns: 1fr 1fr;
  min-height: clamp(500px, 58vw, 640px);
}
.portal-hero__copy {
  display: flex; align-items: center; justify-content: flex-end;
  padding: clamp(56px, 7vw, 88px) clamp(28px, 4vw, 64px) clamp(56px, 7vw, 88px) var(--gutter);
  position: relative; z-index: 1;
}
.portal-hero__copy-wrap { width: 100%; max-width: calc(var(--shell) / 2 - var(--gutter)); }
.portal-hero__copy .section__head { margin-bottom: clamp(28px, 3vw, 38px); }

.portal-hero__figure { position: relative; margin: 0; }
.portal-hero__figure img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center;
}
/* The same join the home page hero uses, tuned to this section's --charcoal
   (#363435) rather than --charcoal-deep. */
.portal-hero__figure::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, var(--charcoal) 0%, rgba(54,52,53,.55) 12%, rgba(54,52,53,0) 38%);
  pointer-events: none;
}

@media (max-width: 860px) {
  /* Stacks copy first, image beneath - the reverse of the home page, because
     ORDER LOGIN and REQUEST AN ORDER LOGIN must stay at the top of this page.
     The join turns vertical so the image still blends upward into the block. */
  .portal-hero__inner { grid-template-columns: 1fr; min-height: 0; }
  .portal-hero__copy {
    justify-content: flex-start;
    padding: clamp(40px, 7vw, 64px) var(--gutter) clamp(32px, 5vw, 48px);
  }
  .portal-hero__copy-wrap { max-width: none; }
  .portal-hero__figure { height: clamp(240px, 52vw, 380px); }
  .portal-hero__figure::after {
    background: linear-gradient(180deg, var(--charcoal) 0%, rgba(54,52,53,0) 42%);
  }
}
